157 lines
6.1 KiB
C#
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 sessionId, string chatInput)
|
|
{
|
|
var webhookUrl = _configuration["ChatSettings:ExternalWebhookUrl"];
|
|
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);
|
|
}
|
|
} |