import { describe, expect, it } from 'bun:test'; import { toParagraphs } from './transcribe'; import type { WhisperSegment } from './transcribe'; // Whisper's own shape: leading space on every segment, times in seconds. const seg = (text: string, start: number, end: number, extra: Partial = {}): WhisperSegment => ({ text, start, end, ...extra, }); describe('toParagraphs', () => { it('joins segments spoken without a real pause into one paragraph', () => { const out = toParagraphs([seg(' I went to the shop.', 0, 2), seg(' It was closed.', 2.2, 4)]); expect(out).toBe('I went to the shop. It was closed.'); }); it('starts a new paragraph after a long silence', () => { const out = toParagraphs([seg(' First thought.', 0, 2), seg(' Second thought.', 5, 7)]); expect(out).toBe('First thought.\n\nSecond thought.'); }); it('does not break on a breath-length pause', () => { const out = toParagraphs([seg(' Hang on,', 0, 1), seg(' let me think.', 1.5, 3)]); expect(out).toBe('Hang on, let me think.'); }); // The lone "." lines in the old response_format=text output came from segments like this. it('attaches stranded punctuation without a space in front of it', () => { const out = toParagraphs([seg(' See you tomorrow morning', 0, 2), seg(' .', 2.1, 2.2)]); expect(out).toBe('See you tomorrow morning.'); }); it('drops segments that are probably silence decoded with low confidence', () => { const out = toParagraphs([ seg(' Real speech here.', 0, 2), seg(' Thanks for watching!', 2.1, 3, { no_speech_prob: 0.95, avg_logprob: -1.8 }), seg(' More real speech.', 3.1, 5), ]); expect(out).toBe('Real speech here. More real speech.'); }); it('keeps a confident segment even when it looks like silence', () => { const out = toParagraphs([seg(' Definitely said.', 0, 2, { no_speech_prob: 0.95, avg_logprob: -0.2 })]); expect(out).toBe('Definitely said.'); }); it('keeps segments that report neither probability', () => { const out = toParagraphs([seg(' No metadata at all.', 0, 2)]); expect(out).toBe('No metadata at all.'); }); it('measures the pause from the last kept segment, not the dropped one', () => { const out = toParagraphs([ seg(' Before.', 0, 2), seg(' Hallucinated.', 2.1, 9, { no_speech_prob: 0.9, avg_logprob: -2 }), seg(' After.', 9.1, 11), ]); // The gap that matters is 2 -> 9.1, so these are separate thoughts. expect(out).toBe('Before.\n\nAfter.'); }); it('collapses internal whitespace and ignores empty segments', () => { const out = toParagraphs([seg(' Too many\n spaces. ', 0, 2), seg(' ', 2.1, 2.2)]); expect(out).toBe('Too many spaces.'); }); it('returns an empty string when every segment is filtered out', () => { expect(toParagraphs([])).toBe(''); expect(toParagraphs([seg(' ', 0, 1)])).toBe(''); }); it('falls back to no break when segments carry no timings', () => { const out = toParagraphs([{ text: ' One.' }, { text: ' Two.' }]); expect(out).toBe('One. Two.'); }); });