import { NextResponse } from 'next/server' import OpenAI from 'openai' type LlmProvider = 'openai' | 'openrouter' function getProvider(): LlmProvider { const configured = (process.env.LLM_PROVIDER ?? '').toLowerCase() if (configured === 'openrouter') return 'openrouter' if (configured === 'openai') return 'openai' return process.env.OPENROUTER_API_KEY ? 'openrouter' : 'openai' } function createClient(provider: LlmProvider) { if (provider === 'openrouter') { const apiKey = process.env.OPENROUTER_API_KEY || '' return new OpenAI({ apiKey, baseURL: process.env.OPENROUTER_BASE_URL || 'https://openrouter.ai/api/v1', defaultHeaders: { ...(process.env.OPENROUTER_SITE_URL ? { 'HTTP-Referer': process.env.OPENROUTER_SITE_URL } : {}), ...(process.env.OPENROUTER_APP_NAME ? { 'X-Title': process.env.OPENROUTER_APP_NAME } : {}), }, }) } return new OpenAI({ apiKey: process.env.OPENAI_API_KEY || '', }) } function getModel(provider: LlmProvider): string { if (provider === 'openrouter') { return process.env.OPENROUTER_MODEL || 'minimax/minimax-m2.5' } return process.env.OPENAI_MODEL || 'gpt-4o-mini' } function hasApiKey(provider: LlmProvider): boolean { if (provider === 'openrouter') return !!process.env.OPENROUTER_API_KEY return !!process.env.OPENAI_API_KEY } function buildFallbackLandingContent(orgName: string, context: string) { const cleanOrg = orgName.trim() const cleanContext = context.trim().replace(/\s+/g, ' ') const shortContext = cleanContext.slice(0, 180) const detailSentence = shortContext ? `Dabei stehen insbesondere ${shortContext}.` : 'Dabei stehen regionale Vernetzung, starke Ausbildung und praxisnahe Unterstützung im Mittelpunkt.' return { title: `${cleanOrg} - Stark im Handwerk`, text: `${cleanOrg} verbindet Betriebe, stärkt die Gemeinschaft und setzt sich für die Interessen des Handwerks vor Ort ein. ${detailSentence}`, fallbackUsed: true, } } export async function POST(req: Request) { let parsedBody: any = null try { const body = await req.json() parsedBody = body const { orgName, context } = body if (!orgName || !context) { return NextResponse.json({ error: 'orgName and context are required' }, { status: 400 }) } const provider = getProvider() const model = getModel(provider) if (!hasApiKey(provider)) { return NextResponse.json(buildFallbackLandingContent(orgName, context)) } const client = createClient(provider) const systemMessage = `Sie sind ein professioneller Copywriter für eine moderne deutsche Innung oder Kreishandwerkerschaft. Erstellen Sie eine moderne, ansprechende Überschrift (Heading) und einen Einleitungstext für eine Landingpage. WICHTIG: Geben Sie AUSSCHLIESSLICH ein valides JSON-Objekt zurück, komplett ohne Markdown-Formatierung (kein \`\`\`json ... \`\`\`), in dieser Struktur: { "title": "Eine moderne, ansprechende Überschrift (max. 6-8 Wörter)", "text": "Ein überzeugender Einleitungstext, der erklärt, wofür die Organisation steht, fokussiert auf die Region und den Kontext (max. 3-4 Sätze)." }` const userMessage = `Name der Organisation: ${orgName}\nZusätzliche Stichpunkte vom Benutzer:\n${context}` const completion = await client.chat.completions.create({ model, messages: [ { role: 'system', content: systemMessage }, { role: 'user', content: userMessage }, ], // some openrouter models ignore response_format, so doing it purely by prompt temperature: 0.7 }) let textResponse = completion.choices[0]?.message?.content || '' // safely remove potential markdown blocks just in case textResponse = textResponse.trim() if (textResponse.startsWith('```json')) { textResponse = textResponse.replace(/^```json\n?/, '').replace(/\n?```$/, '').trim() } else if (textResponse.startsWith('```')) { textResponse = textResponse.replace(/^```\n?/, '').replace(/\n?```$/, '').trim() } const result = JSON.parse(textResponse) return NextResponse.json(result) } catch (error: any) { console.error('Error generating AI landing page content:', error) if (parsedBody?.orgName && parsedBody?.context) { return NextResponse.json(buildFallbackLandingContent(parsedBody.orgName, parsedBody.context)) } return NextResponse.json({ error: error?.message || 'Failed to generate content' }, { status: 500 }) } }