/** * Per-chunk decode quality checks for the long-form pipeline's temperature * fallback (D-WS3a) — faster-whisper's `generate_with_fallback` criteria. */ export interface FallbackOptions { /** Decode temperatures in order; the first is the normal (greedy) pass. */ temperatures: number[]; /** Reject a decode whose text compresses better than this (a loop). */ compressionRatioThreshold: number; /** Reject a decode whose average token log-probability is below this. */ logProbThreshold: number; } /** faster-whisper / OpenAI Whisper defaults (spec Goal 3). */ export const DEFAULT_FALLBACK: FallbackOptions = { temperatures: [0, 0.2, 0.4, 0.6, 0.8, 1.0], compressionRatioThreshold: 2.4, logProbThreshold: -1.0, }; /** * UTF-8 length over zlib-deflated length — `get_compression_ratio` in * faster-whisper (`zlib.compress`). `CompressionStream("deflate")` is the * same zlib format and exists in workers and Bun alike. */ export async function compressionRatio(text: string): Promise { const bytes = new TextEncoder().encode(text); if (bytes.length === 0) return 0; const stream = new Blob([bytes]).stream().pipeThrough(new CompressionStream("deflate")); const compressed = await new Response(stream).arrayBuffer(); return bytes.length / compressed.byteLength; } /** Whether a decode should be retried at the next temperature. */ export function needsFallback( result: { compressionRatio: number; avgLogProb: number | null }, thresholds: Pick = DEFAULT_FALLBACK, ): boolean { if (result.compressionRatio > thresholds.compressionRatioThreshold) return true; return result.avgLogProb !== null && result.avgLogProb < thresholds.logProbThreshold; }