Mercurial
annotate dictation/transcriber.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 |
| rev | line source |
|---|---|
|
275
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
1 from __future__ import annotations |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2 |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
3 import asyncio |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
4 from concurrent.futures import ThreadPoolExecutor |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
5 from dataclasses import dataclass |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
6 from pathlib import Path |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
7 from typing import Protocol |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
8 |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
9 import numpy as np |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
10 |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
11 |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
12 @dataclass(frozen=True) |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
13 class Transcript: |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
14 text: str |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
15 language: str |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
16 probability: float |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
17 |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
18 |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
19 class Transcriber(Protocol): |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
20 async def warmup(self) -> None: |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
21 ... |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
22 |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
23 async def transcribe( |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
24 self, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
25 samples: np.ndarray, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
26 *, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
27 final: bool, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
28 ) -> Transcript: |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
29 ... |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
30 |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
31 |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
32 class FasterWhisperTranscriber: |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
33 def __init__(self, model_dir: Path, compute_type: str) -> None: |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
34 self._model_dir = model_dir |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
35 self._compute_type = compute_type |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
36 self._executor = ThreadPoolExecutor( |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
37 max_workers=1, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
38 thread_name_prefix="dictation", |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
39 ) |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
40 self._model = None |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
41 self._load_lock = asyncio.Lock() |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
42 |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
43 async def warmup(self) -> None: |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
44 if self._model is not None: |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
45 return |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
46 async with self._load_lock: |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
47 if self._model is not None: |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
48 return |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
49 loop = asyncio.get_running_loop() |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
50 self._model = await loop.run_in_executor( |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
51 self._executor, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
52 self._load, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
53 ) |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
54 |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
55 def _load(self): |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
56 from faster_whisper import WhisperModel |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
57 |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
58 if not (self._model_dir / "model.bin").is_file(): |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
59 raise FileNotFoundError( |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
60 f"Model not found at {self._model_dir}. " |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
61 "Run: bazel run //dictation:download_model" |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
62 ) |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
63 return WhisperModel( |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
64 str(self._model_dir), |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
65 device="cuda", |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
66 compute_type=self._compute_type, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
67 local_files_only=True, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
68 ) |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
69 |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
70 async def transcribe( |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
71 self, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
72 samples: np.ndarray, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
73 *, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
74 final: bool, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
75 ) -> Transcript: |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
76 await self.warmup() |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
77 loop = asyncio.get_running_loop() |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
78 return await loop.run_in_executor( |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
79 self._executor, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
80 self._transcribe_sync, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
81 np.asarray(samples, dtype=np.float32), |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
82 final, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
83 ) |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
84 |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
85 def _transcribe_sync( |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
86 self, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
87 samples: np.ndarray, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
88 final: bool, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
89 ) -> Transcript: |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
90 segments, info = self._model.transcribe( |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
91 samples, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
92 beam_size=5 if final else 1, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
93 best_of=5 if final else 1, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
94 condition_on_previous_text=False, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
95 vad_filter=False, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
96 ) |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
97 text = "".join(segment.text for segment in segments).strip() |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
98 return Transcript( |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
99 text=text, |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
100 language=info.language or "", |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
101 probability=float(info.language_probability or 0.0), |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
102 ) |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
103 |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
104 def close(self) -> None: |
|
78699f810817
Add Qwen3-VL and WebRTC dictation services
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
105 self._executor.shutdown(wait=False, cancel_futures=True) |