ai_scheduler/internal/tools/zltx/zltx_order_detail.go

219 lines
6.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package zltx
import (
"ai_scheduler/internal/config"
"ai_scheduler/internal/entitys"
"ai_scheduler/internal/pkg"
"ai_scheduler/internal/pkg/rec_extra"
"ai_scheduler/internal/pkg/utils_ollama"
"context"
"encoding/json"
"fmt"
"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
llm *utils_ollama.Client
}
// NewZltxOrderDetailTool 创建直连天下订单详情工具
func NewZltxOrderDetailTool(config config.ToolConfig, llm *utils_ollama.Client) *ZltxOrderDetailTool {
return &ZltxOrderDetailTool{config: config, llm: llm}
}
// Name 返回工具名称
func (w *ZltxOrderDetailTool) Name() string {
return "zltxOrderDetail"
}
// Description 返回工具描述
func (w *ZltxOrderDetailTool) Description() string {
return "获取直连天下订单详情"
}
// Definition 返回工具定义
func (w *ZltxOrderDetailTool) Definition() entitys.ToolDefinition {
return entitys.ToolDefinition{
Type: "function",
Function: entitys.FunctionDef{
Name: w.Name(),
Description: w.Description(),
Parameters: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"number": map[string]interface{}{
"type": "string",
"description": "订单编号/流水号",
},
},
"required": []string{"number"},
},
},
}
}
// ZltxOrderDetailRequest 直连天下订单详情请求参数
type ZltxOrderDetailRequest struct {
OrderNumber interface{} `json:"order_number"`
}
// ZltxOrderDetailResponse 直连天下订单详情响应
type ZltxOrderDetailResponse struct {
Code int `json:"code"`
Error string `json:"error"`
Data ZltxOrderDetailData `json:"data"`
Mes string `json:"mes"`
}
type ZltxOrderLogResponse struct {
Code int `json:"code"`
Error string `json:"error"`
Data any `json:"data"`
}
// ZltxOrderDetailData 直连天下订单详情数据
type ZltxOrderDetailData struct {
Direct map[string]any `json:"direct"`
Order map[string]any `json:"order"`
}
// Execute 执行直连天下订单详情查询
func (w *ZltxOrderDetailTool) Execute(ctx context.Context, rec *entitys.Recognize) error {
var req = &ZltxOrderDetailRequest{}
if err := req.UnmarshalJSON([]byte(rec.Match.Parameters)); err != nil {
return fmt.Errorf("invalid zltxOrderDetail request: %w", err)
}
if req.OrderNumber == "" {
return fmt.Errorf("number is required")
}
// 这里可以集成真实的直连天下订单详情API
return w.getZltxOrderDetail(rec, req.OrderNumber)
}
func (r *ZltxOrderDetailRequest) UnmarshalJSON(data []byte) error {
var tmp struct {
OrderNumber json.Number `json:"order_number"` // 使用 json.Number 保留原始格式
}
if err := json.Unmarshal(data, &tmp); err != nil {
return err
}
// 根据需要转换为 int64 或 string
if num, err := tmp.OrderNumber.Int64(); err == nil {
r.OrderNumber = num
} else {
r.OrderNumber = tmp.OrderNumber.String()
}
return nil
}
// getMockZltxOrderDetail 获取模拟直连天下订单详情数据
func (w *ZltxOrderDetailTool) getZltxOrderDetail(rec *entitys.Recognize, number interface{}) (err error) {
log.Infof("订单编号:%v,类型:%v")
var orderNum string
switch number.(type) {
case int, int32, int64:
orderNum = fmt.Sprintf("%d", number)
case float64:
orderNum = fmt.Sprintf("%d", int(number.(float64)))
case string:
orderNum = number.(string)
default:
orderNum = fmt.Sprintf("%v", number)
}
ext, err := rec_extra.GetTaskRecExt(rec)
if err != nil {
return
}
//查询订单详情
req := l_request.Request{
Url: fmt.Sprintf(w.config.BaseURL, orderNum),
Headers: map[string]string{
"Authorization": fmt.Sprintf("Bearer %s", ext.Auth),
},
Method: "GET",
}
res, err := req.Send()
if err != nil {
return fmt.Errorf("订单查询失败:网络请求错误:%s", err.Error())
}
var codeMap map[string]interface{}
if err = json.Unmarshal(res.Content, &codeMap); err != nil {
return
}
if codeMap["code"].(float64) != 200 {
return fmt.Errorf("订单查询失败:状态码错误:%s", string(res.Content))
}
var resData ZltxOrderDetailResponse
if err = json.Unmarshal(res.Content, &resData); err != nil {
return
}
entitys.ResJson(rec.Ch, w.Name(), res.Text)
if resData.Data.Direct != nil {
entitys.ResLoading(rec.Ch, w.Name(), "正在分析订单日志")
req = l_request.Request{
Url: fmt.Sprintf(w.config.AddURL, resData.Data.Direct["orderOrderNumber"].(string), resData.Data.Direct["serialNumber"].(string)),
Headers: map[string]string{
"Authorization": fmt.Sprintf("Bearer %s", ext.Auth),
},
Method: "GET",
}
res, err = req.Send()
if err != nil {
return
}
var orderLog ZltxOrderLogResponse
if err = json.Unmarshal(res.Content, &orderLog); err != nil {
return
}
if orderLog.Code != 200 {
return fmt.Errorf("订单日志查询失败:%s", orderLog.Error)
}
dataJson, err := json.Marshal(orderLog.Data)
if err != nil {
return fmt.Errorf("订单日志解析失败:%s", err)
}
err = w.llm.ChatStream(context.TODO(), rec.Ch, []api.Message{
{
Role: "system",
Content: "你是一个订单日志助手。用户可能会提供订单日志,你需要按以下规则处理:\n" +
"1. **先输出结论**:用<conclusion></conclusion>标签包裹关键结论如失败原因或Base64解码内容\n" +
"2. **再输出分析过程**:详细解释如何得出结论;分析过程直接输出分析内容,不需要标明是分析过程\n" +
"3. **订单类型处理**\n" +
" - 失败订单:分析失败原因(如支付超时、库存不足等);\n" +
" - 成功订单提取日志中的Base64编码JSON数据解码后转换为用户可读的格式如表格或JSON。",
},
{
Role: "assistant",
Content: fmt.Sprintf("聊天记录:%s", pkg.JsonStringIgonErr(rec.ChatHis)),
},
{
Role: "assistant",
Content: fmt.Sprintf("需要分析的订单日志:%s", string(dataJson)),
},
{
Role: "user",
Content: rec.UserContent.Text,
},
}, w.Name(), "")
if err != nil {
return fmt.Errorf("订单日志解析失败:%s", err)
}
}
if resData.Data.Direct == nil {
entitys.ResText(rec.Ch, w.Name(), "该订单无充值流水记录,不需要进行订单错误分析,建议检查订单收单模式以及扣款方式等原因😘")
}
return
}