conversations come back as conversations
A probe on the torch stage worker (~/dockers/torch-worker) runs beside every transcription and decides what the recording is: solo dictation returns as paragraphs exactly as before, several voices return speaker-labeled with conversation: true. Nobody declares which — the caller cannot know. Transcription and the worker each get a serial FIFO queue on their own resource, so the probe costs a solo memo nothing and multi-user traffic stays fair. The worker is optional and best-effort throughout: unreachable or failing, everything still transcribes, just never labeled. Speaker attribution is segment-granularity by maximal turn overlap — whisper.cpp's own timestamps, no alignment stage. If boundaries prove sloppy, wav2vec2 alignment returns as a worker endpoint. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,9 @@ type TranscribeArgs = {
|
||||
export type TranscribeResult = {
|
||||
text: string;
|
||||
detectedLanguage: string;
|
||||
/** Raw Whisper segments, kept for speaker attribution (conversation.ts). Not part of the HTTP
|
||||
* response — index.ts decides what leaves the sidecar. */
|
||||
segments: WhisperSegment[];
|
||||
};
|
||||
|
||||
// Above this probability Whisper's own detection is taken as authoritative. Below it the clip is
|
||||
@@ -281,12 +284,12 @@ export type WhisperSegment = {
|
||||
|
||||
// Defaults are chosen so a segment missing either field is kept: dropping real speech is much worse
|
||||
// than keeping a stray word.
|
||||
const isHallucinatedSilence = (segment: WhisperSegment) =>
|
||||
export const isHallucinatedSilence = (segment: WhisperSegment) =>
|
||||
(segment.no_speech_prob ?? 0) > NO_SPEECH_PROB && (segment.avg_logprob ?? 0) < LOW_CONFIDENCE_LOGPROB;
|
||||
|
||||
// Whisper emits each segment with a leading space and now and then strands trailing punctuation in a
|
||||
// segment of its own, which is why the old `response_format=text` output contained lone "." lines.
|
||||
const appendSegment = (paragraph: string, text: string) => {
|
||||
export const appendSegment = (paragraph: string, text: string) => {
|
||||
if (!paragraph) return text;
|
||||
return /^[.,;:!?…)\]]/.test(text) ? paragraph + text : `${paragraph} ${text}`;
|
||||
};
|
||||
@@ -412,5 +415,5 @@ export async function transcribeAudio({
|
||||
const segments = json.segments ?? [];
|
||||
const text = segments.length > 0 ? toParagraphs(segments) : (json.text ?? '').trim();
|
||||
|
||||
return { text, detectedLanguage };
|
||||
return { text, detectedLanguage, segments };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user