import { NextResponse } from 'next/server'; import fs from 'fs'; import path from 'path'; import { requireAuth } from '../../../../lib/jwt'; import type { Locale } from '../../../../lib/i18n'; type LocaleFields = { title: string; teaser: string; description: string }; const SUPPORTED_LOCALES: Locale[] = ['en', 'fi', 'sv']; function loadApiKey() { if (process.env.OPENAI_API_KEY) return process.env.OPENAI_API_KEY; const keyPath = path.join(process.cwd(), 'creds', 'openai.key'); try { return fs.readFileSync(keyPath, 'utf8').trim(); } catch { return null; } } export async function POST(req: Request) { try { await requireAuth(req); } catch (err) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const apiKey = loadApiKey(); if (!apiKey) { return NextResponse.json({ error: 'Missing OpenAI API key' }, { status: 500 }); } let body: any; try { body = await req.json(); } catch { return NextResponse.json({ error: 'Invalid request' }, { status: 400 }); } const incoming = body?.translations as Record | undefined; const currentLocale = (body?.currentLocale as Locale) ?? 'en'; if (!incoming) { return NextResponse.json({ error: 'Missing translations' }, { status: 400 }); } const payload = SUPPORTED_LOCALES.reduce( (acc, loc) => ({ ...acc, [loc]: { title: incoming[loc]?.title || '', teaser: incoming[loc]?.teaser || '', description: incoming[loc]?.description || '', }, }), {} as Record, ); const messages = [ { role: 'system', content: 'You are translating holiday rental listing copy between Finnish, Swedish, and English. Fill in missing locales, keep existing text unchanged, preserve meaning and tone, and respond with JSON only.', }, { role: 'user', content: JSON.stringify( { sourceLocale: currentLocale, targetLocales: SUPPORTED_LOCALES.filter((l) => l !== currentLocale), locales: payload, }, null, 2, ), }, { role: 'system', content: 'Return JSON with top-level "locales" containing keys en, fi, sv. Each locale has title, teaser, description. Do not include explanations.', }, ]; let content = ''; try { const res = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}`, }, body: JSON.stringify({ model: 'gpt-4o-mini', temperature: 0.2, messages, }), }); if (!res.ok) { const errText = await res.text(); return NextResponse.json({ error: 'AI request failed', detail: errText }, { status: 500 }); } const data = await res.json(); content = data?.choices?.[0]?.message?.content ?? ''; } catch (err) { return NextResponse.json({ error: 'AI request failed' }, { status: 500 }); } const jsonText = content.match(/\{[\s\S]*\}/)?.[0] ?? content; try { const parsed = JSON.parse(jsonText); const locales = parsed?.locales || parsed; if (!locales) throw new Error('missing locales'); const result = SUPPORTED_LOCALES.reduce( (acc, loc) => ({ ...acc, [loc]: { title: locales[loc]?.title ?? '', teaser: locales[loc]?.teaser ?? '', description: locales[loc]?.description ?? '', }, }), {} as Record, ); return NextResponse.json({ translations: result }); } catch (err) { return NextResponse.json({ error: 'Could not parse AI response' }, { status: 500 }); } }