Athspi commited on
Commit
223de58
·
verified ·
1 Parent(s): afaed0f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -115
app.py CHANGED
@@ -12,158 +12,92 @@ import uuid
12
  # Load environment variables
13
  load_dotenv()
14
 
15
- # Define paths and create static audio directory if it doesn't exist
16
  AUDIO_FOLDER = os.path.join('static', 'audio')
17
- if not os.path.exists(AUDIO_FOLDER):
18
- os.makedirs(AUDIO_FOLDER)
19
 
20
- # Initialize Flask app
21
  app = Flask(__name__, static_folder='static')
22
- CORS(app) # Enable CORS for all routes
23
-
24
- # Configure Gemini with a system instruction
25
- system_instruction_text = """
26
- You are a friendly, natural-sounding AI assistant named Athspi.
27
- When responding:
28
- - Use a warm, conversational tone
29
- - Never mention technical terms like "audio", "text", or "response"
30
- - For stories, begin with "Here's your story 👇" followed by a friendly intro
31
- - For explanations, use simple, clear language
32
- - Format responses for pleasant reading and listening
33
- - When audio is requested, include story content between special markers as shown:
34
- [AUDIO_START]
35
- [story content here]
36
- [AUDIO_END]
37
- But DO NOT include these markers in the visible response
38
  """
39
 
40
  genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
41
- model = genai.GenerativeModel(
42
- 'gemini-2.5-flash',
43
- system_instruction=system_instruction_text
44
- )
45
 
46
  def convert_markdown_to_html(text):
47
  html = markdown2.markdown(text, extras=["fenced-code-blocks", "tables"])
48
  html = re.sub(r'<pre><code(.*?)>', r'<pre class="code-block"><code\1>', html)
49
- html = re.sub(r'\*\*(.*?)\*\*', r'<strong>\1</strong>', html)
50
- html = re.sub(r'\*(.*?)\*', r'<em>\1</em>', html)
51
  return html
52
 
 
 
 
 
 
 
 
53
  def detect_audio_request(text):
54
- """Detect if user is requesting audio"""
55
- audio_keywords = [
56
  'audio', 'speak', 'say it', 'read aloud',
57
  'hear', 'listen', 'tell me out loud'
58
  ]
59
- return any(keyword in text.lower() for keyword in audio_keywords)
60
-
61
- def extract_audio_content(full_text):
62
- """Extract audio-specific content between markers"""
63
- pattern = r'\[AUDIO_START\](.*?)\[AUDIO_END\]'
64
- match = re.search(pattern, full_text, re.DOTALL)
65
- if match:
66
- return match.group(1).strip()
67
- return full_text
68
-
69
- def clean_visible_response(full_text):
70
- """Remove audio markers from visible response"""
71
- return re.sub(r'\[AUDIO_(START|END)\]', '', full_text).strip()
72
-
73
- def generate_audio_file(text):
74
- """Generate audio file from text and return filename"""
75
- cleaned_text = re.sub(r'[\*_`#]', '', text)
76
- cleaned_text = re.sub(r'\s+', ' ', cleaned_text).strip()
77
-
78
- if not cleaned_text:
79
- return None
80
 
81
- filename = f"{uuid.uuid4()}.mp3"
 
 
 
82
  filepath = os.path.join(AUDIO_FOLDER, filename)
83
-
84
- tts = gTTS(text=cleaned_text, lang='en', slow=False)
85
  tts.save(filepath)
86
-
87
  return filename
88
 
89
  @app.route('/chat', methods=['POST'])
90
  def chat():
91
  try:
92
  data = request.json
93
- user_message = data.get('message')
94
 
95
  if not user_message:
96
- return jsonify({"error": "No message provided"}), 400
97
-
98
- # Detect if user is requesting audio
99
  audio_requested = detect_audio_request(user_message)
100
-
101
- # Add instruction for audio markers if requested
102
- if audio_requested:
103
- user_message += "\n\nPlease include [AUDIO_START] and [AUDIO_END] markers around the story content."
104
-
105
  response = model.generate_content(user_message)
106
- full_response = response.text
107
 
108
- # Clean visible response by removing audio markers
109
- visible_response = clean_visible_response(full_response)
 
 
 
110
 
111
- # Generate audio if requested
112
- audio_url = None
113
- if audio_requested:
114
- # Extract audio-specific content
115
- audio_content = extract_audio_content(full_response)
116
- if not audio_content:
117
- audio_content = visible_response
118
-
119
- # Generate audio file
120
- audio_filename = generate_audio_file(audio_content)
121
- if audio_filename:
122
- audio_url = f"/static/audio/{audio_filename}"
123
 
124
- html_response = convert_markdown_to_html(visible_response)
125
-
126
- return jsonify({
127
- "response_html": html_response,
128
- "response_text": visible_response,
129
- "audio_url": audio_url
130
- })
131
 
132
  except Exception as e:
133
- app.logger.error(f"Chat Error: {e}")
134
  return jsonify({"error": str(e)}), 500
135
 
136
- @app.route('/generate-audio', methods=['POST'])
137
- def generate_audio():
138
  try:
139
- data = request.json
140
- text_to_speak = data.get('text')
141
-
142
- if not text_to_speak:
143
- return jsonify({"error": "No text provided"}), 400
144
-
145
- cleaned_text = re.sub(r'[\*_`#]', '', text_to_speak)
146
- cleaned_text = re.sub(r'\s+', ' ', cleaned_text).strip()
147
-
148
- if not cleaned_text:
149
- return jsonify({"error": "Text became empty after cleaning"}), 400
150
-
151
- filename = f"{uuid.uuid4()}.mp3"
152
- filepath = os.path.join(AUDIO_FOLDER, filename)
153
-
154
- tts = gTTS(text=cleaned_text, lang='en', slow=False)
155
- tts.save(filepath)
156
-
157
- audio_url = f"/static/audio/{filename}"
158
- return jsonify({"audio_url": audio_url})
159
-
160
- except Exception as e:
161
- app.logger.error(f"Audio Generation Error: {e}")
162
- return jsonify({"error": str(e)}), 500
163
-
164
- @app.route('/static/audio/<filename>')
165
- def serve_audio(filename):
166
- return send_from_directory(AUDIO_FOLDER, filename)
167
 
168
  @app.route('/')
169
  def serve_index():
 
12
  # Load environment variables
13
  load_dotenv()
14
 
15
+ # Configure paths
16
  AUDIO_FOLDER = os.path.join('static', 'audio')
17
+ os.makedirs(AUDIO_FOLDER, exist_ok=True)
 
18
 
 
19
  app = Flask(__name__, static_folder='static')
20
+ CORS(app)
21
+
22
+ # AI Configuration
23
+ system_instruction = """
24
+ You are a helpful AI assistant named Athspi. When responding:
25
+ 1. Never mention "audio" or technical terms
26
+ 2. For audio responses, include content between these markers only:
27
+ [AUDIO]content here[/AUDIO]
28
+ 3. Keep responses natural and friendly
29
+ 4. Always respond in a conversational tone
30
+ Example good response:
31
+ Here's your story!
32
+ [AUDIO]Once upon a time...[/AUDIO]
 
 
 
33
  """
34
 
35
  genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
36
+ model = genai.GenerativeModel('gemini-1.5-pro', system_instruction=system_instruction)
 
 
 
37
 
38
  def convert_markdown_to_html(text):
39
  html = markdown2.markdown(text, extras=["fenced-code-blocks", "tables"])
40
  html = re.sub(r'<pre><code(.*?)>', r'<pre class="code-block"><code\1>', html)
 
 
41
  return html
42
 
43
+ def process_response(full_response):
44
+ """Extract visible text and audio content"""
45
+ audio_match = re.search(r'\[AUDIO\](.*?)\[/AUDIO\]', full_response, re.DOTALL)
46
+ audio_content = audio_match.group(1).strip() if audio_match else None
47
+ visible_text = re.sub(r'\[/?AUDIO\]', '', full_response).strip()
48
+ return visible_text, audio_content
49
+
50
  def detect_audio_request(text):
51
+ audio_triggers = [
 
52
  'audio', 'speak', 'say it', 'read aloud',
53
  'hear', 'listen', 'tell me out loud'
54
  ]
55
+ return any(trigger in text.lower() for trigger in audio_triggers)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
+ def generate_audio(text):
58
+ """Generate audio file from text"""
59
+ text = re.sub(r'[^\w\s.,!?\-]', '', text)
60
+ filename = f"audio_{uuid.uuid4()}.mp3"
61
  filepath = os.path.join(AUDIO_FOLDER, filename)
62
+ tts = gTTS(text=text, lang='en', slow=False)
 
63
  tts.save(filepath)
 
64
  return filename
65
 
66
  @app.route('/chat', methods=['POST'])
67
  def chat():
68
  try:
69
  data = request.json
70
+ user_message = data.get('message', '').strip()
71
 
72
  if not user_message:
73
+ return jsonify({"error": "Message required"}), 400
74
+
 
75
  audio_requested = detect_audio_request(user_message)
 
 
 
 
 
76
  response = model.generate_content(user_message)
77
+ visible_text, audio_content = process_response(response.text)
78
 
79
+ result = {
80
+ "response_text": visible_text,
81
+ "response_html": convert_markdown_to_html(visible_text),
82
+ "has_audio": False
83
+ }
84
 
85
+ if audio_requested and audio_content:
86
+ audio_filename = generate_audio(audio_content)
87
+ result["audio_filename"] = audio_filename
88
+ result["has_audio"] = True
 
 
 
 
 
 
 
 
89
 
90
+ return jsonify(result)
 
 
 
 
 
 
91
 
92
  except Exception as e:
 
93
  return jsonify({"error": str(e)}), 500
94
 
95
+ @app.route('/download/<filename>')
96
+ def download_audio(filename):
97
  try:
98
+ return send_from_directory(AUDIO_FOLDER, filename, as_attachment=True)
99
+ except FileNotFoundError:
100
+ return jsonify({"error": "Audio file not found"}), 404
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
 
102
  @app.route('/')
103
  def serve_index():