# app.py - Complete AI Chat with Memory + Auto Link Shortening + Audio from flask import Flask, request, jsonify, send_from_directory, make_response import google.generativeai as genai from dotenv import load_dotenv import os from flask_cors import CORS import markdown2 import re import requests from gtts import gTTS import uuid # Load environment variables load_dotenv() # Configure paths AUDIO_FOLDER = os.path.join('static', 'audio') os.makedirs(AUDIO_FOLDER, exist_ok=True) app = Flask(__name__, static_folder='static') CORS(app) # AI Configuration system_instruction = """ You are a helpful AI assistant named Athspi. When responding: 1. Never mention "audio" or technical terms 2. For responses that would benefit from audio (like stories, explanations, or content meant to be heard), include the audio version between these markers: [AUDIO]content here[/AUDIO] 3. Keep responses natural and friendly 4. Decide automatically when to include audio based on the content type 5. For stories, always include audio version 6. If a URL is present in the user's message, respond with: [SHORTEN]original_url|short_url[/SHORTEN] Example: I've shortened your link for convenience: [SHORTEN]https://example.com|https://tinyurl.com/abc123[/SHORTEN] """ genai.configure(api_key=os.getenv("GEMINI_API_KEY")) model = genai.GenerativeModel('gemini-2.5-flash', system_instruction=system_instruction) # In-memory session storage (use Redis in production) chat_sessions = {} def convert_markdown_to_html(text): html = markdown2.markdown(text, extras=["fenced-code-blocks", "tables"]) html = re.sub(r'
', r'
', html)
    return html

def process_response(full_response):
    """Extract visible text, audio content, and short links"""
    audio_match = re.search(r'\[AUDIO\](.*?)\[/AUDIO\]', full_response, re.DOTALL)
    audio_content = audio_match.group(1).strip() if audio_match else None
    visible_text = re.sub(r'\[/?AUDIO\]', '', full_response)

    short_link_match = re.search(r'\[SHORTEN\](.*?)\|([^|]*?)\[/SHORTEN\]', visible_text, re.DOTALL)
    if short_link_match:
        original_url = short_link_match.group(1).strip()
        short_url = short_link_match.group(2).strip()
        link_html = f'

🔗 Original: {original_url}

' \ f'

✂️ Shortened: {short_url}

' visible_text = re.sub(r'\[SHORTEN\].*?\[/SHORTEN\]', link_html, visible_text) return visible_text, audio_content def generate_audio(text): """Generate audio file from text""" text = re.sub(r'[^\w\s.,!?\-]', '', text) filename = f"audio_{uuid.uuid4()}.mp3" filepath = os.path.join(AUDIO_FOLDER, filename) tts = gTTS(text=text, lang='en', slow=False) tts.save(filepath) return filename def shorten_url_with_tinyurl(url): """Shorten URL using TinyURL public API""" try: response = requests.get(f"http://tinyurl.com/api-create.php?url={url}") if response.status_code == 200 and response.text.strip(): return response.text.strip() return None except Exception as e: print("TinyURL error:", e) return None @app.route('/chat', methods=['POST']) def chat(): try: data = request.json user_message = data.get('message', '').strip() session_id = request.cookies.get('session_id') or str(uuid.uuid4()) if not user_message: return jsonify({"error": "Message required"}), 400 # Get or create chat session if session_id not in chat_sessions: chat_sessions[session_id] = model.start_chat(history=[]) chat_session = chat_sessions[session_id] # Send message to AI response = chat_session.send_message(user_message) full_text = response.text # Auto-detect any URL and shorten it url_match = re.search(r'https?://[^\s<>"{}|\\^`\[\]]+', user_message) if url_match: original_url = url_match.group(0) short_url = shorten_url_with_tinyurl(original_url) if short_url and "[SHORTEN]" not in full_text: short_tag = f"[SHORTEN]{original_url}|{short_url}[/SHORTEN]" full_text += f"\n\n{short_tag}" # Process response visible_text, audio_content = process_response(full_text) html_response = convert_markdown_to_html(visible_text) result = { "response_html": html_response, "has_audio": False } # Generate audio if needed if audio_content: audio_filename = generate_audio(audio_content) result["audio_filename"] = audio_filename result["has_audio"] = True # Return response + set session cookie resp = make_response(jsonify(result)) resp.set_cookie('session_id', session_id, max_age=3600, httponly=True, samesite='Lax') return resp except Exception as e: print("Error:", str(e)) return jsonify({"error": "Something went wrong."}), 500 @app.route('/new-chat', methods=['POST']) def new_chat(): """Reset chat memory""" session_id = str(uuid.uuid4()) resp = make_response(jsonify({"status": "new chat started"})) resp.set_cookie('session_id', session_id, max_age=3600, httponly=True, samesite='Lax') return resp @app.route('/download/') def download_audio(filename): try: return send_from_directory(AUDIO_FOLDER, filename, as_attachment=True) except FileNotFoundError: return jsonify({"error": "File not found"}), 404 @app.route('/') def serve_index(): return send_from_directory('static', 'index.html') @app.route('/') def serve_static(path): return send_from_directory('static', path) if __name__ == '__main__': app.run(host="0.0.0.0", port=7860)