audiobookshelf/scripts/test-camb-tts.js

133 lines
3.4 KiB
JavaScript

#!/usr/bin/env node
/**
* Standalone integration test for CAMB AI TTS API.
* No audiobookshelf imports — uses native fetch only.
*
* Usage:
* CAMB_API_KEY=xxx node scripts/test-camb-tts.js
* node scripts/test-camb-tts.js --api-key=xxx
*/
const fs = require('fs')
const os = require('os')
const path = require('path')
const API_BASE = 'https://client.camb.ai/apis'
function getApiKey() {
const cliArg = process.argv.find((a) => a.startsWith('--api-key='))
if (cliArg) return cliArg.split('=')[1]
return process.env.CAMB_API_KEY
}
let passed = 0
let failed = 0
function pass(name) {
console.log(` [PASS] ${name}`)
passed++
}
function fail(name, reason) {
console.log(` [FAIL] ${name}${reason}`)
failed++
}
async function testListVoices(apiKey) {
console.log('\nTest 1: List voices')
try {
const res = await fetch(`${API_BASE}/list-voices`, {
headers: { 'x-api-key': apiKey }
})
if (!res.ok) {
fail('list-voices', `HTTP ${res.status}`)
return
}
const voices = await res.json()
if (Array.isArray(voices) && voices.length > 0) {
const firstVoiceId = voices[0].id || voices[0].voice_id
pass(`list-voices (${voices.length} voices, using id=${firstVoiceId})`)
return firstVoiceId
} else {
fail('list-voices', `Unexpected response: ${JSON.stringify(voices).slice(0, 100)}`)
return null
}
} catch (err) {
fail('list-voices', err.message)
}
}
async function testTtsStream(apiKey, voiceId) {
console.log(`\nTest 2: TTS stream (short text, voice_id=${voiceId})`)
try {
const res = await fetch(`${API_BASE}/tts-stream`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': apiKey
},
body: JSON.stringify({
text: 'Hello, this is a test of the CAMB AI text to speech system.',
voice_id: voiceId,
language: 'en-us',
speech_model: 'mars-flash',
output_configuration: { format: 'wav' }
})
})
if (!res.ok) {
const body = await res.text()
fail('tts-stream', `HTTP ${res.status}: ${body.slice(0, 200)}`)
return
}
const buf = Buffer.from(await res.arrayBuffer())
if (buf.length < 100) {
fail('tts-stream', `Response too small (${buf.length} bytes)`)
return
}
const tmpFile = path.join(os.tmpdir(), `camb-tts-test-${Date.now()}.wav`)
fs.writeFileSync(tmpFile, buf)
pass(`tts-stream (${buf.length} bytes → ${tmpFile})`)
} catch (err) {
fail('tts-stream', err.message)
}
}
async function testInvalidKey() {
console.log('\nTest 3: Invalid API key')
try {
const res = await fetch(`${API_BASE}/list-voices`, {
headers: { 'x-api-key': 'invalid-key-12345' }
})
if (res.ok) {
fail('invalid-key', 'Expected non-200 but got 200')
} else {
pass(`invalid-key (HTTP ${res.status})`)
}
} catch (err) {
fail('invalid-key', err.message)
}
}
async function main() {
const apiKey = getApiKey()
if (!apiKey) {
console.error('Error: API key required. Set CAMB_API_KEY env var or use --api-key=KEY')
process.exit(1)
}
console.log('CAMB AI TTS Integration Test')
console.log('============================')
const voiceId = await testListVoices(apiKey)
await testTtsStream(apiKey, voiceId)
await testInvalidKey()
console.log(`\nResults: ${passed} passed, ${failed} failed`)
process.exit(failed > 0 ? 1 : 0)
}
main()