diff --git a/MoneyMap/Pages/ViewReceipt.cshtml b/MoneyMap/Pages/ViewReceipt.cshtml
index e445ab7..203665d 100644
--- a/MoneyMap/Pages/ViewReceipt.cshtml
+++ b/MoneyMap/Pages/ViewReceipt.cshtml
@@ -165,20 +165,25 @@
diff --git a/MoneyMap/Pages/ViewReceipt.cshtml.cs b/MoneyMap/Pages/ViewReceipt.cshtml.cs
index 9b7cacf..45f8e1c 100644
--- a/MoneyMap/Pages/ViewReceipt.cshtml.cs
+++ b/MoneyMap/Pages/ViewReceipt.cshtml.cs
@@ -4,6 +4,8 @@ using Microsoft.EntityFrameworkCore;
using MoneyMap.Data;
using MoneyMap.Models;
using MoneyMap.Services;
+using System.Text.Json;
+using System.Text.Json.Nodes;
namespace MoneyMap.Pages
{
@@ -12,22 +14,33 @@ namespace MoneyMap.Pages
private readonly MoneyMapContext _db;
private readonly IReceiptManager _receiptManager;
private readonly IEnumerable _parsers;
+ private readonly LlamaCppVisionClient _llamaClient;
+ private readonly IConfiguration _config;
+ private readonly IWebHostEnvironment _env;
public ViewReceiptModel(
MoneyMapContext db,
IReceiptManager receiptManager,
- IEnumerable parsers)
+ IEnumerable parsers,
+ LlamaCppVisionClient llamaClient,
+ IConfiguration config,
+ IWebHostEnvironment env)
{
_db = db;
_receiptManager = receiptManager;
_parsers = parsers;
+ _llamaClient = llamaClient;
+ _config = config;
+ _env = env;
}
public Receipt? Receipt { get; set; }
public List LineItems { get; set; } = new();
public List ParseLogs { get; set; } = new();
public List AvailableParsers { get; set; } = new();
+ public List AvailableModels { get; set; } = new();
public string ReceiptUrl { get; set; } = "";
+ public string SelectedModel => _config["AI:ReceiptParsingModel"] ?? "gpt-4o-mini";
[TempData]
public string? SuccessMessage { get; set; }
@@ -59,6 +72,9 @@ namespace MoneyMap.Pages
FullName = p.GetType().Name
}).ToList();
+ // Get available LlamaCpp models
+ AvailableModels = await _llamaClient.GetAvailableModelsAsync();
+
return Page();
}
@@ -94,6 +110,12 @@ namespace MoneyMap.Pages
return RedirectToPage(new { id });
}
+ // Save selected model to config if it changed
+ if (!string.IsNullOrEmpty(model) && model != SelectedModel)
+ {
+ await SaveSelectedModelAsync(model);
+ }
+
var result = await selectedParser.ParseReceiptAsync(id, model);
if (result.IsSuccess)
@@ -108,6 +130,33 @@ namespace MoneyMap.Pages
return RedirectToPage(new { id });
}
+ private async Task SaveSelectedModelAsync(string model)
+ {
+ try
+ {
+ var appSettingsPath = Path.Combine(_env.ContentRootPath, "appsettings.json");
+ var json = await System.IO.File.ReadAllTextAsync(appSettingsPath);
+ var jsonNode = JsonNode.Parse(json);
+
+ if (jsonNode == null) return;
+
+ // Ensure AI section exists
+ if (jsonNode["AI"] == null)
+ {
+ jsonNode["AI"] = new JsonObject();
+ }
+
+ jsonNode["AI"]!["ReceiptParsingModel"] = model;
+
+ var options = new JsonSerializerOptions { WriteIndented = true };
+ await System.IO.File.WriteAllTextAsync(appSettingsPath, jsonNode.ToJsonString(options));
+ }
+ catch
+ {
+ // Silently fail - not critical if we can't save the preference
+ }
+ }
+
public class ParserOption
{
public string Name { get; set; } = "";
diff --git a/MoneyMap/Services/AIReceiptParser.cs b/MoneyMap/Services/AIReceiptParser.cs
index c2ac467..d569704 100644
--- a/MoneyMap/Services/AIReceiptParser.cs
+++ b/MoneyMap/Services/AIReceiptParser.cs
@@ -21,6 +21,7 @@ namespace MoneyMap.Services
private readonly LlamaCppVisionClient _llamaCppClient;
private readonly IMerchantService _merchantService;
private readonly IServiceProvider _serviceProvider;
+ private readonly IConfiguration _configuration;
private readonly ILogger _logger;
private string? _promptTemplate;
@@ -34,6 +35,7 @@ namespace MoneyMap.Services
LlamaCppVisionClient llamaCppClient,
IMerchantService merchantService,
IServiceProvider serviceProvider,
+ IConfiguration configuration,
ILogger logger)
{
_db = db;
@@ -45,6 +47,7 @@ namespace MoneyMap.Services
_llamaCppClient = llamaCppClient;
_merchantService = merchantService;
_serviceProvider = serviceProvider;
+ _configuration = configuration;
_logger = logger;
}
@@ -57,7 +60,7 @@ namespace MoneyMap.Services
if (receipt == null)
return ReceiptParseResult.Failure("Receipt not found.");
- var selectedModel = model ?? "gpt-4o-mini";
+ var selectedModel = model ?? _configuration["AI:ReceiptParsingModel"] ?? "gpt-4o-mini";
var isLlamaCpp = selectedModel.StartsWith("llamacpp:");
var isOllama = selectedModel.StartsWith("ollama:");
var isClaude = selectedModel.StartsWith("claude-");