import { createPost } from "../../db/community"; export const LYRA_TOPICS = [ "motivation", "tipp", "zitat", "witzig", "news", "feature", ] as const; export type LyraTopic = (typeof LYRA_TOPICS)[number]; export const TOPIC_HINTS: Record = { motivation: "Schreibe einen kurzen, stillen Gedanken für Menschen die heute kämpfen. Nicht übertrieben – eher ruhig stark.", tipp: "Teile einen kleinen, konkreten Trick aus der Verhaltensforschung oder CBT gegen Spieldrang. Praktisch und direkt.", zitat: "Teile ein tiefgründiges Zitat aus Psychologie, Stoizismus oder Verhaltensforschung – ohne das Wort 'Sucht' zu verwenden. Kurz kommentiert.", witzig: "Schreibe einen witzigen, selbstironischen Post über das Thema Ablenkung, Impulskontrolle oder Gewohnheiten – leicht und menschlich, nicht flach.", news: "Beschreibe kurz eine typische Taktik der Glücksspielindustrie (z.B. Push-Notifications, Bonusangebote) – sachlich und als Warnung formuliert.", feature: "Weise freundlich auf ein ReBreak-Feature hin (Blocker, Streak, Mail-Agent, Lyra-Chat, SOS-Atemübung) – wähle eines zufällig oder nutze den gegebenen Kontext.", }; const LYRA_SYSTEM_PROMPT = `Du bist Lyra – Recovery-Coach und Begleiterin der ReBreak-Community. Du hast tiefes Wissen in CBT, Verhaltenspsychologie und dem Alltag von Menschen mit Spielsucht. Du schreibst kurze Community-Beiträge. Deine Stimme: - Direkt und persönlich – du sprichst die Person an ("du") - Warmherzig, geerdet, wie jemand der wirklich zuhört - Niemals klischeehafte Motivationsfloskeln ("Du schaffst das!!!") - Kein KI-Sprech, keine Listen, keine Aufzählungen - Keine Casino-Werbung, keine Links, keine medizinischen Diagnosen - Auf Deutsch, max. 3–4 Sätze Antworte NUR mit dem Post-Text. Kein "Lyra:" Prefix, keine Anführungszeichen.`; const REBREAK_SYSTEM_PROMPT = `Du bist der offizielle ReBreak Account. ReBreak ist eine App zur Überwindung von Glücksspielsucht. Du postest Neuigkeiten, Updates und Community-Ankündigungen. Deine Tonalität: - Offiziell aber nahbar – wie ein Team-Update, nicht wie Werbung - Kurz (max. 3–4 Sätze) - Sachlich und informativ, gelegentlich motivierend - Keine medizinischen Ratschläge, keine Links - Auf Deutsch Antworte NUR mit dem Post-Text. Kein "ReBreak:" Prefix, keine Anführungszeichen.`; /** POST /api/admin/lyra-post — manueller Bot-Post vom Admin-Dashboard */ export default defineEventHandler(async (event) => { const config = useRuntimeConfig(); const adminSecret = getHeader(event, "x-admin-secret"); if (!config.adminSecret || adminSecret !== config.adminSecret) { throw createError({ statusCode: 401, message: "Unauthorized" }); } const body = await readBody(event); const author: "lyra" | "rebreak" = body?.author === "rebreak" ? "rebreak" : "lyra"; const botUserId = author === "rebreak" ? config.rebreakBotUserId : config.lyraBotUserId; if (!botUserId) { throw createError({ statusCode: 500, message: `${author === "rebreak" ? "REBREAK_BOT_USER_ID" : "LYRA_BOT_USER_ID"} nicht konfiguriert`, }); } let content: string; if (body?.customContent?.trim()) { // Admin hat Text direkt eingegeben – kein LLM-Call nötig content = body.customContent.trim(); } else { if (!config.groqApiKey) { throw createError({ statusCode: 500, message: "Groq API Key fehlt", }); } const topic: LyraTopic = LYRA_TOPICS.includes(body?.topic) ? body.topic : LYRA_TOPICS[Math.floor(Math.random() * LYRA_TOPICS.length)]; const context: string | undefined = body?.context?.trim() || undefined; const userPrompt = context ? `${TOPIC_HINTS[topic]}\n\nZusätzlicher Kontext für diesen Post: ${context}` : TOPIC_HINTS[topic]; const systemPrompt = author === "rebreak" ? REBREAK_SYSTEM_PROMPT : LYRA_SYSTEM_PROMPT; const response = await $fetch<{ choices: { message: { content: string } }[]; }>("https://api.groq.com/openai/v1/chat/completions", { method: "POST", headers: { Authorization: `Bearer ${config.groqApiKey}`, "Content-Type": "application/json", }, body: { model: "llama-3.3-70b-versatile", max_tokens: 200, messages: [ { role: "system", content: systemPrompt }, { role: "user", content: userPrompt }, ], }, }); content = response.choices?.[0]?.message?.content?.trim() ?? ""; if (!content) { throw createError({ statusCode: 500, message: "Keine Antwort von LLM" }); } } const post = await createPost(botUserId, "community", content); return { success: true, postId: post.id, author, content }; });