251 lines
8.7 KiB
Plaintext
251 lines
8.7 KiB
Plaintext
@page "/chat"
|
|
@page "/chat/{InitialSessionId}"
|
|
@rendermode InteractiveServer
|
|
@inject IChatSessionService ChatSessionService
|
|
@inject NavigationManager NavigationManager
|
|
@using Alchegos.HCI.Models
|
|
@using Alchegos.HCI.Services
|
|
@implements IAsyncDisposable
|
|
|
|
<PageTitle>Chat</PageTitle>
|
|
|
|
<h1>Chat Session</h1>
|
|
|
|
<div class="session-selector">
|
|
<input @bind="currentSessionIdInput" placeholder="Enter or Generate Session ID" />
|
|
<button @onclick="LoadSession" disabled="@isLoading">Load / Start Session</button>
|
|
<button @onclick="GenerateSessionId" disabled="@isLoading">Generate New ID</button>
|
|
<input @bind="externalWebhookUrl" placeholder="Server url">
|
|
@if (!string.IsNullOrEmpty(activeSessionId))
|
|
{
|
|
<span>Active Session: @activeSessionId</span>
|
|
}
|
|
</div>
|
|
|
|
@if (isLoading)
|
|
{
|
|
<p><em>Loading session...</em></p>
|
|
}
|
|
else if (currentSession != null)
|
|
{
|
|
<div class="chat-history" style="height: 400px; overflow-y: scroll; border: 1px solid #ccc; margin-bottom: 10px; padding: 5px;">
|
|
@foreach (var message in currentSession.Messages)
|
|
{
|
|
<div class="@(message.IsUser ? "user-message" : "server-message")">
|
|
<strong>@(message.IsUser ? "You" : "Server"):</strong>
|
|
<span>@message.Content</span>
|
|
<small style="font-size: 0.7em; color: grey; display: block;">@message.Timestamp.ToLocalTime()</small>
|
|
</div>
|
|
}
|
|
@if (currentSession.IsWaitingForResponse)
|
|
{
|
|
<p><em>Waiting for response...</em></p>
|
|
}
|
|
</div>
|
|
|
|
<div class="chat-input">
|
|
<input @bind="newMessage" placeholder="Type your message..." @onkeydown="HandleKeyDown" disabled="@currentSession.IsWaitingForResponse" />
|
|
<button @onclick="SendMessage" disabled="@(currentSession.IsWaitingForResponse || string.IsNullOrWhiteSpace(newMessage))">Send</button>
|
|
</div>
|
|
}
|
|
else if (sessionLoadAttempted)
|
|
{
|
|
<p><em>Enter a Session ID and click "Load / Start Session" or generate a new one.</em></p>
|
|
}
|
|
|
|
|
|
@code {
|
|
[Parameter] public string? InitialSessionId { get; set; }
|
|
|
|
private string currentSessionIdInput { get; set; } = string.Empty;
|
|
private string activeSessionId { get; set; } = string.Empty;
|
|
private ChatSession? currentSession;
|
|
private string newMessage { get; set; } = string.Empty;
|
|
private bool isLoading = false;
|
|
private bool sessionLoadAttempted = false;
|
|
private string externalWebhookUrl { get; set; } = string.Empty;
|
|
|
|
|
|
private string? _previousSessionId = null;
|
|
|
|
protected override async Task OnParametersSetAsync()
|
|
{
|
|
Console.WriteLine($"--- OnParametersSetAsync START. InitialSessionId: {InitialSessionId} ---");
|
|
if (InitialSessionId != _previousSessionId && !string.IsNullOrEmpty(InitialSessionId))
|
|
{
|
|
isLoading = true;
|
|
sessionLoadAttempted = true;
|
|
|
|
if (!string.IsNullOrEmpty(_previousSessionId) && _previousSessionId != InitialSessionId)
|
|
{
|
|
Console.WriteLine($"Parameter changed from {_previousSessionId} to {InitialSessionId}. Unregistering old callbacks for {_previousSessionId}.");
|
|
var oldId = _previousSessionId;
|
|
_ = Task.Run(() => ChatSessionService.UnregisterSessionCallbacks(oldId));
|
|
}
|
|
|
|
|
|
activeSessionId = InitialSessionId;
|
|
_previousSessionId = InitialSessionId;
|
|
|
|
Console.WriteLine($"Loading session from parameter: {activeSessionId}");
|
|
currentSession = ChatSessionService.GetOrCreateSession(activeSessionId);
|
|
|
|
if (currentSession != null)
|
|
{
|
|
Console.WriteLine($"Session obtained: {currentSession.SessionId}");
|
|
await RegisterCallbacksAsync();
|
|
}
|
|
else
|
|
Console.WriteLine("!!! Failed to get/create session in OnParametersSetAsync!");
|
|
|
|
|
|
|
|
isLoading = false;
|
|
Console.WriteLine("--- OnParametersSetAsync END. isLoading set to false ---");
|
|
|
|
}
|
|
else if (string.IsNullOrEmpty(InitialSessionId) && _previousSessionId != null)
|
|
{
|
|
Console.WriteLine("--- OnParametersSetAsync: InitialSessionId became null/empty. Clearing session. ---");
|
|
await UnregisterCallbacksAsync();
|
|
currentSession = null;
|
|
activeSessionId = string.Empty;
|
|
_previousSessionId = null;
|
|
currentSessionIdInput = string.Empty;
|
|
sessionLoadAttempted = false;
|
|
}
|
|
else if (InitialSessionId == _previousSessionId)
|
|
{
|
|
Console.WriteLine($"--- OnParametersSetAsync: InitialSessionId '{InitialSessionId}' did not change. Skipping load. ---");
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"--- OnParametersSetAsync: InitialSessionId '{InitialSessionId}' is null/empty and no previous ID. Initial state. ---");
|
|
}
|
|
}
|
|
|
|
protected override void OnInitialized()
|
|
{
|
|
if (!string.IsNullOrEmpty(InitialSessionId))
|
|
currentSessionIdInput = InitialSessionId;
|
|
}
|
|
|
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
{
|
|
if (firstRender && !string.IsNullOrEmpty(activeSessionId))
|
|
await RegisterCallbacksAsync();
|
|
}
|
|
|
|
|
|
private void GenerateSessionId()
|
|
{
|
|
var newId = Guid.NewGuid().ToString("N");
|
|
currentSessionIdInput = newId;
|
|
Console.WriteLine($"--- GenerateSessionId: Generated {newId}, Navigating... ---");
|
|
NavigationManager.NavigateTo($"/chat/{newId}");
|
|
}
|
|
|
|
private void LoadSession()
|
|
{
|
|
if (string.IsNullOrWhiteSpace(currentSessionIdInput))
|
|
{
|
|
Console.WriteLine("--- LoadSession Clicked: Input empty, doing nothing. ---");
|
|
return;
|
|
}
|
|
|
|
var sessionIdToLoad = currentSessionIdInput;
|
|
var targetUrl = $"/chat/{sessionIdToLoad}";
|
|
string currentPathAndQuery = new Uri(NavigationManager.Uri).PathAndQuery;
|
|
|
|
if (!currentPathAndQuery.Equals(targetUrl, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
Console.WriteLine($"--- LoadSession Clicked: Navigating to {targetUrl}... ---");
|
|
NavigationManager.NavigateTo(targetUrl);
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"--- LoadSession Clicked: Already at {targetUrl}. No navigation needed. ---");
|
|
}
|
|
}
|
|
|
|
|
|
private async Task SendMessage()
|
|
{
|
|
if (currentSession == null || string.IsNullOrWhiteSpace(newMessage) || currentSession.IsWaitingForResponse || String.IsNullOrWhiteSpace(externalWebhookUrl))
|
|
return;
|
|
|
|
var userMessage = new ChatMessage { IsUser = true, Content = newMessage };
|
|
ChatSessionService.AddMessage(activeSessionId, userMessage);
|
|
ChatSessionService.SetWaitingStatus(activeSessionId, true);
|
|
|
|
var messageToSend = newMessage;
|
|
newMessage = string.Empty;
|
|
|
|
StateHasChanged();
|
|
|
|
await ChatSessionService.SendMessageToExternalWebhook(externalWebhookUrl, activeSessionId, messageToSend);
|
|
|
|
}
|
|
|
|
private async Task HandleKeyDown(KeyboardEventArgs e)
|
|
{
|
|
if (e.Key == "Enter" && !currentSession.IsWaitingForResponse && !string.IsNullOrWhiteSpace(newMessage))
|
|
await SendMessage();
|
|
}
|
|
|
|
|
|
[JSInvokable]
|
|
public async Task HandleMessageReceived(ChatMessage message)
|
|
{
|
|
await InvokeAsync(StateHasChanged);
|
|
}
|
|
|
|
[JSInvokable]
|
|
public async Task HandleSessionClosed()
|
|
{
|
|
await InvokeAsync(() =>
|
|
{
|
|
if (currentSession != null && currentSession.SessionId == activeSessionId)
|
|
{
|
|
Console.WriteLine($"UI notified session closed: {activeSessionId}");
|
|
currentSession = null;
|
|
activeSessionId = string.Empty;
|
|
currentSessionIdInput = string.Empty;
|
|
NavigationManager.NavigateTo("/chat", forceLoad: false);
|
|
StateHasChanged();
|
|
}
|
|
});
|
|
}
|
|
|
|
private async Task RegisterCallbacksAsync()
|
|
{
|
|
if (currentSession != null)
|
|
{
|
|
_ = Task.Run(() =>
|
|
{
|
|
ChatSessionService.RegisterSessionCallbacks(
|
|
currentSession.SessionId,
|
|
HandleMessageReceived,
|
|
HandleSessionClosed
|
|
);
|
|
});
|
|
await Task.CompletedTask;
|
|
}
|
|
}
|
|
|
|
private async Task UnregisterCallbacksAsync()
|
|
{
|
|
if (!string.IsNullOrEmpty(activeSessionId))
|
|
{
|
|
var capturedSessionId = activeSessionId;
|
|
_ = Task.Run(() => ChatSessionService.UnregisterSessionCallbacks(capturedSessionId));
|
|
await Task.CompletedTask;
|
|
}
|
|
}
|
|
|
|
public async ValueTask DisposeAsync()
|
|
{
|
|
await UnregisterCallbacksAsync();
|
|
}
|
|
|
|
} |