import React, { useState } from 'react'; import { GoogleGenAI, Type } from "@google/genai"; import { Scenario } from '../types'; import { CBT_GLOSSARY } from '../constants'; import { Sparkles, X, Loader2, AlertCircle, Info, Target, UserCircle2, BrainCircuit, Check, BarChart } from 'lucide-react'; import { Button } from './ui/button'; import { Textarea } from './ui/textarea'; import { ScrollArea } from './ui/scroll-area'; import { Card } from './ui/card'; import { Badge } from './ui/badge'; interface ScenarioGeneratorProps { onGenerate: (scenario: Scenario) => void; onCancel: () => void; } const ScenarioGenerator: React.FC = ({ onGenerate, onCancel }) => { const [prompt, setPrompt] = useState(''); const [selectedConcepts, setSelectedConcepts] = useState([]); const [selectedDifficulty, setSelectedDifficulty] = useState('Intermediate'); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const toggleConcept = (term: string) => { setSelectedConcepts(prev => prev.includes(term) ? prev.filter(t => t !== term) : [...prev, term] ); }; const handleGenerate = async () => { if (!prompt.trim() && selectedConcepts.length === 0) return; setIsLoading(true); setError(null); try { const ai = new GoogleGenAI({ apiKey: import.meta.env.VITE_GEMINI_API_KEY }); const schema = { type: Type.OBJECT, properties: { id: { type: Type.STRING }, title: { type: Type.STRING }, characterName: { type: Type.STRING }, description: { type: Type.STRING }, category: { type: Type.STRING, enum: ['Social Anxiety', 'Workplace', 'Relationships', 'Self-Talk'] }, difficulty: { type: Type.STRING, enum: ['Beginner', 'Intermediate', 'Advanced'] }, systemInstruction: { type: Type.STRING }, initialMessage: { type: Type.STRING }, cbtFocus: { type: Type.ARRAY, items: { type: Type.STRING } } }, required: ['id', 'title', 'characterName', 'description', 'category', 'difficulty', 'systemInstruction', 'initialMessage', 'cbtFocus'] }; const selectedContext = selectedConcepts.length > 0 ? `Focus specifically on these CBT concepts: ${selectedConcepts.join(', ')}.` : ''; const result = await ai.models.generateContent({ model: 'gemini-3-flash-preview', config: { responseMimeType: 'application/json', responseSchema: schema, systemInstruction: ` [CONTEXT] You are a Clinical CBT Scenario Architect. The user requires a structured clinical simulation designed to address specific cognitive distortions and behavioral challenges. Clinical Focus: ${selectedContext} [TASK] Transform the user's prompt into a cohesive, structured clinical scenario that sets up a targeted roleplay environment. [CONSTRAINTS] - CATEGORIZATION: You MUST categorize the scenario appropriately (Social Anxiety, Workplace, Relationships, or Self-Talk). - DIFFICULTY CALIBRATION: The requested difficulty is '${selectedDifficulty}'. - 'Beginner': Low stakes, high support, clear-cut distortions, AI character is cooperative. - 'Intermediate': Ambiguous stakes, moderate social friction, subtle distortions, AI character has specific needs. - 'Advanced': High emotional triggers, persistent clinical resistance, complex cognitive patterns. - INTERNAL LOGIC: Provide a detailed "INTERNAL CBT LOGIC" section instructing the AI character how to react to the user's progress or cognitive lapses during the future roleplay. - CHARACTER VOICE: Define a realistic, emotionally consistent voice profile. [OUTPUT REQUIREMENTS] Return ONLY a valid JSON object conforming exactly to the requested schema. Ensure all arrays and nested objects are populated correctly. ` }, contents: [ { role: 'user', parts: [{ text: `Generate a clinical scenario for: ${prompt || 'A scenario exploring the chosen CBT concepts.'}` }] } ] }); if (result.text) { const scenario = JSON.parse(result.text) as Scenario; // Enforce the user-selected difficulty in the final object scenario.difficulty = selectedDifficulty; scenario.id = `custom-${Date.now()}-${scenario.id}`; onGenerate(scenario); } else { throw new Error("No content generated"); } } catch (err: any) { console.error("Generation error:", err); setError("Clinical scenario synthesis failed. Please refine your parameters."); } finally { setIsLoading(false); } }; const getConceptVariant = (category: string, isSelected: boolean) => { if (!isSelected) return 'outline'; return 'default'; }; const getConceptColorClass = (category: string, isSelected: boolean) => { if (!isSelected) return 'text-slate-500 border-slate-200 hover:border-slate-300'; switch (category) { case 'Distortion': return 'bg-rose-600 border-rose-600 hover:bg-rose-700 shadow-md shadow-rose-100'; case 'Technique': return 'bg-teal-600 border-teal-600 hover:bg-teal-700 shadow-md shadow-teal-100'; case 'Concept': return 'bg-amber-600 border-amber-600 hover:bg-amber-700 shadow-md shadow-amber-100'; default: return 'bg-slate-800 border-slate-800 hover:bg-slate-900'; } }; return (
{/* Header */}

Scenario Synthesis

Construct an evidence-based clinical environment.

{/* Prompting Guide */}

Clinical Blueprint

Character Role

Define who the AI plays.

The Challenge

Describe the social friction.

CBT Focus

Target specific distortions.

{/* Difficulty Selection */}
{(['Beginner', 'Intermediate', 'Advanced'] as const).map((level) => ( ))}
{/* Clinical Targets (Selection) */}
{CBT_GLOSSARY.map(concept => { const isSelected = selectedConcepts.includes(concept.term); return ( toggleConcept(concept.term)} className={`px-3 py-1.5 rounded-lg text-[10px] font-bold border transition-all flex items-center gap-1.5 cursor-pointer hover:opacity-90 ${getConceptColorClass(concept.category, isSelected)}`} > {isSelected && } {concept.term} ); })}