feat: integrate AI-driven selection panel with context-aware text summarization and quiz generation features.

This commit is contained in:
2026-04-26 20:36:08 +02:00
parent 82d726097f
commit 39a9ca5706
25 changed files with 819 additions and 219 deletions
@@ -7,13 +7,17 @@
@inject IJSRuntime JS
@inject IFocusModeService FocusMode
@inject IKnowledgeGraphService GraphService
@inject IReaderInteractionService InteractionService
<div class="knowledge-graph-container" id="@ContainerId">
@if (GraphData == null)
@if (GraphService.IsLoading || GraphService.CurrentGraphData == null)
{
<div class="loading-state">
<NexusIcon Name="robot" Size="48" Class="neon-glow" />
<NexusTypography>Analyzing Chapter Nodes...</NexusTypography>
<div class="preloader-robot">
<NexusIcon Name="robot" Size="64" Class="neon-pulse" />
<div class="scan-line"></div>
</div>
<NexusTypography Variant="NexusTypography.TypographyVariant.UI">Mapowanie relacji rozdziału...</NexusTypography>
</div>
}
else
@@ -31,7 +35,6 @@
[Parameter] public EventCallback<string> OnNodeSelected { get; set; }
private string ContainerId = "d3-graph-container";
private GraphDataDto? GraphData;
private IJSObjectReference? _module;
private DotNetObjectReference<KnowledgeGraph>? _dotNetHelper;
@@ -40,12 +43,22 @@
FocusMode.OnFocusModeChanged += HandleFocusSimulation;
GraphService.OnGraphUpdated += HandleGraphUpdate;
GraphService.OnActiveNodeChanged += HandleActiveNodeChange;
GraphService.OnLoadingChanged += HandleLoadingChange;
}
private async void HandleGraphUpdate()
{
if (_module == null) return;
await _module.InvokeVoidAsync("updateData", GraphService.CurrentGraphData);
if (GraphService.CurrentGraphData == null)
{
await _module.InvokeVoidAsync("clear");
}
else
{
await _module.InvokeVoidAsync("updateData", GraphService.CurrentGraphData);
}
await InvokeAsync(StateHasChanged);
}
@@ -55,16 +68,20 @@
await _module.InvokeVoidAsync("setActiveNode", nodeId);
}
private async void HandleLoadingChange(bool isLoading)
{
await InvokeAsync(StateHasChanged);
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var result = await Mediator.Send(new GetKnowledgeGraphQuery());
if (result.IsSuccess)
await InitializeGraphAsync();
if (GraphService.CurrentGraphData != null)
{
GraphData = result.Value;
StateHasChanged();
await InitializeGraphAsync();
HandleGraphUpdate();
}
}
}
@@ -73,7 +90,7 @@
{
_module = await JS.InvokeAsync<IJSObjectReference>("import", "./_content/NexusReader.UI.Shared/js/knowledgeGraph.js");
_dotNetHelper = DotNetObjectReference.Create(this);
await _module.InvokeVoidAsync("mount", ContainerId, GraphData, _dotNetHelper);
await _module.InvokeVoidAsync("mount", ContainerId, GraphService.CurrentGraphData, _dotNetHelper);
}
private async Task ZoomIn() => await (_module?.InvokeVoidAsync("zoomIn") ?? ValueTask.CompletedTask);
@@ -83,6 +100,8 @@
[JSInvokable]
public async Task OnNodeClicked(string nodeId)
{
InteractionService.NotifyNodeSelected(nodeId);
if (OnNodeSelected.HasDelegate)
{
await OnNodeSelected.InvokeAsync(nodeId);
@@ -106,6 +125,10 @@
public async ValueTask DisposeAsync()
{
FocusMode.OnFocusModeChanged -= HandleFocusSimulation;
GraphService.OnGraphUpdated -= HandleGraphUpdate;
GraphService.OnActiveNodeChanged -= HandleActiveNodeChange;
GraphService.OnLoadingChanged -= HandleLoadingChange;
try
{
if (_module is not null)
@@ -114,14 +137,7 @@
await _module.DisposeAsync();
}
}
catch (JSDisconnectedException)
{
// Ignored, the circuit is already closed
}
catch (TaskCanceledException)
{
// Ignored, the circuit is already closed
}
catch { }
_dotNetHelper?.Dispose();
}