131 lines
6.4 KiB
C#
131 lines
6.4 KiB
C#
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<string> 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<ScenarioFunction>();
|
|
}
|
|
|
|
[Function("GenerateScenario")]
|
|
public async Task<HttpResponseData> 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<ScenarioRequest>(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<string, Schema>
|
|
{
|
|
{ "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<string> { "Social Anxiety", "Workplace", "Relationships", "Self-Talk" } } },
|
|
{ "difficulty", new Schema { Type = TypeEnum.String, Enum = new List<string> { "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<string> { "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<Part> { 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;
|
|
}
|
|
}
|
|
}
|
|
}
|