ai_scheduler/internal/tools_bot/dtalk_bot.go

135 lines
4.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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}
}
// 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)
}