- 饮食: 新增 DietCommentaryPolicy + diet_record_logic, 饮食记录逻辑抽取复用 - 通知管理: 分隔线改为仿通知中心样式, 跳过图标区域只留文字下方 - 侧边栏: 对话记录操作栏浮层修复 + 常用功能间距收紧 - 智能体: 欢迎卡片去 400ms 延迟 + 胶囊去阴影 - 后端: AI 会话仓库新增方法 + 饮食评论策略 + 健康记录规则调整 - 其他: api_client IP 适配 + 多页面 UI 微调 + 新增测试
69 lines
2.8 KiB
C#
69 lines
2.8 KiB
C#
using Health.Application.AI;
|
|
|
|
namespace Health.Infrastructure.AI;
|
|
|
|
public sealed class EfAiConversationRepository(AppDbContext db) : IAiConversationRepository
|
|
{
|
|
private readonly AppDbContext _db = db;
|
|
|
|
public Task<Conversation?> GetOwnedAsync(Guid userId, Guid conversationId, CancellationToken ct) =>
|
|
_db.Conversations.FirstOrDefaultAsync(c => c.Id == conversationId && c.UserId == userId, ct);
|
|
|
|
public Task<Conversation?> GetAsync(Guid conversationId, CancellationToken ct) =>
|
|
_db.Conversations.FirstOrDefaultAsync(c => c.Id == conversationId, ct);
|
|
|
|
public async Task<IReadOnlyList<Conversation>> ListAsync(Guid userId, CancellationToken ct) =>
|
|
await _db.Conversations
|
|
.Where(c => c.UserId == userId)
|
|
.OrderByDescending(c => c.UpdatedAt)
|
|
.ToListAsync(ct);
|
|
|
|
public async Task<IReadOnlyList<ConversationMessage>> GetMessagesAsync(Guid conversationId, CancellationToken ct) =>
|
|
await _db.ConversationMessages
|
|
.Where(m => m.ConversationId == conversationId)
|
|
.OrderBy(m => m.CreatedAt)
|
|
.ToListAsync(ct);
|
|
|
|
public async Task<IReadOnlyList<ConversationMessage>> GetRecentMessagesAsync(Guid conversationId, int limit, CancellationToken ct) =>
|
|
await _db.ConversationMessages
|
|
.Where(m => m.ConversationId == conversationId)
|
|
.OrderByDescending(m => m.CreatedAt)
|
|
.Take(limit)
|
|
.ToListAsync(ct);
|
|
|
|
public async Task AddConversationAsync(Conversation conversation, CancellationToken ct) =>
|
|
await _db.Conversations.AddAsync(conversation, ct);
|
|
|
|
public async Task AddMessageAsync(ConversationMessage message, CancellationToken ct) =>
|
|
await _db.ConversationMessages.AddAsync(message, ct);
|
|
|
|
public async Task<int> DeleteLegacyDietCommentaryArtifactsAsync(
|
|
Guid userId,
|
|
string promptPrefix,
|
|
CancellationToken ct)
|
|
{
|
|
var candidates = await _db.Conversations
|
|
.Include(conversation => conversation.Messages)
|
|
.Where(conversation =>
|
|
conversation.UserId == userId &&
|
|
conversation.Messages.Any(message =>
|
|
message.Role == MessageRole.User &&
|
|
message.Content.StartsWith(promptPrefix)))
|
|
.ToListAsync(ct);
|
|
var artifacts = candidates
|
|
.Where(conversation => DietCommentaryPolicy.IsLegacyArtifact(conversation.Messages))
|
|
.ToList();
|
|
if (artifacts.Count == 0) return 0;
|
|
|
|
_db.Conversations.RemoveRange(artifacts);
|
|
await _db.SaveChangesAsync(ct);
|
|
return artifacts.Count;
|
|
}
|
|
|
|
public void Delete(Conversation conversation) =>
|
|
_db.Conversations.Remove(conversation);
|
|
|
|
public Task SaveChangesAsync(CancellationToken ct) =>
|
|
_db.SaveChangesAsync(ct);
|
|
}
|