diff --git a/MoneyMap/MoneyMap.csproj b/MoneyMap/MoneyMap.csproj index 1bac5aa..547a48e 100644 --- a/MoneyMap/MoneyMap.csproj +++ b/MoneyMap/MoneyMap.csproj @@ -30,4 +30,10 @@ + + + PreserveNewest + + + diff --git a/MoneyMap/Prompts/ReceiptParserPrompt.txt b/MoneyMap/Prompts/ReceiptParserPrompt.txt new file mode 100644 index 0000000..784faed --- /dev/null +++ b/MoneyMap/Prompts/ReceiptParserPrompt.txt @@ -0,0 +1,28 @@ +Analyze this receipt image and extract the following information as JSON: +{ + "merchant": "store name", + "receiptDate": "YYYY-MM-DD" (or null if not found), + "dueDate": "YYYY-MM-DD" (or null if not found - for bills only), + "subtotal": 0.00 (or null if not found), + "tax": 0.00 (or null if not found), + "total": 0.00, + "confidence": 0.95, + "lineItems": [ + { + "description": "item name", + "quantity": 1.0 (or null), + "unitPrice": 0.00 (or null), + "lineTotal": 0.00 + } + ] +} + +Extract all line items you can see on the receipt. For each item: +- description: The item or service name +- quantity: Only include if this is an actual countable product (like groceries). For services, fees, charges, or taxes, set to null. +- unitPrice: Price per unit if quantity applies, otherwise null +- lineTotal: The total amount for this line (required) + +For utility bills, service charges, fees, and taxes - these are NOT products with quantities, so set quantity and unitPrice to null. + +If this is a bill (utility, credit card, etc.), look for a due date, payment due date, or deadline and extract it as dueDate. For regular receipts, dueDate should be null. \ No newline at end of file diff --git a/MoneyMap/Services/OpenAIReceiptParser.cs b/MoneyMap/Services/OpenAIReceiptParser.cs index 6b247dc..fb1e715 100644 --- a/MoneyMap/Services/OpenAIReceiptParser.cs +++ b/MoneyMap/Services/OpenAIReceiptParser.cs @@ -28,6 +28,7 @@ namespace MoneyMap.Services private readonly HttpClient _httpClient; private readonly IMerchantService _merchantService; private readonly IServiceProvider _serviceProvider; + private string? _promptTemplate; public OpenAIReceiptParser( MoneyMapContext db, @@ -205,38 +206,26 @@ namespace MoneyMap.Services }); } + private async Task LoadPromptTemplateAsync() + { + if (_promptTemplate != null) + return _promptTemplate; + + var promptPath = Path.Combine(AppContext.BaseDirectory, "Prompts", "ReceiptParserPrompt.txt"); + + if (!File.Exists(promptPath)) + throw new FileNotFoundException($"Receipt parser prompt template not found at: {promptPath}"); + + _promptTemplate = await File.ReadAllTextAsync(promptPath); + return _promptTemplate; + } + private async Task CallOpenAIVisionAsync(string apiKey, string base64Image, string mediaType, string? transactionName = null) { - // Build the prompt with optional transaction context - var promptText = @"Analyze this receipt image and extract the following information as JSON: -{ - ""merchant"": ""store name"", - ""receiptDate"": ""YYYY-MM-DD"" (or null if not found), - ""dueDate"": ""YYYY-MM-DD"" (or null if not found - for bills only), - ""subtotal"": 0.00 (or null if not found), - ""tax"": 0.00 (or null if not found), - ""total"": 0.00, - ""confidence"": 0.95, - ""lineItems"": [ - { - ""description"": ""item name"", - ""quantity"": 1.0 (or null), - ""unitPrice"": 0.00 (or null), - ""lineTotal"": 0.00 - } - ] -} - -Extract all line items you can see on the receipt. For each item: -- description: The item or service name -- quantity: Only include if this is an actual countable product (like groceries). For services, fees, charges, or taxes, set to null. -- unitPrice: Price per unit if quantity applies, otherwise null -- lineTotal: The total amount for this line (required) - -For utility bills, service charges, fees, and taxes - these are NOT products with quantities, so set quantity and unitPrice to null. - -If this is a bill (utility, credit card, etc.), look for a due date, payment due date, or deadline and extract it as dueDate. For regular receipts, dueDate should be null."; + // Load the prompt template from file + var promptText = await LoadPromptTemplateAsync(); + // Add transaction context if available if (!string.IsNullOrWhiteSpace(transactionName)) { promptText += $"\n\nNote: This transaction was recorded as \"{transactionName}\" in the bank statement, which may help identify the merchant if the receipt is unclear.";