Skip to content

Instantly share code, notes, and snippets.

@JupyterJones
Created June 27, 2025 06:42
Show Gist options
  • Save JupyterJones/ca089b196a0695e8f84bc4008c76e352 to your computer and use it in GitHub Desktop.
Save JupyterJones/ca089b196a0695e8f84bc4008c76e352 to your computer and use it in GitHub Desktop.
Voice Code by Phone
import os
import sqlite3
import re
import time
import uuid
import glob
from flask import Flask, render_template_string, request, url_for, session
from werkzeug.utils import secure_filename
from typing import Union
# --- LLM and Vector DB Imports ---
import google.generativeai as genai
import chromadb
from chromadb.utils import embedding_functions
# ==============================================================================
# 1. CONFIGURATION
# ==============================================================================
app = Flask(__name__)
app.secret_key = os.urandom(24)
# --- Gemini API Configuration ---
#GEMINI_API_KEY = "PASTE_YOUR_GEMINI_API_KEY_HERE"
GEMINI_API_KEY = "AIzaSyAkMjjLbLx37JWwmAGE8uLiyyyz0QnIqW0"
# --- Database & File Path Configurations ---
CHROMA_PATH = "./chroma_db"
CHROMA_COLLECTION = "code_talk_collection"
SQLITE_PATH = 'code_talk_database.db'
SAVE_CODE_PATH = 'saved_code'
# --- Static Prompt for the AI ---
STATIC_PROMPT = """You are a web designer specializing in css and JavaScript animation effects and html games. You enjoy code conversations as well as providing code examples.
When asked for code, provide a single, complete, and runnable HTML file that includes all necessary HTML, CSS (in a <style> tag), and JavaScript (in a <script> tag).
Do not explain the code in the same response as the code block. First provide the code block, then explain it in a separate message if asked.
The code should be enclosed in a single markdown block like this: ```html ... ```
"""
# ==============================================================================
# 2. DATABASE AND MODEL SETUP
# ==============================================================================
try:
if "PASTE_YOUR" in GEMINI_API_KEY:
print("WARNING: Gemini API key is a placeholder.")
GENERATION_MODEL = None
else:
genai.configure(api_key=GEMINI_API_KEY)
GENERATION_MODEL = genai.GenerativeModel(model_name="gemini-1.5-flash-latest")
except Exception as e:
print(f"Error configuring Gemini: {e}")
GENERATION_MODEL = None
def init_sqlite_db():
with sqlite3.connect(SQLITE_PATH) as conn:
cursor = conn.cursor()
cursor.execute('''CREATE TABLE IF NOT EXISTS stories (id INTEGER PRIMARY KEY, story_content TEXT NOT NULL)''')
conn.commit()
try:
embedding_func = embedding_functions.SentenceTransformerEmbeddingFunction(model_name="all-mpnet-base-v2")
chroma_client = chromadb.PersistentClient(path=CHROMA_PATH)
KNOWLEDGE_COLLECTION = chroma_client.get_collection(name=CHROMA_COLLECTION, embedding_function=embedding_func)
print("Successfully connected to ChromaDB collection.")
except Exception as e:
print("="*50, "\n!!! CRITICAL ERROR: Could not connect to ChromaDB. !!!", f"\nError details: {e}\n", "="*50)
KNOWLEDGE_COLLECTION = None
init_sqlite_db()
os.makedirs(SAVE_CODE_PATH, exist_ok=True)
os.makedirs(os.path.join('static', 'preview'), exist_ok=True)
# ==============================================================================
# 3. HELPER FUNCTIONS
# ==============================================================================
def extract_and_prepare_code_for_preview(ai_response_text: str) -> Union[str, None]:
"""Extracts code, saves it to a NEW unique file, and returns the new filename."""
code_blocks = re.findall(r'```(?:html)?\s*(.*?)\s*```', ai_response_text, re.DOTALL)
if not code_blocks: return None
full_code = max(code_blocks, key=len)
unique_filename = f"{uuid.uuid4()}.html"
preview_filepath = os.path.join('static', 'preview', unique_filename)
if not full_code.strip().lower().startswith('<!doctype html>'):
style_match = re.search(r'<style>(.*?)</style>', full_code, re.DOTALL)
script_match = re.search(r'<script>(.*?)</script>', full_code, re.DOTALL)
css_part = style_match.group(1) if style_match else ""
js_part = script_match.group(1) if script_match else ""
html_part = re.sub(r'<style>.*?</style>|<script>.*?</script>', '', full_code, flags=re.DOTALL)
full_code = f"""<!DOCTYPE html><html lang="en"><head><title>Live Preview</title><style>{css_part}</style></head><body>{html_part}<script>{js_part}</script></body></html>"""
with open(preview_filepath, 'w', encoding='utf-8') as f: f.write(full_code)
return unique_filename
# ==============================================================================
# 4. FLASK WEB APPLICATION
# ==============================================================================
HTML_TEMPLATE = '''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Code Talk</title>
<style>
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; background-color: #121212; color: #e0e0e0; margin: 0; padding: 1em; display: flex; flex-direction: column; height: 100vh; box-sizing: border-box; }
.container { display: flex; flex: 1; gap: 1em; overflow: hidden; }
.controls-column { flex: 1; display: flex; flex-direction: column; gap: 1em; min-width: 350px; overflow-y: auto; padding-right: 10px; }
.preview-column { flex: 1.5; display: flex; flex-direction: column; background-color: #1e1e1e; border-radius: 8px; overflow: hidden; }
.preview-header { padding: 10px; background-color: #2c2c2c; color: #bb86fc; font-weight: bold; }
iframe { flex: 1; width: 100%; height: 100%; border: none; }
h1, h2 { color: #bb86fc; }
h2 { margin-top: 0; font-size: 1.2em; }
form { background-color: #1e1e1e; padding: 20px; border-radius: 8px; box-shadow: 0 0 15px rgba(0,0,0,0.5); display: flex; flex-direction: column; }
label { display: block; margin-bottom: 5px; color: #a0a0a0; font-weight: bold; }
textarea, input[type="text"] { width: calc(100% - 22px); padding: 10px; margin-bottom: 15px; border: 1px solid #333; border-radius: 4px; background-color: #2c2c2c; color: #e0e0e0; font-size: 14px; resize: vertical; }
textarea[readonly] { background-color: #252525; color: #999; }
input[type="submit"], button { background-color: #03dac6; color: #121212; padding: 12px 20px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; font-weight: bold; transition: background-color 0.3s; margin-top: 5px; }
input[type="submit"]:hover, button:hover { background-color: #37ebde; }
button { background-color: #444; color: #eee; }
button:hover { background-color: #555; }
.message { padding: 15px; margin-bottom: 1em; border-radius: 4px; }
.message.success { background-color: #1e4620; color: #a7d7a9; border: 1px solid #3c8c40; }
.message.error { background-color: #4a1c1c; color: #f8baba; border: 1px solid #cf6679; }
.file-list { list-style-type: none; padding: 0; }
.file-list li a { color: #8ab4f8; text-decoration: none; display: block; padding: 4px 0; }
.file-list li a:hover { text-decoration: underline; }
@media (max-width: 800px) { .container { flex-direction: column; } .controls-column, .preview-column { min-height: 50vh; overflow-y: visible; } }
</style>
<script>
function clearTextArea() {
document.getElementById("user_input").value = "";
}
</script>
</head>
<body>
<h1>AI Code Talk</h1>
{% if error %}<div class="message error"><strong>Chat Error:</strong> {{ error }}</div>{% endif %}
{% if message %}<div class="message success">{{ message }}</div>{% endif %}
{% if save_message %}<div class="message success">{{ save_message }}</div>{% endif %}
{% if save_error %}<div class="message error"><strong>Save Error:</strong> {{ save_error }}</div>{% endif %}
<div class="container">
<div class="controls-column">
<!-- CHAT FORM -->
<form method="POST">
<h2>1. Chat with the AI</h2>
<input type="hidden" name="action" value="chat">
<label for="user_input">Your Question or Idea:</label>
<textarea name="user_input" id="user_input" rows="3">{{ user_input }}</textarea>
<input type="submit" value="Send to AI">
<button type="button" onclick="clearTextArea()">Clear Input</button>
<label for="retrieved_context">Retrieved Context:</label>
<textarea name="retrieved_context" id="retrieved_context" rows="4" readonly>{{ retrieved_context }}</textarea>
<label for="story_content">Conversation History:</label>
<textarea name="story_content" id="story_content" rows="10" readonly>{{ story_content }}</textarea>
</form>
<!-- SAVE CODE FORM -->
<form method="POST">
<h2>2. Save Code to File</h2>
<input type="hidden" name="action" value="save_code">
<label for="filename">Filename:</label>
<input type="text" name="filename" id="filename" required>
<label for="code_to_save">Code / Text to Save:</label>
<textarea name="code_to_save" id="code_to_save" rows="8"></textarea>
<input type="submit" value="Save File">
</form>
<div class="saved-previews">
<h2>3. Saved Previews</h2>
{% if files %}
<ul class="file-list">
{% for file in files %}
<li>
<!-- <<<--- THIS IS THE FIX: The template logic is now much simpler. ---<<< -->
<a href="{{ url_for('static', filename='preview/' + file) }}" target="_blank">
{{ file }}
</a>
</li>
{% endfor %}
</ul>
{% else %}
<p>No previews generated yet.</p>
{% endif %}
</div>
</div>
<div class="preview-column">
<div class="preview-header">Live Preview</div>
{% if preview_url %}
<iframe src="{{ preview_url }}"></iframe>
{% else %}
<div style="padding: 20px; color: #888;">AI-generated previews will appear here.</div>
{% endif %}
</div>
</div>
</body>
</html>
'''
@app.route("/", methods=["GET", "POST"])
def index():
# Initialize all variables to be passed to the template
story_content, user_input, retrieved_context, message, error, save_message, save_error, preview_url = "", "", "", None, None, None, None, None
retrieved_context = "Context from your knowledge base will appear here..."
if "PASTE_YOUR" in GEMINI_API_KEY or not GENERATION_MODEL or not KNOWLEDGE_COLLECTION:
error = "A critical component (API Key, Gemini, or ChromaDB) failed to initialize. Check console."
# Still get files to display on the error page
files = [os.path.basename(f) for f in glob.glob(os.path.join('static', 'preview', '*.html'))]
return render_template_string(HTML_TEMPLATE, **locals())
with sqlite3.connect(SQLITE_PATH) as conn:
cursor = conn.cursor()
if request.method == "POST":
story_content, user_input = request.form.get("story_content", ""), request.form.get("user_input", "")
action = request.form.get("action")
if action == 'save_code':
code_to_save, filename = request.form.get('code_to_save'), request.form.get('filename')
if filename and code_to_save:
safe_filename = secure_filename(filename)
if safe_filename:
with open(os.path.join(SAVE_CODE_PATH, safe_filename), 'w', encoding='utf-8') as f:
f.write(code_to_save)
save_message = f"Saved to '{safe_filename}'."
else: save_error = "Invalid filename."
else: save_error = "Filename and content are required."
elif action == 'chat':
if user_input.strip():
try:
results = KNOWLEDGE_COLLECTION.query(query_texts=[user_input], n_results=3)
retrieved_docs = results.get('documents', [[]])[0]
if retrieved_docs: retrieved_context = "--- CONTEXT ---\n" + "\n\n---\n\n".join(retrieved_docs)
full_prompt = f"{STATIC_PROMPT}\n\nCONTEXT:\n{retrieved_context}\n\nHISTORY:\n{story_content}\n\nUSER:\n{user_input}\n\nAI:"
response = GENERATION_MODEL.generate_content(full_prompt)
new_story_part = response.text
story_content += f"\n\n>> USER: {user_input}\n\n>> AI:\n{new_story_part}"
cursor.execute("INSERT INTO stories (story_content) VALUES (?)", (story_content,))
conn.commit()
message = "Conversation continued."
new_preview_filename = extract_and_prepare_code_for_preview(new_story_part)
if new_preview_filename: session['preview_file'] = new_preview_filename
except Exception as e:
error = f"Generation error: {e}"
print(f"Detailed Error: {e}")
else: error = "Please provide some input."
if request.method == "GET":
cursor.execute("SELECT story_content FROM stories ORDER BY id DESC LIMIT 1")
result = cursor.fetchone()
if result: story_content = result[0]
# <<<--- THIS IS THE FIX: Process the file paths in Python, not the template. ---<<<
full_file_paths = glob.glob(os.path.join('static', 'preview', '*.html'))
# Sort files by modification time (newest first)
full_file_paths.sort(key=os.path.getmtime, reverse=True)
# Get just the filename for the template
files = [os.path.basename(f) for f in full_file_paths]
if 'preview_file' in session:
session_file_path = os.path.join('static', 'preview', session['preview_file'])
if os.path.exists(session_file_path):
preview_url = url_for('static', filename=f"preview/{session['preview_file']}") + f'?t={time.time()}'
return render_template_string(HTML_TEMPLATE, **locals())
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5100, debug=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment