Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
Update app.py
Browse files
app.py
CHANGED
@@ -328,6 +328,73 @@ def create_file(prompt, response, file_type="md"):
|
|
328 |
f.write(prompt + "\n\n" + response)
|
329 |
return filename
|
330 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
331 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
332 |
# 4. OPTIMIZED AUDIO GENERATION (ASYNC TTS + CACHING)
|
333 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
328 |
f.write(prompt + "\n\n" + response)
|
329 |
return filename
|
330 |
|
331 |
+
|
332 |
+
|
333 |
+
def get_download_link(file, file_type="zip"):
|
334 |
+
"""
|
335 |
+
Convert a file to base64 and return an HTML link for download.
|
336 |
+
"""
|
337 |
+
with open(file, "rb") as f:
|
338 |
+
b64 = base64.b64encode(f.read()).decode()
|
339 |
+
if file_type == "zip":
|
340 |
+
return f'<a href="data:application/zip;base64,{b64}" download="{os.path.basename(file)}">π Download {os.path.basename(file)}</a>'
|
341 |
+
elif file_type == "mp3":
|
342 |
+
return f'<a href="data:audio/mpeg;base64,{b64}" download="{os.path.basename(file)}">π΅ Download {os.path.basename(file)}</a>'
|
343 |
+
elif file_type == "wav":
|
344 |
+
return f'<a href="data:audio/wav;base64,{b64}" download="{os.path.basename(file)}">π Download {os.path.basename(file)}</a>'
|
345 |
+
elif file_type == "md":
|
346 |
+
return f'<a href="data:text/markdown;base64,{b64}" download="{os.path.basename(file)}">π Download {os.path.basename(file)}</a>'
|
347 |
+
else:
|
348 |
+
return f'<a href="data:application/octet-stream;base64,{b64}" download="{os.path.basename(file)}">Download {os.path.basename(file)}</a>'
|
349 |
+
|
350 |
+
def clean_for_speech(text: str) -> str:
|
351 |
+
"""Clean up text for TTS output."""
|
352 |
+
text = text.replace("\n", " ")
|
353 |
+
text = text.replace("</s>", " ")
|
354 |
+
text = text.replace("#", "")
|
355 |
+
text = re.sub(r"\(https?:\/\/[^\)]+\)", "", text)
|
356 |
+
text = re.sub(r"\s+", " ", text).strip()
|
357 |
+
return text
|
358 |
+
|
359 |
+
async def edge_tts_generate_audio(text, voice="en-US-AriaNeural", rate=0, pitch=0, file_format="mp3"):
|
360 |
+
"""Async TTS generation with edge-tts library."""
|
361 |
+
text = clean_for_speech(text)
|
362 |
+
if not text.strip():
|
363 |
+
return None
|
364 |
+
rate_str = f"{rate:+d}%"
|
365 |
+
pitch_str = f"{pitch:+d}Hz"
|
366 |
+
communicate = edge_tts.Communicate(text, voice, rate=rate_str, pitch=pitch_str)
|
367 |
+
out_fn = generate_filename(text, text, file_type=file_format)
|
368 |
+
await communicate.save(out_fn)
|
369 |
+
return out_fn
|
370 |
+
|
371 |
+
def speak_with_edge_tts(text, voice="en-US-AriaNeural", rate=0, pitch=0, file_format="mp3"):
|
372 |
+
"""Wrapper for the async TTS generate call."""
|
373 |
+
return asyncio.run(edge_tts_generate_audio(text, voice, rate, pitch, file_format))
|
374 |
+
|
375 |
+
def play_and_download_audio(file_path, file_type="mp3"):
|
376 |
+
"""Streamlit audio + a quick download link."""
|
377 |
+
if file_path and os.path.exists(file_path):
|
378 |
+
st.audio(file_path)
|
379 |
+
dl_link = get_download_link(file_path, file_type=file_type)
|
380 |
+
st.markdown(dl_link, unsafe_allow_html=True)
|
381 |
+
|
382 |
+
def save_qa_with_audio(question, answer, voice=None):
|
383 |
+
"""Save Q&A to markdown and also generate audio."""
|
384 |
+
if not voice:
|
385 |
+
voice = st.session_state['tts_voice']
|
386 |
+
|
387 |
+
combined_text = f"# Question\n{question}\n\n# Answer\n{answer}"
|
388 |
+
md_file = create_file(question, answer, "md")
|
389 |
+
audio_text = f"{question}\n\nAnswer: {answer}"
|
390 |
+
audio_file = speak_with_edge_tts(
|
391 |
+
audio_text,
|
392 |
+
voice=voice,
|
393 |
+
file_format=st.session_state['audio_format']
|
394 |
+
)
|
395 |
+
return md_file, audio_file
|
396 |
+
|
397 |
+
|
398 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
399 |
# 4. OPTIMIZED AUDIO GENERATION (ASYNC TTS + CACHING)
|
400 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|