Spaces:
Sleeping
Sleeping
File size: 4,281 Bytes
9b73f19 57db340 4677012 57db340 c13b073 fc3f34d d1693f1 fc3f34d 9b73f19 4677012 fc3f34d 57db340 fc3f34d 9b73f19 4677012 fc3f34d 9b73f19 fc3f34d 4677012 fc3f34d 9b73f19 fc3f34d 9b73f19 fc3f34d 9b73f19 fc3f34d 57db340 fc3f34d 9b73f19 fc3f34d c13b073 4677012 fc3f34d c13b073 4677012 9b73f19 c13b073 fc3f34d 4677012 fc3f34d 4677012 9b73f19 fc3f34d 9b73f19 c13b073 57db340 c13b073 57db340 c13b073 57db340 c13b073 57db340 | 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 | import os
import time
import tempfile
import warnings
import asyncio
import edge_tts
from transformers import pipeline
# -------------------------------------------------------------------------
# Speech-to-Text (STT): Whisper-small running locally on CPU
# - ~242MB model, good Hindi accuracy, no API dependency
# -------------------------------------------------------------------------
_stt_pipeline = None
def _get_stt_pipeline():
"""Lazily loads the Whisper-small pipeline (only once on first call)."""
global _stt_pipeline
if _stt_pipeline is None:
print("Loading Whisper-small model for STT (this takes ~30s on first run)...")
# Suppress the duplicate logits-processor warning that appears
# when language/task are passed alongside the model's own processor setup.
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore",
message="A custom logits processor of type",
category=UserWarning,
)
_stt_pipeline = pipeline(
task="automatic-speech-recognition",
model="openai/whisper-small",
device="cpu",
generate_kwargs={"language": "hindi", "task": "transcribe"},
)
print("Whisper-small ready.")
return _stt_pipeline
def speech_to_text(audio_filepath: str) -> str:
"""
Transcribes a Hindi audio recording into Hindi text (Devanagari).
Args:
audio_filepath: Path to the audio file (wav/mp3/webm/ogg).
Returns:
Transcribed Hindi string, or an error message beginning with 'Error:'.
"""
if not audio_filepath:
return ""
if not os.path.exists(audio_filepath):
return f"Error: audio file not found at {audio_filepath}"
try:
pipe = _get_stt_pipeline()
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore",
message="A custom logits processor of type",
category=UserWarning,
)
result = pipe(audio_filepath)
transcript = result.get("text", "").strip()
if not transcript:
return "Error: Could not transcribe audio - please speak clearly and try again."
return transcript
except Exception as exc:
print(f"[STT Error] {exc}")
return f"Error: Could not transcribe audio ({exc})"
# -------------------------------------------------------------------------
# Text-to-Speech (TTS): Edge-TTS – high-quality neural Hindi voice
# - Saves to /tmp/ so it works on read-only deployments like HF Spaces
# -------------------------------------------------------------------------
async def _async_tts(text: str, output_path: str):
"""Async helper to run the Edge TTS communication."""
communicate = edge_tts.Communicate(text, "hi-IN-SwaraNeural")
await communicate.save(output_path)
def text_to_speech(text: str) -> str | None:
"""
Converts Hindi text to a high-quality spoken MP3 file using edge-tts.
Saves into /tmp/ to ensure write access regardless of the deployment
environment (HF Spaces /app directory is read-only).
Args:
text: Hindi text in Devanagari.
Returns:
Absolute path to the saved MP3 file, or None on failure.
"""
if not text or text.startswith("Error:"):
return None
max_retries = 3
for attempt in range(max_retries):
try:
# Use a named temp file so Gradio can serve it correctly
tmp = tempfile.NamedTemporaryFile(
suffix=".mp3", delete=False, dir="/tmp"
)
output_path = tmp.name
tmp.close()
# Run the async edge-tts code synchronously
asyncio.run(_async_tts(text, output_path))
return output_path
except Exception as exc:
err = str(exc)
if "429" in err and attempt < max_retries - 1:
wait = 2 ** attempt
print(f"[TTS] Rate-limited, retrying in {wait}s... (attempt {attempt + 1}/{max_retries})")
time.sleep(wait)
else:
print(f"[TTS Error] {exc}")
return None
|