aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio_22/Tango.Portal.Chat.Web/Controllers/ChatController.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Software/Visual_Studio_22/Tango.Portal.Chat.Web/Controllers/ChatController.cs')
-rw-r--r--Software/Visual_Studio_22/Tango.Portal.Chat.Web/Controllers/ChatController.cs108
1 files changed, 96 insertions, 12 deletions
diff --git a/Software/Visual_Studio_22/Tango.Portal.Chat.Web/Controllers/ChatController.cs b/Software/Visual_Studio_22/Tango.Portal.Chat.Web/Controllers/ChatController.cs
index a13b6a47a..396651e3f 100644
--- a/Software/Visual_Studio_22/Tango.Portal.Chat.Web/Controllers/ChatController.cs
+++ b/Software/Visual_Studio_22/Tango.Portal.Chat.Web/Controllers/ChatController.cs
@@ -19,13 +19,15 @@ namespace Tango.Portal.Chat.Web.Controllers
private readonly KqlGuard _guard;
private readonly KustoQueryService _adx;
private readonly LlmClient _llm;
+ private readonly ChatMessageLogger _logger;
- public ChatController(SchemaRegistry schema, KqlGuard guard, KustoQueryService adx, LlmClient llm)
+ public ChatController(SchemaRegistry schema, KqlGuard guard, KustoQueryService adx, LlmClient llm, ChatMessageLogger logger)
{
_schema = schema;
_guard = guard;
_adx = adx;
_llm = llm;
+ _logger = logger;
}
[HttpPost("ask")]
@@ -33,6 +35,36 @@ namespace Tango.Portal.Chat.Web.Controllers
{
try
{
+ if (!SessionUtils.IsUserAuthenticated(HttpContext))
+ {
+ return new ChatResponse
+ {
+ Answer = "User is not authenticated or session expired",
+ ThreadId = req.ThreadId
+ };
+ }
+
+ var sessionUser = SessionUtils.GetSessionUser(HttpContext);
+ var sessionId = HttpContext.Session.Id;
+
+ // Log the question
+ _ = Task.Run(async () =>
+ {
+ try
+ {
+ await _logger.LogQuestionAsync(
+ sessionId,
+ sessionUser?.Email ?? "unknown",
+ sessionUser?.FullName ?? "unknown",
+ req.Question,
+ ct);
+ }
+ catch
+ {
+ // Ignore logging failures
+ }
+ }, ct);
+
var schemaJson = _schema.GetSchemaJson();
var plannerPrompt = _schema.GetPlannerPrompt();
var plotySample = _schema.GetPlotySample();
@@ -50,30 +82,77 @@ namespace Tango.Portal.Chat.Web.Controllers
plan = await _llm.ProposeKqlAsync(plannerPrompt, plotySample, req.Question, schemaJson, req.History, ct);
}
+ ChatResponse response;
if (plan.Assistant == "data" || plan.Assistant == "ploty")
{
- return await AnswerWithDataAssistant(req, plan, ct);
+ response = await AnswerWithDataAssistant(req, plan, ct);
}
else if (plan.Assistant == "docs")
{
- return await AnswerWithDocsAssistant(req, plan, ct);
+ response = await AnswerWithDocsAssistant(req, plan, ct);
}
else
{
- return AnswerWithPlannerConversation(req, plan);
+ response = AnswerWithPlannerConversation(req, plan);
}
+
+ // Log the answer
+ _ = Task.Run(async () =>
+ {
+ try
+ {
+ await _logger.LogAnswerAsync(
+ sessionId,
+ sessionUser?.Email ?? "unknown",
+ sessionUser?.FullName ?? "unknown",
+ response,
+ plan.Assistant,
+ plan.Provider.ToString(),
+ ct);
+ }
+ catch
+ {
+ // Ignore logging failures
+ }
+ }, ct);
+
+ return response;
}
catch (Exception ex)
{
- return new ChatResponse
+ var errorResponse = new ChatResponse
{
Answer = $"Ooops something went wrong...\n{ex.Message}",
ThreadId = req.ThreadId
};
+
+ // Log the error response
+ var sessionUser = SessionUtils.GetSessionUser(HttpContext);
+ var sessionId = req.ThreadId ?? Guid.NewGuid().ToString();
+ _ = Task.Run(async () =>
+ {
+ try
+ {
+ await _logger.LogAnswerAsync(
+ sessionId,
+ sessionUser?.Email ?? "unknown",
+ sessionUser?.FullName ?? "unknown",
+ errorResponse,
+ "error",
+ "Unknown",
+ ct);
+ }
+ catch
+ {
+ // Ignore logging failures
+ }
+ }, ct);
+
+ return errorResponse;
}
}
- private static ActionResult<ChatResponse> AnswerWithPlannerConversation(ChatRequest req, ProposeKqlResult plan)
+ private ChatResponse AnswerWithPlannerConversation(ChatRequest req, ProposeKqlResult plan)
{
return new ChatResponse
{
@@ -82,7 +161,7 @@ namespace Tango.Portal.Chat.Web.Controllers
};
}
- private async Task<ActionResult<ChatResponse>> AnswerWithDocsAssistant(ChatRequest req, ProposeKqlResult plan, CancellationToken ct)
+ private async Task<ChatResponse> AnswerWithDocsAssistant(ChatRequest req, ProposeKqlResult plan, CancellationToken ct)
{
// AFTER
var run = await _llm.AnswerWithAssistantAsync(
@@ -100,7 +179,7 @@ namespace Tango.Portal.Chat.Web.Controllers
};
}
- private async Task<ActionResult<ChatResponse>> AnswerWithDataAssistant(ChatRequest req, ProposeKqlResult plan, CancellationToken ct)
+ private async Task<ChatResponse> AnswerWithDataAssistant(ChatRequest req, ProposeKqlResult plan, CancellationToken ct)
{
// 2) Guardrail validation
var val = _guard.Validate(plan.Kql);
@@ -125,7 +204,12 @@ namespace Tango.Portal.Chat.Web.Controllers
{
if (plan.Provider == LlmProvider.OpenAI)
{
- return await Ask(req, ct, LlmProvider.Claude);
+ var fallbackResult = await Ask(req, ct, LlmProvider.Claude);
+ return fallbackResult.Value ?? new ChatResponse
+ {
+ Answer = "Fallback to Claude failed",
+ ThreadId = req.ThreadId
+ };
}
else
{
@@ -156,7 +240,7 @@ namespace Tango.Portal.Chat.Web.Controllers
}
}
- private async Task<ActionResult<ChatResponse>> AnswerWithDataAssistantInternal(ChatRequest req, ProposeKqlResult plan, DataTable table, CancellationToken ct)
+ private async Task<ChatResponse> AnswerWithDataAssistantInternal(ChatRequest req, ProposeKqlResult plan, DataTable table, CancellationToken ct)
{
var preview = DataHelper.ToPreview(table, 200);
var facts = JsonSerializer.Serialize(preview);
@@ -181,7 +265,7 @@ namespace Tango.Portal.Chat.Web.Controllers
};
}
- private static ActionResult<ChatResponse> AnswerWithMarkdownTable(ChatRequest req, ProposeKqlResult plan, DataTable table)
+ private ChatResponse AnswerWithMarkdownTable(ChatRequest req, ProposeKqlResult plan, DataTable table)
{
var markdown = DataHelper.ToMarkdownTable(table);
@@ -194,7 +278,7 @@ namespace Tango.Portal.Chat.Web.Controllers
};
}
- private static ActionResult<ChatResponse> AnswerWithPloty(ChatRequest req, ProposeKqlResult plan, DataTable table)
+ private ChatResponse AnswerWithPloty(ChatRequest req, ProposeKqlResult plan, DataTable table)
{
String? ploty = table.Rows[0]["ploty"]?.ToString();