diff --git a/internal/biz/do/handle.go b/internal/biz/do/handle.go index 76f1257..d2ef661 100644 --- a/internal/biz/do/handle.go +++ b/internal/biz/do/handle.go @@ -11,10 +11,12 @@ import ( "ai_scheduler/internal/entitys" "ai_scheduler/internal/gateway" "ai_scheduler/internal/pkg" + "ai_scheduler/internal/pkg/dingtalk" "ai_scheduler/internal/pkg/l_request" "ai_scheduler/internal/pkg/mapstructure" "ai_scheduler/internal/pkg/rec_extra" "ai_scheduler/internal/pkg/util" + "ai_scheduler/internal/tool_callback" "ai_scheduler/internal/tools" "ai_scheduler/internal/tools/public" errorsSpecial "errors" @@ -28,16 +30,19 @@ import ( "strings" "github.com/coze-dev/coze-go" + "github.com/gofiber/fiber/v2/log" "gorm.io/gorm/utils" ) type Handle struct { - Ollama *llm_service.OllamaService - toolManager *tools.Manager - - conf *config.Config - sessionImpl *impl.SessionImpl - workflowManager *runtime.Registry + Ollama *llm_service.OllamaService + toolManager *tools.Manager + conf *config.Config + sessionImpl *impl.SessionImpl + workflowManager *runtime.Registry + dingtalkOldClient *dingtalk.OldClient + dingtalkContactClient *dingtalk.ContactClient + dingtalkNotableClient *dingtalk.NotableClient } func NewHandle( @@ -45,16 +50,20 @@ func NewHandle( toolManager *tools.Manager, conf *config.Config, sessionImpl *impl.SessionImpl, - workflowManager *runtime.Registry, + dingtalkOldClient *dingtalk.OldClient, + dingtalkContactClient *dingtalk.ContactClient, + dingtalkNotableClient *dingtalk.NotableClient, ) *Handle { return &Handle{ - Ollama: Ollama, - toolManager: toolManager, - conf: conf, - sessionImpl: sessionImpl, - - workflowManager: workflowManager, + Ollama: Ollama, + toolManager: toolManager, + conf: conf, + sessionImpl: sessionImpl, + workflowManager: workflowManager, + dingtalkOldClient: dingtalkOldClient, + dingtalkContactClient: dingtalkContactClient, + dingtalkNotableClient: dingtalkNotableClient, } } @@ -119,10 +128,12 @@ func (r *Handle) HandleMatch(ctx context.Context, client *gateway.Client, rec *e switch constants.TaskType(pointTask.Type) { case constants.TaskTypeApi: return r.handleApiTask(ctx, rec, pointTask) - case constants.TaskTypeFunc: - return r.handleTask(ctx, rec, pointTask) case constants.TaskTypeKnowle: return r.handleKnowle(ctx, rec, pointTask) + case constants.TaskTypeFunc: + return r.handleTask(ctx, rec, pointTask) + case constants.TaskTypeBot: + return r.handleBot(ctx, rec, pointTask) case constants.TaskTypeEinoWorkflow: return r.handleEinoWorkflow(ctx, rec, pointTask) case constants.TaskTypeCozeWorkflow: @@ -235,6 +246,74 @@ func (r *Handle) handleKnowle(ctx context.Context, rec *entitys.Recognize, task return } +// bot 临时实现,后续转到 eino 工作流 +func (r *Handle) handleBot(ctx context.Context, rec *entitys.Recognize, task *model.AiTask) (err error) { + if task.Index == "bug_optimization_submit" { + // Ext 中获取 sessionId + sessionID := rec.GetSession() + // 获取dingtalk accessToken + accessToken, _ := r.dingtalkOldClient.GetAccessToken() + // 获取创建者 dingtalk unionId + unionId := r.getUserDingtalkUnionId(ctx, accessToken, sessionID) + baseId := "YQBnd5ExVE6qAbnOiANQg2KKJyeZqMmz" + // 获取第一个数据表 + // sheetIdOrName := r.getFirstSheetIdOrName(ctx, baseId) + recordId, err := r.dingtalkNotableClient.InsertRecord(accessToken, &dingtalk.InsertRecordReq{ + BaseId: baseId, + SheetIdOrName: "数据表", + OperatorId: tool_callback.BotBugOptimizationSubmitAdminUnionId, + CreatorUnionId: unionId, + Content: rec.Match.Parameters, + }) + if err != nil { + return err + } + + if recordId == "" { + return errors.NewBusinessErr(422, "创建记录失败") + } + + entitys.ResText(rec.Ch, "", fmt.Sprintf("创建记录成功,记录ID: %s", recordId)) + + return nil + } + + return errors.NewBusinessErr(422, "bot 任务未实现") +} + +// getUserDingtalkUnionId 获取用户的 dingtalk unionId +func (r *Handle) getUserDingtalkUnionId(ctx context.Context, accessToken, sessionID string) (unionId string) { + // 查询用户名 + session, has, err := r.sessionImpl.FindOne(r.sessionImpl.WithSessionId(sessionID)) + if err != nil || !has { + log.Warnf("session not found: %s", sessionID) + return + } + creatorName := session.UserName + + // 获取创建者uid 用户名 -> dingtalk uid + creatorId, err := r.dingtalkContactClient.SearchUserOne(accessToken, creatorName) + if err != nil { + log.Warnf("search dingtalk user one failed: %v", err) + return + } + + // 获取用户详情 dingtalk uid -> dingtalk unionId + userDetails, err := r.dingtalkOldClient.QueryUserDetails(ctx, creatorId) + if err != nil { + log.Warnf("query user dingtalk details failed: %v", err) + return + } + if userDetails == nil { + log.Warnf("user details not found: %s", creatorId) + return + } + + unionId = userDetails.UnionID + + return +} + func (r *Handle) handleApiTask(ctx context.Context, rec *entitys.Recognize, task *model.AiTask) (err error) { var ( request l_request.Request diff --git a/internal/pkg/dingtalk/notable_client.go b/internal/pkg/dingtalk/notable_client.go index d7d5434..27a2f89 100644 --- a/internal/pkg/dingtalk/notable_client.go +++ b/internal/pkg/dingtalk/notable_client.go @@ -72,3 +72,48 @@ func (c *NotableClient) UpdateRecord(accessToken string, req *UpdateRecordReq) ( return true, nil } + +type InsertRecordReq struct { + BaseId string + SheetIdOrName string + OperatorId string + CreatorUnionId string + Content string +} + +func (c *NotableClient) InsertRecord(accessToken string, req *InsertRecordReq) (string, error) { + // 默认使用“数据表” + if req.SheetIdOrName == "" { + req.SheetIdOrName = "数据表" + } + + headers := ¬able.InsertRecordsHeaders{} + headers.XAcsDingtalkAccessToken = tea.String(accessToken) + resp, err := c.cli.InsertRecordsWithOptions( + tea.String(req.BaseId), + tea.String(req.SheetIdOrName), + ¬able.InsertRecordsRequest{ + OperatorId: tea.String(req.OperatorId), + Records: []*notable.InsertRecordsRequestRecords{ + { + Fields: map[string]any{ + "需求内容": req.Content, + "提交人": []map[string]any{ + { + "unionId": req.CreatorUnionId, + }, + }, + }, + }, + }, + }, headers, &util.RuntimeOptions{}) + if err != nil { + return "", err + } + + if resp.Body == nil || resp.Body.Value == nil || len(resp.Body.Value) == 0 { + return "", errorcode.ParamErrf("empty response body") + } + + return *resp.Body.Value[0].Id, nil +}