/** * GET /api/lyra/welcome-back * * Generiert einen kurzen, freundlichen Motivations-Text wenn der User nach * einer Schutz-Deaktivierung den Schutz wieder aktiviert hat. * * Pattern: erst LLM-Call (OpenRouter falls Key da, sonst OpenAI), bei Fehler * fällt's auf einen statischen Pool von vorgeschriebenen Sätzen zurück — * UX-Fallback statt User-facing-Error. * * Response: { message: string, source: "ai" | "fallback" } */ const WELCOME_BACK_PROMPT = `Du bist Lyra, der KI-Coach der Rebreak-App. Der Nutzer hat seinen Glücksspiel-Schutz kurz deaktiviert und gerade wieder aktiviert. Schreibe ihm GENAU EINE freundliche, warme Nachricht (max 3 kurze Sätze, Deutsch, du-Form). WICHTIG: - Kein Urteil, keine Belehrung - Kein Schuldgefühl, kein "endlich" - Anerkennung dass Rückfälle/Ausrutscher zur Recovery gehören - Stärke betonen dass er WIEDER aktiviert hat - Kein Wort "Sucht", "süchtig", "Rückfall" — stattdessen: "Phase", "Moment", "Stärke" Antwort: nur die Nachricht, keine Anführungszeichen, kein Kontext.`; const FALLBACK_MESSAGES = [ "Schön dass du wieder da bist. Diese eine Geste — den Schutz wieder einzuschalten — zeigt mehr Stärke als die meisten je sehen werden. Ich bin stolz auf dich.", "Hey. Ausrutscher gehören zum Weg. Was zählt ist dass du jetzt hier bist, mit dem Schutz an. Das ist die wichtige Entscheidung.", "Willkommen zurück. Du hast eine Pause genommen — und bist jetzt wieder hier. Genau so läuft Recovery: nicht linear, sondern echt. Lass uns weitermachen.", "Gut dich wieder zu sehen. Manchmal braucht es einen kurzen Umweg um den eigenen Weg klarer zu sehen. Du gehst ihn weiter — das ist das Wichtige.", "Hey, alles gut. Du hast den Schutz wieder aktiv — das war eine bewusste Entscheidung gegen den Impuls. Genau das ist der Muskel den wir hier trainieren.", ]; export default defineEventHandler(async (event) => { await requireUser(event); const config = useRuntimeConfig(event); const openrouterKey = config.openrouterApiKey as string | undefined; const openaiKey = config.openaiApiKey as string | undefined; const key = openrouterKey ?? openaiKey; // Fallback wenn keine Keys konfiguriert if (!key) { return { message: pickRandom(FALLBACK_MESSAGES), source: "fallback" as const, }; } const isOpenRouter = !!openrouterKey; const url = isOpenRouter ? "https://openrouter.ai/api/v1/chat/completions" : "https://api.openai.com/v1/chat/completions"; const model = isOpenRouter ? "meta-llama/llama-3.1-8b-instruct" : "gpt-4o-mini"; try { const res = await $fetch<{ choices: { message: { content: string } }[] }>( url, { method: "POST", headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json", ...(isOpenRouter && { "HTTP-Referer": "https://rebreak.org", "X-Title": "ReBreak Welcome-Back", }), }, body: { model, max_tokens: 200, temperature: 0.85, messages: [ { role: "system", content: WELCOME_BACK_PROMPT }, { role: "user", content: "Schreibe mir die Welcome-Back-Nachricht." }, ], }, timeout: 6000, }, ); const text = res.choices?.[0]?.message?.content?.trim(); if (text && text.length > 10 && text.length < 600) { return { message: text, source: "ai" as const }; } return { message: pickRandom(FALLBACK_MESSAGES), source: "fallback" as const }; } catch (e: any) { console.warn("[lyra.welcome-back] LLM-call failed:", e?.message ?? e); return { message: pickRandom(FALLBACK_MESSAGES), source: "fallback" as const }; } }); function pickRandom(arr: readonly T[]): T { return arr[Math.floor(Math.random() * arr.length)]; }