/** * POST /api/coach/sos-session — Erstellt Session für SSE-Stream * * Client sendet messages + locale, Backend generiert sessionId * und speichert Daten in-memory. Client nutzt dann GET /api/coach/sos-stream?session=xyz * * Grund: react-native-sse (EventSource API) unterstützt nur GET, nicht POST. * Daher 2-Step-Flow: POST Session erstellen → GET Stream öffnen. * * Safety: Deterministischer Crisis-Pre-Filter (crisis-filter.ts) läuft HIER, * bevor das LLM überhaupt gestartet wird. Das Ergebnis (crisisLevel) wird in * der Session gespeichert und von sos-stream.get.ts genutzt um Krisen-Chips * LLM-unabhängig einzublenden. */ import { detectCrisis } from "../../utils/crisis-filter"; export default defineEventHandler(async (event) => { const user = await requireUser(event); const body = await readBody(event); const { messages, locale, llmProvider } = body as { messages: Array<{ role: "user" | "assistant"; content: string }>; locale?: string; llmProvider?: string; }; if (!messages || !Array.isArray(messages)) { throw createError({ statusCode: 400, message: "messages fehlt" }); } // ── Deterministischer Crisis-Pre-Filter ────────────────────────────────── // Prüfe die letzten 3 User-Nachrichten (nicht nur die letzte — Kontext zählt). // Läuft synchron, kein Overhead, kein LLM-Aufruf. const userTexts = messages .filter((m) => m.role === "user") .slice(-3) .map((m) => m.content); const crisisResult = detectCrisis(userTexts); if (crisisResult.isCrisis) { console.log( `[crisis-filter] MATCH user=${user.id} level=${crisisResult.level} ` + `group=${crisisResult.matchedGroup} pattern="${crisisResult.matchedPattern}"`, ); } // Session-ID generieren const sessionId = `sos_${user.id}_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`; // In globalem Store speichern (siehe server/utils/sosSessions.ts) const { setSosSession } = await import("../../utils/sosSessions"); setSosSession(sessionId, { userId: user.id, messages, locale: locale ?? "de", llmProvider, createdAt: Date.now(), crisisLevel: crisisResult.level, }); return { sessionId, // crisisDetected wird transparent ans Frontend zurückgegeben — // Frontend kann damit sofort (noch vor Stream-Start) die Krisen-UI aktivieren. crisisDetected: crisisResult.isCrisis, crisisLevel: crisisResult.level, }; });