namespace MiaoJiZhang.Api.Services; public interface ILlmClient { bool IsEnabled { get; } Task TryParseIntentAsync(string userText, CancellationToken ct = default); Task TryGenerateReplyAsync(string systemPrompt, string userText, CancellationToken ct = default); Task?> AnalyzeImageAsync( byte[] imageBytes, string mimeType, CancellationToken ct = default); Task<(bool Ok, string? Error)> TestConnectionAsync(CancellationToken ct = default); Task RunAgentAsync( string systemPrompt, string userText, IReadOnlyList tools, Func> executeTool, Func? onToken = null, Func? onToolRunning = null, CancellationToken ct = default); /// 流式生成回复。将 LLM 返回的 token 逐个写入 writer,完成时返回。 Task StreamReplyAsync( string systemPrompt, string userText, Func onToken, CancellationToken ct = default); } public record AgentToolDefinition( string Name, string Description, object Parameters); public record AgentToolCall( string CallId, string Name, string Arguments); public record AgentRunResponse( string Text, int ToolCallCount); public record ImageParseResult( string Type, decimal Amount, string CategoryName, string? PaymentMethod, string Note, DateTime? OccurredAt); public class NullLlmClient : ILlmClient { public bool IsEnabled => false; public Task TryParseIntentAsync( string userText, CancellationToken ct = default) => Task.FromResult(null); public Task TryGenerateReplyAsync( string systemPrompt, string userText, CancellationToken ct = default) => Task.FromResult(null); public Task?> AnalyzeImageAsync( byte[] imageBytes, string mimeType, CancellationToken ct = default) => Task.FromResult?>(null); public Task<(bool Ok, string? Error)> TestConnectionAsync( CancellationToken ct = default) => Task.FromResult<(bool, string?)>((false, "API Key 为空")); public Task RunAgentAsync( string systemPrompt, string userText, IReadOnlyList tools, Func> executeTool, Func? onToken = null, Func? onToolRunning = null, CancellationToken ct = default) => Task.FromResult(new AgentRunResponse("", 0)); public async Task StreamReplyAsync( string systemPrompt, string userText, Func onToken, CancellationToken ct = default) { await Task.CompletedTask; } }