Add AI categorization with Ollama: settings, auto-classify on sync/import, and manual classify from Transactions
Adds local LLM-based transaction categorization using Ollama: - Settings UI to configure Ollama URL, model, confidence threshold - Auto-categorization during bank sync and file import - Manual "Classify Uncategorized" button on Transactions screen that respects active filters - Payee default category learning loop for classified transactions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
using Purrse.Core.Enums;
|
||||
|
||||
namespace Purrse.Core.DTOs;
|
||||
|
||||
// Settings
|
||||
public record AiCategorizationSettingsResponse(
|
||||
bool IsEnabled,
|
||||
string OllamaUrl,
|
||||
string ModelName,
|
||||
double ConfidenceThreshold,
|
||||
int TimeoutSeconds,
|
||||
bool UpdatePayeeDefaults);
|
||||
|
||||
public record UpdateAiCategorizationSettingsRequest(
|
||||
bool IsEnabled,
|
||||
string OllamaUrl,
|
||||
string ModelName,
|
||||
double ConfidenceThreshold,
|
||||
int TimeoutSeconds,
|
||||
bool UpdatePayeeDefaults);
|
||||
|
||||
// Connection test
|
||||
public record OllamaConnectionTestResponse(
|
||||
bool Success,
|
||||
string? ErrorMessage,
|
||||
List<string>? AvailableModels);
|
||||
|
||||
// Ollama API communication (internal)
|
||||
public record OllamaChatRequest(string Model, List<OllamaChatMessage> Messages, bool Stream, string Format);
|
||||
public record OllamaChatMessage(string Role, string Content);
|
||||
public record OllamaChatResponse(OllamaChatMessage? Message, bool Done);
|
||||
public record OllamaTagsResponse(List<OllamaModelInfo>? Models);
|
||||
public record OllamaModelInfo(string Name, string? Model);
|
||||
|
||||
// Classify uncategorized (manual trigger from Transactions screen)
|
||||
public record ClassifyUncategorizedRequest(
|
||||
Guid? AccountId,
|
||||
DateTime? StartDate,
|
||||
DateTime? EndDate,
|
||||
string? SearchText,
|
||||
TransactionStatus? Status);
|
||||
|
||||
public record ClassifyUncategorizedResponse(
|
||||
int TotalUncategorized,
|
||||
int Classified,
|
||||
int Skipped);
|
||||
|
||||
// Classification result
|
||||
public record TransactionClassification(int TransactionIndex, Guid? CategoryId, string? CategoryName, double Confidence);
|
||||
@@ -0,0 +1,13 @@
|
||||
using Purrse.Core.DTOs;
|
||||
using Purrse.Core.Models;
|
||||
|
||||
namespace Purrse.Core.Interfaces.Services;
|
||||
|
||||
public interface IAiCategorizationService
|
||||
{
|
||||
Task<AiCategorizationSettingsResponse> GetSettingsAsync(Guid userId);
|
||||
Task<AiCategorizationSettingsResponse> UpdateSettingsAsync(Guid userId, UpdateAiCategorizationSettingsRequest request);
|
||||
Task<OllamaConnectionTestResponse> TestConnectionAsync(Guid userId);
|
||||
Task<List<TransactionClassification>> ClassifyTransactionsAsync(Guid userId, List<Transaction> uncategorizedTransactions);
|
||||
Task<ClassifyUncategorizedResponse> ClassifyUncategorizedAsync(Guid userId, ClassifyUncategorizedRequest request);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Purrse.Core.Models;
|
||||
|
||||
public class AiCategorizationSettings
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid UserId { get; set; }
|
||||
public bool IsEnabled { get; set; }
|
||||
public string OllamaUrl { get; set; } = "http://localhost:11434";
|
||||
public string ModelName { get; set; } = "llama3.1:8b";
|
||||
public double ConfidenceThreshold { get; set; } = 0.7;
|
||||
public int TimeoutSeconds { get; set; } = 30;
|
||||
public bool UpdatePayeeDefaults { get; set; } = true;
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
public User User { get; set; } = null!;
|
||||
}
|
||||
@@ -14,4 +14,5 @@ public class User
|
||||
public ICollection<Account> Accounts { get; set; } = new List<Account>();
|
||||
public ICollection<SyncConnection> SyncConnections { get; set; } = new List<SyncConnection>();
|
||||
public BankSyncSettings? BankSyncSettings { get; set; }
|
||||
public AiCategorizationSettings? AiCategorizationSettings { get; set; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user