using System.Net; using System.Text.Json; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.Extensions.Logging; using Google.GenAI; using System.Text.Json.Serialization; namespace CognitiveClarity.api { public class ScenarioRequest { [JsonPropertyName("prompt")] public string Prompt { get; set; } = string.Empty; [JsonPropertyName("selectedConcepts")] public List SelectedConcepts { get; set; } = new(); [JsonPropertyName("difficulty")] public string Difficulty { get; set; } = "Intermediate"; } public class ScenarioFunction { private readonly ILogger _logger; public ScenarioFunction(ILoggerFactory loggerFactory) { _logger = loggerFactory.CreateLogger(); } [Function("GenerateScenario")] public async Task Run( [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "scenario/generate")] HttpRequestData req) { _logger.LogInformation("C# HTTP trigger function processed a scenario generation request."); var requestBody = await new StreamReader(req.Body).ReadToEndAsync(); var data = JsonSerializer.Deserialize(requestBody); if (data == null || (string.IsNullOrWhiteSpace(data.Prompt) && data.SelectedConcepts.Count == 0)) { var badResponse = req.CreateResponse(HttpStatusCode.BadRequest); await badResponse.WriteStringAsync("Please pass a prompt or concepts in the request body"); return badResponse; } var apiKey = Environment.GetEnvironmentVariable("GEMINI_API_KEY"); if (string.IsNullOrEmpty(apiKey)) { _logger.LogError("GEMINI_API_KEY is missing from environment variables."); return req.CreateResponse(HttpStatusCode.InternalServerError); } // Initialize the Gemini Client var ai = new GeminiClient(apiKey: apiKey); var selectedContext = data.SelectedConcepts.Count > 0 ? $"Focus specifically on these CBT concepts: {string.Join(", ", data.SelectedConcepts)}." : ""; var 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 '{data.Difficulty}'. - '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. "; var schema = new Schema { Type = TypeEnum.Object, Properties = new Dictionary { { "id", new Schema { Type = TypeEnum.String } }, { "title", new Schema { Type = TypeEnum.String } }, { "characterName", new Schema { Type = TypeEnum.String } }, { "description", new Schema { Type = TypeEnum.String } }, { "category", new Schema { Type = TypeEnum.String, Enum = new List { "Social Anxiety", "Workplace", "Relationships", "Self-Talk" } } }, { "difficulty", new Schema { Type = TypeEnum.String, Enum = new List { "Beginner", "Intermediate", "Advanced" } } }, { "systemInstruction", new Schema { Type = TypeEnum.String } }, { "initialMessage", new Schema { Type = TypeEnum.String } }, { "cbtFocus", new Schema { Type = TypeEnum.Array, Items = new Schema { Type = TypeEnum.String } } } }, Required = new List { "id", "title", "characterName", "description", "category", "difficulty", "systemInstruction", "initialMessage", "cbtFocus" } }; var promptText = $"Generate a clinical scenario for: {(string.IsNullOrWhiteSpace(data.Prompt) ? "A scenario exploring the chosen CBT concepts." : data.Prompt)}"; try { var response = await ai.Models.GenerateContentAsync( model: "gemini-3.0-flash", contents: promptText, new GenerateContentConfig { SystemInstruction = new Content { Parts = new List { new Part { Text = systemInstruction } } }, ResponseMimeType = "application/json", ResponseSchema = schema }); var successResponse = req.CreateResponse(HttpStatusCode.OK); successResponse.Headers.Add("Content-Type", "application/json"); await successResponse.WriteStringAsync(response.Text!); return successResponse; } catch (Exception ex) { _logger.LogError(ex, "Failed to generate scenario via Gemini API."); var errorResponse = req.CreateResponse(HttpStatusCode.InternalServerError); await errorResponse.WriteStringAsync("Error communicating with Gemini API."); return errorResponse; } } } }