/** * Test-time access to the recordings in tests/audio_files: decode with * ffmpeg-static (trusted devDependency) and the WER text normalization used * by tests/live-real-model.test.ts. */ import { join } from "node:path"; import ffmpegPath from "ffmpeg-static"; export const AUDIO_DIR = join(import.meta.dir, "audio_files"); /** Decode `tests/audio_files/` to mono float32 PCM at `rate` (16 kHz by default). */ export async function decodeClip(name: string, rate = 16_000): Promise { const path = join(AUDIO_DIR, name); const proc = Bun.spawn( [ ffmpegPath as unknown as string, ...["-hide_banner", "-loglevel", "error"], ...["-i", path], ...["-ac", "1", "-ar", String(rate), "-f", "f32le", "-"], ], { stdout: "pipe", stderr: "pipe" }, ); const [bytes, errors, exitCode] = await Promise.all([ new Response(proc.stdout).arrayBuffer(), new Response(proc.stderr).text(), proc.exited, ]); if (exitCode !== 0) throw new Error(`ffmpeg failed on ${path}: ${errors}`); return new Float32Array(bytes); } /** Reference transcript of `tests/audio_files/.txt`. */ export function readReference(base: string): Promise { return Bun.file(join(AUDIO_DIR, `${base}.txt`)).text(); } /** * WER normalization: casing, punctuation, and apostrophes are not * transcription accuracy; "Århus"/"Aarhus" unify (same as the real-model test). */ export function normalize(text: string): string { return text .toLowerCase() .replaceAll("århus", "aarhus") .replace(/['’]/g, "") .replace(/[.,!?;:"“”‘‚«»()\-–—…]/g, " ") .replace(/\s+/g, " ") .trim(); }