// Game-spezifischer Kontext für den Prompt const GAME_VIBES: Record = { snake: "Snake – präzise, fließend, ein Moment der Kontrolle", tetris: "Tetris – logisch, fokussiert, Gedanken ordnen statt Chaos", memory: "Memory – Geduld, Konzentration, im Hier und Jetzt bleiben", tictactoe: "Tic-Tac-Toe – ruhig, überlegt, kleine Strategie", }; function getGameVibe(gameName: string): string { const key = gameName.toLowerCase(); for (const [k, v] of Object.entries(GAME_VIBES)) { if (key.includes(k)) return v; } return `${gameName} – ein Moment bewusster Ablenkung`; } function buildFallback( isNewRecord: boolean, myRank: number | null, mode: string, ): string { const parts: string[] = []; if (isNewRecord) parts.push("Neuer persönlicher Rekord! 🏆"); else if (myRank) parts.push(`Rang #${myRank} in der Rangliste`); const challenge = mode === "impulse" ? "Impuls überwunden – kannst du länger standhalten? 💪" : "Kannst du das schlagen? 👊"; parts.push(challenge); return parts.join("\n"); } const SYSTEM_PROMPT = `Du generierst kurze Share-Texte (max 2–3 Zeilen) für die ReBreak-App. ReBreak hilft Menschen bei Glücksspielsucht, indem sie Mini-Games spielen statt zu gamble. Der Text wird im Community-Feed unter dem Spielnamen gepostet – er soll den Vibe des jeweiligen Spiels widerspiegeln. Regeln: - Zeile 1 (optional): Nur wenn neuer Rekord ODER guter Rang, eine kurze Meldung dazu - Letzte Zeile: Kurzer, kreativer Challenge-Satz passend zum Spiel auf Deutsch - 1–2 Emojis, passend zum Spiel und Ton - KEIN Spielname, KEINE Score-Zahl im Text - Keine Hashtags, keine URLs - Antworte NUR mit dem Text, kein Prefix, keine Anführungszeichen`; /** POST /api/games/share-text */ export default defineEventHandler(async (event) => { await requireUser(event); const body = await readBody(event); const { gameName, score, scoreLabel = "Punkte", bestScore, myRank, isNewRecord, mode = "game", } = body as { gameName: string; score: number; scoreLabel?: string; bestScore?: number; myRank?: number | null; isNewRecord?: boolean; mode?: string; }; if (!gameName || score == null) { throw createError({ statusCode: 400, message: "gameName und score erforderlich", }); } const config = useRuntimeConfig(); if (!config.groqApiKey) { return { text: buildFallback(!!isNewRecord, myRank ?? null, mode), }; } const gameVibe = getGameVibe(gameName); const userPrompt = [ `Spiel-Vibe: ${gameVibe}`, isNewRecord ? "NEUER PERSÖNLICHER REKORD!" : null, myRank ? `Rang #${myRank} in der Rangliste` : null, mode === "impulse" ? "Der Spieler hat einen Spielimpuls damit überwunden." : null, ] .filter(Boolean) .join("\n"); try { 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.1-8b-instant", max_tokens: 120, messages: [ { role: "system", content: SYSTEM_PROMPT }, { role: "user", content: userPrompt }, ], }, }); const text = response.choices?.[0]?.message?.content?.trim(); if (!text) throw new Error("empty response"); return { text }; } catch { return { text: buildFallback(!!isNewRecord, myRank ?? null, mode), }; } });