Private
Public Access
1
0

Add AI chat with Ollama tool calling for financial queries

Conversational AI chat that uses Ollama's native tool-calling API to query
transactions, spending reports, account balances, dashboard summaries, and
update transaction categories through natural language. Includes persistent
conversation history, a full-page chat UI with sidebar, and rich inline
rendering of tool results (tables, alerts, cards).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Catherine Renelle
2026-02-09 23:34:16 -05:00
parent 1ceeca0fb6
commit 846edad2a4
20 changed files with 3237 additions and 0 deletions
+143
View File
@@ -0,0 +1,143 @@
using System.Text.Json.Serialization;
namespace Purrse.Core.DTOs;
// API DTOs
public record SendChatMessageRequest(Guid? ConversationId, string Message);
public record SendChatMessageResponse(Guid ConversationId, ChatMessageResponse AssistantMessage);
public record ChatMessageResponse(
Guid Id,
string Role,
string Content,
string? ToolResultType,
string? ToolResultJson,
DateTime CreatedAt
);
public record ChatConversationResponse(
Guid Id,
string? Title,
DateTime CreatedAt,
DateTime UpdatedAt
);
public record ChatConversationDetailResponse(
Guid Id,
string? Title,
List<ChatMessageResponse> Messages,
DateTime CreatedAt,
DateTime UpdatedAt
);
// Ollama tool-calling DTOs (separate from existing OllamaChatRequest to avoid breaking categorization)
public class OllamaToolChatRequest
{
[JsonPropertyName("model")]
public string Model { get; set; } = string.Empty;
[JsonPropertyName("messages")]
public List<OllamaToolMessage> Messages { get; set; } = new();
[JsonPropertyName("stream")]
public bool Stream { get; set; }
[JsonPropertyName("tools")]
public List<OllamaTool>? Tools { get; set; }
}
public class OllamaToolMessage
{
[JsonPropertyName("role")]
public string Role { get; set; } = string.Empty;
[JsonPropertyName("content")]
public string Content { get; set; } = string.Empty;
[JsonPropertyName("tool_calls")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public List<OllamaToolCall>? ToolCalls { get; set; }
}
public class OllamaTool
{
[JsonPropertyName("type")]
public string Type { get; set; } = "function";
[JsonPropertyName("function")]
public OllamaFunction Function { get; set; } = new();
}
public class OllamaFunction
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("description")]
public string Description { get; set; } = string.Empty;
[JsonPropertyName("parameters")]
public OllamaFunctionParameters Parameters { get; set; } = new();
}
public class OllamaFunctionParameters
{
[JsonPropertyName("type")]
public string Type { get; set; } = "object";
[JsonPropertyName("properties")]
public Dictionary<string, OllamaPropertySchema> Properties { get; set; } = new();
[JsonPropertyName("required")]
public List<string>? Required { get; set; }
}
public class OllamaPropertySchema
{
[JsonPropertyName("type")]
public string Type { get; set; } = "string";
[JsonPropertyName("description")]
public string Description { get; set; } = string.Empty;
[JsonPropertyName("enum")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public List<string>? Enum { get; set; }
}
public class OllamaToolCall
{
[JsonPropertyName("function")]
public OllamaToolCallFunction Function { get; set; } = new();
}
public class OllamaToolCallFunction
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("arguments")]
public Dictionary<string, object> Arguments { get; set; } = new();
}
public class OllamaToolChatResponse
{
[JsonPropertyName("message")]
public OllamaToolResponseMessage? Message { get; set; }
[JsonPropertyName("done")]
public bool Done { get; set; }
}
public class OllamaToolResponseMessage
{
[JsonPropertyName("role")]
public string Role { get; set; } = string.Empty;
[JsonPropertyName("content")]
public string Content { get; set; } = string.Empty;
[JsonPropertyName("tool_calls")]
public List<OllamaToolCall>? ToolCalls { get; set; }
}