Files
Alchegos.HCI/Services/InMemoryChatSessionService.cs
2025-05-04 19:11:12 +01:00

157 lines
6.1 KiB
C#

using System.Collections.Concurrent;
using System.Text;
using System.Text.Json;
using Alchegos.HCI.Models;
namespace Alchegos.HCI.Services;
public class InMemoryChatSessionService : IChatSessionService
{
private readonly ConcurrentDictionary<string, ChatSession> _sessions = new();
private readonly IHttpClientFactory _httpClientFactory;
private readonly IConfiguration _configuration;
private readonly ILogger<InMemoryChatSessionService> _logger;
public InMemoryChatSessionService(IHttpClientFactory httpClientFactory, IConfiguration configuration,
ILogger<InMemoryChatSessionService> logger)
{
_httpClientFactory = httpClientFactory;
_configuration = configuration;
_logger = logger;
}
public ChatSession GetOrCreateSession(string sessionId)
{
return _sessions.GetOrAdd(sessionId, id => new ChatSession { SessionId = id });
}
public ChatSession? GetSession(string sessionId)
{
_sessions.TryGetValue(sessionId, out var session);
return session;
}
public void AddMessage(string sessionId, ChatMessage message)
{
if (_sessions.TryGetValue(sessionId, out var session))
{
session.Messages.Add(message);
}
}
public void SetWaitingStatus(string sessionId, bool isWaiting)
{
if (_sessions.TryGetValue(sessionId, out var session))
{
session.IsWaitingForResponse = isWaiting;
}
}
public void RemoveSession(string sessionId)
{
if (_sessions.TryRemove(sessionId, out var session))
_logger.LogInformation("Session removed: {SessionId}", sessionId);
else
_logger.LogWarning("Attempted to remove non-existent session: {SessionId}", sessionId);
}
public void RegisterSessionCallbacks(string sessionId, Func<ChatMessage, Task>? messageCallback,
Func<Task>? closeCallback)
{
if (_sessions.TryGetValue(sessionId, out var session))
{
session.NotifyMessageReceived = messageCallback;
session.NotifySessionClosed = closeCallback;
_logger.LogInformation("Registered callbacks for session: {SessionId}", sessionId);
}
else
_logger.LogWarning("Attempted to register callbacks for non-existent session: {SessionId}", sessionId);
}
public void UnregisterSessionCallbacks(string sessionId)
{
if (_sessions.TryGetValue(sessionId, out var session))
{
session.NotifyMessageReceived = null;
session.NotifySessionClosed = null;
_logger.LogInformation("Unregistered callbacks for session: {SessionId}", sessionId);
}
}
public async Task SendMessageToExternalWebhook(string webhookUrl, string sessionId, string chatInput)
{
//var webhookUrl = Environment.GetEnvironmentVariable("HCI_WEBHOOK_URL");
if (string.IsNullOrEmpty(webhookUrl))
{
_logger.LogError("ExternalWebhookUrl is not configured in ChatSettings.");
SetWaitingStatus(sessionId, false);
return;
}
var payload = new { sessionId, chatInput };
var jsonPayload = JsonSerializer.Serialize(payload);
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
try
{
var httpClient = _httpClientFactory.CreateClient();
_logger.LogInformation("Sending message to webhook for session {SessionId}: {Url}", sessionId, webhookUrl);
var response = await httpClient.PostAsync(webhookUrl, content);
response.EnsureSuccessStatusCode();
_logger.LogInformation("Successfully sent message to webhook for session {SessionId}", sessionId);
}
catch (HttpRequestException ex)
{
_logger.LogError(ex, "Error sending message to external webhook for session {SessionId}", sessionId);
AddMessage(sessionId, new ChatMessage { IsUser = false, Content = $"Error sending message: {ex.Message}" });
SetWaitingStatus(sessionId, false);
await TriggerMessageReceived(sessionId, $"Error: Could not reach the processing service.");
}
catch (Exception ex)
{
_logger.LogError(ex, "Unexpected error sending message to external webhook for session {SessionId}",
sessionId);
AddMessage(sessionId,
new ChatMessage { IsUser = false, Content = $"An unexpected error occurred: {ex.Message}" });
SetWaitingStatus(sessionId, false);
await TriggerMessageReceived(sessionId, $"Error: An unexpected error occurred.");
}
}
public async Task TriggerMessageReceived(string sessionId, string output)
{
if (_sessions.TryGetValue(sessionId, out var session))
{
_logger.LogInformation("Received message via webhook for session {SessionId}", sessionId);
var serverMessage = new ChatMessage { IsUser = false, Content = output };
session.Messages.Add(serverMessage);
session.IsWaitingForResponse = false;
if (session.NotifyMessageReceived != null)
await session.NotifyMessageReceived(serverMessage);
else
_logger.LogWarning("No message callback registered for session {SessionId} to notify.", sessionId);
}
else
_logger.LogWarning("Received message for non-existent or inactive session: {SessionId}", sessionId);
}
public async Task TriggerSessionClosed(string sessionId)
{
if (_sessions.TryGetValue(sessionId, out var session))
{
_logger.LogInformation("Received close request via webhook for session {SessionId}", sessionId);
if (session.NotifySessionClosed != null)
await session.NotifySessionClosed();
else
_logger.LogWarning("No close callback registered for session {SessionId} to notify.", sessionId);
RemoveSession(sessionId);
}
else
_logger.LogWarning("Received close request for non-existent or already removed session: {SessionId}",
sessionId);
}
}