package tools_bot import ( "ai_scheduler/internal/config" "ai_scheduler/internal/data/constants" errors "ai_scheduler/internal/data/error" "ai_scheduler/internal/data/impl" "ai_scheduler/internal/entitys" "ai_scheduler/internal/pkg" "ai_scheduler/internal/pkg/l_request" "ai_scheduler/internal/pkg/utils_ollama" "context" "encoding/json" "fmt" "github.com/gofiber/fiber/v2/log" "github.com/google/uuid" "xorm.io/builder" ) type BotTool struct { config *config.Config llm *utils_ollama.Client sessionImpl *impl.SessionImpl taskMap map[string]string // task_id -> session_id } // NewBotTool 创建直连天下订单详情工具 func NewBotTool(config *config.Config, llm *utils_ollama.Client, sessionImpl *impl.SessionImpl) *BotTool { return &BotTool{config: config, llm: llm, sessionImpl: sessionImpl, taskMap: make(map[string]string)} } // BugOptimizationSubmitForm 工单提交表单参数 type BugOptimizationSubmitForm struct { Mark string `json:"mark"` // 工单标识 Text string `json:"text"` // 工单描述 Img string `json:"img"` // 工单截图 Creator string `json:"creator"` // 工单创建人 TaskId string `json:"task_id"` // 当初任务ID } // Execute 执行直连天下订单详情查询 func (w *BotTool) Execute(ctx context.Context, toolName string, requireData *entitys.RequireData) (err error) { switch toolName { case constants.BotToolsBugOptimizationSubmit: err = w.BugOptimizationSubmit(ctx, requireData) default: log.Errorf("未知的工具类型:%s", toolName) err = errors.ParamErr("未知的工具类型:%s", toolName) } return } const ( // 工单QA BotBugOptimizationSubmitQA = "温子新" BotBugOptimizationSubmitPM = "贺泽琨" ) // 现存问题: // 1. 回调时 session 直接传入不安全 todo // 2. 创建人无法指定[钉钉用户],影响后续状态变化时通知 // 3. 回调接口,[接收人]、[文档地址不能]动态配置 // 4. 测试环境与线上环境,使用的不是同一个钉钉主体 func (w *BotTool) BugOptimizationSubmit(ctx context.Context, requireData *entitys.RequireData) (err error) { // 获取用户信息 cond := builder.NewCond() cond = cond.And(builder.Eq{"session_id": requireData.Session}) sessionInfo, err := w.sessionImpl.GetOneBySearch(&cond) if err != nil { err = errors.SysErr("获取会话信息失败:%v", err.Error()) return } userName := sessionInfo["user_name"].(string) // 构建工单表单参数 body := BugOptimizationSubmitForm{ Mark: requireData.Match.Index, Text: requireData.Req.Text, Img: requireData.Req.Img, Creator: userName, TaskId: uuid.New().String(), } request := l_request.Request{ Url: "https://connector.dingtalk.com/webhook/flow/10352c521dd02104cee9000c", Method: "POST", Headers: map[string]string{ "Content-Type": "application/json", }, JsonByte: pkg.JsonByteIgonErr(body), } res, err := request.Send() if err != nil { log.Errorf("发送请求失败: %s", err.Error()) return } data := make(map[string]bool) if err = json.Unmarshal(res.Content, &data); err != nil { return fmt.Errorf("解析工单响应失败:%w", err) } if data["success"] { // 记录 task_id 到 session_id 的映射 w.SetTaskMapping(body.TaskId, requireData.Session) entitys.ResLoading(requireData.Ch, requireData.Match.Index, "问题内容记录中...") return } entitys.ResJson(requireData.Ch, requireData.Match.Index, fmt.Sprintf("bug问题请咨询 @%s ,优化建议请咨询 @%s 。", BotBugOptimizationSubmitQA, BotBugOptimizationSubmitPM)) return } // SetTaskMapping 设置 task_id 到 session_id 的映射(内存版)。 // 后续考虑使用 Redis,确保幂等与过期清理。 func (w *BotTool) SetTaskMapping(taskID, sessionID string) { if taskID == "" || sessionID == "" { return } w.taskMap[taskID] = sessionID } // GetSessionByTaskID 读取映射 func (w *BotTool) GetSessionByTaskID(taskID string) (string, bool) { v, ok := w.taskMap[taskID] return v, ok } // DelTaskMapping 删除 task_id 到 session_id 的映射(内存版)。 func (w *BotTool) DelTaskMapping(taskID string) { delete(w.taskMap, taskID) }