chahinebrini f2e822be95 feat(sos): llmProvider toggle + sort:latency + bench scaffolding
- backend/coach: routing zu Sonnet (default) / Haiku / Groq Llama je nach
  sessionData.llmProvider. sort:latency für Anthropic-Modelle (-30..58% TTFB).
- frontend: LlmProviderToggle (Sonnet/Haiku/Groq pills), llmProvider.ts
  Storage-Helper. sosStream.ts schickt llmProvider im /sos-session-Body.
- bench: SosTtsBenchmark sammelt Marker (req->session, lyra-ttfb, lyra-done,
  tts-fired/headers/body/file, audio-loaded, first-audio); Output als console.table.
- ops: backend/scripts/llm-bench.sh + Python-Variante für realistic SOS-Prompt.
- speak-cartesia + speak-elevenlabs Endpoints (waren ungetracked, jetzt mit drin).
2026-05-06 13:58:07 +02:00

57 lines
2.9 KiB
TypeScript

// Konstanten für den SOS-Screen: Chip-Sets, Atemphasen, Emotion-Regex.
export type ChipSet = 'start' | 'help' | 'after_breathing' | 'after_game' | 'overcome_check' | 'overcome_done' | 'none';
type Chip = { label: string; action: string };
export const CHIP_SETS: Record<ChipSet, Chip[]> = {
start: [
{ label: '😤 Wütend', action: 'feel:Ich bin gerade sehr wütend.' },
{ label: '😰 Ängstlich', action: 'feel:Ich bin ängstlich und nervös.' },
{ label: '😔 Traurig', action: 'feel:Ich bin traurig.' },
{ label: '😤 Gestresst', action: 'feel:Ich bin gerade gestresst.' },
{ label: '😶 Leer', action: 'feel:Ich fühle mich innerlich leer.' },
{ label: '🤔 Etwas anderes...', action: 'need_help' },
],
help: [
{ label: '🫁 Atemübung', action: 'breathing' },
{ label: '🎮 Spiel starten', action: 'game_picker' },
],
after_breathing: [
{ label: '😌 Besser', action: 'send_text:Ich fühle mich nach der Atemübung besser.' },
{ label: '🔄 Nochmal', action: 'breathing' },
{ label: '🎮 Spiel', action: 'game_picker' },
{ label: '❤️ Überwunden', action: 'overcome' },
],
after_game: [
{ label: '😌 Ruhiger', action: 'send_text:Das Spiel hat geholfen, ich bin ruhiger.' },
{ label: '🔄 Nochmal', action: 'game_picker' },
{ label: '❤️ Überwunden', action: 'overcome' },
],
overcome_check: [
{ label: '✅ Ja, ich habe es geschafft', action: 'overcome' },
{ label: '💪 Noch nicht ganz', action: 'send_text:Der Spielimpuls ist noch da, ich brauche noch Hilfe.' },
],
overcome_done: [
{ label: '✨ Erfolg teilen', action: 'share_success' },
{ label: '⭐ Diese Session bewerten', action: 'rate_session' },
{ label: '📊 Meine Statistik', action: 'show_stats' },
{ label: '✅ Fertig', action: 'close' },
],
none: [],
};
// ── Breathing guide ──────────────────────────────────────────────────────────
export type BreathPhase = 'inhale' | 'hold' | 'exhale';
export type BreathState = 'idle' | 'countdown' | 'active';
// speakLine bewusst durchgehend null — Phase-TTS würde Lyras laufende Audio abbrechen
// (User-Wahrnehmung: "Stimme ändert sich"). Visuelles Pulsieren + Countdown reicht.
export const BREATH_PHASES: { phase: BreathPhase; duration: number; label: string; color: string; speakLine: string | null }[] = [
{ phase: 'inhale', duration: 4, label: 'Einatmen', color: '#6366f1', speakLine: 'Einatmen' },
{ phase: 'hold', duration: 7, label: 'Halten', color: '#f97316', speakLine: 'Halten' },
{ phase: 'exhale', duration: 8, label: 'Ausatmen', color: '#16a34a', speakLine: 'Ausatmen' },
];
export const TOTAL_ROUNDS = 3;
export const EMPATHY_RE = /schwer|rückfall|traurig|schlimm|hoffnungslos|verloren|scham|schuld|verzweifelt/i;
export const HAPPY_RE = /toll|super|geschafft|stark|stolz|fantastisch|prima/i;