chore(audio): generate Vietnamese clips for both voices

- Run scripts/generate-audio.py to produce 184 MP3 clips (92 each
  for vi-VN-HoaiMyNeural and vi-VN-NamMinhNeural), ~2.2 MB total.
- Cap edge-tts concurrency at 4 with 4-attempt exponential retry on
  NoAudioReceived — earlier all-at-once gather() hit the upstream
  rate limit and bailed mid-voice.
- .gitignore: add .venv/ + __pycache__/ for the local generator venv.
This commit is contained in:
tiennm99 committed 2026-04-27 09:11:13 +07:00
1 parent 69edd30529
commit bc0622a0dd
187 files changed
+32 -3

No files matched your search

+29 -2
View File
@@ -57,10 +57,37 @@ def display_label(short_name: str, gender: str) -> str:
return f"{given} ({gender_vi})"
# Microsoft's TTS endpoint rate-limits aggressive concurrency and
# occasionally returns empty streams. Cap parallelism + retry transient
# failures so one voice run doesn't bail halfway through.
CONCURRENCY = 4
MAX_RETRIES = 4
RETRY_BACKOFF_SEC = 1.5
_sem: asyncio.Semaphore | None = None
def _semaphore() -> asyncio.Semaphore:
global _sem
if _sem is None:
_sem = asyncio.Semaphore(CONCURRENCY)
return _sem
async def synth(text: str, voice: str, out: str) -> None:
import edge_tts
await edge_tts.Communicate(text, voice).save(out)
print(f" {out} ← \"{text}\"")
from edge_tts.exceptions import NoAudioReceived
async with _semaphore():
for attempt in range(1, MAX_RETRIES + 1):
try:
await edge_tts.Communicate(text, voice).save(out)
print(f" {out} ← \"{text}\"")
return
except NoAudioReceived:
if attempt == MAX_RETRIES:
raise
await asyncio.sleep(RETRY_BACKOFF_SEC * attempt)
async def main() -> None: