* fix(asr): repoint two 404 ASR model repo IDs in catalog (closes #239) Model install failed with HTTP 404 for two ASR entries whose Hugging Face repos don't exist: - UsefulSensors/moonshine-small -> UsefulSensors/moonshine-tiny (Moonshine ships tiny/base; there is no 300M 'small') - Systran/faster-whisper-large-v3-turbo -> deepdml/faster-whisper-large-v3-turbo-ct2 (Systran publishes no turbo repo; deepdml is a valid CTranslate2 build) Audited all 25 catalog repo_ids — every one resolves 200 on HF after the swap. Adds a static (no-network, CI-safe) regression test asserting repo_ids are well-formed and the known-404 IDs can't reappear. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test/docs(asr): safer repo_id access + flag turbo repo as community build (PR #242 review) - test_known_404_repo_ids_absent: m.get('repo_id','') so a missing field gives a clean assertion instead of KeyError regardless of test order. - models.yaml: note the turbo entry is a community CTranslate2 conversion to re-verify on future audits (greptile). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
56 lines
2.0 KiB
Python
56 lines
2.0 KiB
Python
"""Regression guard for the bundled model catalog (``backend/config/models.yaml``).
|
|
|
|
Issue #239: two ASR entries pointed at Hugging Face repo IDs that returned
|
|
HTTP 404 ("Repository Not Found"), so users could not install those ASR models:
|
|
|
|
* ``UsefulSensors/moonshine-small`` — no such model (Moonshine ships *tiny* /
|
|
*base*, there is no 300M "small").
|
|
* ``Systran/faster-whisper-large-v3-turbo`` — Systran publishes no turbo repo.
|
|
|
|
These tests are intentionally **static** (no network) so they run in CI: they
|
|
assert every ``repo_id`` is well-formed and that the known-bad IDs can never be
|
|
reintroduced. They do not verify live HF availability — that would be flaky and
|
|
slow — but they stop the catalog from shipping the exact IDs that broke #239.
|
|
"""
|
|
import re
|
|
from pathlib import Path
|
|
|
|
import yaml
|
|
|
|
_YAML = Path(__file__).resolve().parents[1] / "backend" / "config" / "models.yaml"
|
|
# org-or-user / repo-name, both segments HF-legal (letters, digits, _, -, .).
|
|
_REPO_RE = re.compile(r"^[A-Za-z0-9][\w.-]*/[\w.-]+$")
|
|
# Repo IDs that returned HTTP 404 on Hugging Face (issue #239). Must never reappear.
|
|
_KNOWN_BAD = {
|
|
"UsefulSensors/moonshine-small",
|
|
"Systran/faster-whisper-large-v3-turbo",
|
|
}
|
|
|
|
|
|
def _models():
|
|
data = yaml.safe_load(_YAML.read_text(encoding="utf-8"))
|
|
return data["models"] if isinstance(data, dict) and "models" in data else data
|
|
|
|
|
|
def test_catalog_loads_and_has_entries():
|
|
models = _models()
|
|
assert isinstance(models, list) and len(models) > 0
|
|
|
|
|
|
def test_every_repo_id_is_well_formed():
|
|
for m in _models():
|
|
rid = m.get("repo_id")
|
|
assert rid and _REPO_RE.match(rid), f"malformed repo_id: {rid!r}"
|
|
|
|
|
|
def test_required_fields_present():
|
|
for m in _models():
|
|
for field in ("repo_id", "label", "role"):
|
|
assert m.get(field), f"{m.get('repo_id')!r} missing required field {field!r}"
|
|
|
|
|
|
def test_known_404_repo_ids_absent():
|
|
ids = {m.get("repo_id", "") for m in _models()}
|
|
leaked = ids & _KNOWN_BAD
|
|
assert not leaked, f"known-404 repo IDs reintroduced (issue #239): {leaked}"
|