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:
@@ -42,6 +42,7 @@
|
||||
setTimeout(hidePreloader, 3000);
|
||||
})();
|
||||
</script>
|
||||
<script src="_content/NexusReader.UI.Shared/js/auth.js"></script>
|
||||
</body>
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using NexusReader.Infrastructure;
|
||||
using NexusReader.Application.Abstractions.Services;
|
||||
using NexusReader.Application.Queries.User;
|
||||
using NexusReader.Application.Commands.Library;
|
||||
using NexusReader.Application.Queries.Library;
|
||||
using MediatR;
|
||||
using NexusReader.Web.Client.Services;
|
||||
using NexusReader.UI.Shared.Services;
|
||||
@@ -235,6 +236,7 @@ if (!app.Environment.IsDevelopment())
|
||||
app.UseHttpsRedirection();
|
||||
}
|
||||
|
||||
app.UseRouting();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.UseAntiforgery();
|
||||
@@ -253,7 +255,9 @@ app.MapGet("/api/epub/{ebookId:guid}/{index:int}", async (Guid ebookId, int inde
|
||||
return Results.BadRequest(errorMsg);
|
||||
}).RequireAuthorization();
|
||||
|
||||
var knowledgeApi = app.MapGroup("/api/knowledge").RequireAuthorization("HasAvailableTokens");
|
||||
var knowledgeApi = app.MapGroup("/api/knowledge")
|
||||
.RequireAuthorization("HasAvailableTokens")
|
||||
.DisableAntiforgery();
|
||||
|
||||
knowledgeApi.MapPost("/", async (KnowledgeRequest request, ClaimsPrincipal user, IKnowledgeService knowledgeService) =>
|
||||
{
|
||||
@@ -319,6 +323,7 @@ app.MapPost("/api/library/ingest", async ([FromBody] IngestEbookRequest request,
|
||||
request.AuthorName,
|
||||
coverData,
|
||||
epubData,
|
||||
request.Description,
|
||||
userId
|
||||
);
|
||||
|
||||
@@ -328,6 +333,18 @@ app.MapPost("/api/library/ingest", async ([FromBody] IngestEbookRequest request,
|
||||
return Results.BadRequest(result.Errors.FirstOrDefault()?.Message ?? "Ingestion failed");
|
||||
}).RequireAuthorization().DisableAntiforgery();
|
||||
|
||||
app.MapGet("/api/library/books", async (ClaimsPrincipal user, IMediator mediator) =>
|
||||
{
|
||||
var userId = user.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
if (string.IsNullOrEmpty(userId)) return Results.Unauthorized();
|
||||
|
||||
var result = await mediator.Send(new GetMyEbooksQuery(userId));
|
||||
if (result.IsSuccess) return Results.Ok(result.Value);
|
||||
|
||||
var errorMsg = result.Errors.Count > 0 ? result.Errors[0].Message : "Unknown server error";
|
||||
return Results.BadRequest(errorMsg);
|
||||
}).RequireAuthorization();
|
||||
|
||||
app.MapPost("/api/StripeWebhook", async (
|
||||
HttpContext context,
|
||||
UserManager<NexusUser> userManager,
|
||||
@@ -369,7 +386,7 @@ app.MapPost("/api/StripeWebhook", async (
|
||||
{
|
||||
return Results.BadRequest(e.Message);
|
||||
}
|
||||
});
|
||||
}).DisableAntiforgery();
|
||||
|
||||
async Task HandleSubscriptionSuccess(
|
||||
string? email,
|
||||
|
||||
Reference in New Issue
Block a user