Mercurial
comparison dictation/transcriber.py @ 280:49e9e591c9bb
Add persistent dictation, prewarmed WebRTC speech input, Copilot SDK routing, animated conversation lifecycle controls, parking, and architecture coverage.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Tue, 18 Aug 2026 19:14:53 -0700 |
| parents | 78699f810817 |
| children |
comparison
equal
deleted
inserted
replaced
| 279:b3b547563ec7 | 280:49e9e591c9bb |
|---|---|
| 47 if self._model is not None: | 47 if self._model is not None: |
| 48 return | 48 return |
| 49 loop = asyncio.get_running_loop() | 49 loop = asyncio.get_running_loop() |
| 50 self._model = await loop.run_in_executor( | 50 self._model = await loop.run_in_executor( |
| 51 self._executor, | 51 self._executor, |
| 52 self._load, | 52 self._load_and_warmup, |
| 53 ) | 53 ) |
| 54 | 54 |
| 55 def _load(self): | 55 def _load_and_warmup(self): |
| 56 from faster_whisper import WhisperModel | 56 from faster_whisper import WhisperModel |
| 57 | 57 |
| 58 if not (self._model_dir / "model.bin").is_file(): | 58 if not (self._model_dir / "model.bin").is_file(): |
| 59 raise FileNotFoundError( | 59 raise FileNotFoundError( |
| 60 f"Model not found at {self._model_dir}. " | 60 f"Model not found at {self._model_dir}. " |
| 61 "Run: bazel run //dictation:download_model" | 61 "Run: bazel run //dictation:download_model" |
| 62 ) | 62 ) |
| 63 return WhisperModel( | 63 model = WhisperModel( |
| 64 str(self._model_dir), | 64 str(self._model_dir), |
| 65 device="cuda", | 65 device="cuda", |
| 66 compute_type=self._compute_type, | 66 compute_type=self._compute_type, |
| 67 local_files_only=True, | 67 local_files_only=True, |
| 68 ) | 68 ) |
| 69 # Loading weights does not initialize all CUDA kernels. Execute and | |
| 70 # consume one short silent inference now so the user's first utterance | |
| 71 # does not pay the one-time GPU setup cost. | |
| 72 segments, _ = model.transcribe( | |
| 73 np.zeros(8000, dtype=np.float32), | |
| 74 beam_size=1, | |
| 75 best_of=1, | |
| 76 condition_on_previous_text=False, | |
| 77 vad_filter=False, | |
| 78 without_timestamps=True, | |
| 79 ) | |
| 80 list(segments) | |
| 81 return model | |
| 69 | 82 |
| 70 async def transcribe( | 83 async def transcribe( |
| 71 self, | 84 self, |
| 72 samples: np.ndarray, | 85 samples: np.ndarray, |
| 73 *, | 86 *, |
| 87 samples: np.ndarray, | 100 samples: np.ndarray, |
| 88 final: bool, | 101 final: bool, |
| 89 ) -> Transcript: | 102 ) -> Transcript: |
| 90 segments, info = self._model.transcribe( | 103 segments, info = self._model.transcribe( |
| 91 samples, | 104 samples, |
| 92 beam_size=5 if final else 1, | 105 beam_size=1, |
| 93 best_of=5 if final else 1, | 106 best_of=1, |
| 94 condition_on_previous_text=False, | 107 condition_on_previous_text=False, |
| 95 vad_filter=False, | 108 vad_filter=False, |
| 109 without_timestamps=True, | |
| 96 ) | 110 ) |
| 97 text = "".join(segment.text for segment in segments).strip() | 111 text = "".join(segment.text for segment in segments).strip() |
| 98 return Transcript( | 112 return Transcript( |
| 99 text=text, | 113 text=text, |
| 100 language=info.language or "", | 114 language=info.language or "", |