Let the next dictation start while the last one is still working

Pressing the shortcut while a transcript was being transcribed or cleaned up
did nothing, and the thought you had while waiting was lost. The microphone is
free the moment a recording stops, so the next dictation can now be spoken at
once; the pipeline queues it and each one is finished, pasted and reported in
the order it was spoken. The corner indicator stays with the recording under
way rather than being wiped by the previous run's progress, and a stop that
lands behind an unfinished run says it is waiting its turn.
This commit is contained in:
2026-08-25 14:52:17 +03:00
parent 3663c7fd57
commit be09cc3ac6
6 changed files with 142 additions and 35 deletions
+29 -8
View File
@@ -6,6 +6,7 @@ whatever came of it: an answer to a question, or a sentence saying what was
done.
"""
import collections
import os
import shutil
import sys
@@ -45,6 +46,13 @@ class Pipeline(QObject):
self.conf = conf
self._thread = None
self._stop = threading.Event()
# Recordings waiting their turn, and whether a thread is working them
# off. The flag rather than the thread's own liveness, because a thread
# stays alive for a moment after deciding it is done, and a job arriving
# in that moment would be left in the queue with nobody coming back.
self._jobs = collections.deque()
self._draining = False
self._jobs_lock = threading.Lock()
@property
def busy(self):
@@ -53,17 +61,30 @@ class Pipeline(QObject):
def run(self, wav_path, duration, rms_values=(), ask=False, paste=None):
"""`paste` overrides the setting for this one run, which is what a
dictation asked for from a terminal wants: the text comes back down the
socket, and pasting it into whatever had focus is nobody's intention."""
if self.busy:
return
socket, and pasting it into whatever had focus is nobody's intention.
A run started while one is going waits its turn rather than being
dropped: the next dictation can be spoken while the last one is still
being cleaned up, and each one is finished, pasted and reported in the
order it was spoken."""
with self._jobs_lock:
self._jobs.append((wav_path, duration, list(rms_values), ask, paste))
if self._draining:
return
self._draining = True
self._stop.clear()
self._thread = threading.Thread(
target=self._work,
args=(wav_path, duration, list(rms_values), ask, paste),
daemon=True,
)
self._thread = threading.Thread(target=self._drain, daemon=True)
self._thread.start()
def _drain(self):
while True:
with self._jobs_lock:
if not self._jobs:
self._draining = False
return
job = self._jobs.popleft()
self._work(*job)
def cancel(self):
"""Give up on a job already under way.