File size: 6,530 Bytes
ffca18d 018463a 3ebc508 1deacc5 76e5528 465bca7 3ebc508 223de58 14c0817 223de58 14c0817 1deacc5 223de58 018463a 223de58 018463a ffca18d 14c0817 3ebc508 568c572 3ebc508 ffca18d 018463a ec9b387 1deacc5 223de58 76e5528 223de58 76e5528 1d2d978 223de58 018463a ffca18d 223de58 76141c4 76e5528 ffca18d 76e5528 ffca18d 76e5528 ffca18d 3ebc508 ec9b387 3ebc508 223de58 018463a 263ee79 223de58 018463a 1d2d978 018463a ffca18d 1d2d978 76e5528 ffca18d 76e5528 ffca18d 76e5528 ffca18d 76e5528 ffca18d 1d2d978 018463a 223de58 018463a 223de58 018463a ffca18d 7192a9d 223de58 ffca18d 018463a ffca18d 018463a 3ebc508 ffca18d 018463a 14c0817 223de58 14c0817 223de58 ffca18d 76141c4 3ebc508 1deacc5 3ebc508 e81567c ec9b387 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# app.py - Flask Backend with Reliable Link Shortening
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 in the user's message, summarize it and say you've shortened it.
Example: "Here's your shortened link:" followed by [SHORTEN]original|short[/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
chat_sessions = {}
def convert_markdown_to_html(text):
html = markdown2.markdown(text, extras=["fenced-code-blocks", "tables"])
html = re.sub(r'<pre><code(.*?)>', r'<pre class="code-block"><code\1>', 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'<p><strong>π Original:</strong> <a href="{original_url}" target="_blank">{original_url}</a></p>' \
f'<p><strong>βοΈ Shortened:</strong> <a href="{short_url}" target="_blank">{short_url}</a></p>'
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"""
clean_text = re.sub(r'[^\w\s.,!?\-]', '', text)
if not clean_text.strip():
clean_text = "Hello, this is your AI assistant."
filename = f"audio_{uuid.uuid4()}.mp3"
filepath = os.path.join(AUDIO_FOLDER, filename)
try:
tts = gTTS(text=clean_text, lang='en', slow=False)
tts.save(filepath)
return filename
except Exception as e:
print("TTS Error:", str(e))
return None
def shorten_url_reliable(url):
"""Try multiple services to shorten URL"""
services = [
f"https://tinyurl.com/api-create.php?url={url}",
f"https://is.gd/create.php?format=simple&url={url}"
]
for service_url in services:
try:
response = requests.get(service_url, timeout=5)
if response.status_code == 200:
result = response.text.strip()
if result.startswith("http") and len(result) > 10:
return result
except Exception as e:
print(f"Shortener failed: {service_url} | Error: {e}")
continue
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]
# Always send to AI
response = chat_session.send_message(user_message)
full_text = response.text
# Force shortening if URL detected
url_match = re.search(r'https?://[^\s<>"{}|\\^`\[\]]+', user_message)
if url_match:
original_url = url_match.group(0)
short_url = shorten_url_reliable(original_url)
if short_url:
short_tag = f"[SHORTEN]{original_url}|{short_url}[/SHORTEN]"
if "[SHORTEN]" not in full_text:
full_text += f"\n\nHere's your shortened link:\n{short_tag}"
else:
full_text += "\n\nI found a link but couldn't shorten it right now."
# Process final 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 available
if audio_content:
audio_filename = generate_audio(audio_content)
if audio_filename:
result["audio_filename"] = audio_filename
result["has_audio"] = True
# Return with 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("Server Error:", str(e))
return jsonify({"error": "Failed to get response. Try again."}), 500
@app.route('/new-chat', methods=['POST'])
def new_chat():
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/<filename>')
def download_audio(filename):
try:
return send_from_directory(AUDIO_FOLDER, filename, as_attachment=True)
except FileNotFoundError:
return jsonify({"error": "Audio file not found"}), 404
@app.route('/')
def serve_index():
return send_from_directory('static', 'index.html')
@app.route('/<path:path>')
def serve_static(path):
return send_from_directory('static', path)
if __name__ == '__main__':
app.run(host="0.0.0.0", port=7860) |