mirror of
https://github.com/escalante29/WealthySmart.git
synced 2026-07-17 10:08:46 +02:00
Add Playwright assistant regression coverage
This commit is contained in:
59
frontend/e2e/narration.ts
Normal file
59
frontend/e2e/narration.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { execFile, execFileSync } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
let sayChecked = false;
|
||||
let sayAvailable = false;
|
||||
|
||||
function hasSay() {
|
||||
if (!sayChecked) {
|
||||
sayChecked = true;
|
||||
try {
|
||||
execFileSync("say", ["-v", "?"], { stdio: "ignore" });
|
||||
sayAvailable = true;
|
||||
} catch {
|
||||
console.warn("`say` not found — skipping TTS narration (subtitles still work).");
|
||||
}
|
||||
}
|
||||
return sayAvailable;
|
||||
}
|
||||
|
||||
const cache = new Map<string, Promise<{ path: string; durationMs: number } | null>>();
|
||||
|
||||
/** Synthesizes Spanish narration for a caption via macOS `say`. Returns null (never throws) if unavailable. */
|
||||
export function synthesize(
|
||||
text: string,
|
||||
outDir: string,
|
||||
index: number,
|
||||
voice = "Paulina",
|
||||
): Promise<{ path: string; durationMs: number } | null> {
|
||||
const key = `${voice}:${text}`;
|
||||
const cached = cache.get(key);
|
||||
if (cached) return cached;
|
||||
|
||||
const promise = (async () => {
|
||||
if (!hasSay()) return null;
|
||||
fs.mkdirSync(outDir, { recursive: true });
|
||||
const file = path.join(outDir, `narration-${String(index).padStart(2, "0")}.aiff`);
|
||||
try {
|
||||
await execFileAsync("say", ["-v", voice, "-o", file, text]);
|
||||
const { stdout } = await execFileAsync("ffprobe", [
|
||||
"-v", "error",
|
||||
"-show_entries", "format=duration",
|
||||
"-of", "csv=p=0",
|
||||
file,
|
||||
]);
|
||||
const durationMs = Math.round(parseFloat(stdout.trim()) * 1000);
|
||||
return { path: file, durationMs };
|
||||
} catch (err) {
|
||||
console.warn(`Narration synthesis failed for "${text.slice(0, 40)}…": ${err}`);
|
||||
fs.rmSync(file, { force: true });
|
||||
return null;
|
||||
}
|
||||
})();
|
||||
cache.set(key, promise);
|
||||
return promise;
|
||||
}
|
||||
Reference in New Issue
Block a user