Salvage follow-up to #132976. hermes_platform/resolver/whisper.py only wrapped pm.installed_package(), which tools/ already calls directly elsewhere (agent-browser, cua-driver, tirith).
100 lines
4.1 KiB
Python
100 lines
4.1 KiB
Python
"""The managed command remains passive until transcription and caches verified models."""
|
|
|
|
import hashlib
|
|
import threading
|
|
from functools import partial
|
|
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
|
|
from pathlib import Path
|
|
from types import SimpleNamespace
|
|
|
|
import pytest
|
|
|
|
|
|
def test_models_download_once_per_profile_and_reject_bad_bytes(tmp_path, monkeypatch):
|
|
from pm.downloader import HashError
|
|
from pm import downloader
|
|
from tools import transcription_whisper_cpp as cpp
|
|
|
|
served = tmp_path / "served"
|
|
served.mkdir()
|
|
data = b"model fixture"
|
|
(served / "model.bin").write_bytes(data)
|
|
requests = []
|
|
|
|
class Handler(SimpleHTTPRequestHandler):
|
|
def log_message(self, fmt, *args):
|
|
requests.append(args)
|
|
|
|
server = ThreadingHTTPServer(("127.0.0.1", 0), partial(Handler, directory=str(served)))
|
|
thread = threading.Thread(target=server.serve_forever, daemon=True)
|
|
thread.start()
|
|
url = f"http://127.0.0.1:{server.server_port}/model.bin"
|
|
digest = hashlib.sha256(data).hexdigest()
|
|
monkeypatch.setattr(cpp, "_MODEL_FILES", (("model.bin", url, digest),))
|
|
hashes = []
|
|
original_hash = downloader._sha256_file
|
|
def hash_file(path):
|
|
hashes.append(path)
|
|
return original_hash(path)
|
|
monkeypatch.setattr(downloader, "_sha256_file", hash_file)
|
|
try:
|
|
for profile in ("A", "B", "A"):
|
|
monkeypatch.setenv("HERMES_HOME", str(tmp_path / profile))
|
|
before = len(requests)
|
|
hashes_before = len(hashes)
|
|
cached = cpp._model_dir() / "model.bin"
|
|
was_cached = cached.exists()
|
|
cpp.ensure_whisper_cpp_models("base")
|
|
assert cached.read_bytes() == data
|
|
assert (len(requests) == before) == was_cached
|
|
assert (len(hashes) == hashes_before) == was_cached
|
|
cached.write_bytes(b"corrupt")
|
|
monkeypatch.setattr(cpp, "_MODEL_FILES", (("model.bin", url, "0" * 64),))
|
|
with pytest.raises(HashError):
|
|
cpp.ensure_whisper_cpp_models("base")
|
|
assert cached.read_bytes() == b"corrupt" # failed transfer was never published
|
|
with pytest.raises(ValueError, match="currently supports"):
|
|
cpp.ensure_whisper_cpp_models("small")
|
|
finally:
|
|
server.shutdown()
|
|
thread.join()
|
|
server.server_close()
|
|
|
|
|
|
def test_local_resolution_is_passive_and_command_override_wins(tmp_path, monkeypatch):
|
|
from tools import transcription_local as local
|
|
from tools import transcription_tools as stt
|
|
from tools import transcription_whisper_cpp as cpp
|
|
import pm
|
|
from pm.packages import WhisperCppCpu
|
|
from pm.store import ALL_TARGETS
|
|
|
|
package = WhisperCppCpu()
|
|
assert [t for t in ALL_TARGETS if package.missing_reason(t) is None] == ["win32-arm64"]
|
|
monkeypatch.delenv("HERMES_LOCAL_STT_COMMAND", raising=False)
|
|
monkeypatch.setenv("HERMES_HOME", str(tmp_path / "profile with spaces"))
|
|
binary = tmp_path / "program files" / "whisper-cli.exe"
|
|
monkeypatch.setattr(pm, "installed_package",
|
|
lambda name: SimpleNamespace(binary=binary) if name == "whispercpp-cpu" else None)
|
|
monkeypatch.setattr(stt, "_HAS_FASTER_WHISPER", False)
|
|
calls = []
|
|
monkeypatch.setattr(cpp, "ensure_whisper_cpp_models", lambda model: calls.append(model))
|
|
assert stt._detect_local_backend() == "local_command"
|
|
assert calls == []
|
|
assert not cpp._model_dir().exists()
|
|
audio = tmp_path / "voice note.wav"
|
|
audio.write_bytes(b"RIFF")
|
|
|
|
def run(command, **kwargs):
|
|
assert command[command.index("-f") + 1] == str(audio)
|
|
assert command[command.index("-l") + 1] == "en"
|
|
assert "-ng" in command and "--vad" in command
|
|
Path(command[command.index("-of") + 1] + ".txt").write_text("hello")
|
|
|
|
monkeypatch.setattr(local, "_run_quiet", run)
|
|
result = local._transcribe_local_command(str(audio), "base", language="en")
|
|
assert result["success"] and result["transcript"] == "hello"
|
|
assert calls == ["base"]
|
|
monkeypatch.setenv("HERMES_LOCAL_STT_COMMAND", "custom-command {input_path}")
|
|
assert local._get_local_command_template() == "custom-command {input_path}"
|