scripts/fetch_voice_model.py
Rama main · réplica de lectura del repositorio original.
"""Fetch the two voice models into models/.
Not committed, for the same reason FFmpeg is not (see fetch_ffmpeg.py): a
binary in git is paid for by everyone who clones, forever. The installer
build fetches them and bundles them, so an installed copy needs no network.
python scripts/fetch_voice_model.py
analysis/voice_turns.py uses the pair to tell a second voice from the main
one, so its captions can take another colour:
- pyannote's segmentation-3.0 (MIT), as exported to ONNX for sherpa-onnx:
who is talking when, ten seconds at a time.
- WeSpeaker's VoxCeleb ResNet34-LM (CC BY 4.0): whose voice a turn is.
No account is needed to download either.
"""
import hashlib
import sys
import urllib.request
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
MODELS = ROOT / "models"
# (file, what it is, URL, SHA-256 as Hugging Face publishes it). Each URL is
# pinned to a commit, so the file behind the checksum can't change under it.
WANTED = [
(
"wespeaker_resnet34_lm.onnx",
"WeSpeaker speaker model",
"https://huggingface.co/Wespeaker/wespeaker-voxceleb-resnet34-LM/resolve/"
"f0c48c298fd835726c27956a5d617bad7115627e/voxceleb_resnet34_LM.onnx",
"7bb2f06e9df17cdf1ef14ee8a15ab08ed28e8d0ef5054ee135741560df2ec068",
),
(
"pyannote_segmentation_3.onnx",
"pyannote segmentation model",
"https://huggingface.co/csukuangfj/sherpa-onnx-pyannote-segmentation-3-0/resolve/"
"9403a6902bb58e3d5ae8c7e77c3422de279db2e0/model.onnx",
"220ad67ca923bef2fa91f2390c786097bf305bceb5e261d4af67b38e938e1079",
),
]
def _sha256(data: bytes) -> str:
return hashlib.sha256(data).hexdigest()
def _fetch(name: str, label: str, url: str, sha256: str) -> bool:
dest = MODELS / name
if dest.exists() and _sha256(dest.read_bytes()) == sha256:
print(f"Already have {dest.name} ({dest.stat().st_size / 1e6:.1f} MB)")
return True
print(f"Fetching the {label} from Hugging Face ...")
try:
req = urllib.request.Request(url, headers={"User-Agent": "clips-studio"})
with urllib.request.urlopen(req, timeout=600) as r:
data = r.read()
except Exception as e:
print(f" failed: {e.__class__.__name__}: {str(e)[:80]}")
return False
if _sha256(data) != sha256:
print(" the download doesn't match the published checksum, not keeping it")
return False
dest.write_bytes(data)
print(f" wrote {dest} ({len(data) / 1e6:.1f} MB)")
return True
def main() -> int:
MODELS.mkdir(parents=True, exist_ok=True)
# Not all(): one failing must not stop the other being fetched.
got = [_fetch(*wanted) for wanted in WANTED]
if all(got):
return 0
print(
"\nCould not fetch the voice models.\n"
"Clipping still works without them: captions stay one colour, whoever\n"
"is talking."
)
return 1
if __name__ == "__main__":
sys.exit(main())