feat: 问诊对话+建档引导+报告+日历+趋势页重写+视觉统一
- 问诊对话页: 新建consultation_provider, 完整AI分身聊天UI - 首次建档引导: OnboardingPrompt+ManageArchiveTool+前端卡片 - 报告模块: POST端点 + report_agent_handler接VLM - 健康日历: GET /api/calendar端点 + 前端接API - 趋势页重写: 删除Mock数据 + 真实API + 手动录入 - 饮食保存: submit按钮接后端API - 侧边栏: 健康概览横排 + 统一紫色配色 - 运动计划: 修复JSON反序列化(record→手动解析) - VLM: prompt优化 + 模型切qwen3-vl-plus + 1280px压缩 - UI颜色: 加深主色 8B9CF7→6C5CE7 - 个人信息页精简 + 健康档案可编辑重设计 - 保洁: 删除无用agent_bar + 删除意见反馈/关于我们 - 新增AI提示词文档
This commit is contained in:
@@ -28,6 +28,7 @@ public static class AiChatEndpoints
|
||||
AppDbContext db,
|
||||
DeepSeekClient llmClient,
|
||||
PromptManager promptManager,
|
||||
VisionClient visionClient,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
// 支持 token 通过 query string(浏览器 EventSource)或 header 传递
|
||||
@@ -153,7 +154,7 @@ public static class AiChatEndpoints
|
||||
object toolResult;
|
||||
try
|
||||
{
|
||||
toolResult = await ExecuteToolCall(tc.Function.Name, tc.Function.Arguments, db, userId.Value);
|
||||
toolResult = await ExecuteToolCall(tc.Function.Name, tc.Function.Arguments, db, userId.Value, visionClient);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -265,24 +266,23 @@ public static class AiChatEndpoints
|
||||
await file.CopyToAsync(stream, ct);
|
||||
|
||||
var compressedPath = Path.Combine(uploadsDir, $"compressed_{safeName}");
|
||||
CompressImage(filePath, compressedPath, maxWidth: 1280, quality: 75L);
|
||||
CompressImage(filePath, compressedPath, maxWidth: 1280, quality: 85L);
|
||||
var compressedBytes = await File.ReadAllBytesAsync(compressedPath, ct);
|
||||
var base64 = Convert.ToBase64String(compressedBytes);
|
||||
imageUrls.Add($"data:image/jpeg;base64,{base64}");
|
||||
}
|
||||
|
||||
var prompt = """
|
||||
识别图片中的食物,以 JSON 数组格式返回,每项包含:
|
||||
- name: 食物名称
|
||||
- portion: 份量描述(如"约1碗"、"约200g")
|
||||
- calories: 估算热量(千卡,整数)
|
||||
只返回 JSON 数组,不要任何其他文字。
|
||||
示例:[{"name":"米饭","portion":"约1碗","calories":150},{"name":"番茄炒蛋","portion":"约1份","calories":200},{...}]
|
||||
Describe everything you see in this image in detail. What objects are present? What are their colors, shapes, labels?
|
||||
If there are any food items, drinks, or beverages, identify them specifically by name.
|
||||
Then, for each food/drink item, estimate the portion size and calories (kcal).
|
||||
Return ONLY a JSON array: [{"name":"item name","portion":"estimated portion","calories":estimated_calories}]
|
||||
If you cannot identify something, say so in the name field.
|
||||
""";
|
||||
|
||||
try
|
||||
{
|
||||
var response = await visionClient.VisionAsync(prompt, imageUrls, userText: "请看图识别食物", ct: ct);
|
||||
var response = await visionClient.VisionAsync(prompt, imageUrls, userText: "请看图识别食物", maxTokens: 8192, ct: ct);
|
||||
var result = response.Choices?.FirstOrDefault()?.Message?.Content ?? "{}";
|
||||
return Results.Ok(new { code = 0, data = result, message = (string?)null });
|
||||
}
|
||||
@@ -328,10 +328,11 @@ public static class AiChatEndpoints
|
||||
AgentType.Consultation => ConsultationAgentHandler.Tools,
|
||||
AgentType.Report => ReportAgentHandler.Tools,
|
||||
AgentType.Exercise => ExerciseAgentHandler.Tools,
|
||||
AgentType.Onboarding => [CommonAgentHandler.ManageArchiveTool, CommonAgentHandler.CheckArchiveTool],
|
||||
_ => CommonAgentHandler.Tools,
|
||||
};
|
||||
|
||||
private static Task<object> ExecuteToolCall(string toolName, string arguments, AppDbContext db, Guid userId)
|
||||
private static Task<object> ExecuteToolCall(string toolName, string arguments, AppDbContext db, Guid userId, VisionClient? visionClient = null)
|
||||
{
|
||||
using var jsonDoc = JsonDocument.Parse(arguments);
|
||||
var root = jsonDoc.RootElement;
|
||||
@@ -343,8 +344,11 @@ public static class AiChatEndpoints
|
||||
"check_archive" => CommonAgentHandler.Execute(toolName, root, db, userId),
|
||||
"manage_medication" => MedicationAgentHandler.Execute(toolName, root, db, userId),
|
||||
"estimate_food_text" => DietAgentHandler.Execute(toolName, root, db, userId),
|
||||
"analyze_report" => ReportAgentHandler.Execute(toolName, root, db, userId),
|
||||
"analyze_report" => visionClient != null
|
||||
? ReportAgentHandler.AnalyzeReport(db, userId, root, visionClient)
|
||||
: Task.FromResult<object>(new { success = false, message = "VLM服务未配置" }),
|
||||
"manage_exercise" => ExerciseAgentHandler.Execute(toolName, root, db, userId),
|
||||
"manage_archive" => CommonAgentHandler.ExecuteManageArchive(db, userId, root),
|
||||
"request_doctor" => ConsultationAgentHandler.Execute(toolName, root, db, userId),
|
||||
_ => Task.FromResult<object>(new { success = false, message = $"未知工具: {toolName}" })
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user