From 324ab2c627cd45f47a4c8a3d830e164f01b5b488 Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Sun, 15 Feb 2026 19:26:40 -0500 Subject: [PATCH] Fix: ViewReceipt parse button now uses parse queue instead of direct parsing Co-Authored-By: Claude Opus 4.6 --- MoneyMap/Pages/ViewReceipt.cshtml | 36 +++++++++------------- MoneyMap/Pages/ViewReceipt.cshtml.cs | 45 +++++++++------------------- MoneyMap/Services/AIReceiptParser.cs | 7 +++-- 3 files changed, 33 insertions(+), 55 deletions(-) diff --git a/MoneyMap/Pages/ViewReceipt.cshtml b/MoneyMap/Pages/ViewReceipt.cshtml index 5cbe52f..164df1e 100644 --- a/MoneyMap/Pages/ViewReceipt.cshtml +++ b/MoneyMap/Pages/ViewReceipt.cshtml @@ -156,28 +156,20 @@ Parse Receipt
- @if (Model.AvailableParsers.Any()) - { -
- -

- Using: @Model.SelectedModel - Change -

-
- - -
- -
- } - else - { -

No parsers available

- } +
+

+ Using: @Model.SelectedModel + Change +

+
+ + +
+ +
diff --git a/MoneyMap/Pages/ViewReceipt.cshtml.cs b/MoneyMap/Pages/ViewReceipt.cshtml.cs index 0afef18..aea9f85 100644 --- a/MoneyMap/Pages/ViewReceipt.cshtml.cs +++ b/MoneyMap/Pages/ViewReceipt.cshtml.cs @@ -11,25 +11,24 @@ namespace MoneyMap.Pages { private readonly MoneyMapContext _db; private readonly IReceiptManager _receiptManager; - private readonly IEnumerable _parsers; + private readonly IReceiptParseQueue _parseQueue; private readonly IConfiguration _config; public ViewReceiptModel( MoneyMapContext db, IReceiptManager receiptManager, - IEnumerable parsers, + IReceiptParseQueue parseQueue, IConfiguration config) { _db = db; _receiptManager = receiptManager; - _parsers = parsers; + _parseQueue = parseQueue; _config = config; } public Receipt? Receipt { get; set; } public List LineItems { get; set; } = new(); public List ParseLogs { get; set; } = new(); - public List AvailableParsers { get; set; } = new(); public string ReceiptUrl { get; set; } = ""; public string SelectedModel => _config["AI:ReceiptParsingModel"] ?? "gpt-4o-mini"; @@ -62,13 +61,6 @@ namespace MoneyMap.Pages // Get receipt URL for display - use handler parameter ReceiptUrl = $"/ViewReceipt/{id}?handler=file"; - // Get available parsers - AvailableParsers = _parsers.Select(p => new ParserOption - { - Name = p.GetType().Name.Replace("ReceiptParser", ""), - FullName = p.GetType().Name - }).ToList(); - return Page(); } @@ -94,35 +86,26 @@ namespace MoneyMap.Pages return File(fileBytes, receipt.ContentType); } - public async Task OnPostParseAsync(long id, string parser) + public async Task OnPostParseAsync(long id) { - var selectedParser = _parsers.FirstOrDefault(p => p.GetType().Name == parser); + var receipt = await _db.Receipts.FindAsync(id); - if (selectedParser == null) + if (receipt == null) { - ErrorMessage = "Parser not found."; + ErrorMessage = "Receipt not found."; return RedirectToPage(new { id }); } - // Use the configured model from settings, pass user notes - var result = await selectedParser.ParseReceiptAsync(id, SelectedModel, ParsingNotes); + // Save parsing notes to the receipt entity so the worker can use them + receipt.ParsingNotes = ParsingNotes; + receipt.ParseStatus = ReceiptParseStatus.Queued; + await _db.SaveChangesAsync(); - if (result.IsSuccess) - { - SuccessMessage = result.Message; - } - else - { - ErrorMessage = result.Message; - } + // Enqueue the receipt for parsing + await _parseQueue.EnqueueAsync(id); + SuccessMessage = "Receipt queued for parsing."; return RedirectToPage(new { id }); } - - public class ParserOption - { - public string Name { get; set; } = ""; - public string FullName { get; set; } = ""; - } } } \ No newline at end of file diff --git a/MoneyMap/Services/AIReceiptParser.cs b/MoneyMap/Services/AIReceiptParser.cs index 165b441..ae620bb 100644 --- a/MoneyMap/Services/AIReceiptParser.cs +++ b/MoneyMap/Services/AIReceiptParser.cs @@ -60,6 +60,9 @@ namespace MoneyMap.Services if (!File.Exists(filePath)) return ReceiptParseResult.Failure("Receipt file not found on disk."); + // Fall back to receipt.ParsingNotes if notes parameter is null + var effectiveNotes = notes ?? receipt.ParsingNotes; + var selectedModel = model ?? _configuration["AI:ReceiptParsingModel"] ?? "gpt-4o-mini"; var (client, provider) = _clientResolver.Resolve(selectedModel); @@ -79,7 +82,7 @@ namespace MoneyMap.Services try { var (base64Data, mediaType) = await PrepareImageDataAsync(receipt, filePath); - var promptText = await BuildPromptAsync(receipt, notes, client); + var promptText = await BuildPromptAsync(receipt, effectiveNotes, client); var visionResult = await CallVisionClientAsync(client, base64Data, mediaType, promptText, selectedModel); if (!visionResult.IsSuccess) @@ -89,7 +92,7 @@ namespace MoneyMap.Services } var parseData = ParseResponse(visionResult.Content); - await ApplyParseResultAsync(receipt, receiptId, parseData, notes); + await ApplyParseResultAsync(receipt, receiptId, parseData, effectiveNotes); parseLog.Success = true; parseLog.Confidence = parseData.Confidence;