virtual-class / scripts /prebuild_audio.py
tourmii's picture
Deploy HF Spaces
905b7fd
Raw
History Blame Contribute Delete
3.62 kB
#!/usr/bin/env python3
"""Render every spoken line of the pre-authored packs into the audio cache.
python scripts/prebuild_audio.py # tất cả pack, tốc độ 1.0
python scripts/prebuild_audio.py --pack bai-10-tu-giac
python scripts/prebuild_audio.py --speeds 0.9 1.0 1.1
python scripts/prebuild_audio.py --force # dựng lại kể cả đã có
Run this once after editing a pack, or as a build step before deploying. The
lines are known in advance, so there is no reason for a student to wait on the
model: the first click should start talking immediately.
The cache key covers provider, voice, speed and format, so changing
SPEECH_PROVIDER or VIENEU_VOICE means re-running this — the old clips stay put
but will never be read again. Delete content/.audio-cache to reclaim the space.
"""
import argparse
import os
import sys
import time
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "backend"))
from app.config import settings # noqa: E402
from app.services import audio_cache, packs, speech # noqa: E402
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--pack", help="chỉ dựng một pack")
parser.add_argument("--speeds", nargs="+", type=float, default=[1.0])
parser.add_argument("--voice", help="ghi đè giọng mặc định")
parser.add_argument("--force", action="store_true", help="dựng lại cả câu đã có")
args = parser.parse_args()
if settings.speech_provider == "browser":
print(
"SPEECH_PROVIDER=browser nên máy chủ không đọc hộ — trình duyệt tự tổng hợp\n"
"bằng Web Speech API và không có gì để dựng sẵn cả.\n"
"Đặt SPEECH_PROVIDER=vieneu (hoặc google) rồi chạy lại.",
file=sys.stderr,
)
return 1
chosen = [packs.PACKS[args.pack]] if args.pack else list(packs.PACKS.values())
if args.pack and args.pack not in packs.PACKS:
print(f"Không có pack '{args.pack}'. Hiện có: {', '.join(packs.PACKS)}", file=sys.stderr)
return 1
print(f"provider: {settings.speech_provider}")
print(f"giọng: {args.voice or settings.vieneu_voice}")
speech.warm_up()
total = built = skipped = failed = 0
started = time.time()
for pack in chosen:
lines = pack.spoken_lines()
print(f"\n{pack.title}{len(lines)} câu × {len(args.speeds)} tốc độ")
for speed in args.speeds:
for i, line in enumerate(lines, 1):
total += 1
if not args.force and audio_cache.get(line, speed, args.voice) is not None:
skipped += 1
continue
try:
clip = speech.synthesize(line, speed=speed, voice=args.voice, use_cache=False)
audio_cache.put(line, speed, args.voice, clip)
built += 1
print(f" [{i:3d}/{len(lines)}] {speed:.2f}× {line[:58]}…")
except Exception as exc: # noqa: BLE001 - một câu hỏng không dừng cả mẻ
failed += 1
print(f" [{i:3d}/{len(lines)}] LỖI: {exc}", file=sys.stderr)
stats = audio_cache.stats()
print(
f"\nXong sau {time.time() - started:.1f}s — dựng mới {built}, bỏ qua {skipped}, "
f"lỗi {failed}, tổng {total}.\n"
f"Cache hiện có {stats['clips']} clip, {stats['size_mb']} MB."
)
return 1 if failed else 0
if __name__ == "__main__":
raise SystemExit(main())