feat: 后端架构重构 — Endpoint→Service→Repository分层 + AI确认机制 + 异步任务持久化
- 核心业务拆分为 Endpoint → Application Service → Repository 三层 - AI写入操作必须用户确认后才写库(确认卡片机制) - 报告/饮食/用药分析改为持久化任务队列(原子领取/重试/重启恢复) - 运动计划修复: 连续真实日期替代周模板 - 用药提醒去重 + 通知Outbox预留 - 认证收拢到AuthService, 管理员收拢到AdminService - AI会话加用户归属校验防串号 - 提示词调整为患者视角 - 开发假数据已关闭 - 21/21测试通过, 0警告0错误
This commit is contained in:
42
backend/src/Health.Infrastructure/Diets/DietImageAnalyzer.cs
Normal file
42
backend/src/Health.Infrastructure/Diets/DietImageAnalyzer.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using Health.Application.Diets;
|
||||
using Health.Infrastructure.AI;
|
||||
|
||||
namespace Health.Infrastructure.Diets;
|
||||
|
||||
public sealed class DietImageAnalyzer(VisionClient vision) : IDietImageAnalyzer
|
||||
{
|
||||
private readonly VisionClient _vision = vision;
|
||||
|
||||
public async Task<DietImageAnalysisResult> AnalyzeAsync(DietImageAnalysisJob job, CancellationToken ct)
|
||||
{
|
||||
var imageUrls = new List<string>();
|
||||
foreach (var filePath in job.FilePaths)
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
return new DietImageAnalysisResult(false, 40004, null, "待识别图片不存在");
|
||||
|
||||
var bytes = await File.ReadAllBytesAsync(filePath, ct);
|
||||
var base64 = Convert.ToBase64String(bytes);
|
||||
if (base64.Length > 7 * 1024 * 1024)
|
||||
return new DietImageAnalysisResult(false, 40001, null, "图片过大,请压缩后重新上传");
|
||||
|
||||
var extension = Path.GetExtension(filePath).ToLowerInvariant();
|
||||
var mime = extension switch
|
||||
{
|
||||
".png" => "image/png",
|
||||
".heic" => "image/heic",
|
||||
_ => "image/jpeg"
|
||||
};
|
||||
imageUrls.Add($"data:{mime};base64,{base64}");
|
||||
}
|
||||
|
||||
var prompt = """
|
||||
识别图片中的食物和饮品,返回JSON数组:
|
||||
[{"name":"名称","portion":"份量","calories":热量}]
|
||||
只返回JSON,不要其他内容。
|
||||
""";
|
||||
var response = await _vision.VisionAsync(prompt, imageUrls, userText: null, maxTokens: 8192, ct: ct);
|
||||
var result = response.Choices?.FirstOrDefault()?.Message?.Content ?? "[]";
|
||||
return new DietImageAnalysisResult(true, 0, result, null);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user