Files
talkscore-asr/build/download_models.py
T
Vladimir BryzgalovandClaude Opus 5 9dc67bda5c talkscore-asr 0.1.0: сервис транскрибации и диаризации
Локальный FastAPI-сервис поверх GigaAM v3 и sherpa-onnx: приём аудио,
очередь задач, разделение по говорящим, постобработка терминов.

Доставка на Windows - ZIP со встроенным Python, без установки чего-либо.
Обновление кода при запуске тянется из релизов Gitea: меняется только
папка app, десятки килобайт вместо всего пакета.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-15 21:41:04 +05:00

113 lines
4.7 KiB
Python

#!/usr/bin/env python3
"""Скачивает модели распознавания и диаризации в папку models.
Запускается один раз после распаковки. Около 900 МБ.
"""
import os
import sys
import tarfile
from pathlib import Path
# Встраиваемая сборка Python идёт без хранилища сертификатов, поэтому urllib
# на HTTPS падает. Берём requests: он ходит через certifi, который уже в пакете.
import requests
BASE = Path(os.environ.get("TALKSCORE_ASR_HOME") or Path(__file__).resolve().parent)
MODELS = BASE / "models"
SEG_URL = ("https://github.com/k2-fsa/sherpa-onnx/releases/download/"
"speaker-segmentation-models/sherpa-onnx-pyannote-segmentation-3-0.tar.bz2")
EMB_URL = ("https://github.com/k2-fsa/sherpa-onnx/releases/download/"
"speaker-recongition-models/nemo_en_titanet_small.onnx")
def setup_console() -> None:
"""Windows-консоль по умолчанию не в UTF-8, иначе русский текст рассыпается."""
for stream in (sys.stdout, sys.stderr):
try:
stream.reconfigure(encoding="utf-8", errors="replace")
except (AttributeError, ValueError):
pass
def download(url: str, dst: Path, label: str) -> None:
if dst.exists() and dst.stat().st_size > 0:
print(f" {label}: уже на месте")
return
dst.parent.mkdir(parents=True, exist_ok=True)
tmp = dst.with_suffix(dst.suffix + ".part")
with requests.get(url, stream=True, timeout=60) as r:
r.raise_for_status()
total = int(r.headers.get("Content-Length", 0))
done = 0
with tmp.open("wb") as out:
for chunk in r.iter_content(chunk_size=1 << 20):
out.write(chunk)
done += len(chunk)
if total:
sys.stdout.write(
f"\r {label}: {done / total * 100:5.1f}% "
f"({done / 1e6:.0f}/{total / 1e6:.0f} МБ)")
sys.stdout.flush()
# Переименование в самом конце: прерванная закачка не оставит битый файл,
# который на следующем запуске сочли бы готовым.
tmp.replace(dst)
print()
def fetch_gigaam(target: Path) -> None:
"""Качает модель распознавания с Hugging Face.
Ускоренный транспорт xet на части сетей не проходит, поэтому при неудаче
повторяем обычным способом - он медленнее, но работает везде.
"""
os.environ.setdefault("HF_HUB_DISABLE_SYMLINKS_WARNING", "1")
from huggingface_hub import snapshot_download
# Только вариант e2e_rnnt: он единственный ставит пунктуацию и заглавные.
kwargs = dict(repo_id="istupakov/gigaam-v3-onnx", local_dir=str(target),
allow_patterns=["*e2e_rnnt*", "config.json"])
try:
snapshot_download(**kwargs)
except Exception as exc: # noqa: BLE001 - причина может быть любой, важен откат
print(f"\n Быстрая загрузка не удалась ({type(exc).__name__}), пробую обычную")
os.environ["HF_HUB_DISABLE_XET"] = "1"
snapshot_download(**kwargs)
def main() -> int:
setup_console()
MODELS.mkdir(parents=True, exist_ok=True)
print("Диаризация:")
download(EMB_URL, MODELS / "nemo_en_titanet_small.onnx", "голосовые отпечатки")
seg_dir = MODELS / "sherpa-onnx-pyannote-segmentation-3-0"
if (seg_dir / "model.onnx").is_file():
print(" сегментация: уже на месте")
else:
archive = MODELS / "seg.tar.bz2"
download(SEG_URL, archive, "сегментация")
with tarfile.open(archive, "r:bz2") as tar:
tar.extractall(MODELS)
archive.unlink()
print("\nРаспознавание (GigaAM v3, около 850 МБ):")
target = MODELS / "gigaam"
if (target / "config.json").is_file():
print(" уже на месте")
else:
fetch_gigaam(target)
print("\nГотово. Теперь запустите start.bat")
return 0
if __name__ == "__main__":
try:
sys.exit(main())
except requests.RequestException as exc:
print(f"\nОшибка сети: {exc}")
print("Проверьте подключение и доступность github.com и huggingface.co")
sys.exit(1)