Mercurial
comparison dictation/config.py @ 275:78699f810817
Add Qwen3-VL and WebRTC dictation services
Add Bazel targets for the CUDA-backed Qwen3-VL server and a local WebRTC faster-whisper dictation service.
Co-authored-by: Copilot <[email protected]>
Copilot-Session: e3d8cb06-6c95-4ae0-9757-651d3796ab00
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 17 Aug 2026 10:58:47 -0700 |
| parents | |
| children | 49e9e591c9bb |
comparison
equal
deleted
inserted
replaced
| 274:c9be578316a6 | 275:78699f810817 |
|---|---|
| 1 from __future__ import annotations | |
| 2 | |
| 3 from dataclasses import dataclass | |
| 4 import os | |
| 5 from pathlib import Path | |
| 6 | |
| 7 | |
| 8 MODEL_REPOSITORY = "Systran/faster-whisper-small" | |
| 9 MODEL_REVISION = "536b0662742c02347bc0e980a01041f333bce120" | |
| 10 | |
| 11 | |
| 12 def _integer(name: str, default: int, minimum: int, maximum: int) -> int: | |
| 13 raw = os.environ.get(name) | |
| 14 if raw is None: | |
| 15 return default | |
| 16 try: | |
| 17 value = int(raw) | |
| 18 except ValueError as error: | |
| 19 raise ValueError(f"{name} must be an integer") from error | |
| 20 if value < minimum or value > maximum: | |
| 21 raise ValueError(f"{name} must be between {minimum} and {maximum}") | |
| 22 return value | |
| 23 | |
| 24 | |
| 25 def _float(name: str, default: float, minimum: float, maximum: float) -> float: | |
| 26 raw = os.environ.get(name) | |
| 27 if raw is None: | |
| 28 return default | |
| 29 try: | |
| 30 value = float(raw) | |
| 31 except ValueError as error: | |
| 32 raise ValueError(f"{name} must be a number") from error | |
| 33 if value < minimum or value > maximum: | |
| 34 raise ValueError(f"{name} must be between {minimum} and {maximum}") | |
| 35 return value | |
| 36 | |
| 37 | |
| 38 @dataclass(frozen=True) | |
| 39 class DictationConfig: | |
| 40 host: str | |
| 41 port: int | |
| 42 model_dir: Path | |
| 43 compute_type: str | |
| 44 max_sessions: int | |
| 45 partial_interval_ms: int | |
| 46 silence_ms: int | |
| 47 max_utterance_seconds: int | |
| 48 speech_threshold: float | |
| 49 | |
| 50 @classmethod | |
| 51 def from_environment(cls) -> "DictationConfig": | |
| 52 cache_root = Path( | |
| 53 os.environ.get( | |
| 54 "XDG_CACHE_HOME", | |
| 55 str(Path.home() / ".cache"), | |
| 56 ) | |
| 57 ) | |
| 58 model_dir = Path( | |
| 59 os.environ.get( | |
| 60 "DICTATION_MODEL_DIR", | |
| 61 str(cache_root / "zenbu" / "faster-whisper-small"), | |
| 62 ) | |
| 63 ).expanduser() | |
| 64 compute_type = os.environ.get( | |
| 65 "DICTATION_COMPUTE_TYPE", | |
| 66 "int8_float16", | |
| 67 ) | |
| 68 if compute_type not in { | |
| 69 "float16", | |
| 70 "int8_float16", | |
| 71 "int8", | |
| 72 }: | |
| 73 raise ValueError( | |
| 74 "DICTATION_COMPUTE_TYPE must be float16, int8_float16, or int8" | |
| 75 ) | |
| 76 host = os.environ.get("DICTATION_HOST", "127.0.0.1") | |
| 77 if not host: | |
| 78 raise ValueError("DICTATION_HOST must not be empty") | |
| 79 return cls( | |
| 80 host=host, | |
| 81 port=_integer("DICTATION_PORT", 8090, 1, 65535), | |
| 82 model_dir=model_dir, | |
| 83 compute_type=compute_type, | |
| 84 max_sessions=_integer("DICTATION_MAX_SESSIONS", 1, 1, 8), | |
| 85 partial_interval_ms=_integer( | |
| 86 "DICTATION_PARTIAL_INTERVAL_MS", | |
| 87 1200, | |
| 88 500, | |
| 89 10000, | |
| 90 ), | |
| 91 silence_ms=_integer("DICTATION_SILENCE_MS", 700, 200, 5000), | |
| 92 max_utterance_seconds=_integer( | |
| 93 "DICTATION_MAX_UTTERANCE_SECONDS", | |
| 94 30, | |
| 95 3, | |
| 96 120, | |
| 97 ), | |
| 98 speech_threshold=_float( | |
| 99 "DICTATION_SPEECH_THRESHOLD", | |
| 100 0.012, | |
| 101 0.001, | |
| 102 0.5, | |
| 103 ), | |
| 104 ) |