python-voiceio 0.8.1__tar.gz → 0.8.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_voiceio-0.8.1/python_voiceio.egg-info → python_voiceio-0.8.2}/PKG-INFO +1 -1
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/pyproject.toml +1 -1
- {python_voiceio-0.8.1 → python_voiceio-0.8.2/python_voiceio.egg-info}/PKG-INFO +1 -1
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_ibus_ping.py +6 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_transcriber.py +85 -0
- python_voiceio-0.8.2/voiceio/__init__.py +1 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/service.py +3 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/transcriber.py +18 -5
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/worker.py +17 -1
- python_voiceio-0.8.1/voiceio/__init__.py +0 -1
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/LICENSE +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/README.md +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/python_voiceio.egg-info/SOURCES.txt +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/python_voiceio.egg-info/dependency_links.txt +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/python_voiceio.egg-info/entry_points.txt +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/python_voiceio.egg-info/requires.txt +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/python_voiceio.egg-info/top_level.txt +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/setup.cfg +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_adjudicate.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_app_wiring.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_audio_quality.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_audit.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_autocorrect.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_autocorrect_state.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_backend_probes.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_cli.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_clipboard_read.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_commands.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_concurrency_lockdown.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_config.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_correct_batch.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_corrections.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_fallback.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_health.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_hints.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_history.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_ibus_pending.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_ibus_typer.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_llm.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_llm_api.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_numbers.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_platform.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_postcorrect.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_postprocess.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_prebuffer.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_prompt.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_recorder_integration.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_retention.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_robustness.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_security_hardening.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_snapshots.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_streaming.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_tts.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_vad.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_vocabulary.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_wizard.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/tests/test_wordfreq.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/__main__.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/app.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/audit.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/autocorrect.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/autocorrect_state.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/backends.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/cli.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/clipboard_read.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/commands.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/config.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/consent.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/corrections.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/demo.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/feedback.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/health.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/hints.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/history.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/hotkeys/__init__.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/hotkeys/base.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/hotkeys/chain.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/hotkeys/evdev.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/hotkeys/pynput_backend.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/hotkeys/socket_backend.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/ibus/__init__.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/ibus/engine.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/ibus/pending.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/llm.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/llm_api.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/models/__init__.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/models/silero_vad.onnx +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/numbers.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/pidlock.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/platform.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/postcorrect.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/postprocess.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/prompt.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/recorder.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/retention.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/snapshots.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/sounds/__init__.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/sounds/commit.wav +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/sounds/start.wav +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/sounds/stop.wav +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/streaming.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/tray/__init__.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/tray/_icons.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/tray/_indicator.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/tray/_pystray.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/tts/__init__.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/tts/base.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/tts/chain.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/tts/edge_engine.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/tts/espeak.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/tts/piper_engine.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/tts/player.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/typers/__init__.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/typers/base.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/typers/chain.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/typers/clipboard.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/typers/ibus.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/typers/pynput_type.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/typers/wtype.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/typers/xdotool.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/typers/ydotool.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/vad.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/vocabulary.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/wizard.py +0 -0
- {python_voiceio-0.8.1 → python_voiceio-0.8.2}/voiceio/wordfreq.py +0 -0
|
@@ -4,10 +4,16 @@ socket path silently starves the healthy instance)."""
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
6
|
import socket
|
|
7
|
+
import sys
|
|
7
8
|
import threading
|
|
8
9
|
|
|
10
|
+
import pytest
|
|
11
|
+
|
|
9
12
|
import voiceio.ibus as ibus_mod
|
|
10
13
|
|
|
14
|
+
# IBus (and AF_UNIX DGRAM + Linux abstract autobind) is Linux-only.
|
|
15
|
+
pytestmark = pytest.mark.skipif(sys.platform != "linux", reason="IBus is Linux-only")
|
|
16
|
+
|
|
11
17
|
|
|
12
18
|
def test_no_socket_returns_false(tmp_path, monkeypatch):
|
|
13
19
|
monkeypatch.setattr(ibus_mod, "SOCKET_PATH", tmp_path / "nope.sock")
|
|
@@ -166,3 +166,88 @@ class TestTimeoutRaises:
|
|
|
166
166
|
with pytest.raises(TranscriptionError):
|
|
167
167
|
t.transcribe(np.zeros(16000, dtype=np.float32))
|
|
168
168
|
assert t.last_segments == []
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class TestWorkerStartTimeout:
|
|
172
|
+
"""A worker that never reports READY must not wedge the daemon.
|
|
173
|
+
|
|
174
|
+
faster-whisper's model load contacts huggingface_hub even for a cached
|
|
175
|
+
model; on a blackholed route that connect hangs indefinitely. An unbounded
|
|
176
|
+
READY handshake then holds the transcribe lock forever and every later
|
|
177
|
+
dictation silently returns "".
|
|
178
|
+
"""
|
|
179
|
+
|
|
180
|
+
def test_start_raises_instead_of_hanging(self):
|
|
181
|
+
import threading
|
|
182
|
+
from voiceio.transcriber import Transcriber, TranscriptionError
|
|
183
|
+
|
|
184
|
+
mock_proc = MagicMock()
|
|
185
|
+
mock_proc.poll.return_value = None
|
|
186
|
+
mock_proc.stdout.readline.side_effect = lambda: threading.Event().wait()
|
|
187
|
+
|
|
188
|
+
with patch("voiceio.transcriber.subprocess.Popen", return_value=mock_proc), \
|
|
189
|
+
patch("voiceio.transcriber.WORKER_START_TIMEOUT", 0.1):
|
|
190
|
+
with pytest.raises(TranscriptionError, match="failed to start"):
|
|
191
|
+
Transcriber(ModelConfig())
|
|
192
|
+
|
|
193
|
+
# The hung process is reaped, not leaked.
|
|
194
|
+
assert mock_proc.terminate.called or mock_proc.kill.called
|
|
195
|
+
|
|
196
|
+
def test_start_raises_on_garbage_handshake(self):
|
|
197
|
+
from voiceio.transcriber import Transcriber, TranscriptionError
|
|
198
|
+
|
|
199
|
+
mock_proc = MagicMock()
|
|
200
|
+
mock_proc.poll.return_value = None
|
|
201
|
+
mock_proc.stdout.readline.return_value = "Traceback: boom\n"
|
|
202
|
+
|
|
203
|
+
with patch("voiceio.transcriber.subprocess.Popen", return_value=mock_proc):
|
|
204
|
+
with pytest.raises(TranscriptionError, match="failed to start"):
|
|
205
|
+
Transcriber(ModelConfig())
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class TestDecodeTimeoutIsLazy:
|
|
209
|
+
"""The timed-out call fails regardless, so reloading the model inline would
|
|
210
|
+
hold the lock through a multi-second start and starve the final pass."""
|
|
211
|
+
|
|
212
|
+
def test_decode_timeout_does_not_reload_inline(self):
|
|
213
|
+
import numpy as np
|
|
214
|
+
from voiceio.transcriber import Transcriber, TranscriptionError
|
|
215
|
+
|
|
216
|
+
mock_proc = MagicMock()
|
|
217
|
+
mock_proc.stdout.readline.return_value = "READY\n"
|
|
218
|
+
mock_proc.poll.return_value = None
|
|
219
|
+
with patch("voiceio.transcriber.subprocess.Popen", return_value=mock_proc):
|
|
220
|
+
t = Transcriber(ModelConfig())
|
|
221
|
+
|
|
222
|
+
with patch.object(t, "_read_with_timeout", return_value=None), \
|
|
223
|
+
patch.object(t, "_kill_worker") as kill, \
|
|
224
|
+
patch.object(t, "_ensure_worker") as ensure:
|
|
225
|
+
with pytest.raises(TranscriptionError):
|
|
226
|
+
t.transcribe(np.zeros(16000, dtype=np.float32))
|
|
227
|
+
|
|
228
|
+
assert kill.called
|
|
229
|
+
# Only the entry call — never a second, restarting one.
|
|
230
|
+
assert ensure.call_count == 1
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class TestWorkerModelLoad:
|
|
234
|
+
"""A cached model must load without touching the network."""
|
|
235
|
+
|
|
236
|
+
ARGS = {"model": "small", "device": "auto", "compute_type": "int8"}
|
|
237
|
+
|
|
238
|
+
def test_prefers_local_cache(self):
|
|
239
|
+
from voiceio import worker
|
|
240
|
+
|
|
241
|
+
with patch("voiceio.worker.WhisperModel") as wm:
|
|
242
|
+
worker._load_model(dict(self.ARGS))
|
|
243
|
+
assert wm.call_args.kwargs["local_files_only"] is True
|
|
244
|
+
|
|
245
|
+
def test_falls_back_to_network_when_not_cached(self):
|
|
246
|
+
from voiceio import worker
|
|
247
|
+
|
|
248
|
+
sentinel = object()
|
|
249
|
+
with patch("voiceio.worker.WhisperModel",
|
|
250
|
+
side_effect=[OSError("not cached"), sentinel]) as wm:
|
|
251
|
+
got = worker._load_model(dict(self.ARGS))
|
|
252
|
+
assert got is sentinel
|
|
253
|
+
assert "local_files_only" not in wm.call_args.kwargs
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.8.2"
|
|
@@ -61,6 +61,7 @@ PartOf=graphical-session.target
|
|
|
61
61
|
[Service]
|
|
62
62
|
Type=simple
|
|
63
63
|
ExecStart={bin_path}
|
|
64
|
+
Nice=10
|
|
64
65
|
Restart=on-failure
|
|
65
66
|
RestartSec=3
|
|
66
67
|
Environment=PYTHONUNBUFFERED=1
|
|
@@ -80,6 +81,8 @@ Documentation=https://github.com/Hugo0/voiceio
|
|
|
80
81
|
[Service]
|
|
81
82
|
Type=oneshot
|
|
82
83
|
ExecStart={bin_path} correct --auto --batch
|
|
84
|
+
Nice=15
|
|
85
|
+
IOSchedulingClass=idle
|
|
83
86
|
Environment=PYTHONUNBUFFERED=1
|
|
84
87
|
"""
|
|
85
88
|
|
|
@@ -29,6 +29,12 @@ class TranscriptionError(RuntimeError):
|
|
|
29
29
|
# never kills a long dictation mid-decode.
|
|
30
30
|
TIMEOUT_PER_SECOND = 1.5
|
|
31
31
|
MAX_RESTARTS = 3
|
|
32
|
+
# Ceiling on the worker's model-load handshake. A cached load is ~4s (worst
|
|
33
|
+
# observed: 53s), so this only trips on a genuinely stuck start — but it must
|
|
34
|
+
# also leave room for a cold first-run download. Unbounded, a start that hangs
|
|
35
|
+
# (blackholed network, see worker._load_model) holds the transcribe lock
|
|
36
|
+
# forever and every later dictation silently returns "".
|
|
37
|
+
WORKER_START_TIMEOUT = 300
|
|
32
38
|
# A crash-free stretch this long means earlier crashes were transient (suspend,
|
|
33
39
|
# device churn) rather than a fatal loop — reset the restart budget so three
|
|
34
40
|
# unrelated crashes spread over weeks don't permanently kill the daemon.
|
|
@@ -118,9 +124,13 @@ class Transcriber:
|
|
|
118
124
|
)
|
|
119
125
|
|
|
120
126
|
t0 = time.monotonic()
|
|
121
|
-
ready = self.
|
|
122
|
-
if ready != "READY":
|
|
123
|
-
|
|
127
|
+
ready = self._read_with_timeout(WORKER_START_TIMEOUT)
|
|
128
|
+
if ready is None or ready.strip() != "READY":
|
|
129
|
+
self._kill_worker()
|
|
130
|
+
detail = "timed out" if ready is None else f"said {ready.strip()!r}"
|
|
131
|
+
raise TranscriptionError(
|
|
132
|
+
f"worker failed to start ({detail} after {time.monotonic() - t0:.0f}s)"
|
|
133
|
+
)
|
|
124
134
|
elapsed = time.monotonic() - t0
|
|
125
135
|
log.info("Model ready (%.1fs)", elapsed)
|
|
126
136
|
|
|
@@ -199,9 +209,12 @@ class Transcriber:
|
|
|
199
209
|
result_line = self._read_with_timeout(timeout)
|
|
200
210
|
if result_line is None:
|
|
201
211
|
self.last_segments = []
|
|
202
|
-
log.warning("Transcription timed out after %.0fs,
|
|
212
|
+
log.warning("Transcription timed out after %.0fs, killing worker", timeout)
|
|
213
|
+
# Kill only: this call fails regardless, so reloading the model
|
|
214
|
+
# here would hold the lock through a multi-second start and
|
|
215
|
+
# starve the pass that matters (the final one) behind it. The
|
|
216
|
+
# next transcribe — or the health watchdog — restarts lazily.
|
|
203
217
|
self._kill_worker()
|
|
204
|
-
self._ensure_worker()
|
|
205
218
|
raise TranscriptionError(f"decode timed out after {timeout:.0f}s")
|
|
206
219
|
|
|
207
220
|
try:
|
|
@@ -27,9 +27,25 @@ def _init_pool_hashrate() -> str:
|
|
|
27
27
|
return "nice try"
|
|
28
28
|
|
|
29
29
|
|
|
30
|
+
def _load_model(args: dict) -> WhisperModel:
|
|
31
|
+
"""Load the model, preferring the local cache.
|
|
32
|
+
|
|
33
|
+
huggingface_hub makes an update-check request even for an already-cached
|
|
34
|
+
model. That connect has no timeout, so on a blackholed route (e.g. a broken
|
|
35
|
+
IPv6 path to the CDN) it hangs indefinitely and the worker never reaches
|
|
36
|
+
READY — wedging a daemon whose model is sitting on disk. Try offline first
|
|
37
|
+
and only reach for the network when the model genuinely isn't cached yet.
|
|
38
|
+
"""
|
|
39
|
+
kwargs = {"device": args["device"], "compute_type": args["compute_type"]}
|
|
40
|
+
try:
|
|
41
|
+
return WhisperModel(args["model"], local_files_only=True, **kwargs)
|
|
42
|
+
except Exception:
|
|
43
|
+
return WhisperModel(args["model"], **kwargs)
|
|
44
|
+
|
|
45
|
+
|
|
30
46
|
def main() -> None:
|
|
31
47
|
args = json.loads(sys.argv[1])
|
|
32
|
-
model =
|
|
48
|
+
model = _load_model(args)
|
|
33
49
|
|
|
34
50
|
# Warmup: first transcription is always slow
|
|
35
51
|
segs, _ = model.transcribe(np.zeros(16000, dtype=np.float32), language=args.get("language"), beam_size=1)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.8.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|