diff --git a/config/config.yaml b/config/config.yaml index c1e8c08..4b568b4 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -23,7 +23,7 @@ redis: host: 47.97.27.195:6379 type: node pass: lansexiongdi@666 - key: report-api-test + key: report-api pollSize: 5 #连接池大小,不配置,或配置为0表示不启用连接池 minIdleConns: 2 #最小空闲连接数 maxIdleTime: 30 #每个连接最大空闲时间,如果超过了这个时间会被关闭 diff --git a/internal/biz/ding_talk_bot.go b/internal/biz/ding_talk_bot.go index f2abea1..74f2a47 100644 --- a/internal/biz/ding_talk_bot.go +++ b/internal/biz/ding_talk_bot.go @@ -6,8 +6,8 @@ import ( "ai_scheduler/internal/data/impl" "ai_scheduler/internal/data/model" "ai_scheduler/internal/entitys" - "ai_scheduler/internal/pkg/mapstructure" "context" + "encoding/json" "fmt" "github.com/gofiber/fiber/v2/log" @@ -47,10 +47,11 @@ func (d *DingTalkBotBiz) GetDingTalkBotCfgList() (dingBotList []entitys.DingTalk err = d.botConfigImpl.GetRangeToMapStruct(&cond, &botConfig) for _, v := range botConfig { var config entitys.DingTalkBot - err = mapstructure.Decode(v, &config) + err = json.Unmarshal([]byte(v.BotConfig), &config) if err != nil { d.log.Info("初始化“%s”失败:%s", v.BotName, err.Error()) } + config.BotIndex = v.BotIndex dingBotList = append(dingBotList, config) } return diff --git a/internal/biz/do/handle.go b/internal/biz/do/handle.go index 3a5ffac..169f025 100644 --- a/internal/biz/do/handle.go +++ b/internal/biz/do/handle.go @@ -48,6 +48,7 @@ func NewHandle( func (r *Handle) Recognize(ctx context.Context, rec *entitys.Recognize, promptProcessor PromptOption) (match entitys.Match, err error) { entitys.ResLog(rec.Ch, "recognize_start", "准备意图识别") + prompt, err := promptProcessor.CreatePrompt(ctx, rec) //意图识别 recognizeMsg, err := r.Ollama.IntentRecognize(ctx, &entitys.ToolSelect{ diff --git a/internal/biz/handle/dingtalk/auth.go b/internal/biz/handle/dingtalk/auth.go new file mode 100644 index 0000000..8ddd0c1 --- /dev/null +++ b/internal/biz/handle/dingtalk/auth.go @@ -0,0 +1,69 @@ +package dingtalk + +import ( + "ai_scheduler/internal/config" + "ai_scheduler/internal/data/constants" + "ai_scheduler/internal/pkg/l_request" + "context" + "encoding/json" + "errors" + "net/http" + "time" + + "github.com/redis/go-redis/v9" +) + +type Auth struct { + redis *redis.Client + cfg *config.Config +} + +func NewAuth(cfg *config.Config, redis *redis.Client) *Auth { + return &Auth{ + redis: redis, + cfg: cfg, + } +} + +func (a *Auth) GetAccessToken(ctx context.Context, clientId string, clientSecret string) (accessToken string, err error) { + if clientId == "" { + return "", errors.New("clientId is empty") + } + token := a.redis.Get(ctx, a.getKey(clientId)).String() + if token == "" { + authInfo, _err := a.getNewAccessToken(ctx, clientId, clientSecret) + if _err != nil { + return "", _err + } + a.redis.SetEx(ctx, a.getKey(clientId), authInfo.AccessToken, time.Duration(authInfo.ExpiresIn-3600)*time.Second) + accessToken = authInfo.AccessToken + } + return +} + +func (a *Auth) getKey(clientId string) string { + return a.cfg.Redis.Key + ":" + constants.DingTalkAuthBaseKeyPrefix + ":" + clientId +} + +func (a *Auth) getNewAccessToken(ctx context.Context, clientId string, clientSecret string) (auth AuthInfo, err error) { + if clientId == "" || clientSecret == "" { + err = errors.New("clientId or clientSecret is empty") + return + } + + req := l_request.Request{ + Method: http.MethodPost, + Url: constants.GetDingTalkRequestUrl(constants.RequestUrlGetAccessToken, nil), + Data: map[string]string{ + "appkey": clientId, + "appsecret": clientSecret, + }, + } + res, err := req.Send() + if err != nil { + return + } + err = json.Unmarshal(res.Content, &auth) + + return +} diff --git a/internal/biz/handle/dingtalk/dept.go b/internal/biz/handle/dingtalk/dept.go new file mode 100644 index 0000000..14327c9 --- /dev/null +++ b/internal/biz/handle/dingtalk/dept.go @@ -0,0 +1,35 @@ +package dingtalk + +import ( + "ai_scheduler/internal/data/impl" + "ai_scheduler/internal/entitys" + "database/sql" + "errors" +) + +type Dept struct { + dingUserImpl *impl.BotUserImpl +} + +func NewDept(dingUserImpl *impl.BotUserImpl) *User { + return &User{ + dingUserImpl: dingUserImpl, + } +} + +func (u *User) GetDeptInfo(userId string) (userInfo *entitys.DingTalkUserInfo, err error) { + if len(userId) == 0 { + return + } + user, err := u.dingUserImpl.GetByStaffId(userId) + if err != nil { + if !errors.Is(err, sql.ErrNoRows) { + return + } + } + //如果没有找到,则新增 + if user == nil { + + } + return +} diff --git a/internal/biz/handle/dingtalk/option.go b/internal/biz/handle/dingtalk/option.go new file mode 100644 index 0000000..fb473c7 --- /dev/null +++ b/internal/biz/handle/dingtalk/option.go @@ -0,0 +1,21 @@ +package dingtalk + +import "ai_scheduler/internal/data/model" + +type Bot struct { + id int + botConfig *model.AiBotConfig +} +type BotOption func(*Bot) + +func WithId(id int) BotOption { + return func(b *Bot) { + b.id = id + } +} + +func WithBootConfig(BotConfig *model.AiBotConfig) BotOption { + return func(bot *Bot) { + bot.botConfig = BotConfig + } +} diff --git a/internal/biz/handle/dingtalk/types.go b/internal/biz/handle/dingtalk/types.go new file mode 100644 index 0000000..1e9fe76 --- /dev/null +++ b/internal/biz/handle/dingtalk/types.go @@ -0,0 +1,59 @@ +package dingtalk + +type AuthInfo struct { + AccessToken string `json:"accessToken"` + ExpiresIn int64 `json:"expiresIn"` +} + +type UserInfoResResult struct { + Errcode string `json:"errcode"` + Result Result `json:"result"` + Errmsg string `json:"errmsg"` +} +type Result struct { + Extension string `json:"extension"` + Unionid string `json:"unionid"` + Boss string `json:"boss"` + RoleList struct { + GroupName string `json:"group_name"` + Name string `json:"name"` + Id string `json:"id"` + } `json:"role_list"` + ExclusiveAccount bool `json:"exclusive_account"` + ManagerUserid string `json:"manager_userid"` + Admin string `json:"admin"` + Remark string `json:"remark"` + Title string `json:"title"` + HiredDate int `json:"hired_date"` + Userid string `json:"userid"` + WorkPlace string `json:"work_place"` + DeptOrderList struct { + DeptId string `json:"dept_id"` + Order string `json:"order"` + } `json:"dept_order_list"` + RealAuthed string `json:"real_authed"` + DeptIdList string `json:"dept_id_list"` + JobNumber string `json:"job_number"` + Email string `json:"email"` + LeaderInDept struct { + Leader string `json:"leader"` + DeptId string `json:"dept_id"` + } `json:"leader_in_dept"` + Mobile string `json:"mobile"` + Active string `json:"active"` + OrgEmail string `json:"org_email"` + Telephone string `json:"telephone"` + Avatar string `json:"avatar"` + HideMobile string `json:"hide_mobile"` + Senior string `json:"senior"` + Name string `json:"name"` + UnionEmpExt struct { + UnionEmpMapList struct { + Userid string `json:"userid"` + CorpId string `json:"corp_id"` + } `json:"union_emp_map_list"` + Userid string `json:"userid"` + CorpId string `json:"corp_id"` + } `json:"union_emp_ext"` + StateCode string `json:"state_code"` +} diff --git a/internal/biz/handle/dingtalk/user.go b/internal/biz/handle/dingtalk/user.go new file mode 100644 index 0000000..7d213c2 --- /dev/null +++ b/internal/biz/handle/dingtalk/user.go @@ -0,0 +1,140 @@ +package dingtalk + +import ( + "ai_scheduler/internal/data/constants" + "ai_scheduler/internal/data/impl" + "ai_scheduler/internal/data/model" + "ai_scheduler/internal/entitys" + "ai_scheduler/internal/pkg" + "ai_scheduler/internal/pkg/l_request" + "context" + "database/sql" + "encoding/json" + "errors" + "fmt" + "net/http" + "strings" + "time" + + "github.com/gofiber/fiber/v2/log" + "xorm.io/builder" +) + +type User struct { + dingUserImpl *impl.BotUserImpl + botConfigImpl *impl.BotConfigImpl + auth *Auth + logger log.Logger +} + +func NewUser( + dingUserImpl *impl.BotUserImpl, + botConfig *impl.BotConfigImpl, + auth *Auth, + logger log.Logger, +) *User { + return &User{ + dingUserImpl: dingUserImpl, + botConfigImpl: botConfig, + logger: logger, + auth: auth, + } +} + +func (u *User) GetUserInfo(ctx context.Context, staffId string, botOption ...BotOption) (userInfo *entitys.DingTalkUserInfo, err error) { + if len(staffId) == 0 { + return + } + user, err := u.dingUserImpl.GetByStaffId(staffId) + if err != nil { + if !errors.Is(err, sql.ErrNoRows) { + return + } + } + //如果没有找到,则新增 + if user == nil { + DingUserInfo, _err := u.GetUserInfoFromDingTalkWithBot(ctx, staffId, botOption...) + if _err != nil { + return nil, _err + } + dingUserDo := &model.AiBotUser{ + StaffID: DingUserInfo.Userid, + Name: DingUserInfo.Name, + Title: DingUserInfo.Title, + Extension: DingUserInfo.Extension, + DeptIDList: DingUserInfo.DeptIdList, + IsBoss: int32(pkg.Ter(DingUserInfo.Boss == "true", constants.IsBossTrue, constants.IsBossFalse)), + IsSenior: int32(pkg.Ter(DingUserInfo.Boss == "true", constants.IsSeniorTrue, constants.IsSeniorFalse)), + HiredDate: time.Unix(int64(DingUserInfo.HiredDate), 0), + } + //deptIdList, _err := pkg.StringToSlice(DingUserInfo.DeptIdList) + //if err != nil { + // return nil, _err + //} + dingUserDo.DeptIDList = strings.Trim(dingUserDo.DeptIDList, "[]") + } + return +} + +func (u *User) GetUserInfoFromDingTalkWithBot(ctx context.Context, staffId string, botOption ...BotOption) (userInfo Result, err error) { + botInfo := &Bot{} + for _, option := range botOption { + option(botInfo) + } + + if botInfo.id == 0 && botInfo.botConfig == nil { + err = errors.New("botInfo is nil") + return + } + if botInfo.botConfig == nil { + cond := builder.NewCond() + cond = cond.And(builder.Eq{"bot_id": botInfo.id}) + err = u.botConfigImpl.GetOneBySearchToStrut(&cond, botInfo.botConfig) + if err != nil { + return + } + + } + var config entitys.DingTalkBot + err = json.Unmarshal([]byte(botInfo.botConfig.BotConfig), &config) + if err != nil { + log.Infof("初始化“%s”失败:%s", botInfo.botConfig.BotName, err.Error()) + return + } + token, err := u.auth.GetAccessToken(ctx, config.ClientId, config.ClientSecret) + if err != nil { + return + } + + return u.GetUserInfoFromDingTalk(ctx, token, staffId) +} + +func (u *User) GetUserInfoFromDingTalk(ctx context.Context, token string, staffId string) (user Result, err error) { + if token == "" && staffId == "" { + err = errors.New("获取钉钉用户信息的必要参数不足") + return + } + + req := l_request.Request{ + Method: http.MethodPost, + Url: constants.GetDingTalkRequestUrl(constants.RequestUrlGetUserGet, map[string]string{ + "access_token": token, + }), + Data: map[string]string{ + "userid": staffId, + }, + } + res, err := req.Send() + if err != nil { + return + } + var userInfoResResult UserInfoResResult + err = json.Unmarshal(res.Content, &userInfoResResult) + if err != nil { + return + } + if userInfoResResult.Errcode != "0" { + fmt.Errorf("钉钉请求报错:%s", userInfoResResult.Errmsg) + } + return userInfoResResult.Result, err +} diff --git a/internal/biz/router.go b/internal/biz/router.go index c164c31..b5add80 100644 --- a/internal/biz/router.go +++ b/internal/biz/router.go @@ -65,6 +65,7 @@ func (r *AiRouterBiz) RouteWithSocket(client *gateway.Client, req *entitys.ChatS return } //意图识别 + requireData.Match, err = r.handle.Recognize(ctx, &rec, &do.WithSys{}) if err != nil { log.Errorf("意图识别失败: %s", err.Error()) diff --git a/internal/data/constants/bot.go b/internal/data/constants/bot.go index 2b24cfe..446519a 100644 --- a/internal/data/constants/bot.go +++ b/internal/data/constants/bot.go @@ -31,3 +31,5 @@ type BotType int const ( BotTypeDingTalk BotType = 1 // 系统的bug/优化建议 ) + +const DingTalkAuthBaseKeyPrefix = "dingTalk_auth" diff --git a/internal/data/constants/const.go b/internal/data/constants/const.go index f06e906..b0731ad 100644 --- a/internal/data/constants/const.go +++ b/internal/data/constants/const.go @@ -30,3 +30,5 @@ var UseFulMap = map[UseFul]string{ UseFulNotUnclear: "回答不明确", UseFulNotError: "理解错误", } + +type BaseBool int32 diff --git a/internal/data/constants/dingtalk.go b/internal/data/constants/dingtalk.go new file mode 100644 index 0000000..dd730cc --- /dev/null +++ b/internal/data/constants/dingtalk.go @@ -0,0 +1,38 @@ +package constants + +import "net/url" + +const DingTalkBseUrl = "https://oapi.dingtalk.com" + +type RequestUrl string + +const ( + RequestUrlGetAccessToken RequestUrl = "/v1.0/oauth2/accessToken" + RequestUrlGetUserGet RequestUrl = "/topapi/v2/user/get" +) + +func GetDingTalkRequestUrl(path RequestUrl, query map[string]string) string { + u, _ := url.Parse(DingTalkBseUrl + string(path)) + q := u.Query() + for key, val := range query { + q.Add(key, val) + } + u.RawQuery = q.Encode() + return u.String() +} + +// IsBoss 是否是老板 +type IsBoss int + +const ( + IsBossTrue IsBoss = 1 + IsBossFalse IsBoss = 0 +) + +// IsSenior 是否是老板 +type IsSenior int + +const ( + IsSeniorTrue IsSenior = 1 + IsSeniorFalse IsSenior = 0 +) diff --git a/internal/data/constants/user_test.go b/internal/data/constants/user_test.go new file mode 100644 index 0000000..eee1b17 --- /dev/null +++ b/internal/data/constants/user_test.go @@ -0,0 +1,91 @@ +package constants + +import ( + "ai_scheduler/internal/biz" + "ai_scheduler/internal/biz/do" + "ai_scheduler/internal/biz/llm_service" + "ai_scheduler/internal/data/impl" + "ai_scheduler/internal/entitys" + "ai_scheduler/internal/gateway" + "ai_scheduler/internal/pkg/dingtalk" + "ai_scheduler/internal/pkg/utils_ollama" + "ai_scheduler/internal/pkg/utils_vllm" + "ai_scheduler/internal/server" + "ai_scheduler/internal/services" + "ai_scheduler/internal/tools" + "ai_scheduler/internal/tools_bot" + "ai_scheduler/utils" + "os" + "testing" +) + +const + +func TestMain(m *testing.M) { + bootstrap := initialize.LoadConfigWithTest() + businessLogger := log2.NewBusinessLogger(bootstrap.Logs, id, Name, Version) + helper := pkg.NewLogHelper(businessLogger, bootstrap) + + db, cleanup := utils.NewGormDb(configConfig) + sysImpl := impl.NewSysImpl(db) + taskImpl := impl.NewTaskImpl(db) + chatHisImpl := impl.NewChatHisImpl(db) + doDo := do.NewDo(sysImpl, taskImpl, chatHisImpl, configConfig) + client, cleanup2, err := utils_ollama.NewClient(configConfig) + if err != nil { + cleanup() + return nil, nil, err + } + utils_vllmClient, cleanup3, err := utils_vllm.NewClient(configConfig) + if err != nil { + cleanup2() + cleanup() + return nil, nil, err + } + ollamaService := llm_service.NewOllamaGenerate(client, utils_vllmClient, configConfig, chatHisImpl) + manager := tools.NewManager(configConfig, client) + sessionImpl := impl.NewSessionImpl(db) + botTool := tools_bot.NewBotTool(configConfig, client, sessionImpl) + handle := do.NewHandle(ollamaService, manager, configConfig, sessionImpl, botTool) + aiRouterBiz := biz.NewAiRouterBiz(doDo, handle) + chatHistoryBiz := biz.NewChatHistoryBiz(chatHisImpl, taskImpl) + gatewayGateway := gateway.NewGateway() + chatService := services.NewChatService(aiRouterBiz, chatHistoryBiz, gatewayGateway, configConfig) + sessionBiz := biz.NewSessionBiz(configConfig, sessionImpl, sysImpl, chatHisImpl) + sessionService := services.NewSessionService(sessionBiz, chatHistoryBiz) + taskBiz := biz.NewTaskBiz(configConfig, taskImpl) + taskService := services.NewTaskService(sessionBiz, taskBiz) + oldClient := dingtalk.NewOldClient(configConfig) + contactClient, err := dingtalk.NewContactClient(configConfig) + if err != nil { + cleanup3() + cleanup2() + cleanup() + return nil, nil, err + } + notableClient, err := dingtalk.NewNotableClient(configConfig) + if err != nil { + cleanup3() + cleanup2() + cleanup() + return nil, nil, err + } + callbackService := services.NewCallbackService(configConfig, gatewayGateway, oldClient, contactClient, notableClient, botTool) + historyService := services.NewHistoryService(chatHistoryBiz) + app := server.NewHTTPServer(chatService, sessionService, taskService, gatewayGateway, callbackService, historyService) + botConfigImpl := impl.NewBotConfigImpl(db) + dingTalkBotBiz := biz.NewDingTalkBotBiz(doDo, handle, botConfigImpl) + dingBotService := services.NewDingBotService(configConfig, dingTalkBotBiz) + v := server.ProvideAllDingBotServices(dingBotService) + dingTalkBotServer := server.NewDingTalkBotServer(v) + servers := server.NewServers(configConfig, app, dingTalkBotServer) + code := m.Run() + os.Exit(code) +} + +func Test_GetUserInfo(t *testing.T) { + var c entitys.TaskConfig + config := `{"param": {"type": "object", "required": ["number"], "properties": {"number": {"type": "string", "description": "订单编号/流水号"}}}, "request": {"url": "http://www.baidu.com/${number}", "headers": {"Authorization": "${authorization}"}, "method": "GET"}}` + err := json.Unmarshal([]byte(config), &c) + t.Log(err) +} diff --git a/internal/data/impl/bot_user.go b/internal/data/impl/bot_user.go new file mode 100644 index 0000000..25d0d16 --- /dev/null +++ b/internal/data/impl/bot_user.go @@ -0,0 +1,27 @@ +package impl + +import ( + "ai_scheduler/internal/data/model" + "ai_scheduler/tmpl/dataTemp" + "ai_scheduler/utils" + "database/sql" +) + +type BotUserImpl struct { + dataTemp.DataTemp +} + +func NewBotUserImpl(db *utils.Db) *BotUserImpl { + return &BotUserImpl{ + DataTemp: *dataTemp.NewDataTemp(db, new(model.AiBotUser)), + } +} + +func (k BotUserImpl) GetByStaffId(staffId string) (data *model.AiBotUser, err error) { + data = &model.AiBotUser{} + err = k.Db.Model(k.Model).Where("staff_id = ?", staffId).Find(data).Error + if data == nil { + err = sql.ErrNoRows + } + return +} diff --git a/internal/data/model/ai_bot_config.gen.go b/internal/data/model/ai_bot_config.gen.go index 5c4f27a..6885e81 100644 --- a/internal/data/model/ai_bot_config.gen.go +++ b/internal/data/model/ai_bot_config.gen.go @@ -14,9 +14,10 @@ const TableNameAiBotConfig = "ai_bot_config" type AiBotConfig struct { BotID int32 `gorm:"column:bot_id;primaryKey;autoIncrement:true" json:"bot_id"` SysID int32 `gorm:"column:sys_id;not null" json:"sys_id"` - BotType int32 `gorm:"column:bot_type;not null;default:1" json:"bot_type"` - BotName string `gorm:"column:bot_name;not null" json:"bot_name"` - BotConfig string `gorm:"column:bot_config;not null" json:"bot_config"` + BotType int32 `gorm:"column:bot_type;not null;default:1;comment:类型,1为钉钉机器人" json:"bot_type"` // 类型,1为钉钉机器人 + BotName string `gorm:"column:bot_name;not null;comment:名字" json:"bot_name"` // 名字 + BotConfig string `gorm:"column:bot_config;not null;comment:配置" json:"bot_config"` // 配置 + BotIndex string `gorm:"column:bot_index;not null;comment:索引" json:"bot_index"` // 索引 CreateAt time.Time `gorm:"column:create_at;default:CURRENT_TIMESTAMP" json:"create_at"` UpdatedAt time.Time `gorm:"column:updated_at;default:CURRENT_TIMESTAMP" json:"updated_at"` Status int32 `gorm:"column:status;not null" json:"status"` diff --git a/internal/data/model/ai_bot_user.gen.go b/internal/data/model/ai_bot_user.gen.go new file mode 100644 index 0000000..bad185a --- /dev/null +++ b/internal/data/model/ai_bot_user.gen.go @@ -0,0 +1,33 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNameAiBotUser = "ai_bot_user" + +// AiBotUser mapped from table +type AiBotUser struct { + UserID int32 `gorm:"column:user_id;primaryKey" json:"user_id"` + StaffID string `gorm:"column:staff_id;not null;comment:标记用户用的唯一id,钉钉:钉钉侧提供的user_id" json:"staff_id"` // 标记用户用的唯一id,钉钉:钉钉侧提供的user_id + Name string `gorm:"column:name;not null;comment:用户名称" json:"name"` // 用户名称 + Title string `gorm:"column:title;not null;comment:职位" json:"title"` // 职位 + Extension string `gorm:"column:extension;not null;default:1;comment:信息面板" json:"extension"` // 信息面板 + RoleList string `gorm:"column:role_list;not null;comment:角色列表。" json:"role_list"` // 角色列表。 + DeptIDList string `gorm:"column:dept_id_list;not null;comment:所在部门id列表" json:"dept_id_list"` // 所在部门id列表 + IsBoss int32 `gorm:"column:is_boss;not null;comment:是否是老板" json:"is_boss"` // 是否是老板 + IsSenior int32 `gorm:"column:is_senior;not null;comment:是否是高管" json:"is_senior"` // 是否是高管 + HiredDate time.Time `gorm:"column:hired_date;not null;default:CURRENT_TIMESTAMP;comment:入职时间" json:"hired_date"` // 入职时间 + Status int32 `gorm:"column:status;not null" json:"status"` + DeleteAt time.Time `gorm:"column:delete_at" json:"delete_at"` + CreateAt time.Time `gorm:"column:create_at;default:CURRENT_TIMESTAMP" json:"create_at"` +} + +// TableName AiBotUser's table name +func (*AiBotUser) TableName() string { + return TableNameAiBotUser +} diff --git a/internal/entitys/bot.go b/internal/entitys/bot.go index 568822c..3e59b0d 100644 --- a/internal/entitys/bot.go +++ b/internal/entitys/bot.go @@ -8,9 +8,6 @@ import ( ) type RequireDataDingTalkBot struct { - Session string - Key string - Sys model.AiSy Histories []model.AiChatHi SessionInfo model.AiSession Tasks []model.AiTask @@ -24,7 +21,7 @@ type RequireDataDingTalkBot struct { } type DingTalkBot struct { - BotIndex string - ClientId string - ClientSecret string + BotIndex string `json:"bot_index"` + ClientId string `json:"client_id"` + ClientSecret string `json:"client_secret"` } diff --git a/internal/entitys/dingtalk.go b/internal/entitys/dingtalk.go new file mode 100644 index 0000000..bddf9b4 --- /dev/null +++ b/internal/entitys/dingtalk.go @@ -0,0 +1,17 @@ +package entitys + +type DingTalkUserInfo struct { + UserId string `json:"user_id"` + StaffId string `json:"staff_id"` + Name string `json:"name"` + Dept []Dept `json:"dept"` + IsBoss int `json:"is_boss"` + IsSenior int `json:"is_senior"` + HiredDate int `json:"hired_date"` + Extension string `json:"extension"` +} + +type Dept struct { + DeptName string `json:"dept_name"` + DeptId int `json:"dept_id"` +} diff --git a/internal/pkg/func.go b/internal/pkg/func.go index f6006ac..2197726 100644 --- a/internal/pkg/func.go +++ b/internal/pkg/func.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "net/url" + "strconv" "strings" ) @@ -65,3 +66,31 @@ func HexEncode(src, dst []byte) int { } return len(src) * 2 } + +// Ter 三目运算 Ter(true, 1, 2) +func Ter[T any](cond bool, a, b T) T { + if cond { + return a + } + return b +} + +// StringToSlice [num,num]转slice +func StringToSlice(s string) ([]int, error) { + // 1. 去掉两端的方括号 + trimmed := strings.Trim(s, "[]") + + // 2. 按逗号分割 + parts := strings.Split(trimmed, ",") + + // 3. 转换为 []int + result := make([]int, 0, len(parts)) + for _, part := range parts { + num, err := strconv.Atoi(strings.TrimSpace(part)) + if err != nil { + return nil, err + } + result = append(result, num) + } + return result, nil +} diff --git a/internal/server/ding_talk_bot.go b/internal/server/ding_talk_bot.go index 9a63812..f68f543 100644 --- a/internal/server/ding_talk_bot.go +++ b/internal/server/ding_talk_bot.go @@ -62,10 +62,10 @@ func (d *DingTalkBotServer) Run(ctx context.Context, botIndex string) { } err := cli.Start(ctx) if err != nil { - log.Info("%s启动失败", name) + log.Infof("%s启动失败", name) continue } - log.Info("%s启动成功", name) + log.Infof("%s启动成功", name) } } func DingBotServerInit(clientId string, clientSecret string, service DingBotServiceInterface) (cli *client.StreamClient) { diff --git a/internal/services/dtalk_bot.go b/internal/services/dtalk_bot.go index 864f5d7..e4e9e8d 100644 --- a/internal/services/dtalk_bot.go +++ b/internal/services/dtalk_bot.go @@ -31,7 +31,7 @@ func (d *DingBotService) OnChatBotMessageReceived(ctx context.Context, data *cha return } go func() { - defer close(requireData.Ch) + //defer close(requireData.Ch) //if match, _err := d.dingTalkBotBiz.Recognize(ctx, data); _err != nil { // requireData.Ch <- entitys.Response{ // Type: entitys.ResponseEnd,