Send the audio as mp3, and stop cutting a file that fits in one request

Whisper hears in thirty second windows and decides for itself where one cue
ends and the next begins. A chunk that starts in the middle of a sentence can
answer with one cue per window, twenty seconds of text at a time, for the whole
rest of the chunk: a twenty five minute recording was fine until 20:00, which
was where the second cut fell, and ran on in paragraphs from there. Sending the
same audio in one request instead of three gives cues of two and a half seconds
throughout.

The cuts were only ever there for the upload limit, and we were the ones
walking into it: ffmpeg opened a 24 MB m4a into 48 MB of uncompressed WAV, over
the 25 MB the APIs take, so the file had to be cut every ten minutes. As mp3 it
is 9 MB, and an hour of speech goes in one request. A server on this machine is
still handed the WAV, where nothing is uploaded and the encoder would only cost
quality. How long a chunk may be is now measured from the encoded file rather
than assumed from a bitrate.

Where a file still has to be cut, the chunks overlap by a whisper window and
stitch() drops the telling that was cut short, keeping the one that heard the
sentence whole. Meetings, which upload the WAV itself and so still cut every
ten minutes, get the same stitching.
This commit is contained in:
yusufipk
2026-08-02 12:20:26 +03:00
parent 7a507c52eb
commit 395b52d685
4 changed files with 266 additions and 38 deletions
+7 -3
View File
@@ -170,6 +170,7 @@ class MeetingPipeline(QObject):
chunk_dir = os.path.join(workdir, speaker)
os.makedirs(chunk_dir, exist_ok=True)
chunks = filetranscribe.split_wav(path, chunk_dir)
heard = []
for index, (chunk_path, offset) in enumerate(chunks, start=1):
self._check()
self._say(t("Transcribing {side}: {index}/{count}",
@@ -178,12 +179,15 @@ class MeetingPipeline(QObject):
# would cost money to be told so, and can invent a sentence.
if self._silent(chunk_path):
continue
segments.extend(
(start + offset, end + offset, text, speaker)
# The chunks overlap, so what the cut fell in the middle of is
# in two of them; stitch keeps the one that heard it whole.
heard = filetranscribe.stitch(heard, [
(start + offset, end + offset, text)
for start, end, text in api.transcribe_segments(
target, chunk_path, language=language, prompt=hint
)
)
])
segments.extend((start, end, text, speaker) for start, end, text in heard)
if not segments:
raise api.ApiError(t("Neither side of the recording had any speech in it."))