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)