131 lines
3.2 KiB
Go
131 lines
3.2 KiB
Go
package services
|
||
|
||
import (
|
||
"ai_scheduler/internal/config"
|
||
"ai_scheduler/internal/data/constants"
|
||
errorcode "ai_scheduler/internal/data/error"
|
||
"ai_scheduler/internal/domain/workflow/runtime"
|
||
"ai_scheduler/internal/entitys"
|
||
"ai_scheduler/internal/pkg/util"
|
||
"ai_scheduler/internal/pkg/utils_ollama"
|
||
"context"
|
||
"fmt"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/gofiber/fiber/v2"
|
||
"github.com/ollama/ollama/api"
|
||
)
|
||
|
||
// CapabilityService 统一回调入口
|
||
type CapabilityService struct {
|
||
cfg *config.Config
|
||
workflowManager *runtime.Registry
|
||
}
|
||
|
||
func NewCapabilityService(cfg *config.Config, workflowManager *runtime.Registry) *CapabilityService {
|
||
return &CapabilityService{
|
||
cfg: cfg,
|
||
workflowManager: workflowManager,
|
||
}
|
||
}
|
||
|
||
// 产品数据提取入参
|
||
type ProductIngestReq struct {
|
||
Url string `json:"url"` // 商品详情页URL
|
||
Title string `json:"title"` // 商品标题
|
||
Text string `json:"text"` // 商品描述
|
||
Images []string `json:"images"` // 商品图片URL列表
|
||
Timestamp int64 `json:"timestamp"` // 商品发布时间戳
|
||
}
|
||
|
||
// ProductIngest 产品数据提取
|
||
func (s *CapabilityService) ProductIngest(c *fiber.Ctx) error {
|
||
// 请求头校验
|
||
if err := s.checkRequestHeader(c); err != nil {
|
||
return err
|
||
}
|
||
|
||
// 解析请求参数
|
||
req := ProductIngestReq{}
|
||
if err := c.BodyParser(&req); err != nil {
|
||
return errorcode.ParamErr("invalid request body: %v", err)
|
||
}
|
||
// 必要参数校验
|
||
if req.Text == "" {
|
||
return errorcode.ParamErr("missing required fields")
|
||
}
|
||
|
||
// 模型调用
|
||
client, cleanup, err := utils_ollama.NewClient(s.cfg)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
defer cleanup()
|
||
|
||
res, err := client.Chat(context.Background(), []api.Message{
|
||
{
|
||
Role: "system",
|
||
Content: fmt.Sprintf(constants.SystemPrompt, constants.HYTProductPropertyTemplateZH),
|
||
},
|
||
{
|
||
Role: "user",
|
||
Content: req.Text,
|
||
},
|
||
{
|
||
Role: "user",
|
||
Content: "商品图片URL列表:" + strings.Join(req.Images, ","),
|
||
},
|
||
})
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// res.Message.Content Go中map会无序,交给前端解析
|
||
|
||
// 解析模型输出
|
||
c.JSON(res.Message.Content)
|
||
|
||
return nil
|
||
}
|
||
|
||
// checkRequestHeader 校验请求头
|
||
func (s *CapabilityService) checkRequestHeader(c *fiber.Ctx) error {
|
||
// 读取头
|
||
token := strings.TrimSpace(c.Get("X-Source-Key"))
|
||
ts := strings.TrimSpace(c.Get("X-Timestamp"))
|
||
|
||
// 时间窗口校验
|
||
if ts != "" && !util.IsInTimeWindow(ts, 5*time.Minute) {
|
||
return errorcode.AuthNotFound
|
||
}
|
||
// token校验
|
||
if token == "" || token != "A7f9KQ3mP2X8LZC4R5e" {
|
||
return errorcode.KeyErr()
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// ProductUploadHyt 商品上传至货易通
|
||
func (s *CapabilityService) ProductUploadHyt(c *fiber.Ctx) error {
|
||
// 请求头校验
|
||
if err := s.checkRequestHeader(c); err != nil {
|
||
return err
|
||
}
|
||
|
||
// 获取 body json 串
|
||
raw := append([]byte(nil), c.BodyRaw()...)
|
||
bodyStr := string(raw)
|
||
|
||
// 调用eino工作流,实现商品上传到货易通
|
||
workflowId := "hyt.productUpload"
|
||
rec := &entitys.Recognize{UserContent: &entitys.RecognizeUserContent{Text: bodyStr}}
|
||
res, err := s.workflowManager.Invoke(context.Background(), workflowId, rec)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
return c.JSON(res)
|
||
}
|