fix: 调整代码层级
This commit is contained in:
parent
36db8e7a86
commit
39d2fc1e62
|
|
@ -0,0 +1,290 @@
|
||||||
|
package biz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ai_scheduler/internal/config"
|
||||||
|
"ai_scheduler/internal/data/constants"
|
||||||
|
"ai_scheduler/internal/data/impl"
|
||||||
|
"ai_scheduler/internal/domain/tools/common/knowledge_base"
|
||||||
|
"ai_scheduler/internal/pkg/dingtalk"
|
||||||
|
"ai_scheduler/internal/pkg/util"
|
||||||
|
"ai_scheduler/internal/pkg/utils_ollama"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/card"
|
||||||
|
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/chatbot"
|
||||||
|
"github.com/alibabacloud-go/dingtalk/card_1_0"
|
||||||
|
"github.com/alibabacloud-go/tea/tea"
|
||||||
|
"github.com/gofiber/fiber/v2/log"
|
||||||
|
"github.com/ollama/ollama/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CallbackBiz struct {
|
||||||
|
cfg *config.Config
|
||||||
|
ollamaClient *utils_ollama.Client
|
||||||
|
dingtalkCardClient *dingtalk.CardClient
|
||||||
|
botConfigImpl *impl.BotConfigImpl
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCallbackBiz(
|
||||||
|
cfg *config.Config,
|
||||||
|
ollamaClient *utils_ollama.Client,
|
||||||
|
dingtalkCardClient *dingtalk.CardClient,
|
||||||
|
botConfigImpl *impl.BotConfigImpl,
|
||||||
|
) *CallbackBiz {
|
||||||
|
return &CallbackBiz{
|
||||||
|
cfg: cfg,
|
||||||
|
ollamaClient: ollamaClient,
|
||||||
|
dingtalkCardClient: dingtalkCardClient,
|
||||||
|
botConfigImpl: botConfigImpl,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IssueHandlingGroup 问题处理群机器人回调
|
||||||
|
// 能力1: 通过[内容提取] 宏,分析用户QA问题,调出QA表单卡片
|
||||||
|
// 能力2: 通过[QA收集] 宏,收集用户反馈,写入知识库
|
||||||
|
// 能力3: 通过[知识库查询] 宏,查询知识库,返回答案
|
||||||
|
func (c *CallbackBiz) IssueHandlingGroup(data chatbot.BotCallbackDataModel) error {
|
||||||
|
// 能力1、2:分析用户QA问题,写入知识库
|
||||||
|
if strings.Contains(data.Text.Content, "[内容提取]") || strings.Contains(data.Text.Content, "[QA收集]") {
|
||||||
|
c.issueHandlingExtractContent(data)
|
||||||
|
}
|
||||||
|
// 能力3:查询知识库,返回答案
|
||||||
|
if strings.Contains(data.Text.Content, "[知识库查询]") {
|
||||||
|
c.issueHandlingQueryKnowledgeBase(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 问题处理群机器人内容提取
|
||||||
|
func (c *CallbackBiz) issueHandlingExtractContent(data chatbot.BotCallbackDataModel) {
|
||||||
|
// 1.提取用户输入
|
||||||
|
prompt := fmt.Sprintf(constants.IssueHandlingExtractContentPrompt, data.Text.Content)
|
||||||
|
log.Infof("问题提取提示词: %s", prompt)
|
||||||
|
// LLM 提取
|
||||||
|
generateResp, err := c.ollamaClient.Generation(context.Background(), &api.GenerateRequest{
|
||||||
|
Model: c.cfg.Ollama.GenerateModel,
|
||||||
|
Prompt: prompt,
|
||||||
|
Stream: util.AnyToPoint(false),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("问题提取失败: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 解析 JSON 响应
|
||||||
|
var resp struct {
|
||||||
|
Items []struct {
|
||||||
|
Question string `json:"question"`
|
||||||
|
Answer string `json:"answer"`
|
||||||
|
Confidence string `json:"confidence"`
|
||||||
|
} `json:"items"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal([]byte(generateResp.Response), &resp); err != nil {
|
||||||
|
log.Errorf("解析 JSON 响应失败: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.构建文本域内容
|
||||||
|
cardContentTpl := "问题:%s \n答案:%s"
|
||||||
|
var cardContentList []string
|
||||||
|
for _, item := range resp.Items {
|
||||||
|
cardContentList = append(cardContentList, fmt.Sprintf(cardContentTpl, item.Question, item.Answer))
|
||||||
|
}
|
||||||
|
cardContent := strings.Join(cardContentList, "\n\n")
|
||||||
|
|
||||||
|
// 3.获取应用AppKey
|
||||||
|
appKey, err := c.botConfigImpl.GetRobotAppKey(data.RobotCode)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("获取应用配置失败: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4.创建并投放卡片
|
||||||
|
outTrackId := constants.BuildCardOutTrackId(data.ConversationId, data.RobotCode) // 构建卡片 OutTrackId
|
||||||
|
_, err = c.dingtalkCardClient.CreateAndDeliver(
|
||||||
|
appKey,
|
||||||
|
&card_1_0.CreateAndDeliverRequest{
|
||||||
|
CardTemplateId: tea.String(c.cfg.Dingtalk.Card.Template.ContentCollect),
|
||||||
|
OutTrackId: tea.String(outTrackId),
|
||||||
|
CallbackType: tea.String("HTTP"),
|
||||||
|
CallbackRouteKey: tea.String(c.cfg.Dingtalk.Card.CallbackRouteKey),
|
||||||
|
CardData: &card_1_0.CreateAndDeliverRequestCardData{
|
||||||
|
CardParamMap: map[string]*string{
|
||||||
|
"title": tea.String("QA知识收集"),
|
||||||
|
"button_display": tea.String("true"),
|
||||||
|
"QA_details_now": tea.String(cardContent),
|
||||||
|
"textarea_display": tea.String("normal"),
|
||||||
|
"action_id": tea.String("collect_qa"),
|
||||||
|
"tenant_id": tea.String(constants.KnowledgeTenantIdDefault),
|
||||||
|
"_CARD_DEBUG_TOOL_ENTRY": tea.String(c.cfg.Dingtalk.Card.DebugToolEntryShow), // 调试字段
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ImGroupOpenSpaceModel: &card_1_0.CreateAndDeliverRequestImGroupOpenSpaceModel{
|
||||||
|
SupportForward: tea.Bool(false),
|
||||||
|
},
|
||||||
|
OpenSpaceId: tea.String("dtv1.card//im_group." + data.ConversationId),
|
||||||
|
ImGroupOpenDeliverModel: &card_1_0.CreateAndDeliverRequestImGroupOpenDeliverModel{
|
||||||
|
RobotCode: tea.String(c.cfg.Dingtalk.SceneGroup.GroupTemplateRobotIDIssueHandling),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 问题处理群机器人查询知识库
|
||||||
|
func (c *CallbackBiz) issueHandlingQueryKnowledgeBase(data chatbot.BotCallbackDataModel) {
|
||||||
|
// 获取应用配置
|
||||||
|
appKey, err := c.botConfigImpl.GetRobotAppKey(data.RobotCode)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("应用机器人配置不存在: %s, err: %v", data.RobotCode, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 创建卡片
|
||||||
|
outTrackId := constants.BuildCardOutTrackId(data.ConversationId, data.RobotCode)
|
||||||
|
_, err = c.dingtalkCardClient.CreateAndDeliver(
|
||||||
|
appKey,
|
||||||
|
&card_1_0.CreateAndDeliverRequest{
|
||||||
|
CardTemplateId: tea.String(c.cfg.Dingtalk.Card.Template.BaseMsg),
|
||||||
|
CardData: &card_1_0.CreateAndDeliverRequestCardData{
|
||||||
|
CardParamMap: map[string]*string{
|
||||||
|
"title": tea.String(data.Text.Content),
|
||||||
|
"markdown": tea.String("知识库检索中..."),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
OutTrackId: tea.String(outTrackId),
|
||||||
|
ImGroupOpenSpaceModel: &card_1_0.CreateAndDeliverRequestImGroupOpenSpaceModel{
|
||||||
|
SupportForward: tea.Bool(false),
|
||||||
|
},
|
||||||
|
OpenSpaceId: tea.String("dtv1.card//im_group." + data.ConversationId),
|
||||||
|
ImGroupOpenDeliverModel: &card_1_0.CreateAndDeliverRequestImGroupOpenDeliverModel{
|
||||||
|
RobotCode: tea.String(data.RobotCode),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// 查询知识库
|
||||||
|
knowledgeBase := knowledge_base.New(c.cfg.KnowledgeConfig)
|
||||||
|
knowledgeResp, err := knowledgeBase.Query(&knowledge_base.QueryRequest{
|
||||||
|
TenantID: constants.KnowledgeTenantIdDefault,
|
||||||
|
Query: data.Text.Content,
|
||||||
|
Mode: constants.KnowledgeModeMix,
|
||||||
|
Stream: false,
|
||||||
|
Think: false,
|
||||||
|
OnlyRAG: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("查询知识库失败: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
knowledgeRespBytes, err := io.ReadAll(knowledgeResp)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("读取知识库响应失败: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 卡片更新
|
||||||
|
message, isRetrieved, err := knowledge_base.ParseOpenAIHTTPData(string(knowledgeRespBytes))
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("读取知识库 SSE 数据失败: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
content := message.Content
|
||||||
|
if !isRetrieved {
|
||||||
|
content = "知识库未检测到匹配信息,请核查知识库数据是否正确。"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 卡片更新
|
||||||
|
_, err = c.dingtalkCardClient.UpdateCard(
|
||||||
|
appKey,
|
||||||
|
&card_1_0.UpdateCardRequest{
|
||||||
|
OutTrackId: tea.String(outTrackId),
|
||||||
|
CardData: &card_1_0.UpdateCardRequestCardData{
|
||||||
|
CardParamMap: map[string]*string{
|
||||||
|
"markdown": tea.String(content),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CardUpdateOptions: &card_1_0.UpdateCardRequestCardUpdateOptions{
|
||||||
|
UpdateCardDataByKey: tea.Bool(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("更新卡片失败: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IssueHandlingCollectQA 问题处理群机器人 QA 收集回调
|
||||||
|
func (c *CallbackBiz) IssueHandlingCollectQA(data card.CardRequest) *card.CardResponse {
|
||||||
|
// 确认提交,文本写入知识库
|
||||||
|
if data.CardActionData.CardPrivateData.Params["submit"] == "submit" {
|
||||||
|
content := data.CardActionData.CardPrivateData.Params["QA_details"].(string)
|
||||||
|
tenantID := data.CardActionData.CardPrivateData.Params["tenant_id"].(string)
|
||||||
|
|
||||||
|
// 协程执行耗时操作,防止阻塞
|
||||||
|
util.SafeGo("inject_knowledge_base", func() {
|
||||||
|
knowledgeBase := knowledge_base.New(c.cfg.KnowledgeConfig)
|
||||||
|
err := knowledgeBase.IngestText(&knowledge_base.IngestTextRequest{
|
||||||
|
TenantID: tenantID,
|
||||||
|
Text: content,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("注入知识库失败: %v", err)
|
||||||
|
} else {
|
||||||
|
log.Infof("注入知识库成功: tenantID=%s", tenantID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析当前卡片的 ConversationId 和 robotCode
|
||||||
|
conversationId, robotCode := constants.ParseCardOutTrackId(data.OutTrackId)
|
||||||
|
|
||||||
|
// 获取应用配置
|
||||||
|
appKey, err := c.botConfigImpl.GetRobotAppKey(robotCode)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("获取应用机器人配置失败: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送卡片通知用户注入成功
|
||||||
|
outTrackId := constants.BuildCardOutTrackId(conversationId, robotCode)
|
||||||
|
c.dingtalkCardClient.CreateAndDeliver(
|
||||||
|
appKey,
|
||||||
|
&card_1_0.CreateAndDeliverRequest{
|
||||||
|
CardTemplateId: tea.String(c.cfg.Dingtalk.Card.Template.BaseMsg),
|
||||||
|
OutTrackId: tea.String(outTrackId),
|
||||||
|
CardData: &card_1_0.CreateAndDeliverRequestCardData{
|
||||||
|
CardParamMap: map[string]*string{
|
||||||
|
"title": tea.String("QA知识收集结果"),
|
||||||
|
"markdown": tea.String("[Get] **成功**"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ImGroupOpenSpaceModel: &card_1_0.CreateAndDeliverRequestImGroupOpenSpaceModel{
|
||||||
|
SupportForward: tea.Bool(false),
|
||||||
|
},
|
||||||
|
OpenSpaceId: tea.String("dtv1.card//im_group." + conversationId),
|
||||||
|
ImGroupOpenDeliverModel: &card_1_0.CreateAndDeliverRequestImGroupOpenDeliverModel{
|
||||||
|
RobotCode: tea.String(robotCode),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消提交,禁用输入框
|
||||||
|
resp := &card.CardResponse{
|
||||||
|
CardUpdateOptions: &card.CardUpdateOptions{
|
||||||
|
UpdateCardDataByKey: true,
|
||||||
|
},
|
||||||
|
CardData: &card.CardDataDto{
|
||||||
|
CardParamMap: map[string]string{
|
||||||
|
"textarea_display": "disabled",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
@ -20,8 +20,13 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/card"
|
||||||
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/chatbot"
|
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/chatbot"
|
||||||
|
|
||||||
|
dingtalkPkg "ai_scheduler/internal/pkg/dingtalk"
|
||||||
|
|
||||||
|
"github.com/alibabacloud-go/dingtalk/card_1_0"
|
||||||
|
"github.com/alibabacloud-go/tea/tea"
|
||||||
"github.com/gofiber/fiber/v2/log"
|
"github.com/gofiber/fiber/v2/log"
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
|
|
@ -45,6 +50,9 @@ type DingTalkBotBiz struct {
|
||||||
groupConfigBiz *GroupConfigBiz
|
groupConfigBiz *GroupConfigBiz
|
||||||
reportDailyCacheImpl *impl.ReportDailyCacheImpl
|
reportDailyCacheImpl *impl.ReportDailyCacheImpl
|
||||||
macro *do.Macro
|
macro *do.Macro
|
||||||
|
dingtalkOauth2Client *dingtalkPkg.Oauth2Client
|
||||||
|
dingTalkOld *dingtalkPkg.OldClient
|
||||||
|
dingtalkCardClient *dingtalkPkg.CardClient
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDingTalkBotBiz
|
// NewDingTalkBotBiz
|
||||||
|
|
@ -61,6 +69,9 @@ func NewDingTalkBotBiz(
|
||||||
cardSend *dingtalk.SendCardClient,
|
cardSend *dingtalk.SendCardClient,
|
||||||
groupConfigBiz *GroupConfigBiz,
|
groupConfigBiz *GroupConfigBiz,
|
||||||
macro *do.Macro,
|
macro *do.Macro,
|
||||||
|
dingtalkOauth2Client *dingtalkPkg.Oauth2Client,
|
||||||
|
dingTalkOld *dingtalkPkg.OldClient,
|
||||||
|
dingtalkCardClient *dingtalkPkg.CardClient,
|
||||||
) *DingTalkBotBiz {
|
) *DingTalkBotBiz {
|
||||||
return &DingTalkBotBiz{
|
return &DingTalkBotBiz{
|
||||||
do: do,
|
do: do,
|
||||||
|
|
@ -76,6 +87,9 @@ func NewDingTalkBotBiz(
|
||||||
cardSend: cardSend,
|
cardSend: cardSend,
|
||||||
reportDailyCacheImpl: reportDailyCacheImpl,
|
reportDailyCacheImpl: reportDailyCacheImpl,
|
||||||
macro: macro,
|
macro: macro,
|
||||||
|
dingtalkOauth2Client: dingtalkOauth2Client,
|
||||||
|
dingTalkOld: dingTalkOld,
|
||||||
|
dingtalkCardClient: dingtalkCardClient,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -408,3 +422,209 @@ func (d *DingTalkBotBiz) defaultPrompt() string {
|
||||||
-parameters 必须是 **转义后的 JSON 字符串**(如 "{\"product_name\": \"京东月卡\"}")。
|
-parameters 必须是 **转义后的 JSON 字符串**(如 "{\"product_name\": \"京东月卡\"}")。
|
||||||
当前时间:` + now + `,所有的时间识别精确到秒`
|
当前时间:` + now + `,所有的时间识别精确到秒`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateIssueHandlingGroupAndInit 创建问题处理群聊并初始化
|
||||||
|
func (d *DingTalkBotBiz) CreateIssueHandlingGroupAndInit(ctx context.Context, data *card.CardRequest) (resp *card.CardResponse, err error) {
|
||||||
|
|
||||||
|
// 解析 OutTrackId 以获取 SpaceId 和 BotId
|
||||||
|
spaceId, botId := constants.ParseCardOutTrackId(data.OutTrackId)
|
||||||
|
|
||||||
|
// 获取新群聊人员
|
||||||
|
var userIds []string
|
||||||
|
userIds, err = d.buildNewGroupUserIds(spaceId, botId, data.UserId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建群聊及群初始化(异步响应)
|
||||||
|
if data.CardActionData.CardPrivateData.Params["status"] == "confirm" {
|
||||||
|
go func() {
|
||||||
|
err := d.createIssueHandlingGroupAndInit(ctx, data.CardActionData.CardPrivateData.Params, spaceId, botId, userIds)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("创建群聊及群初始化失败: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建关闭创建群组卡片按钮的响应
|
||||||
|
return d.buildCreateGroupCardResp(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildNewGroupUserIds 构建新群聊人员列表
|
||||||
|
func (d *DingTalkBotBiz) buildNewGroupUserIds(spaceId, botId, groupOwner string) ([]string, error) {
|
||||||
|
// 群id+机器人id确认一个群配置
|
||||||
|
botGroup, err := d.botGroupImpl.GetByConversationIdAndRobotCode(spaceId, botId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取群配置
|
||||||
|
var groupConfig model.AiBotGroupConfig
|
||||||
|
cond := builder.NewCond().And(builder.Eq{"config_id": botGroup.ConfigID})
|
||||||
|
err = d.botGroupConfigImpl.GetOneBySearchToStrut(&cond, &groupConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取处理人列表
|
||||||
|
issueOwnerJson := groupConfig.IssueOwner
|
||||||
|
type issueOwnerType struct {
|
||||||
|
UserId string `json:"userid"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
var issueOwner []issueOwnerType
|
||||||
|
if err = json.Unmarshal([]byte(issueOwnerJson), &issueOwner); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 合并所有userid
|
||||||
|
userIds := []string{groupOwner} // 当前用户为群主
|
||||||
|
for _, owner := range issueOwner {
|
||||||
|
userIds = append(userIds, owner.UserId)
|
||||||
|
}
|
||||||
|
|
||||||
|
return userIds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// createIssueHandlingGroupAndInit 创建问题处理群聊及群初始化
|
||||||
|
func (d *DingTalkBotBiz) createIssueHandlingGroupAndInit(ctx context.Context, callbackParams map[string]any, spaceId, botId string, userIds []string) error {
|
||||||
|
// 获取应用配置
|
||||||
|
appKey, err := d.botConfigImpl.GetRobotAppKey(botId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取 access_token
|
||||||
|
accessToken, err := d.dingtalkOauth2Client.GetAccessToken(appKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
appKey.AccessToken = accessToken
|
||||||
|
|
||||||
|
// 创建群聊
|
||||||
|
_, openConversationId, err := d.createIssueHandlingGroup(ctx, accessToken, userIds)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加当前机器人到新群 - SDK 有问题,后续再考虑使用
|
||||||
|
// _, err = d.dingtalkImClient.AddRobotToConversation(
|
||||||
|
// appKey,
|
||||||
|
// &im_1_0.AddRobotToConversationRequest{
|
||||||
|
// OpenConversationId: tea.String(openConversationId),
|
||||||
|
// RobotCode: tea.String(botId),
|
||||||
|
// })
|
||||||
|
// if err != nil {
|
||||||
|
// fmt.Printf("添加机器人到会话失败: %v", err)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 返回新群分享链接,直接进群 - SDK 有问题,后续再考虑使用
|
||||||
|
// newGroupShareLink, err = d.dingTalkOld.GetJoinGroupQrcode(ctx, chatId, data.UserId)
|
||||||
|
// if err != nil {
|
||||||
|
// fmt.Printf("获取入群二维码失败: %v", err)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 初始化群聊
|
||||||
|
groupScope := callbackParams["group_scope"].(string) // 群主题
|
||||||
|
d.initIssueHandlingGroup(appKey, openConversationId, groupScope)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// createIssueHandlingGroup 创建问题处理群聊会话
|
||||||
|
func (d *DingTalkBotBiz) createIssueHandlingGroup(ctx context.Context, accessToken string, userIds []string) (chatId, openConversationId string, err error) {
|
||||||
|
// 是否使用模板群开关
|
||||||
|
var useTemplateGroup bool = true
|
||||||
|
|
||||||
|
// 创建内部群会话
|
||||||
|
if !useTemplateGroup {
|
||||||
|
return d.dingTalkOld.CreateInternalGroupConversation(ctx, accessToken, "问题处理群", userIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据群模板ID创建群
|
||||||
|
if useTemplateGroup {
|
||||||
|
return d.dingTalkOld.CreateSceneGroupConversation(ctx, accessToken, "问题处理群", userIds, d.conf.Dingtalk.SceneGroup.GroupTemplateIDIssueHandling)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// initIssueHandlingGroup 初始化问题处理群聊
|
||||||
|
func (d *DingTalkBotBiz) initIssueHandlingGroup(appKey dingtalkPkg.AppKey, openConversationId, groupScope string) error {
|
||||||
|
// 1.开场白
|
||||||
|
outTrackId := constants.BuildCardOutTrackId(openConversationId, d.conf.Dingtalk.SceneGroup.GroupTemplateRobotIDIssueHandling)
|
||||||
|
_, err := d.dingtalkCardClient.CreateAndDeliver(
|
||||||
|
appKey,
|
||||||
|
&card_1_0.CreateAndDeliverRequest{
|
||||||
|
CardTemplateId: tea.String(d.conf.Dingtalk.Card.Template.BaseMsg),
|
||||||
|
OutTrackId: tea.String(outTrackId),
|
||||||
|
CallbackType: tea.String("HTTP"),
|
||||||
|
CardData: &card_1_0.CreateAndDeliverRequestCardData{
|
||||||
|
CardParamMap: map[string]*string{
|
||||||
|
"title": tea.String("当前会话主题"),
|
||||||
|
"markdown": tea.String("问题:" + groupScope),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ImGroupOpenSpaceModel: &card_1_0.CreateAndDeliverRequestImGroupOpenSpaceModel{
|
||||||
|
SupportForward: tea.Bool(false),
|
||||||
|
},
|
||||||
|
OpenSpaceId: tea.String("dtv1.card//im_group." + openConversationId),
|
||||||
|
ImGroupOpenDeliverModel: &card_1_0.CreateAndDeliverRequestImGroupOpenDeliverModel{
|
||||||
|
RobotCode: tea.String(d.conf.Dingtalk.SceneGroup.GroupTemplateRobotIDIssueHandling),
|
||||||
|
AtUserIds: map[string]*string{
|
||||||
|
"@ALL": tea.String("@ALL"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 机器人能力
|
||||||
|
// 构建卡片 OutTrackId
|
||||||
|
outTrackId = constants.BuildCardOutTrackId(openConversationId, d.conf.Dingtalk.SceneGroup.GroupTemplateRobotIDIssueHandling)
|
||||||
|
_, err = d.dingtalkCardClient.CreateAndDeliver(
|
||||||
|
appKey,
|
||||||
|
&card_1_0.CreateAndDeliverRequest{
|
||||||
|
CardTemplateId: tea.String(d.conf.Dingtalk.Card.Template.BaseMsg),
|
||||||
|
OutTrackId: tea.String(outTrackId),
|
||||||
|
CallbackType: tea.String("HTTP"),
|
||||||
|
CardData: &card_1_0.CreateAndDeliverRequestCardData{
|
||||||
|
CardParamMap: map[string]*string{
|
||||||
|
"title": tea.String("当前机器人能力"),
|
||||||
|
"markdown": tea.String("- 聊天内容提取(@机器人 [内容提取]{聊天记录/问答描述}) \n - QA知识收集(卡片信息收集) \n - QA知识问答(@机器人 [知识库查询]{问题描述})"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ImGroupOpenSpaceModel: &card_1_0.CreateAndDeliverRequestImGroupOpenSpaceModel{
|
||||||
|
SupportForward: tea.Bool(false),
|
||||||
|
},
|
||||||
|
OpenSpaceId: tea.String("dtv1.card//im_group." + openConversationId),
|
||||||
|
ImGroupOpenDeliverModel: &card_1_0.CreateAndDeliverRequestImGroupOpenDeliverModel{
|
||||||
|
RobotCode: tea.String(d.conf.Dingtalk.SceneGroup.GroupTemplateRobotIDIssueHandling),
|
||||||
|
AtUserIds: map[string]*string{
|
||||||
|
"@ALL": tea.String("@ALL"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildCreateGroupCardResp 构建关闭创建群组卡片按钮
|
||||||
|
func (d *DingTalkBotBiz) buildCreateGroupCardResp() *card.CardResponse {
|
||||||
|
return &card.CardResponse{
|
||||||
|
CardData: &card.CardDataDto{
|
||||||
|
CardParamMap: map[string]string{
|
||||||
|
"button_display": "false",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CardUpdateOptions: &card.CardUpdateOptions{
|
||||||
|
UpdateCardDataByKey: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -476,7 +476,7 @@ func (g *GroupConfigBiz) GetReportCache(ctx context.Context, day time.Time, tota
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleKnowledgeV2 处理知识库V2版本
|
// handleKnowledge 处理知识库V2版本
|
||||||
func (g *GroupConfigBiz) handleKnowledge(ctx context.Context, rec *entitys.Recognize, groupConfig *model.AiBotGroupConfig, callback *chatbot.BotCallbackDataModel) (err error) {
|
func (g *GroupConfigBiz) handleKnowledge(ctx context.Context, rec *entitys.Recognize, groupConfig *model.AiBotGroupConfig, callback *chatbot.BotCallbackDataModel) (err error) {
|
||||||
// 请求知识库工具
|
// 请求知识库工具
|
||||||
knowledgeBase := knowledge_base.New(g.conf.KnowledgeConfig)
|
knowledgeBase := knowledge_base.New(g.conf.KnowledgeConfig)
|
||||||
|
|
|
||||||
|
|
@ -6,31 +6,24 @@ import (
|
||||||
"ai_scheduler/internal/config"
|
"ai_scheduler/internal/config"
|
||||||
"ai_scheduler/internal/data/constants"
|
"ai_scheduler/internal/data/constants"
|
||||||
errorcode "ai_scheduler/internal/data/error"
|
errorcode "ai_scheduler/internal/data/error"
|
||||||
"ai_scheduler/internal/data/impl"
|
|
||||||
"ai_scheduler/internal/domain/component/callback"
|
"ai_scheduler/internal/domain/component/callback"
|
||||||
"ai_scheduler/internal/domain/tools/common/knowledge_base"
|
|
||||||
"ai_scheduler/internal/entitys"
|
"ai_scheduler/internal/entitys"
|
||||||
"ai_scheduler/internal/gateway"
|
"ai_scheduler/internal/gateway"
|
||||||
"ai_scheduler/internal/pkg"
|
"ai_scheduler/internal/pkg"
|
||||||
"ai_scheduler/internal/pkg/dingtalk"
|
"ai_scheduler/internal/pkg/dingtalk"
|
||||||
"ai_scheduler/internal/pkg/util"
|
"ai_scheduler/internal/pkg/util"
|
||||||
"ai_scheduler/internal/pkg/utils_ollama"
|
|
||||||
"ai_scheduler/internal/tool_callback"
|
"ai_scheduler/internal/tool_callback"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/card"
|
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/card"
|
||||||
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/chatbot"
|
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/chatbot"
|
||||||
"github.com/alibabacloud-go/dingtalk/card_1_0"
|
|
||||||
"github.com/alibabacloud-go/tea/tea"
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/gofiber/fiber/v2/log"
|
"github.com/gofiber/fiber/v2/log"
|
||||||
"github.com/ollama/ollama/api"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CallbackService 统一回调入口
|
// CallbackService 统一回调入口
|
||||||
|
|
@ -43,8 +36,9 @@ type CallbackService struct {
|
||||||
dingtalkCardClient *dingtalk.CardClient
|
dingtalkCardClient *dingtalk.CardClient
|
||||||
callbackManager callback.Manager
|
callbackManager callback.Manager
|
||||||
dingTalkBotBiz *biz.DingTalkBotBiz
|
dingTalkBotBiz *biz.DingTalkBotBiz
|
||||||
ollamaClient *utils_ollama.Client
|
callbackBiz *biz.CallbackBiz
|
||||||
botConfigImpl *impl.BotConfigImpl
|
// ollamaClient *utils_ollama.Client
|
||||||
|
// botConfigImpl *impl.BotConfigImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCallbackService(
|
func NewCallbackService(
|
||||||
|
|
@ -56,8 +50,9 @@ func NewCallbackService(
|
||||||
dingtalkCardClient *dingtalk.CardClient,
|
dingtalkCardClient *dingtalk.CardClient,
|
||||||
callbackManager callback.Manager,
|
callbackManager callback.Manager,
|
||||||
dingTalkBotBiz *biz.DingTalkBotBiz,
|
dingTalkBotBiz *biz.DingTalkBotBiz,
|
||||||
ollamaClient *utils_ollama.Client,
|
callbackBiz *biz.CallbackBiz,
|
||||||
botConfigImpl *impl.BotConfigImpl,
|
// ollamaClient *utils_ollama.Client,
|
||||||
|
// botConfigImpl *impl.BotConfigImpl,
|
||||||
) *CallbackService {
|
) *CallbackService {
|
||||||
return &CallbackService{
|
return &CallbackService{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
|
|
@ -68,8 +63,9 @@ func NewCallbackService(
|
||||||
dingtalkCardClient: dingtalkCardClient,
|
dingtalkCardClient: dingtalkCardClient,
|
||||||
callbackManager: callbackManager,
|
callbackManager: callbackManager,
|
||||||
dingTalkBotBiz: dingTalkBotBiz,
|
dingTalkBotBiz: dingTalkBotBiz,
|
||||||
ollamaClient: ollamaClient,
|
callbackBiz: callbackBiz,
|
||||||
botConfigImpl: botConfigImpl,
|
// ollamaClient: ollamaClient,
|
||||||
|
// botConfigImpl: botConfigImpl,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -411,9 +407,10 @@ func (s *CallbackService) CallbackDingtalkRobot(c *fiber.Ctx) (err error) {
|
||||||
switch data.RobotCode {
|
switch data.RobotCode {
|
||||||
case s.cfg.Dingtalk.SceneGroup.GroupTemplateRobotIDIssueHandling:
|
case s.cfg.Dingtalk.SceneGroup.GroupTemplateRobotIDIssueHandling:
|
||||||
// 问题处理群机器人
|
// 问题处理群机器人
|
||||||
err := s.issueHandling(c, data)
|
// err := s.issueHandling(data)
|
||||||
|
err := s.callbackBiz.IssueHandlingGroup(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("issueHandling failed: %v", err)
|
return fmt.Errorf("IssueHandlingGroup failed: %v", err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// 其他机器人
|
// 其他机器人
|
||||||
|
|
@ -423,190 +420,6 @@ func (s *CallbackService) CallbackDingtalkRobot(c *fiber.Ctx) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// issueHandling 问题处理群机器人回调
|
|
||||||
// 能力1: 通过[内容提取] 宏,分析用户QA问题,调出QA表单卡片
|
|
||||||
// 能力2: 通过[QA收集] 宏,收集用户反馈,写入知识库
|
|
||||||
// 能力3: 通过[知识库查询] 宏,查询知识库,返回答案
|
|
||||||
func (s *CallbackService) issueHandling(c *fiber.Ctx, data chatbot.BotCallbackDataModel) error {
|
|
||||||
// 能力1、2:分析用户QA问题,写入知识库
|
|
||||||
if strings.Contains(data.Text.Content, "[内容提取]") || strings.Contains(data.Text.Content, "[QA收集]") {
|
|
||||||
s.issueHandlingExtractContent(data)
|
|
||||||
}
|
|
||||||
// 能力3:查询知识库,返回答案
|
|
||||||
if strings.Contains(data.Text.Content, "[知识库查询]") {
|
|
||||||
s.issueHandlingQueryKnowledgeBase(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 问题处理群机器人内容提取
|
|
||||||
func (s *CallbackService) issueHandlingExtractContent(data chatbot.BotCallbackDataModel) {
|
|
||||||
// 1.提取用户输入
|
|
||||||
prompt := fmt.Sprintf(constants.IssueHandlingExtractContentPrompt, data.Text.Content)
|
|
||||||
log.Infof("问题提取提示词: %s", prompt)
|
|
||||||
// LLM 提取
|
|
||||||
generateResp, err := s.ollamaClient.Generation(context.Background(), &api.GenerateRequest{
|
|
||||||
Model: s.cfg.Ollama.GenerateModel,
|
|
||||||
Prompt: prompt,
|
|
||||||
Stream: util.AnyToPoint(false),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("问题提取失败: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 解析 JSON 响应
|
|
||||||
var resp struct {
|
|
||||||
Items []struct {
|
|
||||||
Question string `json:"question"`
|
|
||||||
Answer string `json:"answer"`
|
|
||||||
Confidence string `json:"confidence"`
|
|
||||||
} `json:"items"`
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal([]byte(generateResp.Response), &resp); err != nil {
|
|
||||||
log.Errorf("解析 JSON 响应失败: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2.构建文本域内容
|
|
||||||
cardContentTpl := "问题:%s \n答案:%s"
|
|
||||||
var cardContentList []string
|
|
||||||
for _, item := range resp.Items {
|
|
||||||
cardContentList = append(cardContentList, fmt.Sprintf(cardContentTpl, item.Question, item.Answer))
|
|
||||||
}
|
|
||||||
cardContent := strings.Join(cardContentList, "\n\n")
|
|
||||||
|
|
||||||
// 3.获取应用AppKey
|
|
||||||
appKey, err := s.botConfigImpl.GetRobotAppKey(data.RobotCode)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("获取应用配置失败: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4.创建并投放卡片
|
|
||||||
outTrackId := constants.BuildCardOutTrackId(data.ConversationId, data.RobotCode) // 构建卡片 OutTrackId
|
|
||||||
_, err = s.dingtalkCardClient.CreateAndDeliver(
|
|
||||||
appKey,
|
|
||||||
&card_1_0.CreateAndDeliverRequest{
|
|
||||||
CardTemplateId: tea.String(s.cfg.Dingtalk.Card.Template.ContentCollect),
|
|
||||||
OutTrackId: tea.String(outTrackId),
|
|
||||||
CallbackType: tea.String("HTTP"),
|
|
||||||
CallbackRouteKey: tea.String(s.cfg.Dingtalk.Card.CallbackRouteKey),
|
|
||||||
CardData: &card_1_0.CreateAndDeliverRequestCardData{
|
|
||||||
CardParamMap: map[string]*string{
|
|
||||||
"title": tea.String("QA知识收集"),
|
|
||||||
"button_display": tea.String("true"),
|
|
||||||
"QA_details_now": tea.String(cardContent),
|
|
||||||
"textarea_display": tea.String("normal"),
|
|
||||||
"action_id": tea.String("collect_qa"),
|
|
||||||
"tenant_id": tea.String(constants.KnowledgeTenantIdDefault),
|
|
||||||
"_CARD_DEBUG_TOOL_ENTRY": tea.String(s.cfg.Dingtalk.Card.DebugToolEntryShow), // 调试字段
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ImGroupOpenSpaceModel: &card_1_0.CreateAndDeliverRequestImGroupOpenSpaceModel{
|
|
||||||
SupportForward: tea.Bool(false),
|
|
||||||
},
|
|
||||||
OpenSpaceId: tea.String("dtv1.card//im_group." + data.ConversationId),
|
|
||||||
ImGroupOpenDeliverModel: &card_1_0.CreateAndDeliverRequestImGroupOpenDeliverModel{
|
|
||||||
RobotCode: tea.String(s.cfg.Dingtalk.SceneGroup.GroupTemplateRobotIDIssueHandling),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// 问题处理群机器人查询知识库
|
|
||||||
func (s *CallbackService) issueHandlingQueryKnowledgeBase(data chatbot.BotCallbackDataModel) {
|
|
||||||
// // 获取应用主机器人
|
|
||||||
// mainRobotCode := data.RobotCode
|
|
||||||
// if robotCode, ok := constants.GroupTemplateRobotIdMap[data.RobotCode]; ok {
|
|
||||||
// mainRobotCode = robotCode
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 获取应用配置
|
|
||||||
appKey, err := s.botConfigImpl.GetRobotAppKey(data.RobotCode)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("应用机器人配置不存在: %s, err: %v", data.RobotCode, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 创建卡片
|
|
||||||
outTrackId := constants.BuildCardOutTrackId(data.ConversationId, data.RobotCode)
|
|
||||||
_, err = s.dingtalkCardClient.CreateAndDeliver(
|
|
||||||
appKey,
|
|
||||||
&card_1_0.CreateAndDeliverRequest{
|
|
||||||
CardTemplateId: tea.String(s.cfg.Dingtalk.Card.Template.BaseMsg),
|
|
||||||
CardData: &card_1_0.CreateAndDeliverRequestCardData{
|
|
||||||
CardParamMap: map[string]*string{
|
|
||||||
"title": tea.String(data.Text.Content),
|
|
||||||
"markdown": tea.String("知识库检索中..."),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
OutTrackId: tea.String(outTrackId),
|
|
||||||
ImGroupOpenSpaceModel: &card_1_0.CreateAndDeliverRequestImGroupOpenSpaceModel{
|
|
||||||
SupportForward: tea.Bool(false),
|
|
||||||
},
|
|
||||||
OpenSpaceId: tea.String("dtv1.card//im_group." + data.ConversationId),
|
|
||||||
ImGroupOpenDeliverModel: &card_1_0.CreateAndDeliverRequestImGroupOpenDeliverModel{
|
|
||||||
RobotCode: tea.String(data.RobotCode),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
// 查询知识库
|
|
||||||
knowledgeBase := knowledge_base.New(s.cfg.KnowledgeConfig)
|
|
||||||
knowledgeResp, err := knowledgeBase.Query(&knowledge_base.QueryRequest{
|
|
||||||
TenantID: constants.KnowledgeTenantIdDefault,
|
|
||||||
Query: data.Text.Content,
|
|
||||||
Mode: constants.KnowledgeModeMix,
|
|
||||||
Stream: false,
|
|
||||||
Think: false,
|
|
||||||
OnlyRAG: true,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("查询知识库失败: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
knowledgeRespBytes, err := io.ReadAll(knowledgeResp)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("读取知识库响应失败: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 卡片更新
|
|
||||||
message, isRetrieved, err := knowledge_base.ParseOpenAIHTTPData(string(knowledgeRespBytes))
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("读取知识库 SSE 数据失败: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
content := message.Content
|
|
||||||
if !isRetrieved {
|
|
||||||
content = "知识库未检测到匹配信息,请核查知识库数据是否正确。"
|
|
||||||
}
|
|
||||||
|
|
||||||
// 卡片更新
|
|
||||||
_, err = s.dingtalkCardClient.UpdateCard(
|
|
||||||
appKey,
|
|
||||||
&card_1_0.UpdateCardRequest{
|
|
||||||
OutTrackId: tea.String(outTrackId),
|
|
||||||
CardData: &card_1_0.UpdateCardRequestCardData{
|
|
||||||
CardParamMap: map[string]*string{
|
|
||||||
"markdown": tea.String(content),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
CardUpdateOptions: &card_1_0.UpdateCardRequestCardUpdateOptions{
|
|
||||||
UpdateCardDataByKey: tea.Bool(true),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("更新卡片失败: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// CallbackDingtalkCard 处理钉钉卡片回调
|
// CallbackDingtalkCard 处理钉钉卡片回调
|
||||||
// 钉钉 callbackRouteKey: gateway.dev.cdlsxd.cn-dingtalk-card
|
// 钉钉 callbackRouteKey: gateway.dev.cdlsxd.cn-dingtalk-card
|
||||||
// 钉钉 apiSecret: aB3dE7fG9hI2jK4L5M6N7O8P9Q0R1S2T
|
// 钉钉 apiSecret: aB3dE7fG9hI2jK4L5M6N7O8P9Q0R1S2T
|
||||||
|
|
@ -640,7 +453,7 @@ func (s *CallbackService) CallbackDingtalkCard(c *fiber.Ctx) error {
|
||||||
switch actionId {
|
switch actionId {
|
||||||
case "collect_qa":
|
case "collect_qa":
|
||||||
// 问题处理群机器人 QA 收集
|
// 问题处理群机器人 QA 收集
|
||||||
resp = s.issueHandlingCollectQA(data)
|
resp = s.callbackBiz.IssueHandlingCollectQA(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -648,79 +461,3 @@ func (s *CallbackService) CallbackDingtalkCard(c *fiber.Ctx) error {
|
||||||
c.Locals("skip_response_wrap", true)
|
c.Locals("skip_response_wrap", true)
|
||||||
return c.JSON(resp)
|
return c.JSON(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 问题处理群机器人 QA 收集
|
|
||||||
func (s *CallbackService) issueHandlingCollectQA(data card.CardRequest) *card.CardResponse {
|
|
||||||
// 确认提交,文本写入知识库
|
|
||||||
if data.CardActionData.CardPrivateData.Params["submit"] == "submit" {
|
|
||||||
content := data.CardActionData.CardPrivateData.Params["QA_details"].(string)
|
|
||||||
tenantID := data.CardActionData.CardPrivateData.Params["tenant_id"].(string)
|
|
||||||
|
|
||||||
// 协程执行耗时操作,防止阻塞
|
|
||||||
util.SafeGo("inject_knowledge_base", func() {
|
|
||||||
knowledgeBase := knowledge_base.New(s.cfg.KnowledgeConfig)
|
|
||||||
err := knowledgeBase.IngestText(&knowledge_base.IngestTextRequest{
|
|
||||||
TenantID: tenantID,
|
|
||||||
Text: content,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("注入知识库失败: %v", err)
|
|
||||||
} else {
|
|
||||||
log.Infof("注入知识库成功: tenantID=%s", tenantID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析当前卡片的 ConversationId 和 robotCode
|
|
||||||
conversationId, robotCode := constants.ParseCardOutTrackId(data.OutTrackId)
|
|
||||||
|
|
||||||
// 获取主应用机器人(这里可能是群模板机器人)
|
|
||||||
// mainRobotId := robotCode
|
|
||||||
// if robotCode, ok := constants.GroupTemplateRobotIdMap[robotCode]; ok {
|
|
||||||
// mainRobotId = robotCode
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 获取应用配置
|
|
||||||
appKey, err := s.botConfigImpl.GetRobotAppKey(robotCode)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("获取应用机器人配置失败: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 发送卡片通知用户注入成功
|
|
||||||
outTrackId := constants.BuildCardOutTrackId(conversationId, robotCode)
|
|
||||||
s.dingtalkCardClient.CreateAndDeliver(
|
|
||||||
appKey,
|
|
||||||
&card_1_0.CreateAndDeliverRequest{
|
|
||||||
CardTemplateId: tea.String(s.cfg.Dingtalk.Card.Template.BaseMsg),
|
|
||||||
OutTrackId: tea.String(outTrackId),
|
|
||||||
CardData: &card_1_0.CreateAndDeliverRequestCardData{
|
|
||||||
CardParamMap: map[string]*string{
|
|
||||||
"title": tea.String("QA知识收集结果"),
|
|
||||||
"markdown": tea.String("[Get] **成功**"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ImGroupOpenSpaceModel: &card_1_0.CreateAndDeliverRequestImGroupOpenSpaceModel{
|
|
||||||
SupportForward: tea.Bool(false),
|
|
||||||
},
|
|
||||||
OpenSpaceId: tea.String("dtv1.card//im_group." + conversationId),
|
|
||||||
ImGroupOpenDeliverModel: &card_1_0.CreateAndDeliverRequestImGroupOpenDeliverModel{
|
|
||||||
RobotCode: tea.String(robotCode),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 取消提交,禁用输入框
|
|
||||||
resp := &card.CardResponse{
|
|
||||||
CardUpdateOptions: &card.CardUpdateOptions{
|
|
||||||
UpdateCardDataByKey: true,
|
|
||||||
},
|
|
||||||
CardData: &card.CardDataDto{
|
|
||||||
CardParamMap: map[string]string{
|
|
||||||
"textarea_display": "disabled",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -4,57 +4,29 @@ import (
|
||||||
"ai_scheduler/internal/biz"
|
"ai_scheduler/internal/biz"
|
||||||
"ai_scheduler/internal/config"
|
"ai_scheduler/internal/config"
|
||||||
"ai_scheduler/internal/data/constants"
|
"ai_scheduler/internal/data/constants"
|
||||||
"ai_scheduler/internal/data/impl"
|
|
||||||
"ai_scheduler/internal/data/model"
|
|
||||||
"ai_scheduler/internal/entitys"
|
"ai_scheduler/internal/entitys"
|
||||||
"ai_scheduler/internal/pkg/dingtalk"
|
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"log"
|
"log"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/card"
|
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/card"
|
||||||
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/chatbot"
|
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/chatbot"
|
||||||
"github.com/alibabacloud-go/dingtalk/card_1_0"
|
|
||||||
"github.com/alibabacloud-go/tea/tea"
|
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
"xorm.io/builder"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type DingBotService struct {
|
type DingBotService struct {
|
||||||
config *config.Config
|
config *config.Config
|
||||||
dingTalkBotBiz *biz.DingTalkBotBiz
|
dingTalkBotBiz *biz.DingTalkBotBiz
|
||||||
dingTalkOld *dingtalk.OldClient
|
|
||||||
dingtalkCardClient *dingtalk.CardClient
|
|
||||||
dingtalkImClient *dingtalk.ImClient
|
|
||||||
dingtalkOauth2Client *dingtalk.Oauth2Client
|
|
||||||
botGroupConfigImpl *impl.BotGroupConfigImpl
|
|
||||||
botGroupImpl *impl.BotGroupImpl
|
|
||||||
botConfigImpl *impl.BotConfigImpl
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDingBotService(
|
func NewDingBotService(
|
||||||
config *config.Config,
|
config *config.Config,
|
||||||
dingTalkBotBiz *biz.DingTalkBotBiz,
|
dingTalkBotBiz *biz.DingTalkBotBiz,
|
||||||
dingTalkOld *dingtalk.OldClient,
|
|
||||||
dingtalkCardClient *dingtalk.CardClient,
|
|
||||||
dingtalkImClient *dingtalk.ImClient,
|
|
||||||
dingtalkOauth2Client *dingtalk.Oauth2Client,
|
|
||||||
botGroupConfigImpl *impl.BotGroupConfigImpl,
|
|
||||||
botGroupImpl *impl.BotGroupImpl,
|
|
||||||
botConfigImpl *impl.BotConfigImpl,
|
|
||||||
) *DingBotService {
|
) *DingBotService {
|
||||||
return &DingBotService{
|
return &DingBotService{
|
||||||
config: config,
|
config: config,
|
||||||
dingTalkBotBiz: dingTalkBotBiz,
|
dingTalkBotBiz: dingTalkBotBiz,
|
||||||
dingTalkOld: dingTalkOld,
|
|
||||||
dingtalkCardClient: dingtalkCardClient,
|
|
||||||
dingtalkImClient: dingtalkImClient,
|
|
||||||
dingtalkOauth2Client: dingtalkOauth2Client,
|
|
||||||
botGroupConfigImpl: botGroupConfigImpl,
|
|
||||||
botGroupImpl: botGroupImpl,
|
|
||||||
botConfigImpl: botConfigImpl,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -174,7 +146,7 @@ func (d *DingBotService) runBackgroundTasks(ctx context.Context, data *chatbot.B
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// **一把梭先搞,后续规范化**
|
// OnCardMessageReceived 处理卡片回调
|
||||||
func (d *DingBotService) OnCardMessageReceived(ctx context.Context, data *card.CardRequest) (resp *card.CardResponse, err error) {
|
func (d *DingBotService) OnCardMessageReceived(ctx context.Context, data *card.CardRequest) (resp *card.CardResponse, err error) {
|
||||||
// 非回调类型暂不接受
|
// 非回调类型暂不接受
|
||||||
if data.Type != constants.CardActionCallbackTypeAction {
|
if data.Type != constants.CardActionCallbackTypeAction {
|
||||||
|
|
@ -185,206 +157,14 @@ func (d *DingBotService) OnCardMessageReceived(ctx context.Context, data *card.C
|
||||||
for _, actionId := range data.CardActionData.CardPrivateData.ActionIdList {
|
for _, actionId := range data.CardActionData.CardPrivateData.ActionIdList {
|
||||||
switch actionId {
|
switch actionId {
|
||||||
case constants.CardActionTypeCreateGroup:
|
case constants.CardActionTypeCreateGroup:
|
||||||
// 解析 OutTrackId 以获取 SpaceId 和 BotId
|
resp, err = d.dingTalkBotBiz.CreateIssueHandlingGroupAndInit(ctx, data)
|
||||||
spaceId, botId := constants.ParseCardOutTrackId(data.OutTrackId)
|
|
||||||
|
|
||||||
// 获取新群聊人员
|
|
||||||
var userIds []string
|
|
||||||
userIds, err = d.buildNewGroupUserIds(ctx, spaceId, botId, data.UserId)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建群聊及群初始化(ws中,直接协程)
|
|
||||||
if data.CardActionData.CardPrivateData.Params["status"] == "confirm" {
|
|
||||||
go func() {
|
|
||||||
err := d.createIssueHandlingGroupAndInit(ctx, data.CardActionData.CardPrivateData.Params, spaceId, botId, userIds)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("创建群聊及群初始化失败: %v", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构建关闭创建群组卡片按钮的响应
|
|
||||||
resp = d.buildCreateGroupCardResp()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &card.CardResponse{}, nil
|
return &card.CardResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildNewGroupUserIds 构建新群聊人员列表
|
|
||||||
func (d *DingBotService) buildNewGroupUserIds(ctx context.Context, spaceId, botId, groupOwner string) ([]string, error) {
|
|
||||||
// 群id+机器人id确认一个群配置
|
|
||||||
botGroup, err := d.botGroupImpl.GetByConversationIdAndRobotCode(spaceId, botId)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取群配置
|
|
||||||
var groupConfig model.AiBotGroupConfig
|
|
||||||
cond := builder.NewCond().And(builder.Eq{"config_id": botGroup.ConfigID})
|
|
||||||
err = d.botGroupConfigImpl.GetOneBySearchToStrut(&cond, &groupConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取处理人列表
|
|
||||||
issueOwnerJson := groupConfig.IssueOwner
|
|
||||||
type issueOwnerType struct {
|
|
||||||
UserId string `json:"userid"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
}
|
|
||||||
var issueOwner []issueOwnerType
|
|
||||||
if err = json.Unmarshal([]byte(issueOwnerJson), &issueOwner); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 合并所有userid
|
|
||||||
userIds := []string{groupOwner} // 当前用户为群主
|
|
||||||
for _, owner := range issueOwner {
|
|
||||||
userIds = append(userIds, owner.UserId)
|
|
||||||
}
|
|
||||||
|
|
||||||
return userIds, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// createIssueHandlingGroupAndInit 创建问题处理群聊及群初始化
|
|
||||||
func (d *DingBotService) createIssueHandlingGroupAndInit(ctx context.Context, callbackParams map[string]any, spaceId, botId string, userIds []string) error {
|
|
||||||
// 获取机器人配置
|
|
||||||
botConfig, err := d.botConfigImpl.GetRobotConfig(botId)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
appKey := dingtalk.AppKey{
|
|
||||||
AppKey: botConfig.ClientId,
|
|
||||||
AppSecret: botConfig.ClientSecret,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取 access_token
|
|
||||||
accessToken, err := d.dingtalkOauth2Client.GetAccessToken(appKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
appKey.AccessToken = accessToken
|
|
||||||
|
|
||||||
// 创建群聊
|
|
||||||
_, openConversationId, err := d.createIssueHandlingGroup(ctx, accessToken, spaceId, botId, userIds)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加当前机器人到新群 - SDK 有问题,后续再考虑使用
|
|
||||||
// _, err = d.dingtalkImClient.AddRobotToConversation(
|
|
||||||
// appKey,
|
|
||||||
// &im_1_0.AddRobotToConversationRequest{
|
|
||||||
// OpenConversationId: tea.String(openConversationId),
|
|
||||||
// RobotCode: tea.String(botId),
|
|
||||||
// })
|
|
||||||
// if err != nil {
|
|
||||||
// fmt.Printf("添加机器人到会话失败: %v", err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 返回新群分享链接,直接进群 - SDK 有问题,后续再考虑使用
|
|
||||||
// newGroupShareLink, err = d.dingTalkOld.GetJoinGroupQrcode(ctx, chatId, data.UserId)
|
|
||||||
// if err != nil {
|
|
||||||
// fmt.Printf("获取入群二维码失败: %v", err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 初始化群聊
|
|
||||||
// 1.开场白
|
|
||||||
|
|
||||||
// 群主题
|
|
||||||
groupScope := callbackParams["group_scope"].(string)
|
|
||||||
// 构建卡片 OutTrackId
|
|
||||||
outTrackId := constants.BuildCardOutTrackId(openConversationId, d.config.Dingtalk.SceneGroup.GroupTemplateRobotIDIssueHandling)
|
|
||||||
_, err = d.dingtalkCardClient.CreateAndDeliver(
|
|
||||||
appKey,
|
|
||||||
&card_1_0.CreateAndDeliverRequest{
|
|
||||||
CardTemplateId: tea.String(d.config.Dingtalk.Card.Template.BaseMsg),
|
|
||||||
OutTrackId: tea.String(outTrackId),
|
|
||||||
CallbackType: tea.String("HTTP"),
|
|
||||||
CardData: &card_1_0.CreateAndDeliverRequestCardData{
|
|
||||||
CardParamMap: map[string]*string{
|
|
||||||
"title": tea.String("当前会话主题"),
|
|
||||||
"markdown": tea.String("问题:" + groupScope),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ImGroupOpenSpaceModel: &card_1_0.CreateAndDeliverRequestImGroupOpenSpaceModel{
|
|
||||||
SupportForward: tea.Bool(false),
|
|
||||||
},
|
|
||||||
OpenSpaceId: tea.String("dtv1.card//im_group." + openConversationId),
|
|
||||||
ImGroupOpenDeliverModel: &card_1_0.CreateAndDeliverRequestImGroupOpenDeliverModel{
|
|
||||||
RobotCode: tea.String(d.config.Dingtalk.SceneGroup.GroupTemplateRobotIDIssueHandling),
|
|
||||||
AtUserIds: map[string]*string{
|
|
||||||
"@ALL": tea.String("@ALL"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
// 2. 机器人能力
|
|
||||||
// 构建卡片 OutTrackId
|
|
||||||
outTrackId = constants.BuildCardOutTrackId(openConversationId, d.config.Dingtalk.SceneGroup.GroupTemplateRobotIDIssueHandling)
|
|
||||||
_, err = d.dingtalkCardClient.CreateAndDeliver(
|
|
||||||
appKey,
|
|
||||||
&card_1_0.CreateAndDeliverRequest{
|
|
||||||
CardTemplateId: tea.String(d.config.Dingtalk.Card.Template.BaseMsg),
|
|
||||||
OutTrackId: tea.String(outTrackId),
|
|
||||||
CallbackType: tea.String("HTTP"),
|
|
||||||
CardData: &card_1_0.CreateAndDeliverRequestCardData{
|
|
||||||
CardParamMap: map[string]*string{
|
|
||||||
"title": tea.String("当前机器人能力"),
|
|
||||||
"markdown": tea.String("- 聊天内容提取(@机器人 [内容提取]{聊天记录/问答描述}) \n - QA知识收集(卡片信息收集) \n - QA知识问答(@机器人 [知识库查询]{问题描述})"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ImGroupOpenSpaceModel: &card_1_0.CreateAndDeliverRequestImGroupOpenSpaceModel{
|
|
||||||
SupportForward: tea.Bool(false),
|
|
||||||
},
|
|
||||||
OpenSpaceId: tea.String("dtv1.card//im_group." + openConversationId),
|
|
||||||
ImGroupOpenDeliverModel: &card_1_0.CreateAndDeliverRequestImGroupOpenDeliverModel{
|
|
||||||
RobotCode: tea.String(d.config.Dingtalk.SceneGroup.GroupTemplateRobotIDIssueHandling),
|
|
||||||
AtUserIds: map[string]*string{
|
|
||||||
"@ALL": tea.String("@ALL"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// createGroupV1 创建普通内部群会话
|
|
||||||
// 这里用的是“统一登录平台”这个应用的接口加入群聊 - 这里用的是“统一登录平台”这个应用的接口
|
|
||||||
func (d *DingBotService) createIssueHandlingGroup(ctx context.Context, accessToken, spaceId, botId string, userIds []string) (chatId, openConversationId string, err error) {
|
|
||||||
// 是否使用模板群开关
|
|
||||||
var useTemplateGroup bool = true
|
|
||||||
|
|
||||||
// 创建内部群会话
|
|
||||||
if !useTemplateGroup {
|
|
||||||
return d.dingTalkOld.CreateInternalGroupConversation(ctx, accessToken, "问题处理群", userIds)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据群模板ID创建群
|
|
||||||
if useTemplateGroup {
|
|
||||||
return d.dingTalkOld.CreateSceneGroupConversation(ctx, accessToken, "问题处理群", userIds, d.config.Dingtalk.SceneGroup.GroupTemplateIDIssueHandling)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// buildCreateGroupCardResp 构建关闭创建群组卡片按钮
|
|
||||||
func (d *DingBotService) buildCreateGroupCardResp() *card.CardResponse {
|
|
||||||
return &card.CardResponse{
|
|
||||||
CardData: &card.CardDataDto{
|
|
||||||
CardParamMap: map[string]string{
|
|
||||||
"button_display": "false",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
CardUpdateOptions: &card.CardUpdateOptions{
|
|
||||||
UpdateCardDataByKey: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ func run() {
|
||||||
qywxAppBiz := biz.NewQywxAppBiz(configConfig, botGroupQywxImpl, group, other)
|
qywxAppBiz := biz.NewQywxAppBiz(configConfig, botGroupQywxImpl, group, other)
|
||||||
groupConfigBiz := biz.NewGroupConfigBiz(toolRegis, utils_ossClient, botGroupConfigImpl, botConfigImpl, registry, configConfig, impl.NewReportDailyCacheImpl(db), rdb, manager, cardClient)
|
groupConfigBiz := biz.NewGroupConfigBiz(toolRegis, utils_ossClient, botGroupConfigImpl, botConfigImpl, registry, configConfig, impl.NewReportDailyCacheImpl(db), rdb, manager, cardClient)
|
||||||
macro := do.NewMacro(botGroupImpl, impl.NewReportDailyCacheImpl(db))
|
macro := do.NewMacro(botGroupImpl, impl.NewReportDailyCacheImpl(db))
|
||||||
dingTalkBotBiz := biz.NewDingTalkBotBiz(doDo, handle, botConfigImpl, botGroupImpl, user, botChatHisImpl, impl.NewReportDailyCacheImpl(db), manager, configConfig, sendCardClient, groupConfigBiz, macro)
|
dingTalkBotBiz := biz.NewDingTalkBotBiz(doDo, handle, botConfigImpl, botGroupImpl, user, botChatHisImpl, impl.NewReportDailyCacheImpl(db), manager, configConfig, sendCardClient, groupConfigBiz, macro, oauth2Client, oldClient, cardClient)
|
||||||
// 初始化钉钉机器人服务
|
// 初始化钉钉机器人服务
|
||||||
cronService = NewCronService(configConfig, dingTalkBotBiz, qywxAppBiz, groupConfigBiz)
|
cronService = NewCronService(configConfig, dingTalkBotBiz, qywxAppBiz, groupConfigBiz)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue