feat(presenter): replace Web Speech API with Piper TTS for high-quality voice
- New API route /api/presenter/tts proxies to compliance-tts-service - usePresenterMode now uses Audio element with Piper-generated MP3 - Client-side audio caching (text hash → blob URL) avoids re-synthesis - Graceful fallback to word-count timer if TTS service unavailable - Add TTS_SERVICE_URL env var to pitch-deck Docker config Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
46
pitch-deck/app/api/presenter/tts/route.ts
Normal file
46
pitch-deck/app/api/presenter/tts/route.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
|
||||
const TTS_SERVICE_URL = process.env.TTS_SERVICE_URL || 'http://compliance-tts-service:8095'
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const { text, language = 'de' } = body
|
||||
|
||||
if (!text || typeof text !== 'string') {
|
||||
return NextResponse.json({ error: 'Text is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const res = await fetch(`${TTS_SERVICE_URL}/synthesize-direct`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ text, language }),
|
||||
signal: AbortSignal.timeout(30000),
|
||||
})
|
||||
|
||||
if (!res.ok) {
|
||||
const errorText = await res.text()
|
||||
console.error('TTS service error:', res.status, errorText)
|
||||
return NextResponse.json(
|
||||
{ error: `TTS service error (${res.status})` },
|
||||
{ status: 502 }
|
||||
)
|
||||
}
|
||||
|
||||
const audioBuffer = await res.arrayBuffer()
|
||||
|
||||
return new NextResponse(audioBuffer, {
|
||||
headers: {
|
||||
'Content-Type': 'audio/mpeg',
|
||||
'Cache-Control': 'public, max-age=86400', // Cache 24h — texts are static
|
||||
'X-TTS-Cache': res.headers.get('X-TTS-Cache') || 'unknown',
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('TTS proxy error:', error)
|
||||
return NextResponse.json(
|
||||
{ error: 'TTS service not reachable' },
|
||||
{ status: 503 }
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user