84 lines
2.3 KiB
TypeScript
84 lines
2.3 KiB
TypeScript
import { resolve } from "path";
|
|
import { generateClip, fileExists } from "./generateTTS";
|
|
|
|
const LABEL_CLIPS: Record<string, string> = {
|
|
A_1: "[calm] A,",
|
|
A_2: "[calm] A,",
|
|
A_3: "[thoughtful] A,",
|
|
A_4: "[measured] A,",
|
|
|
|
B_1: "[calm] B,",
|
|
B_2: "[thoughtful] B,",
|
|
B_3: "[calm] B,",
|
|
B_4: "[measured] B,",
|
|
|
|
C_1: "[thoughtful] C,",
|
|
C_2: "[calm] C,",
|
|
C_3: "[measured] C,",
|
|
C_4: "[calm] C,",
|
|
|
|
D_1: "[measured] D.",
|
|
D_2: "[calm] D.",
|
|
D_3: "[thoughtful] D.",
|
|
D_4: "[measured] D.",
|
|
};
|
|
|
|
const VOICE_SETTINGS = { stability: 0.3, similarity_boost: 0.75 };
|
|
|
|
const TRANSITION_TEXT = "[thoughtful] Let's look at this a different way...";
|
|
|
|
const CORRECT_CLIPS: Record<string, string> = {
|
|
correct_1: "Exactly right.",
|
|
correct_2: "That's it.",
|
|
correct_3: "Spot on.",
|
|
correct_4: "Perfect.",
|
|
};
|
|
|
|
export async function generateLabels() {
|
|
const config = useRuntimeConfig();
|
|
const apiKey = config.elevenlabsApiKey;
|
|
const voiceId = config.elevenlabsVoiceId;
|
|
|
|
if (!apiKey) {
|
|
console.warn("[labels] ELEVENLABS_API_KEY not set — skipping label generation");
|
|
return;
|
|
}
|
|
|
|
const labelsDir = resolve(process.cwd(), "public/audio/labels");
|
|
|
|
for (const [key, text] of Object.entries(LABEL_CLIPS)) {
|
|
const outPath = `${labelsDir}/${key}.mp3`;
|
|
|
|
if (await fileExists(outPath)) continue;
|
|
|
|
console.log(`[labels] generating ${key}.mp3…`);
|
|
await generateClip(text, outPath, apiKey, voiceId, {
|
|
model: "eleven_v3",
|
|
voice_settings: VOICE_SETTINGS,
|
|
});
|
|
}
|
|
|
|
// branch transition clip
|
|
const transitionPath = resolve(process.cwd(), "public/audio/branch-transition.mp3");
|
|
if (!(await fileExists(transitionPath))) {
|
|
console.log("[labels] generating branch-transition.mp3…");
|
|
await generateClip(TRANSITION_TEXT, transitionPath, apiKey, voiceId, {
|
|
model: "eleven_v3",
|
|
voice_settings: VOICE_SETTINGS,
|
|
});
|
|
}
|
|
|
|
// correct affirmation clips
|
|
const audioDir = resolve(process.cwd(), "public/audio");
|
|
for (const [key, text] of Object.entries(CORRECT_CLIPS)) {
|
|
const outPath = `${audioDir}/${key}.mp3`;
|
|
if (await fileExists(outPath)) continue;
|
|
console.log(`[labels] generating ${key}.mp3…`);
|
|
await generateClip(text, outPath, apiKey, voiceId, {
|
|
model: "eleven_v3",
|
|
voice_settings: { stability: 0.35, similarity_boost: 0.8 },
|
|
});
|
|
}
|
|
|
|
console.log("[labels] all label clips ready");
|
|
}
|