diff --git a/config/config.yaml b/config/config.yaml index 4b568b4..a1497f4 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -65,6 +65,13 @@ tools: enabled: true base_url: "https://revcl.1688sup.com/api/admin/afterSales/reseller_pre_ai" +dingtalk: + api_key: "dingsbbntrkeiyazcfdg" + api_secret: "ObqxwyR20r9rVNhju0sCPQyQA98_FZSc32W4vgxnGFH_b02HZr1BPCJsOAF816nu" + table_demand: + url: "https://alidocs.dingtalk.com/i/nodes/YQBnd5ExVE6qAbnOiANQg2KKJyeZqMmz" + base_id: "2Amq4vjg89RnYx9DTp66m2orW3kdP0wQ" + sheet_id_or_name: "数据表" default_prompt: img_recognize: diff --git a/config/config_env.yaml b/config/config_env.yaml index fa6b8ae..e180a4b 100644 --- a/config/config_env.yaml +++ b/config/config_env.yaml @@ -105,6 +105,13 @@ eino_tools: hytGoodsBrandSearch: base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/goods/brand/list" +dingtalk: + api_key: "dingsbbntrkeiyazcfdg" + api_secret: "ObqxwyR20r9rVNhju0sCPQyQA98_FZSc32W4vgxnGFH_b02HZr1BPCJsOAF816nu" + table_demand: + url: "https://alidocs.dingtalk.com/i/nodes/YQBnd5ExVE6qAbnOiANQg2KKJyeZqMmz" + base_id: "YQBnd5ExVE6qAbnOiANQg2KKJyeZqMmz" + sheet_id_or_name: "数据表" default_prompt: diff --git a/config/config_test.yaml b/config/config_test.yaml index 5ea689d..2180e18 100644 --- a/config/config_test.yaml +++ b/config/config_test.yaml @@ -119,6 +119,13 @@ eino_tools: hytGoodsBrandSearch: base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/goods/brand/list" +dingtalk: + api_key: "dingsbbntrkeiyazcfdg" + api_secret: "ObqxwyR20r9rVNhju0sCPQyQA98_FZSc32W4vgxnGFH_b02HZr1BPCJsOAF816nu" + table_demand: + url: "https://alidocs.dingtalk.com/i/nodes/YQBnd5ExVE6qAbnOiANQg2KKJyeZqMmz" + base_id: "YQBnd5ExVE6qAbnOiANQg2KKJyeZqMmz" + sheet_id_or_name: "数据表" default_prompt: img_recognize: diff --git a/internal/biz/do/handle.go b/internal/biz/do/handle.go index d2ef661..ca2392c 100644 --- a/internal/biz/do/handle.go +++ b/internal/biz/do/handle.go @@ -4,6 +4,7 @@ import ( "ai_scheduler/internal/biz/llm_service" "ai_scheduler/internal/config" "ai_scheduler/internal/data/constants" + errorcode "ai_scheduler/internal/data/error" errors "ai_scheduler/internal/data/error" "ai_scheduler/internal/data/impl" "ai_scheduler/internal/data/model" @@ -16,7 +17,6 @@ import ( "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" @@ -255,25 +255,38 @@ func (r *Handle) handleBot(ctx context.Context, rec *entitys.Recognize, task *mo accessToken, _ := r.dingtalkOldClient.GetAccessToken() // 获取创建者 dingtalk unionId unionId := r.getUserDingtalkUnionId(ctx, accessToken, sessionID) - baseId := "YQBnd5ExVE6qAbnOiANQg2KKJyeZqMmz" - // 获取第一个数据表 - // sheetIdOrName := r.getFirstSheetIdOrName(ctx, baseId) + // 附件url + var attachmentUrl string + for _, file := range rec.UserContent.File { + attachmentUrl = file.FileUrl + break + } recordId, err := r.dingtalkNotableClient.InsertRecord(accessToken, &dingtalk.InsertRecordReq{ - BaseId: baseId, - SheetIdOrName: "数据表", - OperatorId: tool_callback.BotBugOptimizationSubmitAdminUnionId, + BaseId: r.conf.Dingtalk.TableDemand.BaseId, + SheetIdOrName: r.conf.Dingtalk.TableDemand.SheetIdOrName, + // OperatorId: tool_callback.BotBugOptimizationSubmitAdminUnionId, + OperatorId: unionId, CreatorUnionId: unionId, - Content: rec.Match.Parameters, + Content: rec.UserContent.Text, + AttachmentUrl: attachmentUrl, }) if err != nil { + errCode := r.dingtalkNotableClient.GetHTTPStatus(err) + // 权限不足 + if errCode == 403 { + return errorcode.ForbiddenErr("您当前没有AI需求表编辑权限,请联系管理员添加权限") + } return err } if recordId == "" { - return errors.NewBusinessErr(422, "创建记录失败") + return errors.NewBusinessErr(422, "创建记录失败,请联系管理员") } - entitys.ResText(rec.Ch, "", fmt.Sprintf("创建记录成功,记录ID: %s", recordId)) + // 构建跳转链接 + detailPage := util.BuildJumpLink(r.conf.Dingtalk.TableDemand.Url, "去查看") + + entitys.ResText(rec.Ch, "", fmt.Sprintf("问题已记录,正在分配相关人员处理,请您耐心等待处理结果。点击查看工单进度:%s", detailPage)) return nil } diff --git a/internal/config/config.go b/internal/config/config.go index 3198ebd..441d09d 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -23,6 +23,7 @@ type Config struct { PermissionConfig PermissionConfig `mapstructure:"permissionConfig"` LLM LLM `mapstructure:"llm"` // DingTalkBots map[string]*DingTalkBot `mapstructure:"ding_talk_bots"` + Dingtalk DingtalkConfig `mapstructure:"dingtalk"` } type SysPrompt struct { @@ -61,6 +62,20 @@ type LLMCapabilityConfig struct { Parameters LLMParameters `mapstructure:"parameters"` } +// DingtalkConfig 钉钉配置 +type DingtalkConfig struct { + ApiKey string `mapstructure:"api_key"` + ApiSecret string `mapstructure:"api_secret"` + TableDemand AITableConfig `mapstructure:"table_demand"` +} + +// TableDemandConfig 需求表配置 +type AITableConfig struct { + Url string `mapstructure:"url"` + BaseId string `mapstructure:"base_id"` + SheetIdOrName string `mapstructure:"sheet_id_or_name"` +} + // SysConfig 系统配置 type SysConfig struct { SessionLen int `mapstructure:"session_len"` diff --git a/internal/data/error/error_code.go b/internal/data/error/error_code.go index 1e2f0b6..390f448 100644 --- a/internal/data/error/error_code.go +++ b/internal/data/error/error_code.go @@ -3,10 +3,11 @@ package errorcode import "fmt" var ( - Success = &BusinessErr{code: 200, message: "成功"} - ParamError = &BusinessErr{code: 401, message: "参数错误"} - NotFoundError = &BusinessErr{code: 404, message: "请求地址未找到"} - SystemError = &BusinessErr{code: 405, message: "系统错误"} + Success = &BusinessErr{code: 200, message: "成功"} + ParamError = &BusinessErr{code: 401, message: "参数错误"} + ForbiddenError = &BusinessErr{code: 403, message: "权限不足"} + NotFoundError = &BusinessErr{code: 404, message: "请求地址未找到"} + SystemError = &BusinessErr{code: 405, message: "系统错误"} ClientNotFound = &BusinessErr{code: 406, message: "未找到client_id"} SessionNotFound = &BusinessErr{code: 407, message: "未找到会话信息"} @@ -67,3 +68,7 @@ func (e *BusinessErr) Wrap(err error) *BusinessErr { func WorkflowErr(message string) *BusinessErr { return NewBusinessErr(WorkflowError.code, message) } + +func ForbiddenErr(message string) *BusinessErr { + return NewBusinessErr(ForbiddenError.code, message) +} diff --git a/internal/pkg/dingtalk/notable_client.go b/internal/pkg/dingtalk/notable_client.go index 27a2f89..885e111 100644 --- a/internal/pkg/dingtalk/notable_client.go +++ b/internal/pkg/dingtalk/notable_client.go @@ -3,6 +3,8 @@ package dingtalk import ( "ai_scheduler/internal/config" errorcode "ai_scheduler/internal/data/error" + "encoding/json" + "time" openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client" notable "github.com/alibabacloud-go/dingtalk/notable_1_0" @@ -79,6 +81,7 @@ type InsertRecordReq struct { OperatorId string CreatorUnionId string Content string + AttachmentUrl string } func (c *NotableClient) InsertRecord(accessToken string, req *InsertRecordReq) (string, error) { @@ -97,12 +100,16 @@ func (c *NotableClient) InsertRecord(accessToken string, req *InsertRecordReq) ( Records: []*notable.InsertRecordsRequestRecords{ { Fields: map[string]any{ + "创建日期": time.Now().Format(time.DateTime), "需求内容": req.Content, "提交人": []map[string]any{ { "unionId": req.CreatorUnionId, }, }, + "附件": map[string]any{ + "link": req.AttachmentUrl, + }, }, }, }, @@ -117,3 +124,20 @@ func (c *NotableClient) InsertRecord(accessToken string, req *InsertRecordReq) ( return *resp.Body.Value[0].Id, nil } + +func (c *NotableClient) GetHTTPStatus(err error) int { + if sdkErr, ok := err.(*tea.SDKError); ok { + if sdkErr.StatusCode != nil { + return *sdkErr.StatusCode + } + if sdkErr.Data != nil { + var m struct { + StatusCode int `json:"statusCode"` + } + if json.Unmarshal([]byte(*sdkErr.Data), &m) == nil { + return m.StatusCode + } + } + } + return 0 // 0 = 非 HTTP 错误 +}