package logic import ( "context" "healthapi/internal/model" "healthapi/internal/svc" "healthapi/internal/types" "healthapi/pkg/ai" "healthapi/pkg/errorx" "github.com/zeromicro/go-zero/core/logx" "gorm.io/gorm" ) type SendMessageLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } func NewSendMessageLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SendMessageLogic { return &SendMessageLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } func (l *SendMessageLogic) SendMessage(req *types.SendMessageReq) (resp *types.MessageResp, err error) { userID, err := GetUserIDFromCtx(l.ctx) if err != nil { return nil, errorx.ErrUnauthorized } // 验证对话属于该用户 var conversation model.Conversation if err := l.svcCtx.DB.Where("id = ? AND user_id = ?", req.Id, userID).First(&conversation).Error; err != nil { return nil, errorx.ErrNotFound } // 保存用户消息 userMessage := model.Message{ ConversationID: conversation.ID, Role: model.RoleUser, Content: req.Content, } if err := l.svcCtx.DB.Create(&userMessage).Error; err != nil { return nil, errorx.ErrServerError } // 获取历史消息构建上下文 var historyMessages []model.Message l.svcCtx.DB.Where("conversation_id = ?", conversation.ID). Order("created_at DESC"). Limit(l.svcCtx.Config.AI.MaxHistoryMessages). Find(&historyMessages) // 获取用户健康档案构建系统提示 systemPrompt := buildSystemPrompt(l.svcCtx.DB, userID) // 构建 AI 消息 aiMessages := []ai.Message{{Role: "system", Content: systemPrompt}} for i := len(historyMessages) - 1; i >= 0; i-- { aiMessages = append(aiMessages, ai.Message{ Role: historyMessages[i].Role, Content: historyMessages[i].Content, }) } // 调用 AI 服务 aiResponse, err := l.svcCtx.AIClient.Chat(l.ctx, aiMessages) if err != nil { l.Logger.Errorf("AI service error: %v", err) aiResponse = "抱歉,AI 服务暂时不可用,请稍后再试。" } // 保存 AI 回复 assistantMessage := model.Message{ ConversationID: conversation.ID, Role: model.RoleAssistant, Content: aiResponse, } if err := l.svcCtx.DB.Create(&assistantMessage).Error; err != nil { return nil, errorx.ErrServerError } // 更新对话标题 if conversation.Title == "新对话" { title := req.Content if len(title) > 50 { title = title[:50] + "..." } l.svcCtx.DB.Model(&conversation).Update("title", title) } return &types.MessageResp{ UserMessage: types.Message{ ID: uint(userMessage.ID), ConversationID: userMessage.ConversationID, Role: userMessage.Role, Content: userMessage.Content, CreatedAt: userMessage.CreatedAt.Format("2006-01-02 15:04:05"), }, AssistantMessage: types.Message{ ID: uint(assistantMessage.ID), ConversationID: assistantMessage.ConversationID, Role: assistantMessage.Role, Content: assistantMessage.Content, CreatedAt: assistantMessage.CreatedAt.Format("2006-01-02 15:04:05"), }, }, nil } // buildSystemPrompt 构建系统提示(包含用户健康档案) func buildSystemPrompt(db *gorm.DB, userID uint) string { basePrompt := `你是一位专业的中医健康顾问,名叫"健康小助手"。你的职责是: 1. 根据用户的健康档案和体质特点,提供个性化的健康建议 2. 解答用户关于中医养生、体质调理的问题 3. 推荐适合用户体质的饮食、运动和生活方式 4. 在必要时提醒用户寻求专业医疗帮助 请注意: - 你的建议仅供参考,不能替代专业医疗诊断 - 回答要简洁明了,通俗易懂 - 适当使用中医术语,但要给出解释 - 保持友好、专业的语气` // 获取用户体质信息 var assessment model.ConstitutionAssessment if err := db.Where("user_id = ?", userID).Order("assessed_at DESC").First(&assessment).Error; err == nil { if assessment.PrimaryConstitution != "" { basePrompt += "\n\n用户体质类型: " + model.ConstitutionNames[assessment.PrimaryConstitution] } } return basePrompt }