// Server-side proxy: the browser never sees TONEPERFECT_API_KEY. // Add your own auth check here before going live (see README). const API = process.env.TONEPERFECT_BASE_URL || 'https://api.toneperfect.app'; const LANGUAGES = new Set(['zh-CN', 'en-US', 'fr-FR', 'es-419', 'de-DE', 'it-IT', 'pt-BR', 'ru-RU', 'ko-KR', 'ja-JP']); export async function POST(request) { const form = await request.formData(); const audio = form.get('audio'); const text = String(form.get('text') || '').slice(0, 500); const language = String(form.get('language') || 'zh-CN'); if (!(audio instanceof Blob) || audio.size === 0 || audio.size > 10 * 1024 * 1024) { return Response.json({ error: { code: 'invalid_audio', message: 'Send one recording up to 10 MB.' } }, { status: 422 }); } if (!text || !LANGUAGES.has(language)) { return Response.json({ error: { code: 'invalid_input', message: 'Send text and a supported language.' } }, { status: 422 }); } const upstream = new FormData(); upstream.append('audio', audio, 'recording.webm'); upstream.append('text', text); upstream.append('language', language); const response = await fetch(`${API}/v1/assess`, { method: 'POST', body: upstream, headers: { Authorization: `Bearer ${process.env.TONEPERFECT_API_KEY}`, // One key per recording attempt; the browser sends it so a retry is not charged twice. 'Idempotency-Key': request.headers.get('idempotency-key') || crypto.randomUUID(), 'TonePerfect-Response': 'compact', }, }); return new Response(await response.text(), { status: response.status, headers: { 'Content-Type': 'application/json' } }); }