135 lines
4.1 KiB
Go
135 lines
4.1 KiB
Go
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)
|
||
}
|