Spaces:
Sleeping
Sleeping
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 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|