Merge remote-tracking branch 'origin/master' into v4-fzy
This commit is contained in:
commit
ece04df2cb
|
|
@ -5,6 +5,9 @@ server:
|
|||
|
||||
ollama:
|
||||
base_url: "http://172.17.0.1:11434"
|
||||
# model: "qwen3:8b"
|
||||
# generate_model: "qwen3:8b"
|
||||
# mapping_model: "qwen3:8b"
|
||||
model: "qwen3-coder:480b-cloud"
|
||||
generate_model: "qwen3-coder:480b-cloud"
|
||||
mapping_model: "deepseek-v3.2:cloud"
|
||||
|
|
@ -36,7 +39,7 @@ sys:
|
|||
channel_pool_len: 100
|
||||
channel_pool_size: 32
|
||||
llm_pool_len: 5
|
||||
heartbeat_interval: 30
|
||||
heartbeat_interval: 300
|
||||
key: report-api
|
||||
pollSize: 5 #连接池大小,不配置,或配置为0表示不启用连接池
|
||||
minIdleConns: 2 #最小空闲连接数
|
||||
|
|
@ -47,7 +50,7 @@ redis:
|
|||
host: 47.97.27.195:6379
|
||||
type: node
|
||||
pass: lansexiongdi@666
|
||||
key: report-api-test
|
||||
key: ai_scheduler_prov
|
||||
pollSize: 5 #连接池大小,不配置,或配置为0表示不启用连接池
|
||||
minIdleConns: 2 #最小空闲连接数
|
||||
maxIdleTime: 30 #每个连接最大空闲时间,如果超过了这个时间会被关闭
|
||||
|
|
@ -109,7 +112,7 @@ tools:
|
|||
api_key: "7583905168607100978"
|
||||
api_secret: "pat_eEN0BdLNDughEtABjJJRYTW71olvDU0qUbfQUeaPc2NnYWO8HeyNoui5aR9z0sSZ"
|
||||
zltxResellerAuthProductToManagerAndDefaultLossReason:
|
||||
base_url: "https://revcl.1688sup.com/api/admin/resellerAuthProductToManagerAndDefaultLossReason"
|
||||
base_url: "https://revcl.1688sup.com/api/admin/reseller/resellerAuthProduct/getManagerAndDefaultLossReason"
|
||||
|
||||
# eino tool 配置
|
||||
eino_tools:
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ server:
|
|||
host: "0.0.0.0"
|
||||
|
||||
ollama:
|
||||
base_url: "http://127.0.0.1:11434"
|
||||
model: "qwen3-coder:480b-cloud"
|
||||
generate_model: "qwen3-coder:480b-cloud"
|
||||
mapping_model: "deepseek-v3.2:cloud"
|
||||
base_url: "http://192.168.6.115:11434"
|
||||
model: "qwen3:8b"
|
||||
generate_model: "qwen3:8b"
|
||||
mapping_model: "qwen3:8b"
|
||||
vl_model: "gemini-3-pro-preview"
|
||||
timeout: "120s"
|
||||
level: "info"
|
||||
|
|
@ -26,11 +26,11 @@ coze:
|
|||
|
||||
lsxd:
|
||||
# 统一登录
|
||||
login_url: "https://api.user.1688sup.com/v1/login/phone"
|
||||
phone: "ORlviZN7N06W2+WKLe76xg=="
|
||||
password: "V5Uh8C4bamEM6UQZh4TCeQ=="
|
||||
code: "456789"
|
||||
check_token_url: "https://api.user.1688sup.com/v1/user/welcome"
|
||||
login_url: "http://api.test.user.1688sup.com/v1/login/phone"
|
||||
phone: "OFJ8UpqOlI7+w3Qklf36ZA=="
|
||||
password: "tEbFegH/DRRh6LutFb7o3g=="
|
||||
code: "123456"
|
||||
check_token_url: "http://api.test.user.1688sup.com/v1/user/welcome"
|
||||
|
||||
|
||||
sys:
|
||||
|
|
@ -43,7 +43,7 @@ redis:
|
|||
host: 47.97.27.195:6379
|
||||
type: node
|
||||
pass: lansexiongdi@666
|
||||
key: ai_scheduler-test
|
||||
key: ai_scheduler_test
|
||||
pollSize: 5 #连接池大小,不配置,或配置为0表示不启用连接池
|
||||
minIdleConns: 2 #最小空闲连接数
|
||||
maxIdleTime: 30 #每个连接最大空闲时间,如果超过了这个时间会被关闭
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"ai_scheduler/internal/data/impl"
|
||||
"ai_scheduler/internal/data/model"
|
||||
"ai_scheduler/internal/entitys"
|
||||
"ai_scheduler/internal/pkg"
|
||||
"ai_scheduler/internal/tools"
|
||||
"ai_scheduler/internal/tools/bbxt"
|
||||
"ai_scheduler/tmpl/dataTemp"
|
||||
|
|
@ -471,11 +472,16 @@ func (d *DingTalkBotBiz) recognize(ctx context.Context, requireData *entitys.Req
|
|||
|
||||
rec.Tasks = append(rec.Tasks, entitys.RegistrationTask{
|
||||
Name: task.Index,
|
||||
Desc: task.Desc,
|
||||
Desc: task.TempPrompt,
|
||||
TaskConfigDetail: taskConfig, // 直接使用解析后的配置,避免重复构建
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
rec.Ext = pkg.JsonByteIgonErr(&entitys.TaskExt{
|
||||
UserName: requireData.Req.SenderNick,
|
||||
})
|
||||
|
||||
err = d.handle.Recognize(ctx, rec, &do.WithDingTalkBot{})
|
||||
return
|
||||
}
|
||||
|
|
@ -644,7 +650,7 @@ func (d *DingTalkBotBiz) defaultPrompt() string {
|
|||
- 注意区分 parameters 中的 必须参数(required) 和 可选参数(optional),按下述参数提取规则处理。
|
||||
- 若**完全无法匹配**,立即设置 is_match: false,并在 chat 中已第一人称的角度提醒用户需要适用何种工具(例:"请问您是要查询订单还是商品呢")。
|
||||
|
||||
1. **参数提取**:
|
||||
3. **参数提取**:
|
||||
|
||||
- 根据 parameters 字段列出的参数名,从用户输入中提取对应值。
|
||||
- **仅提取**明确提及的参数,忽略未列出的内容。
|
||||
|
|
|
|||
|
|
@ -207,7 +207,9 @@ func (r *Handle) HandleMatch(ctx context.Context, client *gateway.Client, rec *e
|
|||
case constants.TaskTypeFunc:
|
||||
return r.handleTask(ctx, rec, pointTask)
|
||||
case constants.TaskTypeBot:
|
||||
return r.handleBot(ctx, rec, pointTask)
|
||||
return r.HandleBot(ctx, rec, &entitys.Task{
|
||||
Index: pointTask.Index,
|
||||
})
|
||||
case constants.TaskTypeEinoWorkflow:
|
||||
return r.handleEinoWorkflow(ctx, rec, pointTask)
|
||||
case constants.TaskTypeCozeWorkflow:
|
||||
|
|
@ -416,23 +418,34 @@ func (r *Handle) readKnowledgeSSE(resp io.ReadCloser, channel chan entitys.Respo
|
|||
}
|
||||
|
||||
// bot 临时实现,后续转到 eino 工作流
|
||||
func (r *Handle) handleBot(ctx context.Context, rec *entitys.Recognize, task *model.AiTask) (err error) {
|
||||
func (r *Handle) HandleBot(ctx context.Context, rec *entitys.Recognize, task *entitys.Task) (err error) {
|
||||
if task.Index == "bug_optimization_submit" {
|
||||
entitys.ResLoading(rec.Ch, task.Index, "需求记录中...")
|
||||
|
||||
// Ext 中获取 sessionId
|
||||
sessionID := rec.GetSession()
|
||||
var unionId string
|
||||
entitys.ResLoading(rec.Ch, task.Index, "需求记录中...\n")
|
||||
// 获取dingtalk accessToken
|
||||
accessToken, _ := r.dingtalkOldClient.GetAccessToken()
|
||||
// 获取创建者 dingtalk unionId
|
||||
unionId := r.getUserDingtalkUnionId(ctx, accessToken, sessionID)
|
||||
// Ext 中获取 sessionId
|
||||
taskExt := rec.GetTaskExt()
|
||||
if taskExt == nil {
|
||||
return errorcode.ParamErr("taskExt参数错误")
|
||||
}
|
||||
if len(taskExt.Session) > 0 {
|
||||
// 获取创建者 dingtalk unionId
|
||||
unionId = r.getUserDingtalkUnionId(ctx, accessToken, taskExt.Session)
|
||||
} else if len(taskExt.UserName) > 0 {
|
||||
unionId = r.getUserDingtalkUnionIdWithUserName(ctx, accessToken, taskExt.UserName)
|
||||
} else {
|
||||
return errorcode.ParamErr("taskExt参数错误,重要参数缺失")
|
||||
}
|
||||
|
||||
// 附件url
|
||||
var attachmentUrl string
|
||||
for _, file := range rec.UserContent.File {
|
||||
attachmentUrl = file.FileUrl
|
||||
break
|
||||
}
|
||||
recordId, err := r.dingtalkNotableClient.InsertRecord(accessToken, &dingtalk.InsertRecordReq{
|
||||
|
||||
req := &dingtalk.InsertRecordReq{
|
||||
BaseId: r.conf.Dingtalk.TableDemand.BaseId,
|
||||
SheetIdOrName: r.conf.Dingtalk.TableDemand.SheetIdOrName,
|
||||
// OperatorId: tool_callback.BotBugOptimizationSubmitAdminUnionId,
|
||||
|
|
@ -440,7 +453,9 @@ func (r *Handle) handleBot(ctx context.Context, rec *entitys.Recognize, task *mo
|
|||
CreatorUnionId: unionId,
|
||||
Content: rec.UserContent.Text,
|
||||
AttachmentUrl: attachmentUrl,
|
||||
})
|
||||
}
|
||||
|
||||
recordId, err := r.dingtalkNotableClient.InsertRecord(accessToken, req)
|
||||
if err != nil {
|
||||
errCode := r.dingtalkNotableClient.GetHTTPStatus(err)
|
||||
// 权限不足
|
||||
|
|
@ -453,12 +468,16 @@ func (r *Handle) handleBot(ctx context.Context, rec *entitys.Recognize, task *mo
|
|||
if recordId == "" {
|
||||
return errors.NewBusinessErr(422, "创建记录失败,请联系管理员")
|
||||
}
|
||||
|
||||
var detailPage string
|
||||
entitys.ResLog(rec.Ch, task.Index, "需求记录完成")
|
||||
|
||||
// 构建跳转链接
|
||||
detailPage := util.BuildJumpLink(r.conf.Dingtalk.TableDemand.Url, "去查看")
|
||||
|
||||
switch rec.OutPutScene {
|
||||
case entitys.OutPutSceneDingTalk:
|
||||
// 构建跳转链接
|
||||
detailPage = "[去查看](" + r.conf.Dingtalk.TableDemand.Url + ")"
|
||||
default:
|
||||
// 构建跳转链接
|
||||
detailPage = util.BuildJumpLink(r.conf.Dingtalk.TableDemand.Url, "去查看")
|
||||
}
|
||||
entitys.ResText(rec.Ch, task.Index, fmt.Sprintf("需求已记录,正在分配相关人员处理,请您耐心等待处理结果。点击查看工单进度:%s", detailPage))
|
||||
|
||||
return nil
|
||||
|
|
@ -469,16 +488,21 @@ func (r *Handle) handleBot(ctx context.Context, rec *entitys.Recognize, task *mo
|
|||
|
||||
// getUserDingtalkUnionId 获取用户的 dingtalk unionId
|
||||
func (r *Handle) getUserDingtalkUnionId(ctx context.Context, accessToken, sessionID string) (unionId string) {
|
||||
// 查询用户名
|
||||
if len(sessionID) == 0 {
|
||||
// 查询用户名
|
||||
return ""
|
||||
}
|
||||
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
|
||||
return r.getUserDingtalkUnionIdWithUserName(ctx, accessToken, session.UserName)
|
||||
}
|
||||
|
||||
func (r *Handle) getUserDingtalkUnionIdWithUserName(ctx context.Context, accessToken, userName string) (unionId string) {
|
||||
// 获取创建者uid 用户名 -> dingtalk uid
|
||||
creatorId, err := r.dingtalkContactClient.SearchUserOne(dingtalk.AppKey{AccessToken: accessToken}, creatorName)
|
||||
creatorId, err := r.dingtalkContactClient.SearchUserOne(dingtalk.AppKey{AccessToken: accessToken}, userName)
|
||||
if err != nil {
|
||||
log.Warnf("search dingtalk user one failed: %v", err)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
package do
|
||||
|
||||
import (
|
||||
"ai_scheduler/internal/config"
|
||||
"ai_scheduler/internal/data/impl"
|
||||
"ai_scheduler/internal/data/model"
|
||||
"ai_scheduler/internal/pkg"
|
||||
|
||||
"ai_scheduler/internal/pkg/lsxd"
|
||||
"ai_scheduler/internal/tools/bbxt"
|
||||
"ai_scheduler/utils"
|
||||
"database/sql"
|
||||
"errors"
|
||||
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
|
@ -23,19 +27,25 @@ import (
|
|||
type Macro struct {
|
||||
botGroupImpl *impl.BotGroupImpl
|
||||
reportDailyCacheImpl *impl.ReportDailyCacheImpl
|
||||
config *config.Config
|
||||
rdb *utils.Rdb
|
||||
}
|
||||
|
||||
func NewMacro(
|
||||
botGroupImpl *impl.BotGroupImpl,
|
||||
reportDailyCacheImpl *impl.ReportDailyCacheImpl,
|
||||
config *config.Config,
|
||||
rdb *utils.Rdb,
|
||||
) *Macro {
|
||||
return &Macro{
|
||||
botGroupImpl: botGroupImpl,
|
||||
reportDailyCacheImpl: reportDailyCacheImpl,
|
||||
config: config,
|
||||
rdb: rdb,
|
||||
}
|
||||
}
|
||||
|
||||
type MacroFunc func(ctx context.Context, content string, groupConfig *model.AiBotGroupConfig) (successMsg string, err error, isFinish bool)
|
||||
type MacroFunc func(ctx context.Context, content string, groupConfig *model.AiBotGroupConfig, config *config.Config) (successMsg string, err error, isFinish bool)
|
||||
|
||||
func (m *Macro) Router(ctx context.Context, reqContent string, groupConfig *model.AiBotGroupConfig) (successMsg string, err error, isFinish bool) {
|
||||
reqContent = strings.TrimSpace(reqContent)
|
||||
|
|
@ -47,60 +57,115 @@ func (m *Macro) Router(ctx context.Context, reqContent string, groupConfig *mode
|
|||
case strings.HasPrefix(reqContent, "[负利润分析]导出"):
|
||||
return m.NegativeProfitGet(ctx)
|
||||
case strings.HasPrefix(reqContent, "[负利润分析]更新"):
|
||||
return m.NegativeProfitUpdate(ctx, reqContent, groupConfig)
|
||||
return m.NegativeProfitUpdate(ctx, reqContent)
|
||||
case strings.HasPrefix(reqContent, "[负利润分析]清理"):
|
||||
return m.NegativeProfitClear()
|
||||
default:
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Macro) NegativeProfitUpdate(ctx context.Context, content string, groupConfig *model.AiBotGroupConfig) (successMsg string, err error, isFinish bool) {
|
||||
//newContent := strings.ReplaceAll(strings.TrimSpace(content), "[负利润分析]更新:", "")
|
||||
jsonData, err := ParseLossData(content)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("解析失败:%v", err)
|
||||
return
|
||||
}
|
||||
func (m *Macro) NegativeProfitClear() (successMsg string, err error, isFinish bool) {
|
||||
dayDate := time.Now().Format(time.DateOnly)
|
||||
cond := builder.NewCond()
|
||||
cond = cond.And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail})
|
||||
cond = cond.And(builder.Eq{"cache_key": dayDate})
|
||||
cond = cond.And(builder.Eq{"status": 1})
|
||||
err = m.reportDailyCacheImpl.UpdateByCond(&cond, &model.AiReportDailyCache{
|
||||
Value: pkg.JsonStringIgonErr(jsonData),
|
||||
Status: 2,
|
||||
})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("解析失败:%v", err)
|
||||
return
|
||||
}
|
||||
isFinish = true
|
||||
successMsg = "清理成功"
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Macro) NegativeProfitUpdate(ctx context.Context, content string) (successMsg string, err error, isFinish bool) {
|
||||
//newContent := strings.ReplaceAll(strings.TrimSpace(content), "[负利润分析]更新:", "")
|
||||
jsonData, err := ParseLossData(content)
|
||||
b, err := bbxt.NewBbxtTools(m.config, lsxd.NewLogin(m.config, m.rdb))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
now := time.Now()
|
||||
dayData := now.Format(time.DateOnly)
|
||||
value, err := b.GetMapResellerLossSumProductRelation(ctx, now, m.GetReportCache)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var setData = make(map[int32]*bbxt.ResellerLossSumProductRelation)
|
||||
for k, v := range jsonData {
|
||||
if _, ok := value[k]; !ok {
|
||||
continue
|
||||
}
|
||||
for productId, product := range v.Products {
|
||||
if _, ok := value[k].Products[productId]; !ok {
|
||||
continue
|
||||
}
|
||||
if value[k].Products[productId].LossReason == product.LossReason {
|
||||
continue
|
||||
}
|
||||
if _, ex := setData[k]; !ex {
|
||||
setData[k] = &bbxt.ResellerLossSumProductRelation{
|
||||
ResellerName: value[k].ResellerName,
|
||||
AfterSaleName: value[k].AfterSaleName,
|
||||
Products: make(map[int32]*bbxt.LossReason),
|
||||
}
|
||||
}
|
||||
setData[k].Products[productId] = &bbxt.LossReason{
|
||||
ProductName: product.ProductName,
|
||||
LossReason: product.LossReason,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cond := builder.NewCond()
|
||||
cond = cond.And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail})
|
||||
cond = cond.And(builder.Eq{"cache_key": dayData})
|
||||
cond = cond.And(builder.Eq{"status": 1})
|
||||
var cache model.AiReportDailyCache
|
||||
err = m.reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &cache)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if cache.ID == 0 {
|
||||
|
||||
cache = model.AiReportDailyCache{
|
||||
CacheKey: dayData,
|
||||
CacheIndex: bbxt.IndexLossSumDetail,
|
||||
Value: pkg.JsonStringIgonErr(setData),
|
||||
}
|
||||
_, err = m.reportDailyCacheImpl.Add(&cache)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
err = m.reportDailyCacheImpl.UpdateByCond(&cond, &model.AiReportDailyCache{
|
||||
Value: pkg.JsonStringIgonErr(setData),
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
isFinish = true
|
||||
successMsg = "更新成功"
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Macro) NegativeProfitGet(ctx context.Context) (successMsg string, err error, isFinish bool) {
|
||||
var (
|
||||
data model.AiReportDailyCache
|
||||
value map[int32]*bbxt.ResellerLossSumProductRelation
|
||||
)
|
||||
isFinish = true
|
||||
cond := builder.NewCond()
|
||||
cond = cond.And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail})
|
||||
cond = cond.And(builder.Eq{"cache_key": time.Now().Format(time.DateOnly)})
|
||||
err = m.reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &data)
|
||||
b, err := bbxt.NewBbxtTools(m.config, lsxd.NewLogin(m.config, m.rdb))
|
||||
if err != nil {
|
||||
err = fmt.Errorf("获取失败:%v", err)
|
||||
return
|
||||
}
|
||||
if data.ID == 0 {
|
||||
successMsg = "暂未获取今日负利润分析数据,请先呼出报表数据"
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal([]byte(data.Value), &value)
|
||||
now := time.Now()
|
||||
value, err := b.GetMapResellerLossSumProductRelation(ctx, now, m.GetReportCache)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("获取失败,格式解析错误:%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
//将value转为string
|
||||
//**[供应商id]供应商名称->商务名称**\n
|
||||
//└──商品名称:亏损原因\n
|
||||
|
|
@ -116,6 +181,7 @@ func (m *Macro) NegativeProfitGet(ctx context.Context) (successMsg string, err e
|
|||
}
|
||||
}
|
||||
successMsg = valueString.String()
|
||||
isFinish = true
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -286,3 +352,109 @@ func ParseLossData(input string) (map[int32]*bbxt.ResellerLossSumProductRelation
|
|||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (m *Macro) GetReportCache(ctx context.Context, day time.Time, totalDetail []*bbxt.ResellerLoss, bbxtObj *bbxt.BbxtTools) error {
|
||||
dayDate := day.Format(time.DateOnly)
|
||||
|
||||
// 1. 从 API 获取数据并填充
|
||||
apiRelations, err := bbxtObj.GetResellerLossMannagerAndLossReasonFromApi(ctx, totalDetail)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get API data failed: %w", err)
|
||||
}
|
||||
|
||||
// 使用 API 数据填充损失原因
|
||||
fillLossReasonFromData(totalDetail, apiRelations, "未填写")
|
||||
|
||||
// 2. 从缓存获取数据并覆盖
|
||||
cachedRelations, err := m.getCachedRelations(dayDate)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get cache data failed: %w", err)
|
||||
}
|
||||
|
||||
// 使用缓存数据覆盖损失原因
|
||||
if cachedRelations != nil {
|
||||
fillLossReasonFromData(totalDetail, cachedRelations, "")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 从缓存获取关系数据
|
||||
func (m *Macro) getCachedRelations(dayDate string) (map[int32]*bbxt.ResellerLossSumProductRelation, error) {
|
||||
cond := builder.NewCond().
|
||||
And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail}).
|
||||
And(builder.Eq{"cache_key": dayDate}).
|
||||
And(builder.Eq{"status": 1})
|
||||
|
||||
var cache model.AiReportDailyCache
|
||||
err := m.reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &cache)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
// 缓存不存在是正常情况
|
||||
return nil, nil
|
||||
}
|
||||
return nil, fmt.Errorf("query cache failed: %w", err)
|
||||
}
|
||||
|
||||
if cache.ID == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var relations map[int32]*bbxt.ResellerLossSumProductRelation
|
||||
if err := json.Unmarshal([]byte(cache.Value), &relations); err != nil {
|
||||
return nil, fmt.Errorf("unmarshal cache failed: %w", err)
|
||||
}
|
||||
|
||||
return relations, nil
|
||||
}
|
||||
|
||||
// 使用指定数据源填充损失原因
|
||||
func fillLossReasonFromData(
|
||||
totalDetail []*bbxt.ResellerLoss,
|
||||
relations map[int32]*bbxt.ResellerLossSumProductRelation,
|
||||
defaultReason string, // 当数据不存在时使用的默认值
|
||||
) {
|
||||
for _, detail := range totalDetail {
|
||||
resellerRelation, exists := relations[detail.ResellerId]
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
|
||||
// 设置售后经理(只有在有值时才设置)
|
||||
if resellerRelation.AfterSaleName != "" {
|
||||
detail.Manager = resellerRelation.AfterSaleName
|
||||
}
|
||||
|
||||
// 为每个产品设置损失原因
|
||||
for _, product := range detail.ProductLoss {
|
||||
setProductLossReason(product, resellerRelation, defaultReason)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置单个产品的损失原因
|
||||
func setProductLossReason(
|
||||
product *bbxt.ProductLoss,
|
||||
resellerRelation *bbxt.ResellerLossSumProductRelation,
|
||||
defaultReason string,
|
||||
) {
|
||||
// 如果该经销商没有产品数据,跳过
|
||||
if resellerRelation.Products == nil {
|
||||
return
|
||||
}
|
||||
|
||||
productRelation, exists := resellerRelation.Products[product.ProductId]
|
||||
if !exists {
|
||||
if defaultReason != "" {
|
||||
product.LossReason = defaultReason
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 如果有损失原因则设置,否则使用默认值
|
||||
if productRelation.LossReason != "" {
|
||||
product.LossReason = productRelation.LossReason
|
||||
} else if defaultReason != "" {
|
||||
product.LossReason = defaultReason
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package biz
|
||||
|
||||
import (
|
||||
"ai_scheduler/internal/biz/do"
|
||||
"ai_scheduler/internal/biz/tools_regis"
|
||||
"ai_scheduler/internal/config"
|
||||
"ai_scheduler/internal/data/constants"
|
||||
|
|
@ -50,6 +51,8 @@ type GroupConfigBiz struct {
|
|||
conf *config.Config
|
||||
rdb *utils.Rdb
|
||||
dingtalkCardClient *dingtalk.CardClient
|
||||
macro *do.Macro
|
||||
handle *do.Handle
|
||||
}
|
||||
|
||||
// NewDingTalkBotBiz
|
||||
|
|
@ -64,6 +67,8 @@ func NewGroupConfigBiz(
|
|||
rdb *utils.Rdb,
|
||||
toolManager *tools.Manager,
|
||||
dingtalkCardClient *dingtalk.CardClient,
|
||||
macro *do.Macro,
|
||||
handle *do.Handle,
|
||||
) *GroupConfigBiz {
|
||||
return &GroupConfigBiz{
|
||||
botTools: tools.BootTools,
|
||||
|
|
@ -76,6 +81,8 @@ func NewGroupConfigBiz(
|
|||
rdb: rdb,
|
||||
toolManager: toolManager,
|
||||
dingtalkCardClient: dingtalkCardClient,
|
||||
macro: macro,
|
||||
handle: handle,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +108,7 @@ func (g *GroupConfigBiz) GetReportLists(ctx context.Context, groupConfig *model.
|
|||
return
|
||||
}
|
||||
|
||||
reports, err = reportList.DailyReport(ctx, time.Now(), bbxt.DownWardValue, product, bbxt.SumFilter, g.ossClient, g.GetReportCache)
|
||||
reports, err = reportList.DailyReport(ctx, time.Now(), bbxt.DownWardValue, product, bbxt.SumFilter, g.ossClient, g.macro.GetReportCache)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -178,7 +185,7 @@ func (g *GroupConfigBiz) handleReport(ctx context.Context, rec *entitys.Recogniz
|
|||
var reports []*bbxt.ReportRes
|
||||
switch rec.Match.Index {
|
||||
case "report_loss_analysis":
|
||||
repo, _err := rep.StatisOursProductLossSum(ctx, t, g.GetReportCache)
|
||||
repo, _err := rep.StatisOursProductLossSum(ctx, t, g.macro.GetReportCache)
|
||||
if _err != nil {
|
||||
return _err
|
||||
}
|
||||
|
|
@ -199,7 +206,7 @@ func (g *GroupConfigBiz) handleReport(ctx context.Context, rec *entitys.Recogniz
|
|||
reports = append(reports, repo)
|
||||
case "report_daily":
|
||||
product := strings.Split(groupConfig.ProductName, ",")
|
||||
repo, _err := rep.DailyReport(ctx, t, bbxt.DownWardValue, product, bbxt.SumFilter, nil, g.GetReportCache)
|
||||
repo, _err := rep.DailyReport(ctx, t, bbxt.DownWardValue, product, bbxt.SumFilter, nil, g.macro.GetReportCache)
|
||||
if _err != nil {
|
||||
return _err
|
||||
}
|
||||
|
|
@ -260,12 +267,18 @@ func (g *GroupConfigBiz) handleMatch(ctx context.Context, rec *entitys.Recognize
|
|||
break
|
||||
}
|
||||
}
|
||||
rec.OutPutScene = entitys.OutPutSceneDingTalk
|
||||
if pointTask == nil || pointTask.Index == "other" {
|
||||
return g.otherTask(ctx, rec)
|
||||
}
|
||||
|
||||
switch constants.TaskType(pointTask.Type) {
|
||||
case constants.TaskTypeFunc:
|
||||
return g.handleTask(ctx, rec, pointTask)
|
||||
case constants.TaskTypeBot:
|
||||
return g.handle.HandleBot(ctx, rec, &entitys.Task{
|
||||
Index: pointTask.Index,
|
||||
})
|
||||
case constants.TaskTypeReport:
|
||||
return g.handleReport(ctx, rec, pointTask, groupConfig)
|
||||
case constants.TaskTypeCozeWorkflow:
|
||||
|
|
@ -318,7 +331,6 @@ func (q *GroupConfigBiz) handleTask(ctx context.Context, rec *entitys.Recognize,
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = q.toolManager.ExecuteTool(ctx, configData.Tool, rec)
|
||||
if err != nil {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ type AiReportDailyCache struct {
|
|||
CacheKey string `gorm:"column:cache_key;not null;default:1;comment:索引方式,可以是任意类型" json:"cache_key"` // 索引方式,可以是任意类型
|
||||
Value string `gorm:"column:value;comment:类型下所需路由以及参数" json:"value"` // 类型下所需路由以及参数
|
||||
CacheIndex string `gorm:"column:cache_index;not null;comment:类型" json:"cache_index"` // 类型
|
||||
Status int32 `gorm:"column:status;not null;default:1" json:"status"`
|
||||
}
|
||||
|
||||
// TableName AiReportDailyCache's table name
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ func (w *statisticsOursProduct) formatContext(ctx context.Context, input *Statis
|
|||
Time: time.Now(),
|
||||
StartTime: startTime,
|
||||
EndTime: endTime,
|
||||
Title: fmt.Sprintf("截止 %s 亏损100以上我们的商品统计", endTimeStr),
|
||||
Title: fmt.Sprintf("截止 %s 电商系统亏损100以上我们的商品统计", endTimeStr),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,3 +29,7 @@ func (d *DingTalkBot) GetAppKey() dingtalk.AppKey {
|
|||
AppSecret: d.ClientSecret,
|
||||
}
|
||||
}
|
||||
|
||||
type Task struct {
|
||||
Index string `json:"bot_index"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,8 +14,14 @@ type Recognize struct {
|
|||
Ch chan Response
|
||||
Match *Match
|
||||
Ext []byte
|
||||
OutPutScene OutPutScene
|
||||
}
|
||||
|
||||
type OutPutScene string
|
||||
|
||||
const OutPutSceneDingTalk OutPutScene = "markdown"
|
||||
const OutPutFormatHtml OutPutScene = "html"
|
||||
|
||||
type TaskExt struct {
|
||||
Auth string `json:"auth"`
|
||||
Session string `json:"session"`
|
||||
|
|
@ -23,6 +29,7 @@ type TaskExt struct {
|
|||
SessionInfo model.AiSession
|
||||
Sys model.AiSy
|
||||
KnowledgeConf KnowledgeBaseRequest
|
||||
UserName string
|
||||
}
|
||||
|
||||
type RegistrationTask struct {
|
||||
|
|
|
|||
|
|
@ -64,7 +64,9 @@ type FunctionCall struct {
|
|||
type ToolDefinition struct {
|
||||
Type string `json:"type"`
|
||||
Function FunctionDef `json:"function"`
|
||||
AuthFunc AuthFunc `json:"function"`
|
||||
}
|
||||
type AuthFunc func(rec *Recognize) (token []byte, err error)
|
||||
|
||||
// FunctionDef 函数定义
|
||||
type FunctionDef struct {
|
||||
|
|
@ -77,7 +79,7 @@ type FunctionDef struct {
|
|||
type Tool interface {
|
||||
Name() string
|
||||
Description() string
|
||||
Definition() ToolDefinition
|
||||
Definition(ctx context.Context) ToolDefinition
|
||||
Execute(ctx context.Context, requireData *Recognize) error
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -165,7 +165,8 @@ func (l *Login) cacheToken(ctx context.Context, token string) error {
|
|||
if token == "" {
|
||||
return errors.New("token is empty")
|
||||
}
|
||||
return l.redisCli.Set(ctx, l.getCacheKey(), token, constants.EXPIRE_LSXD_TOKEN).Err()
|
||||
key := l.getCacheKey()
|
||||
return l.redisCli.Set(ctx, key, token, constants.EXPIRE_LSXD_TOKEN).Err()
|
||||
}
|
||||
|
||||
func (l *Login) doRequest(ctx context.Context, method string, url string, authorization string, body []byte) (int, error) {
|
||||
|
|
@ -190,7 +191,7 @@ func (l *Login) doRequestWithBody(ctx context.Context, method string, url string
|
|||
req.Header.Set("Content-Type", contentType)
|
||||
}
|
||||
if authorization != "" {
|
||||
req.Header.Set("Authorization", authorization)
|
||||
req.Header.Set("Authorization", "Bearer "+authorization)
|
||||
}
|
||||
|
||||
resp, err := (&http.Client{}).Do(req)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"net/url"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ollama/ollama/api"
|
||||
)
|
||||
|
|
@ -43,11 +44,12 @@ func (c *Client) ToolSelect(ctx context.Context, messages []api.Message, tools [
|
|||
|
||||
// 构建聊天请求
|
||||
req := &api.ChatRequest{
|
||||
Model: c.config.Model,
|
||||
Messages: messages,
|
||||
Stream: new(bool), // 设置为false,不使用流式响应
|
||||
Think: &api.ThinkValue{Value: false},
|
||||
Tools: tools,
|
||||
Model: c.config.Model,
|
||||
Messages: messages,
|
||||
Stream: new(bool), // 设置为false,不使用流式响应
|
||||
Think: &api.ThinkValue{Value: false},
|
||||
Tools: tools,
|
||||
KeepAlive: &api.Duration{Duration: 24 * time.Hour},
|
||||
}
|
||||
err = c.client.Chat(ctx, req, func(resp api.ChatResponse) error {
|
||||
res = resp
|
||||
|
|
|
|||
|
|
@ -4,13 +4,14 @@ import (
|
|||
"ai_scheduler/internal/pkg"
|
||||
"ai_scheduler/internal/pkg/l_request"
|
||||
"ai_scheduler/internal/pkg/util"
|
||||
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/go-kratos/kratos/v2/log"
|
||||
)
|
||||
|
||||
type StatisOursProductLossSumReq struct {
|
||||
|
|
@ -252,10 +253,13 @@ func GetManagerAndDefaultLossReasonApi(param *GetManagerAndDefaultLossReasonRequ
|
|||
"Authorization": fmt.Sprintf("Bearer %s", token),
|
||||
},
|
||||
}
|
||||
log.Debug(pkg.JsonStringIgonErr(req.Headers))
|
||||
res, err := req.Send()
|
||||
if err != nil {
|
||||
log.Debug(err.Error())
|
||||
return nil, err
|
||||
}
|
||||
log.Debug(string(res.Content))
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("request failed, status code: %d,resion: %s", res.StatusCode, res.Reason)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ var (
|
|||
SumFilter int32 = -150
|
||||
)
|
||||
|
||||
var resellerBlackListProduct = []string{
|
||||
var ResellerBlackListProduct = []string{
|
||||
"悦跑",
|
||||
"电商-独立",
|
||||
"蓝星严选连续包月",
|
||||
|
|
@ -103,9 +103,7 @@ func (b *BbxtTools) DailyReport(
|
|||
|
||||
return
|
||||
}
|
||||
|
||||
// StatisOursProductLossSum 负利润分析
|
||||
func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time, initFunc LossSumInitFunc) (report []*ReportRes, err error) {
|
||||
func (b *BbxtTools) ResellerLossSort(ctx context.Context, now time.Time) ([]*ResellerLoss, error) {
|
||||
ct := []string{
|
||||
time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Format("2006-01-02 15:04:05"),
|
||||
adjustedTime(now), //adjustedTime(time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, now.Location())),
|
||||
|
|
@ -115,13 +113,10 @@ func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time,
|
|||
Ct: ct,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
var (
|
||||
resellerMap = make(map[int32]*ResellerLoss)
|
||||
total [][]string
|
||||
gt []*ResellerLoss
|
||||
totalDetail []*ResellerLoss
|
||||
)
|
||||
|
||||
for _, info := range data.List {
|
||||
|
|
@ -166,14 +161,66 @@ func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time,
|
|||
sort.Slice(resellers, func(i, j int) bool {
|
||||
return resellers[i].Total < resellers[j].Total
|
||||
})
|
||||
var (
|
||||
totalSum float64
|
||||
return resellers, nil
|
||||
}
|
||||
|
||||
func (b *BbxtTools) GetMapResellerLossSumProductRelation(ctx context.Context, now time.Time, initFunc LossSumInitFunc) (map[int32]*ResellerLossSumProductRelation, error) {
|
||||
resellers, err := b.ResellerLossSort(ctx, now)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var totalDetail []*ResellerLoss
|
||||
for _, v := range resellers {
|
||||
if v.Total <= -100 && !slices.Contains(ResellerBlackListProduct, v.ResellerName) {
|
||||
|
||||
totalDetail = append(totalDetail, v)
|
||||
}
|
||||
|
||||
}
|
||||
if len(totalDetail) > 0 {
|
||||
err = initFunc(ctx, now, totalDetail, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
value := b.ResellerLossToMapResellerLossSumProductRelation(totalDetail)
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (b *BbxtTools) ResellerLossToMapResellerLossSumProductRelation(totalDetail []*ResellerLoss) map[int32]*ResellerLossSumProductRelation {
|
||||
relations := make(map[int32]*ResellerLossSumProductRelation)
|
||||
for _, detail := range totalDetail {
|
||||
if _, ok := relations[detail.ResellerId]; !ok {
|
||||
relations[detail.ResellerId] = &ResellerLossSumProductRelation{
|
||||
ResellerName: detail.ResellerName,
|
||||
AfterSaleName: detail.Manager,
|
||||
Products: make(map[int32]*LossReason),
|
||||
}
|
||||
}
|
||||
for _, product := range detail.ProductLoss {
|
||||
relations[detail.ResellerId].Products[product.ProductId] = &LossReason{
|
||||
ProductName: product.ProductName,
|
||||
LossReason: product.LossReason,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return relations
|
||||
}
|
||||
|
||||
// StatisOursProductLossSum 负利润分析
|
||||
func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time, initFunc LossSumInitFunc) (report []*ReportRes, err error) {
|
||||
resellers, err := b.ResellerLossSort(ctx, now)
|
||||
var (
|
||||
total [][]string
|
||||
gt []*ResellerLoss
|
||||
totalDetail []*ResellerLoss
|
||||
totalSum float64
|
||||
totalSum500 float64
|
||||
)
|
||||
// 构建分组
|
||||
for _, v := range resellers {
|
||||
if v.Total <= -100 && !slices.Contains(resellerBlackListProduct, v.ResellerName) {
|
||||
if v.Total <= -100 && !slices.Contains(ResellerBlackListProduct, v.ResellerName) {
|
||||
total = append(total, []string{
|
||||
fmt.Sprintf("%s", v.ResellerName),
|
||||
fmt.Sprintf("%.2f", v.Total),
|
||||
|
|
@ -181,7 +228,7 @@ func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time,
|
|||
totalSum += v.Total
|
||||
totalDetail = append(totalDetail, v)
|
||||
}
|
||||
if v.Total <= -500 && !slices.Contains(resellerBlackListProduct, v.ResellerName) {
|
||||
if v.Total <= -500 && !slices.Contains(ResellerBlackListProduct, v.ResellerName) {
|
||||
gt = append(gt, v)
|
||||
totalSum500 += v.Total
|
||||
}
|
||||
|
|
@ -263,7 +310,7 @@ func (b *BbxtTools) GetResellerLossMannagerAndLossReasonFromApi(ctx context.Cont
|
|||
for _, product := range v.ProductLoss {
|
||||
relationMap[v.ResellerId].Products[product.ProductId] = &LossReason{
|
||||
ProductName: product.ProductName,
|
||||
LossReason: "未填写", // 初始化为未填写
|
||||
LossReason: "", // 初始化为未填写
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -356,10 +403,6 @@ func (b *BbxtTools) GetProfitRankingSum(now time.Time) (report *ReportRes, err e
|
|||
|
||||
// GetStatisOfficialProductSum 销量同比分析
|
||||
func (b *BbxtTools) GetStatisOfficialProductSum(now time.Time, productName []string) (report *ReportRes, err error) {
|
||||
var productMap = make(map[string]int)
|
||||
for k, v := range productName {
|
||||
productMap[v] = k
|
||||
}
|
||||
ct := []string{
|
||||
time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Format("2006-01-02 15:04:05"),
|
||||
adjustedTime(now),
|
||||
|
|
@ -381,7 +424,11 @@ func (b *BbxtTools) GetStatisOfficialProductSum(now time.Time, productName []str
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
var total = make([][]string, len(ids))
|
||||
|
||||
// 创建临时map存储产品数据
|
||||
productDataMap := make(map[string][]string)
|
||||
var productNamesInResult []string
|
||||
|
||||
for _, v := range data.OfficialProductSum {
|
||||
var (
|
||||
yeterDatyDiff string
|
||||
|
|
@ -397,7 +444,8 @@ func (b *BbxtTools) GetStatisOfficialProductSum(now time.Time, productName []str
|
|||
} else {
|
||||
lastWeekDiff = fmt.Sprintf("%s↓%d", GreenStyle, v.HistoryTwoDiff)
|
||||
}
|
||||
total[productMap[v.OfficialProductName]] = []string{
|
||||
|
||||
rowData := []string{
|
||||
fmt.Sprintf("%s", v.OfficialProductName),
|
||||
fmt.Sprintf("%d", v.CurrentNum),
|
||||
fmt.Sprintf("%d", v.HistoryOneNum),
|
||||
|
|
@ -406,7 +454,20 @@ func (b *BbxtTools) GetStatisOfficialProductSum(now time.Time, productName []str
|
|||
lastWeekDiff,
|
||||
}
|
||||
|
||||
// 存储到map中,key为产品名
|
||||
productDataMap[v.OfficialProductName] = rowData
|
||||
productNamesInResult = append(productNamesInResult, v.OfficialProductName)
|
||||
}
|
||||
|
||||
// 按照productName的顺序构建total
|
||||
var total [][]string
|
||||
|
||||
for _, name := range productName {
|
||||
if rowData, exists := productDataMap[name]; exists {
|
||||
total = append(total, rowData)
|
||||
}
|
||||
}
|
||||
|
||||
timeCh := now.Format("1月2日15点")
|
||||
title := "截至" + timeCh + "销售同比分析"
|
||||
//总量生成excel
|
||||
|
|
|
|||
|
|
@ -72,22 +72,29 @@ func Test_GetStatisOfficialProductSumDecline(t *testing.T) {
|
|||
}
|
||||
s := "官方--腾讯-周卡,官方--腾讯-月卡,官方--腾讯-季卡,官方--腾讯-年卡,官方--优酷周卡,官方--优酷月卡,官方--优酷季卡,官方--优酷年卡,官方--爱奇艺-周卡,官方--爱奇艺-月卡,官方--爱奇艺-季卡,官方--爱奇艺-年卡,官方--芒果-PC周卡,官方--芒果-PC月卡,官方--芒果-PC季卡,官方--美团外卖红包5元,官方--美团外卖红包10元,官方--QQ音乐-绿钻月卡,官方--饿了么超级会员月卡,官方--网易云黑胶vip月卡,官方--喜马拉雅巅峰会员月卡"
|
||||
//s := "官方--QQ音乐-绿钻月卡"
|
||||
now := time.Now()
|
||||
report, err := o.GetStatisOfficialProductSumDecline(time.Date(now.Year(), now.Month(), now.Day(), 12, 0, 0, 0, now.Location()), 1000, strings.Split(s, ","), -150)
|
||||
report, err := o.GetStatisOfficialProductSumDecline(time.Now(), 1000, strings.Split(s, ","), -150)
|
||||
|
||||
t.Log(report, err)
|
||||
|
||||
}
|
||||
|
||||
func Test_GetStatisOfficialProductSum(t *testing.T) {
|
||||
|
||||
run()
|
||||
configs := configConfig
|
||||
o, err := NewBbxtTools(nil, lsxd.NewLogin(configs, utils.NewRdb(configConfig)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
s := "官方--美团外卖红包5元,官方--美团外卖红包10元,官方--饿了么超级会员月卡,官方--网易云黑胶vip月卡,官方--喜马拉雅巅峰会员月卡,官方--芒果-PC季卡,官方--芒果-PC月卡,官方--芒果-PC周卡,官方--腾讯-周卡,官方--优酷周卡,官方--QQ音乐-绿钻月卡,官方--爱奇艺-周卡,官方--腾讯-月卡,官方--腾讯-季卡,官方--腾讯-年卡,官方--优酷月卡,官方--优酷季卡,官方--优酷年卡,官方--爱奇艺-月卡,官方--爱奇艺-季卡,官方--爱奇艺-年卡"
|
||||
report, err := o.GetStatisOfficialProductSum(time.Now(), strings.Split(s, ","))
|
||||
s := "官方--腾讯-周卡,官方--腾讯-月卡,官方--腾讯-季卡,官方--腾讯-年卡,官方--优酷周卡,官方--优酷月卡,官方--优酷季卡,官方--优酷年卡,官方--爱奇艺-周卡,官方--爱奇艺-月卡,官方--爱奇艺-季卡,官方--爱奇艺-年卡,官方--芒果-PC周卡,官方--芒果-PC月卡,官方--芒果-PC季卡,官方--美团外卖红包5元,官方--美团外卖红包10元,官方--QQ音乐-绿钻月卡,官方--饿了么超级会员月卡,官方--网易云黑胶vip月卡,官方--喜马拉雅巅峰会员月卡"
|
||||
now := time.Now()
|
||||
noon := time.Date(
|
||||
now.Year(),
|
||||
now.Month(),
|
||||
now.Day(),
|
||||
12, 0, 0, 0,
|
||||
now.Location(),
|
||||
)
|
||||
report, err := o.GetStatisOfficialProductSum(noon, strings.Split(s, ","))
|
||||
|
||||
t.Log(report, err)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"ai_scheduler/internal/pkg/utils_ollama"
|
||||
"ai_scheduler/internal/tools/public"
|
||||
zltxtool "ai_scheduler/internal/tools/zltx"
|
||||
"ai_scheduler/utils"
|
||||
"context"
|
||||
|
||||
"fmt"
|
||||
|
|
@ -15,10 +16,11 @@ import (
|
|||
type Manager struct {
|
||||
tools map[string]entitys.Tool
|
||||
llm *utils_ollama.Client
|
||||
rdb *utils.Rdb
|
||||
}
|
||||
|
||||
// NewManager 创建工具管理器
|
||||
func NewManager(config *config.Config, llm *utils_ollama.Client) *Manager {
|
||||
func NewManager(config *config.Config, llm *utils_ollama.Client, rdb *utils.Rdb) *Manager {
|
||||
m := &Manager{
|
||||
tools: make(map[string]entitys.Tool),
|
||||
llm: llm,
|
||||
|
|
@ -26,7 +28,7 @@ func NewManager(config *config.Config, llm *utils_ollama.Client) *Manager {
|
|||
|
||||
// 注册直连天下订单详情工具
|
||||
if config.Tools.ZltxOrderDetail.Enabled {
|
||||
zltxOrderDetailTool := zltxtool.NewZltxOrderDetailTool(config.Tools.ZltxOrderDetail, m.llm)
|
||||
zltxOrderDetailTool := zltxtool.NewZltxOrderDetailTool(config, rdb, m.llm)
|
||||
m.tools[zltxOrderDetailTool.Name()] = zltxOrderDetailTool
|
||||
}
|
||||
|
||||
|
|
@ -43,7 +45,7 @@ func NewManager(config *config.Config, llm *utils_ollama.Client) *Manager {
|
|||
}
|
||||
//注册直连天下订单统计工具
|
||||
if config.Tools.ZltxOrderStatistics.Enabled {
|
||||
zltxOrderStatisticsTool := zltxtool.NewZltxOrderStatisticsTool(config.Tools.ZltxOrderStatistics)
|
||||
zltxOrderStatisticsTool := zltxtool.NewZltxOrderStatisticsTool(config, rdb)
|
||||
m.tools[zltxOrderStatisticsTool.Name()] = zltxOrderStatisticsTool
|
||||
}
|
||||
|
||||
|
|
@ -104,5 +106,10 @@ func (m *Manager) ExecuteTool(ctx context.Context, name string, rec *entitys.Rec
|
|||
return fmt.Errorf("tool not found: %s", name)
|
||||
}
|
||||
|
||||
return m.ExecuteToolWithToolObj(ctx, tool, rec)
|
||||
}
|
||||
|
||||
// ExecuteTool 执行工具
|
||||
func (m *Manager) ExecuteToolWithToolObj(ctx context.Context, tool entitys.Tool, rec *entitys.Recognize) error {
|
||||
return tool.Execute(ctx, rec)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ func (c *CozeCompany) Description() string {
|
|||
}
|
||||
|
||||
// Definition 返回工具定义
|
||||
func (c *CozeCompany) Definition() entitys.ToolDefinition {
|
||||
func (c *CozeCompany) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||
return entitys.ToolDefinition{
|
||||
Type: "function",
|
||||
Function: entitys.FunctionDef{
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ func (c *CozeExpress) Description() string {
|
|||
}
|
||||
|
||||
// Definition 返回工具定义
|
||||
func (c *CozeExpress) Definition() entitys.ToolDefinition {
|
||||
func (c *CozeExpress) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||
return entitys.ToolDefinition{
|
||||
Type: "function",
|
||||
Function: entitys.FunctionDef{
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ func (k *KnowledgeBaseTool) Description() string {
|
|||
}
|
||||
|
||||
// Definition 返回工具定义
|
||||
func (k *KnowledgeBaseTool) Definition() entitys.ToolDefinition {
|
||||
func (k *KnowledgeBaseTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||
return entitys.ToolDefinition{
|
||||
Type: "function",
|
||||
Function: entitys.FunctionDef{
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ type NormalChat struct {
|
|||
}
|
||||
|
||||
// Definition 返回工具定义
|
||||
func (w *NormalChatTool) Definition() entitys.ToolDefinition {
|
||||
func (w *NormalChatTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||
return entitys.ToolDefinition{}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ func (w *WeatherTool) Description() string {
|
|||
}
|
||||
|
||||
// Definition 返回工具定义
|
||||
func (w *WeatherTool) Definition() entitys.ToolDefinition {
|
||||
func (w *WeatherTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||
return entitys.ToolDefinition{
|
||||
Type: "function",
|
||||
Function: entitys.FunctionDef{
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ func (t *OrderAfterSaleResellerTool) Description() string {
|
|||
}
|
||||
|
||||
// 未使用-仅实现接口
|
||||
func (t *OrderAfterSaleResellerTool) Definition() entitys.ToolDefinition {
|
||||
func (t *OrderAfterSaleResellerTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||
return entitys.ToolDefinition{}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ func (t *OrderAfterSaleResellerBatchTool) Description() string {
|
|||
}
|
||||
|
||||
// 未使用-仅实现接口
|
||||
func (t *OrderAfterSaleResellerBatchTool) Definition() entitys.ToolDefinition {
|
||||
func (t *OrderAfterSaleResellerBatchTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||
return entitys.ToolDefinition{}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ func (t *OrderAfterSaleSupplierTool) Description() string {
|
|||
}
|
||||
|
||||
// 未使用-仅实现接口
|
||||
func (t *OrderAfterSaleSupplierTool) Definition() entitys.ToolDefinition {
|
||||
func (t *OrderAfterSaleSupplierTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||
return entitys.ToolDefinition{}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,26 +4,30 @@ import (
|
|||
"ai_scheduler/internal/config"
|
||||
"ai_scheduler/internal/entitys"
|
||||
"ai_scheduler/internal/pkg"
|
||||
"ai_scheduler/internal/pkg/lsxd"
|
||||
"ai_scheduler/internal/pkg/rec_extra"
|
||||
"ai_scheduler/internal/pkg/utils_ollama"
|
||||
"ai_scheduler/utils"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gitea.cdlsxd.cn/self-tools/l_request"
|
||||
"github.com/gofiber/fiber/v2/log"
|
||||
"github.com/ollama/ollama/api"
|
||||
)
|
||||
|
||||
// ZltxOrderDetailTool 直连天下订单详情工具
|
||||
type ZltxOrderDetailTool struct {
|
||||
config config.ToolConfig
|
||||
config *config.Config
|
||||
llm *utils_ollama.Client
|
||||
rdb *utils.Rdb
|
||||
}
|
||||
|
||||
// NewZltxOrderDetailTool 创建直连天下订单详情工具
|
||||
func NewZltxOrderDetailTool(config config.ToolConfig, llm *utils_ollama.Client) *ZltxOrderDetailTool {
|
||||
return &ZltxOrderDetailTool{config: config, llm: llm}
|
||||
func NewZltxOrderDetailTool(config *config.Config, rdb *utils.Rdb, llm *utils_ollama.Client) *ZltxOrderDetailTool {
|
||||
return &ZltxOrderDetailTool{config: config, rdb: rdb, llm: llm}
|
||||
}
|
||||
|
||||
// Name 返回工具名称
|
||||
|
|
@ -37,7 +41,7 @@ func (w *ZltxOrderDetailTool) Description() string {
|
|||
}
|
||||
|
||||
// Definition 返回工具定义
|
||||
func (w *ZltxOrderDetailTool) Definition() entitys.ToolDefinition {
|
||||
func (w *ZltxOrderDetailTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||
return entitys.ToolDefinition{
|
||||
Type: "function",
|
||||
Function: entitys.FunctionDef{
|
||||
|
|
@ -54,6 +58,19 @@ func (w *ZltxOrderDetailTool) Definition() entitys.ToolDefinition {
|
|||
"required": []string{"number"},
|
||||
},
|
||||
},
|
||||
AuthFunc: func(rec *entitys.Recognize) ([]byte, error) {
|
||||
ext, err := rec_extra.GetTaskRecExt(rec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(ext.Auth) > 0 {
|
||||
return []byte(ext.Auth), nil
|
||||
} else {
|
||||
login := lsxd.NewLogin(w.config, w.rdb)
|
||||
token := login.GetToken(ctx)
|
||||
return []byte(token), nil
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -62,14 +79,74 @@ type ZltxOrderDetailRequest struct {
|
|||
OrderNumber interface{} `json:"order_number"`
|
||||
}
|
||||
|
||||
//type ZltxOrderDetailResponse struct {
|
||||
// Code int `json:"code"`
|
||||
// Error string `json:"error"`
|
||||
// Data ZltxOrderDetailData `json:"data"`
|
||||
// Mes string `json:"mes"`
|
||||
//}
|
||||
|
||||
// ZltxOrderDetailResponse 直连天下订单详情响应
|
||||
type ZltxOrderDetailResponse struct {
|
||||
Code int `json:"code"`
|
||||
Error string `json:"error"`
|
||||
Data ZltxOrderDetailData `json:"data"`
|
||||
Mes string `json:"mes"`
|
||||
Code int `json:"code"`
|
||||
Data Data `json:"data"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
type Data struct {
|
||||
Direct *Direct `json:"direct"`
|
||||
Order *Order `json:"order"`
|
||||
}
|
||||
|
||||
type Direct struct {
|
||||
SerialNumber string `json:"serialNumber"`
|
||||
OrderOrderNumber string `json:"orderOrderNumber"`
|
||||
TerminalAccount string `json:"terminalAccount"`
|
||||
OursProductId int `json:"oursProductId"`
|
||||
OursProductName string `json:"oursProductName"`
|
||||
Status int `json:"status"`
|
||||
TradePrice float64 `json:"tradePrice"`
|
||||
PlatformProductId int `json:"platformProductId"`
|
||||
PlatformProductName string `json:"platformProductName"`
|
||||
PlatformId int `json:"platformId"`
|
||||
PlatformName string `json:"platformName"`
|
||||
PlatformPrice float64 `json:"platformPrice"`
|
||||
CreateTime int `json:"createTime"`
|
||||
ExecuteTime int `json:"executeTime"`
|
||||
Type int `json:"type"`
|
||||
Reason string `json:"reason"`
|
||||
ResellerId int `json:"resellerId"`
|
||||
ResellerName string `json:"resellerName"`
|
||||
Aftermarket int `json:"aftermarket"`
|
||||
PurchasePrice float64 `json:"purchasePrice"`
|
||||
NeedAi bool `json:"needAi"`
|
||||
AiReason string `json:"aiReason"`
|
||||
}
|
||||
|
||||
type Order struct {
|
||||
Id string `json:"id"`
|
||||
ResellerId int `json:"resellerId"`
|
||||
ResellerName string `json:"resellerName"`
|
||||
Status int `json:"status"`
|
||||
PayStatus int `json:"payStatus"`
|
||||
CreateTime int `json:"createTime"`
|
||||
PayTime int `json:"payTime"`
|
||||
Type int `json:"type"`
|
||||
Account string `json:"account"`
|
||||
Quantity int `json:"quantity"`
|
||||
Amount float64 `json:"amount"`
|
||||
PayAmount float64 `json:"payAmount"`
|
||||
ResellerOrderNumber string `json:"resellerOrderNumber"`
|
||||
Price int `json:"price"`
|
||||
NotifyTime int `json:"notifyTime"`
|
||||
FinishTime int `json:"finishTime"`
|
||||
Aftermarket int `json:"aftermarket"`
|
||||
Remark string `json:"remark"`
|
||||
OursProductId int `json:"oursProductId"`
|
||||
OursProductName string `json:"oursProductName"`
|
||||
OursProductPrice int `json:"oursProductPrice"`
|
||||
TradePrice float64 `json:"tradePrice"`
|
||||
}
|
||||
type ZltxOrderLogResponse struct {
|
||||
Code int `json:"code"`
|
||||
Error string `json:"error"`
|
||||
|
|
@ -93,7 +170,7 @@ func (w *ZltxOrderDetailTool) Execute(ctx context.Context, rec *entitys.Recogniz
|
|||
}
|
||||
|
||||
// 这里可以集成真实的直连天下订单详情API
|
||||
return w.getZltxOrderDetail(rec, req.OrderNumber)
|
||||
return w.getZltxOrderDetail(ctx, rec, req.OrderNumber)
|
||||
}
|
||||
|
||||
func (r *ZltxOrderDetailRequest) UnmarshalJSON(data []byte) error {
|
||||
|
|
@ -113,8 +190,8 @@ func (r *ZltxOrderDetailRequest) UnmarshalJSON(data []byte) error {
|
|||
}
|
||||
|
||||
// getMockZltxOrderDetail 获取模拟直连天下订单详情数据
|
||||
func (w *ZltxOrderDetailTool) getZltxOrderDetail(rec *entitys.Recognize, number interface{}) (err error) {
|
||||
log.Infof("订单编号:%v,类型:%v")
|
||||
func (w *ZltxOrderDetailTool) getZltxOrderDetail(ctx context.Context, rec *entitys.Recognize, number interface{}) (err error) {
|
||||
|
||||
var orderNum string
|
||||
switch number.(type) {
|
||||
case int, int32, int64:
|
||||
|
|
@ -127,15 +204,15 @@ func (w *ZltxOrderDetailTool) getZltxOrderDetail(rec *entitys.Recognize, number
|
|||
orderNum = fmt.Sprintf("%v", number)
|
||||
}
|
||||
|
||||
ext, err := rec_extra.GetTaskRecExt(rec)
|
||||
token, err := w.Definition(ctx).AuthFunc(rec)
|
||||
if err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
//查询订单详情
|
||||
req := l_request.Request{
|
||||
Url: fmt.Sprintf(w.config.BaseURL, orderNum),
|
||||
Url: fmt.Sprintf(w.config.Tools.ZltxOrderDetail.BaseURL, orderNum),
|
||||
Headers: map[string]string{
|
||||
"Authorization": fmt.Sprintf("Bearer %s", ext.Auth),
|
||||
"Authorization": fmt.Sprintf("Bearer %s", token),
|
||||
},
|
||||
Method: "GET",
|
||||
}
|
||||
|
|
@ -156,15 +233,17 @@ func (w *ZltxOrderDetailTool) getZltxOrderDetail(rec *entitys.Recognize, number
|
|||
if err = json.Unmarshal(res.Content, &resData); err != nil {
|
||||
return
|
||||
}
|
||||
entitys.ResJson(rec.Ch, w.Name(), res.Text)
|
||||
|
||||
if resData.Data.Direct != nil {
|
||||
if rec.OutPutScene == entitys.OutPutSceneDingTalk {
|
||||
entitys.ResJson(rec.Ch, w.Name(), resData.ToForm())
|
||||
} else {
|
||||
entitys.ResJson(rec.Ch, w.Name(), res.Text)
|
||||
entitys.ResLoading(rec.Ch, w.Name(), "正在分析订单日志")
|
||||
|
||||
}
|
||||
if resData.Data.Direct != nil {
|
||||
req = l_request.Request{
|
||||
Url: fmt.Sprintf(w.config.AddURL, resData.Data.Direct["orderOrderNumber"].(string), resData.Data.Direct["serialNumber"].(string)),
|
||||
Url: fmt.Sprintf(w.config.Tools.ZltxOrderDetail.AddURL, resData.Data.Direct.OrderOrderNumber, resData.Data.Direct.SerialNumber),
|
||||
Headers: map[string]string{
|
||||
"Authorization": fmt.Sprintf("Bearer %s", ext.Auth),
|
||||
"Authorization": fmt.Sprintf("Bearer %s", token),
|
||||
},
|
||||
Method: "GET",
|
||||
}
|
||||
|
|
@ -184,7 +263,7 @@ func (w *ZltxOrderDetailTool) getZltxOrderDetail(rec *entitys.Recognize, number
|
|||
return fmt.Errorf("订单日志解析失败:%s", err)
|
||||
}
|
||||
|
||||
err = w.llm.ChatStream(context.TODO(), rec.Ch, []api.Message{
|
||||
err = w.llm.ChatStream(ctx, rec.Ch, []api.Message{
|
||||
{
|
||||
Role: "system",
|
||||
Content: "你是一个订单日志助手。用户可能会提供订单日志,你需要按以下规则处理:\n" +
|
||||
|
|
@ -216,3 +295,95 @@ func (w *ZltxOrderDetailTool) getZltxOrderDetail(rec *entitys.Recognize, number
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (z *ZltxOrderDetailResponse) ToForm() string {
|
||||
var res strings.Builder
|
||||
res.WriteString("**普通订单** \n")
|
||||
res.WriteString("\n## 订单号:" + z.Data.Order.Id)
|
||||
res.WriteString("\n## 分销商订单号:" + z.Data.Order.ResellerOrderNumber)
|
||||
res.WriteString("\n## 分销商:" + z.Data.Order.ResellerName)
|
||||
res.WriteString("\n## 订单商品:" + z.Data.Order.OursProductName)
|
||||
res.WriteString("\n## 充值账号:" + z.Data.Order.Account)
|
||||
res.WriteString("\n## 折扣价/原价:" + fmt.Sprintf("%.2f", z.Data.Order.TradePrice))
|
||||
res.WriteString("\n## 数量:" + fmt.Sprintf("%d", z.Data.Order.Quantity))
|
||||
res.WriteString("\n## 订单总额:" + fmt.Sprintf("%.2f", z.Data.Order.Amount))
|
||||
res.WriteString("\n## 订单状态:" + orderStatusMap(z.Data.Order.Status))
|
||||
res.WriteString("\n## 支付状态:" + orderPayStatusMap(z.Data.Order.Status))
|
||||
res.WriteString("\n## 创建时间:" + unixToDateFormat(z.Data.Order.CreateTime))
|
||||
res.WriteString("\n## 完成时间:" + unixToDateFormat(z.Data.Order.FinishTime))
|
||||
res.WriteString("\n---\n")
|
||||
|
||||
res.WriteString("\n**充值流水** \n")
|
||||
res.WriteString("\n## 订单号:" + z.Data.Direct.OrderOrderNumber)
|
||||
res.WriteString("\n## 流水号:" + z.Data.Direct.SerialNumber)
|
||||
res.WriteString("\n## 商品:" + z.Data.Direct.OursProductName)
|
||||
res.WriteString("\n## 使用接口:" + z.Data.Direct.PlatformName)
|
||||
res.WriteString("\n## 接口商品名称:" + z.Data.Direct.PlatformProductName)
|
||||
res.WriteString("\n## 上游价:" + fmt.Sprintf("%.2f", z.Data.Direct.PlatformPrice))
|
||||
res.WriteString("\n## 下游价:" + fmt.Sprintf("%.2f", z.Data.Direct.TradePrice))
|
||||
res.WriteString("\n## 上游采购价:" + fmt.Sprintf("%.2f", z.Data.Direct.PurchasePrice))
|
||||
res.WriteString("\n## 充值账号:" + z.Data.Direct.TerminalAccount)
|
||||
res.WriteString("\n## 创建时间:" + unixToDateFormat(z.Data.Direct.CreateTime))
|
||||
res.WriteString("\n## 处理时间:" + unixToDateFormat(z.Data.Direct.ExecuteTime))
|
||||
res.WriteString("\n## 状态:" + directStatusMap(z.Data.Direct.Status))
|
||||
res.WriteString("\n")
|
||||
res.WriteString("\n")
|
||||
res.WriteString("\n")
|
||||
return res.String()
|
||||
}
|
||||
|
||||
func orderStatusMap(status int) string {
|
||||
var OrderStatus = map[int]string{
|
||||
0: "下单中",
|
||||
1: "订单完成",
|
||||
2: "部分成功",
|
||||
3: "充值处理中",
|
||||
4: "已暂停",
|
||||
-1: "关闭订单",
|
||||
-2: "全部失败",
|
||||
}
|
||||
if _, ok := OrderStatus[status]; !ok {
|
||||
return "未知"
|
||||
}
|
||||
return OrderStatus[status]
|
||||
}
|
||||
|
||||
func unixToDateFormat(unix int) string {
|
||||
return time.Unix(int64(unix), 0).Format("2006-01-02 15:04:05")
|
||||
}
|
||||
func orderPayStatusMap(status int) string {
|
||||
var OrderPayStatus = map[int]string{
|
||||
0: "未支付",
|
||||
1: "支付中",
|
||||
2: "支付成功",
|
||||
3: "退款中",
|
||||
4: "全部退款",
|
||||
5: "部分退款",
|
||||
-1: "支付失败",
|
||||
-2: "退款失败",
|
||||
}
|
||||
if _, ok := OrderPayStatus[status]; !ok {
|
||||
return "未知"
|
||||
}
|
||||
return OrderPayStatus[status]
|
||||
}
|
||||
|
||||
func directStatusMap(status int) string {
|
||||
var DirectStatus = map[int]string{
|
||||
0: "待充值",
|
||||
1: "充值成功",
|
||||
2: "充值中",
|
||||
-1: "充值失败",
|
||||
-2: "失败重试",
|
||||
-98: "下单异常",
|
||||
-99: "查询异常",
|
||||
-6: "手动失败",
|
||||
-5: "手动重试",
|
||||
-4: "叠加卡单",
|
||||
-3: "卡单",
|
||||
}
|
||||
if _, ok := DirectStatus[status]; !ok {
|
||||
return "未知"
|
||||
}
|
||||
return DirectStatus[status]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ func (t *ZltxOrderLogTool) Description() string {
|
|||
return "查询订单日志"
|
||||
}
|
||||
|
||||
func (t *ZltxOrderLogTool) Definition() entitys.ToolDefinition {
|
||||
func (t *ZltxOrderLogTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||
return entitys.ToolDefinition{
|
||||
Type: "function",
|
||||
Function: entitys.FunctionDef{
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ func (z ZltxProductTool) Description() string {
|
|||
return "获取直连天下商品信息"
|
||||
}
|
||||
|
||||
func (z ZltxProductTool) Definition() entitys.ToolDefinition {
|
||||
func (z ZltxProductTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||
return entitys.ToolDefinition{
|
||||
Type: "function",
|
||||
Function: entitys.FunctionDef{
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ package zltx
|
|||
import (
|
||||
"ai_scheduler/internal/config"
|
||||
"ai_scheduler/internal/entitys"
|
||||
"ai_scheduler/internal/pkg/lsxd"
|
||||
"ai_scheduler/internal/pkg/rec_extra"
|
||||
"ai_scheduler/utils"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
|
@ -13,7 +15,8 @@ import (
|
|||
)
|
||||
|
||||
type ZltxOrderStatisticsTool struct {
|
||||
config config.ToolConfig
|
||||
config *config.Config
|
||||
rdb *utils.Rdb
|
||||
}
|
||||
|
||||
func (z ZltxOrderStatisticsTool) Name() string {
|
||||
|
|
@ -24,7 +27,7 @@ func (z ZltxOrderStatisticsTool) Description() string {
|
|||
return "通过账号获取订单统计信息"
|
||||
}
|
||||
|
||||
func (z ZltxOrderStatisticsTool) Definition() entitys.ToolDefinition {
|
||||
func (z ZltxOrderStatisticsTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||
return entitys.ToolDefinition{
|
||||
Type: "function",
|
||||
Function: entitys.FunctionDef{
|
||||
|
|
@ -41,6 +44,19 @@ func (z ZltxOrderStatisticsTool) Definition() entitys.ToolDefinition {
|
|||
"required": []string{"number"},
|
||||
},
|
||||
},
|
||||
AuthFunc: func(rec *entitys.Recognize) ([]byte, error) {
|
||||
ext, err := rec_extra.GetTaskRecExt(rec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(ext.Auth) > 0 {
|
||||
return []byte(ext.Auth), nil
|
||||
} else {
|
||||
login := lsxd.NewLogin(z.config, z.rdb)
|
||||
token := login.GetToken(ctx)
|
||||
return []byte(token), nil
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -56,7 +72,7 @@ func (z ZltxOrderStatisticsTool) Execute(ctx context.Context, rec *entitys.Recog
|
|||
if req.Number == nil {
|
||||
return fmt.Errorf("number is required")
|
||||
}
|
||||
return z.getZltxOrderStatistics(req.Number, rec)
|
||||
return z.getZltxOrderStatistics(ctx, req.Number, rec)
|
||||
}
|
||||
|
||||
type ZltxOrderStatisticsResponse struct {
|
||||
|
|
@ -76,17 +92,17 @@ type ZltxOrderStatisticsData struct {
|
|||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
func (z ZltxOrderStatisticsTool) getZltxOrderStatistics(number interface{}, rec *entitys.Recognize) error {
|
||||
ext, err := rec_extra.GetTaskRecExt(rec)
|
||||
func (z ZltxOrderStatisticsTool) getZltxOrderStatistics(ctx context.Context, number interface{}, rec *entitys.Recognize) error {
|
||||
token, err := z.Definition(ctx).AuthFunc(rec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//查询订单详情
|
||||
url := fmt.Sprintf("%s%s", z.config.BaseURL, fmt.Sprintf("%v", number))
|
||||
url := fmt.Sprintf("%s%s", z.config.Tools.ZltxOrderStatistics.BaseURL, fmt.Sprintf("%v", number))
|
||||
req := l_request.Request{
|
||||
Url: url,
|
||||
Headers: map[string]string{
|
||||
"Authorization": fmt.Sprintf("Bearer %s", ext.Auth),
|
||||
"Authorization": fmt.Sprintf("Bearer %s", string(token)),
|
||||
},
|
||||
Method: "GET",
|
||||
}
|
||||
|
|
@ -116,8 +132,9 @@ func (z ZltxOrderStatisticsTool) getZltxOrderStatistics(number interface{}, rec
|
|||
return nil
|
||||
}
|
||||
|
||||
func NewZltxOrderStatisticsTool(config config.ToolConfig) *ZltxOrderStatisticsTool {
|
||||
func NewZltxOrderStatisticsTool(config *config.Config, rdb *utils.Rdb) *ZltxOrderStatisticsTool {
|
||||
return &ZltxOrderStatisticsTool{
|
||||
config: config,
|
||||
rdb: rdb,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue