Files
jizhi/backend/MiaoJiZhang.Api/Services/LlmClient.cs
T

149 lines
4.7 KiB
C#

namespace MiaoJiZhang.Api.Services;
public interface ILlmClient
{
bool IsEnabled { get; }
Task<IntentResult?> TryParseIntentAsync(string userText, CancellationToken ct = default);
Task<string?> TryGenerateReplyAsync(string systemPrompt, string userText, CancellationToken ct = default);
Task<IReadOnlyList<ImageParseResult>?> AnalyzeImageAsync(
byte[] imageBytes,
string mimeType,
CancellationToken ct = default);
Task<IReadOnlyList<RecognitionBatchModelAction>?> ReconcileRecognitionBatchAsync(
RecognitionBatchModelInput input,
CancellationToken ct = default);
Task<(bool Ok, string? Error)> TestConnectionAsync(CancellationToken ct = default);
Task<AgentRunResponse> RunAgentAsync(
string systemPrompt,
string userText,
IReadOnlyList<AgentToolDefinition> tools,
Func<AgentToolCall, CancellationToken, Task<string>> executeTool,
Func<string, CancellationToken, Task>? onToken = null,
Func<string, CancellationToken, Task>? onToolRunning = null,
CancellationToken ct = default);
/// <summary>流式生成回复。将 LLM 返回的 token 逐个写入 writer,完成时返回。</summary>
Task StreamReplyAsync(
string systemPrompt,
string userText,
Func<string, CancellationToken, Task> 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 record RecognitionBatchModelCandidate(
string CandidateId,
string? FlowSessionId,
string PackageName,
string Type,
decimal Amount,
string? Merchant,
string? OrderId,
DateTime OccurredAt,
string RecognitionKind,
string? CategoryHint,
string Confidence,
IReadOnlyList<string> EvidenceIds);
public record RecognitionBatchModelEvidence(
string EvidenceId,
string? CandidateId,
string? FlowSessionId,
string PackageName,
DateTime CapturedAt,
byte[] ImageBytes,
string MimeType);
public record RecognitionBatchModelInput(
string BatchId,
IReadOnlyList<RecognitionBatchModelCandidate> Candidates,
IReadOnlyList<RecognitionBatchModelEvidence> Evidence,
IReadOnlyList<string> ExpenseCategories,
IReadOnlyList<string> IncomeCategories);
public record RecognitionBatchModelAction(
string Action,
string ActionId,
string? CandidateId,
string? EvidenceId,
string? Type,
decimal? Amount,
string? CategoryName,
string? PaymentMethod,
string? Note,
DateTime? OccurredAt,
double Confidence,
string Reason);
public class NullLlmClient : ILlmClient
{
public bool IsEnabled => false;
public Task<IntentResult?> TryParseIntentAsync(
string userText,
CancellationToken ct = default) =>
Task.FromResult<IntentResult?>(null);
public Task<string?> TryGenerateReplyAsync(
string systemPrompt,
string userText,
CancellationToken ct = default) =>
Task.FromResult<string?>(null);
public Task<IReadOnlyList<ImageParseResult>?> AnalyzeImageAsync(
byte[] imageBytes,
string mimeType,
CancellationToken ct = default) =>
Task.FromResult<IReadOnlyList<ImageParseResult>?>(null);
public Task<IReadOnlyList<RecognitionBatchModelAction>?> ReconcileRecognitionBatchAsync(
RecognitionBatchModelInput input,
CancellationToken ct = default) =>
Task.FromResult<IReadOnlyList<RecognitionBatchModelAction>?>(null);
public Task<(bool Ok, string? Error)> TestConnectionAsync(
CancellationToken ct = default) =>
Task.FromResult<(bool, string?)>((false, "API Key 为空"));
public Task<AgentRunResponse> RunAgentAsync(
string systemPrompt,
string userText,
IReadOnlyList<AgentToolDefinition> tools,
Func<AgentToolCall, CancellationToken, Task<string>> executeTool,
Func<string, CancellationToken, Task>? onToken = null,
Func<string, CancellationToken, Task>? onToolRunning = null,
CancellationToken ct = default) =>
Task.FromResult(new AgentRunResponse("", 0));
public async Task StreamReplyAsync(
string systemPrompt,
string userText,
Func<string, CancellationToken, Task> onToken,
CancellationToken ct = default)
{
await Task.CompletedTask;
}
}