Files
app/app/api/tts/route.ts
Albert f0284ef813 feat: Improve UI layout and navigation
- Increase logo size (48x48 desktop, 56x56 mobile) for better visibility
- Add logo as favicon
- Add logo to mobile header
- Move user menu to navigation bars (sidebar on desktop, bottom bar on mobile)
- Fix desktop chat layout - container structure prevents voice controls cutoff
- Fix mobile bottom bar - use icon-only ActionIcons instead of truncated text buttons
- Hide Create Node/New Conversation buttons on mobile to save header space
- Make fixed header and voice controls work properly with containers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 14:43:11 +00:00

84 lines
2.1 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import { createClient } from '@deepgram/sdk';
/**
* Text-to-Speech API route using Deepgram Aura
*
* Converts text to natural-sounding speech using Deepgram's Aura-2 model.
* Returns audio data that can be played in the browser.
*/
export async function POST(request: NextRequest) {
const deepgramApiKey = process.env.DEEPGRAM_API_KEY;
if (!deepgramApiKey) {
return NextResponse.json(
{ error: 'Deepgram API key not configured' },
{ status: 500 }
);
}
try {
const { text } = await request.json();
if (!text || typeof text !== 'string') {
return NextResponse.json(
{ error: 'Text parameter is required' },
{ status: 400 }
);
}
console.log('[TTS] Generating speech for text:', text.substring(0, 50) + '...');
const deepgram = createClient(deepgramApiKey);
// Generate speech using Deepgram Aura
const response = await deepgram.speak.request(
{ text },
{
model: 'aura-2-thalia-en', // Natural female voice
encoding: 'linear16',
container: 'wav',
}
);
// Get the audio stream
const stream = await response.getStream();
if (!stream) {
throw new Error('No audio stream returned from Deepgram');
}
// Convert stream to buffer
const chunks: Uint8Array[] = [];
const reader = stream.getReader();
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
if (value) chunks.push(value);
}
} finally {
reader.releaseLock();
}
const buffer = Buffer.concat(chunks);
console.log('[TTS] ✓ Generated', buffer.length, 'bytes of audio');
// Return audio with proper headers
return new NextResponse(buffer, {
headers: {
'Content-Type': 'audio/wav',
'Content-Length': buffer.length.toString(),
},
});
} catch (error) {
console.error('[TTS] Error generating speech:', error);
return NextResponse.json(
{ error: 'Failed to generate speech' },
{ status: 500 }
);
}
}