feat: AI 提示词模块化 + AI 同意门控 + AI 草稿存储 + 意图路由 + 医疗引用知识库 + 多页面 UI 优化
- AI 提示词拆分为 markdown 模块(Prompts/global + modules + rag + router) - 新增 AI 同意门控(用户需同意后才能使用 AI 功能) - 新增 AI 录入草稿存储(AiEntryDraftContracts/EfAiEntryDraftStore/AiEntryDraftRecord) - 新增 AI 意图路由(ai_intent_router) - 新增医疗引用知识库(MedicalCitationKnowledge) - 重构 prompt_manager 和 ai_chat_endpoints - 优化聊天/趋势/档案/抽屉/医生端等多个页面 UI - 新增 agent 插画和趋势指标图标资源 - 删除 HANDOFF-2026-07-17.md
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -20,11 +20,12 @@ public static class UserEndpoints
|
||||
var birthDate = DateOnly.TryParse(req.BirthDate, out var parsed) ? parsed : (DateOnly?)null;
|
||||
var updated = await users.UpdateProfileAsync(
|
||||
GetUserId(http),
|
||||
new UserProfileUpdateRequest(req.Name, req.Gender, birthDate),
|
||||
new UserProfileUpdateRequest(req.Name, req.Gender, birthDate, req.AvatarUrl),
|
||||
ct);
|
||||
if (!updated) return Results.Ok(new { code = 40004, message = "用户不存在" });
|
||||
|
||||
return Results.Ok(new { code = 0, data = new { success = true }, message = (string?)null });
|
||||
var profile = await users.GetProfileAsync(GetUserId(http), ct);
|
||||
return Results.Ok(new { code = 0, data = profile, message = (string?)null });
|
||||
});
|
||||
|
||||
group.MapGet("/health-archive", async (HttpContext http, IHealthArchiveService archives, CancellationToken ct) =>
|
||||
@@ -66,7 +67,7 @@ public static class UserEndpoints
|
||||
Guid.TryParse(http.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value, out var id) ? id : Guid.Empty;
|
||||
}
|
||||
|
||||
public sealed record UpdateProfileRequest(string? Name, string? Gender, string? BirthDate);
|
||||
public sealed record UpdateProfileRequest(string? Name, string? Gender, string? BirthDate, string? AvatarUrl);
|
||||
public sealed record UpdateArchiveRequest(
|
||||
string? Diagnosis, string? SurgeryType, string? SurgeryDate,
|
||||
List<string>? Allergies, List<string>? DietRestrictions,
|
||||
|
||||
@@ -16,6 +16,10 @@ public sealed class ExceptionMiddleware(RequestDelegate next, ILogger<ExceptionM
|
||||
{
|
||||
await _next(context);
|
||||
}
|
||||
catch (OperationCanceledException) when (context.RequestAborted.IsCancellationRequested)
|
||||
{
|
||||
// 客户端或启动探针取消请求时,不再尝试写入错误响应。
|
||||
}
|
||||
catch (Health.Domain.ValidationException vex)
|
||||
{
|
||||
// 业务输入校验失败:返回 400,message 为我们自己产生的提示,可安全展示
|
||||
@@ -37,6 +41,7 @@ public sealed class ExceptionMiddleware(RequestDelegate next, ILogger<ExceptionM
|
||||
{
|
||||
// 生产环境不暴露内部异常详情
|
||||
_logger.LogError(ex, "未处理的异常: {Path}", context.Request.Path);
|
||||
if (context.Response.HasStarted) return;
|
||||
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||
context.Response.ContentType = "application/json";
|
||||
|
||||
|
||||
@@ -112,6 +112,7 @@ builder.Services.AddSingleton<SmsService>();
|
||||
builder.Services.AddSingleton<AppleTokenValidator>(); // Apple Sign-In JWT 验证
|
||||
builder.Services.AddSingleton<PromptManager>();
|
||||
builder.Services.AddScoped<IAiWriteConfirmationStore, EfAiWriteConfirmationStore>();
|
||||
builder.Services.AddScoped<IAiEntryDraftStore, EfAiEntryDraftStore>();
|
||||
builder.Services.AddScoped<IAiToolExecutionService, AiToolExecutionService>();
|
||||
builder.Services.AddScoped<IAdminService, AdminService>();
|
||||
builder.Services.AddScoped<IAuthService, AuthService>();
|
||||
@@ -165,8 +166,10 @@ builder.Services.AddHttpClient<DeepSeekClient>(client =>
|
||||
});
|
||||
builder.Services.AddHttpClient<VisionClient>(client =>
|
||||
{
|
||||
client.BaseAddress = new Uri((builder.Configuration["VLM_BASE_URL"] ?? "https://dashscope.aliyuncs.com/compatible-mode/v1").TrimEnd('/') + "/");
|
||||
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", builder.Configuration["VLM_API_KEY"] ?? "");
|
||||
var baseUrl = builder.Configuration["VLM_BASE_URL"] ?? builder.Configuration["QWEN_BASE_URL"] ?? "https://dashscope.aliyuncs.com/compatible-mode/v1";
|
||||
var apiKey = builder.Configuration["VLM_API_KEY"] ?? builder.Configuration["QWEN_API_KEY"] ?? "";
|
||||
client.BaseAddress = new Uri(baseUrl.TrimEnd('/') + "/");
|
||||
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", apiKey);
|
||||
client.Timeout = TimeSpan.FromSeconds(120);
|
||||
});
|
||||
builder.Services.AddHttpClient<FastGptKnowledgeClient>(client =>
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
"JWT_AUDIENCE": "health-manager-app",
|
||||
"DEEPSEEK_BASE_URL": "https://api.deepseek.com/v1",
|
||||
"DEEPSEEK_API_KEY": "sk-your-key-here",
|
||||
"DEEPSEEK_MODEL": "deepseek-chat",
|
||||
"DEEPSEEK_MODEL": "deepseek-v4-flash",
|
||||
"ENABLE_MEDICAL_RAG": false,
|
||||
"QWEN_BASE_URL": "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
||||
"QWEN_API_KEY": "sk-your-key-here",
|
||||
"QWEN_VISION_MODEL": "qwen-vl-max",
|
||||
|
||||
Reference in New Issue
Block a user