Files
archy-demo/neode-ui/scripts/generate-welcome-speech.js
2026-03-17 02:14:04 +00:00

78 lines
2.4 KiB
JavaScript

#!/usr/bin/env node
/**
* Generate "Welcome Noderunner" speech using ElevenLabs AI voice.
* Slower, softer, sci-fi style with reverb/echo effects.
*
* Usage:
* ELEVENLABS_API_KEY=your_key node scripts/generate-welcome-speech.js
*
* Optional voice ID (browse https://elevenlabs.io/voice-library/sensual):
* ELEVENLABS_VOICE_ID=voice_id node scripts/generate-welcome-speech.js
*/
import { writeFileSync, mkdirSync, readFileSync, unlinkSync } from 'fs'
import { dirname, join } from 'path'
import { fileURLToPath } from 'url'
import { execSync } from 'child_process'
const __dirname = dirname(fileURLToPath(import.meta.url))
const API_KEY = process.env.ELEVENLABS_API_KEY
// Sarah - mature, reassuring, confident female (softer than Rachel)
const VOICE_ID = process.env.ELEVENLABS_VOICE_ID || 'EXAVITQu4vr4xnSDxMaL'
const OUTPUT_PATH = join(__dirname, '../public/assets/audio/welcome-noderunner.mp3')
const RAW_PATH = join(__dirname, '../public/assets/audio/welcome-noderunner-raw.mp3')
if (!API_KEY) {
console.error('Set ELEVENLABS_API_KEY (get a free key at elevenlabs.io)')
process.exit(1)
}
// Slower (0.78), softer (higher stability 0.65), more expressive (style 0.6)
const res = await fetch(
`https://api.elevenlabs.io/v1/text-to-speech/${VOICE_ID}?output_format=mp3_44100_128`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'xi-api-key': API_KEY,
},
body: JSON.stringify({
text: 'Welcome Noderunner',
model_id: 'eleven_multilingual_v2',
voice_settings: {
stability: 0.65,
similarity_boost: 0.8,
style: 0.6,
use_speaker_boost: true,
speed: 0.7,
},
}),
}
)
if (!res.ok) {
const err = await res.text()
console.error('ElevenLabs API error:', res.status, err)
process.exit(1)
}
const buf = Buffer.from(await res.arrayBuffer())
mkdirSync(dirname(OUTPUT_PATH), { recursive: true })
writeFileSync(RAW_PATH, buf)
// Add sci-fi reverb: dense short delays that blend (no distinct echo)
try {
execSync(
`ffmpeg -y -i "${RAW_PATH}" -af "aecho=0.6:0.15:25|45|70:0.55|0.45|0.35,highpass=f=80,equalizer=f=4000:t=q:w=1:g=-1" -q:a 2 "${OUTPUT_PATH}" 2>/dev/null`,
{ stdio: 'pipe' }
)
unlinkSync(RAW_PATH)
} catch {
writeFileSync(OUTPUT_PATH, buf)
try { unlinkSync(RAW_PATH) } catch {}
}
console.log('Generated:', OUTPUT_PATH)
console.log('Add this file to git and deploy.')