feat: integrate AI-driven selection panel with context-aware text summarization and quiz generation features.
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
@using NexusReader.UI.Shared.Services
|
||||
@using NexusReader.Application.DTOs.AI
|
||||
@inject KnowledgeCoordinator Coordinator
|
||||
@inject IReaderInteractionService InteractionService
|
||||
|
||||
@if (IsVisible)
|
||||
{
|
||||
<div class="selection-ai-panel expanded @(PositionBelow ? "below" : "")" style="@PanelStyle">
|
||||
<div class="ai-bubble">
|
||||
<div class="ai-avatar">
|
||||
<div class="avatar-ring"></div>
|
||||
<NexusIcon Name="robot" Size="48" Class="neon-pulse" />
|
||||
<div class="avatar-label">
|
||||
<span class="name">E-Czytnik</span>
|
||||
<span class="role">Asystent AI</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ai-content">
|
||||
@if (IsLoading)
|
||||
{
|
||||
<div class="loading-state">
|
||||
<div class="shimmer">Skanowanie fragmentu...</div>
|
||||
</div>
|
||||
}
|
||||
else if (Packet != null)
|
||||
{
|
||||
<div class="summary-box">
|
||||
<NexusTypography Variant="NexusTypography.TypographyVariant.UI">@Packet.Summary</NexusTypography>
|
||||
</div>
|
||||
<div class="ai-actions">
|
||||
<button class="action-btn neon-border" @onclick="GenerateFullQuiz">Generuj Quiz dla całej strony</button>
|
||||
<button class="action-btn ghost" @onclick="Close">Zamknij</button>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="summary-box">
|
||||
<NexusTypography Variant="NexusTypography.TypographyVariant.UI">Wykryto ciekawy fragment! Czy chcesz, abym wygenerował podsumowanie lub quiz z tego rozdziału?</NexusTypography>
|
||||
</div>
|
||||
<div class="ai-actions">
|
||||
<button class="action-btn neon-border" @onclick="RequestSummary">Podsumuj zaznaczenie</button>
|
||||
<button class="action-btn ghost" @onclick="Close">Pomiń</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="bubble-pointer"></div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter] public string SelectedText { get; set; } = string.Empty;
|
||||
[Parameter] public string BlockId { get; set; } = string.Empty;
|
||||
[Parameter] public SelectionCoordinates? Coordinates { get; set; }
|
||||
[Parameter] public string FullPageContent { get; set; } = string.Empty;
|
||||
|
||||
private bool IsVisible => !string.IsNullOrEmpty(SelectedText) && Coordinates != null;
|
||||
private bool IsLoading = false;
|
||||
private KnowledgePacket? Packet;
|
||||
private bool PositionBelow => Coordinates != null && Coordinates.Top < 320;
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
Console.WriteLine($"[SelectionAiPanel] Parameters set. SelectedText: {SelectedText.Length} chars, Coordinates: {Coordinates?.Top}, PositionBelow: {PositionBelow}");
|
||||
// Reset packet when selection changes
|
||||
Packet = null;
|
||||
}
|
||||
|
||||
private string PanelStyle => Coordinates != null
|
||||
? string.Create(System.Globalization.CultureInfo.InvariantCulture,
|
||||
$"top: {(PositionBelow ? Coordinates.Top + 35 : Coordinates.Top - 15):F1}px !important; " +
|
||||
$"left: {Math.Clamp(Coordinates.Left + Coordinates.Width / 2, 280, 1600):F1}px !important; " +
|
||||
$"transform: translate(-50%, {(PositionBelow ? "0" : "-100%")}) !important;")
|
||||
: "";
|
||||
|
||||
private async Task RequestSummary()
|
||||
{
|
||||
IsLoading = true;
|
||||
Packet = await Coordinator.RequestSummaryAndQuizAsync(SelectedText);
|
||||
IsLoading = false;
|
||||
}
|
||||
|
||||
private async Task GenerateFullQuiz()
|
||||
{
|
||||
IsLoading = true;
|
||||
await Coordinator.RequestSummaryAndQuizAsync(FullPageContent);
|
||||
IsLoading = false;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void Close()
|
||||
{
|
||||
Packet = null;
|
||||
InteractionService.NotifyTextSelected(string.Empty, string.Empty, null!);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user