43 lines
1.7 KiB
TypeScript
43 lines
1.7 KiB
TypeScript
/**
|
|
* 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<number> {
|
|
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<FallbackOptions, "compressionRatioThreshold" | "logProbThreshold"> = DEFAULT_FALLBACK,
|
|
): boolean {
|
|
if (result.compressionRatio > thresholds.compressionRatioThreshold) return true;
|
|
return result.avgLogProb !== null && result.avgLogProb < thresholds.logProbThreshold;
|
|
}
|