Package the speech recogniser and its model for apt
No speech recogniser is in Debian, so installing bandsaunter from a .deb left transcription to a manual pip step on every machine. A repository of one's own is not bound by archive policy, so build-repo.sh now packages faster-whisper and the base.en model alongside the application: bandsaunter the application (Architecture: all) bandsaunter-transcribe faster-whisper, vendored (amd64) bandsaunter-model-base-en the model, so nothing reaches the network The wheels land in /usr/lib/bandsaunter/vendor rather than dist-packages, and transcribe.py appends that directory to sys.path -- appends, so an apt-managed numpy or PyYAML still wins and the vendor copy only fills the gap. Duplicates of what Debian already ships are stripped from the tree. resolve_model() turns a bare "base.en" into the packaged copy when one is installed, and leaves it alone to be downloaded when none is. The app package recommends the other two, so "apt install bandsaunter" brings the lot and --no-install-recommends still gets just the scanner. Its postinst explains how to add a recogniser only when there genuinely is not one -- including the case where apt has already unpacked the recogniser package but not yet configured it. Verified with the source tree hidden and no home directory: the packaged CLI runs, and a real recording transcribes offline from the vendored engine and packaged model while numpy still resolves to the system one. apt itself resolves the repository over HTTP and plans all three. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
16f3128690
commit
8d94a52942
5 changed files with 304 additions and 22 deletions
|
|
@ -1,4 +1,5 @@
|
|||
"""Speech to text: the engine plumbing, and how captures reach it."""
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
|
@ -376,3 +377,50 @@ def test_vosk_accepts_the_plain_language_code():
|
|||
result = tr.transcribe(say("one two three", 16000), 16000, engine="vosk",
|
||||
language="en")
|
||||
assert result is not None and not result.note, result.note
|
||||
|
||||
|
||||
# --- packaged engine and models -------------------------------------------
|
||||
|
||||
def test_a_packaged_model_is_used_in_place_of_its_name(tmp_path, monkeypatch):
|
||||
""""base.en" should mean the copy on this machine when one is installed."""
|
||||
monkeypatch.setattr(tr, "MODEL_DIR", tmp_path)
|
||||
(tmp_path / "base.en").mkdir()
|
||||
assert tr.resolve_model("base.en") == str(tmp_path / "base.en")
|
||||
|
||||
|
||||
def test_an_unpackaged_model_keeps_its_name_to_be_downloaded(tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(tr, "MODEL_DIR", tmp_path)
|
||||
assert tr.resolve_model("small.en") == "small.en"
|
||||
assert tr.resolve_model("") == ""
|
||||
|
||||
|
||||
def test_an_explicit_model_directory_wins_over_the_packaged_one(tmp_path, monkeypatch):
|
||||
packaged = tmp_path / "packaged"
|
||||
(packaged / "base.en").mkdir(parents=True)
|
||||
monkeypatch.setattr(tr, "MODEL_DIR", packaged)
|
||||
mine = tmp_path / "base.en"
|
||||
mine.mkdir()
|
||||
assert tr.resolve_model(str(mine)) == str(mine)
|
||||
|
||||
|
||||
def test_the_vendored_engine_is_searched_after_the_system_one(tmp_path, monkeypatch):
|
||||
"""Anything apt provides must still win; the vendor copy fills a gap."""
|
||||
monkeypatch.setattr(sys, "path", list(sys.path))
|
||||
monkeypatch.setattr(tr, "VENDOR_DIR", tmp_path)
|
||||
tr._add_vendor_path()
|
||||
assert sys.path[-1] == str(tmp_path)
|
||||
|
||||
|
||||
def test_the_vendor_path_is_added_once(tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(sys, "path", list(sys.path))
|
||||
monkeypatch.setattr(tr, "VENDOR_DIR", tmp_path)
|
||||
tr._add_vendor_path()
|
||||
tr._add_vendor_path()
|
||||
assert sys.path.count(str(tmp_path)) == 1
|
||||
|
||||
|
||||
def test_a_missing_vendor_directory_is_not_added(tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(sys, "path", list(sys.path))
|
||||
monkeypatch.setattr(tr, "VENDOR_DIR", tmp_path / "absent")
|
||||
tr._add_vendor_path()
|
||||
assert str(tmp_path / "absent") not in sys.path
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue