feat(ai-ux): deduplicate AI queries, handle ServiceUnavailable retries, and optimize reader canvas graph prerendering (#44)

This Pull Request encapsulates all outstanding AI, Blazor InteractiveAuto lifecycle, pgvector, and Firefox authorization/session compatibility fixes.

### Key Accomplishments:
1. **Concurrent Request Deduplication (Option B):** Implemented a thread-safe active task registry in `KnowledgeService` that groups concurrent graph extraction queries for the same content, preventing duplicate AI calls completely.
2. **Resilience Strategy for Downstream Demands:** Extended the `ai-retry` resilience pipeline to automatically intercept and retry on temporary Google API `503 ServiceUnavailable` / `high demand` spikes.
3. **Interactive Graph Generation Guard (Option A):** Prevented server-side prerender-phase graph requests in the reader canvas component.
4. **Firefox Compatibility & Cookie Handler:** Implemented an authentication endpoint and hybrid hidden-form submission flow to solve login, registration, and logout redirections and cookies securely.
5. **Autoscrolling & Graph Exclusions:** Added concept-to-block smooth scrolling, active block badging, and filtered out markdown code blocks from being extracted as nodes.

All unit tests compiled and passed 100% cleanly.

---------

Co-authored-by: Marek Jasiński <jasins.marek@gmail.com>
Reviewed-on: #44
Co-authored-by: Antigravity <antigravity@google.com>
Co-committed-by: Antigravity <antigravity@google.com>
This commit was merged in pull request #44.
This commit is contained in:
2026-05-18 17:53:36 +00:00
committed by Marek Jaisński
parent f808734768
commit 541e9e1fb5
42 changed files with 2351 additions and 155 deletions
@@ -9,6 +9,7 @@ namespace NexusReader.Application.Commands.Library;
/// <param name="AuthorName">The name of the author.</param>
/// <param name="CoverImage">The raw bytes of the cover image (optional).</param>
/// <param name="EpubData">The raw bytes of the EPUB file.</param>
/// <param name="Description">The description or summary of the book (optional).</param>
/// <param name="UserId">The ID of the user owning the book.</param>
/// <param name="TenantId">The tenant ID for multi-tenant isolation. Defaults to "global" for single-tenant or default usage.</param>
public record IngestEbookCommand(
@@ -16,6 +17,7 @@ public record IngestEbookCommand(
string AuthorName,
byte[]? CoverImage,
byte[] EpubData,
string? Description,
string UserId,
string TenantId = "global"
) : ICommand<Guid>;
@@ -63,6 +63,7 @@ public class IngestEbookCommandHandler : IRequestHandler<IngestEbookCommand, Res
Author = author,
FilePath = epubPath,
CoverUrl = coverUrl,
Description = request.Description,
UserId = request.UserId,
TenantId = request.TenantId,
AddedDate = DateTime.UtcNow
@@ -4,5 +4,6 @@ public record IngestEbookRequest(
string Title,
string AuthorName,
string? CoverImageBase64,
string EpubDataBase64
string EpubDataBase64,
string? Description = null
);