327 lines
9.9 KiB
Go
327 lines
9.9 KiB
Go
package gateway
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"mime/multipart"
|
|
"model-gateway/model/entity"
|
|
"time"
|
|
|
|
commonHttp "gitea.redpowerfuture.com/red-future/common/http"
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
"github.com/gogf/gf/v2/os/gtime"
|
|
"github.com/gogf/gf/v2/util/guid"
|
|
)
|
|
|
|
type UploadFileResponse struct {
|
|
FileURL string `json:"fileURL"` // 文件 URL
|
|
FileSize int `json:"fileSize"` // 文件大小(字节)
|
|
FileName string `json:"fileName"` // 文件名
|
|
FileFormat string `json:"fileFormat"` // 文件格式
|
|
FileAddressPrefix string `json:"fileAddressPrefix"` // 文件地址前缀
|
|
}
|
|
|
|
// UploadByTask 通过任务上传文件
|
|
func UploadByTask(ctx context.Context, data []byte, fileExt string) (oss *UploadFileResponse, err error) {
|
|
// multipart
|
|
body := &bytes.Buffer{}
|
|
writer := multipart.NewWriter(body)
|
|
|
|
ext := fileExt
|
|
if ext == "" {
|
|
ext = ".bin"
|
|
}
|
|
if ext[0] != '.' {
|
|
ext = "." + ext
|
|
}
|
|
|
|
filename := fmt.Sprintf("asynch_%d_%s%s", time.Now().Unix(), guid.S(), ext)
|
|
part, err := writer.CreateFormFile("file", filename)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if _, err = part.Write(data); err != nil {
|
|
return nil, err
|
|
}
|
|
//contentType := writer.FormDataContentType()
|
|
if err = writer.Close(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
//headers := util.ForwardHeaders(ctx)
|
|
//headers["Content-Type"] = contentType
|
|
|
|
headers := make(map[string]string)
|
|
headers["Content-Type"] = writer.FormDataContentType()
|
|
if r := g.RequestFromCtx(ctx); r != nil {
|
|
if auth := r.Header.Get("Authorization"); auth != "" {
|
|
headers["Authorization"] = auth
|
|
}
|
|
}
|
|
|
|
fullURL := "oss/file/uploadFile"
|
|
g.Log().Infof(ctx, "[OSS] upload start url=%s filename=%s size=%d", fullURL, filename, len(data))
|
|
|
|
var resp UploadFileResponse
|
|
if err = commonHttp.Post(ctx, fullURL, headers, &resp, body.Bytes()); err != nil {
|
|
return nil, err
|
|
}
|
|
if &resp == nil {
|
|
return nil, errors.New("[OSS] 上传文件失败")
|
|
}
|
|
g.Log().Infof(ctx, "[OSS] 上传成功 url=%s size=%d format=%s", resp.FileURL, resp.FileSize, resp.FileFormat)
|
|
return &resp, nil
|
|
}
|
|
|
|
// CallbackPayload 回调请求体
|
|
type CallbackPayload struct {
|
|
TaskId string `json:"task_id"`
|
|
State int `json:"state"`
|
|
OssFile string `json:"oss_file"`
|
|
FileType string `json:"file_type"`
|
|
ErrorMsg string `json:"error_msg"`
|
|
}
|
|
|
|
// TriggerCallback 任务的回调
|
|
func TriggerCallback(ctx context.Context, t *entity.ModelGatewayTask) {
|
|
headers := make(map[string]string)
|
|
if r := g.RequestFromCtx(ctx); r != nil {
|
|
for k, v := range r.Request.Header {
|
|
if len(v) > 0 {
|
|
headers[k] = v[0]
|
|
}
|
|
}
|
|
}
|
|
var resp struct{}
|
|
payload := CallbackPayload{
|
|
TaskId: t.TaskID,
|
|
State: t.State,
|
|
ErrorMsg: t.ErrorMsg,
|
|
}
|
|
if !g.IsEmpty(t.ResultFile) {
|
|
payload.OssFile = t.ResultFile.OssFile
|
|
payload.FileType = t.ResultFile.FileType
|
|
}
|
|
jsonData, err := json.Marshal(payload)
|
|
if err != nil {
|
|
g.Log().Warningf(ctx, "[回调] JSON序列化失败 taskId=%s 错误=%v", t.TaskID, err)
|
|
return
|
|
}
|
|
g.Log().Infof(ctx, "[回调] 开始发送 taskId=%s 回调地址=%s 请求头数量=%d 消息体大小=%d字节",
|
|
t.TaskID, t.CallbackURL, len(headers), len(jsonData))
|
|
|
|
err = commonHttp.Post(ctx, t.CallbackURL, headers, &resp, jsonData)
|
|
if err != nil {
|
|
g.Log().Warningf(ctx, "[回调] 发送失败 taskId=%s 回调地址=%s 错误=%v", t.TaskID, t.CallbackURL, err)
|
|
return
|
|
}
|
|
g.Log().Infof(ctx, "[回调] 发送成功 taskId=%s 回调地址=%s 消息体大小=%d字节", t.TaskID, t.CallbackURL, len(jsonData))
|
|
}
|
|
|
|
// PromptsCallbackPayload 提示词回调请求体
|
|
type PromptsCallbackPayload struct {
|
|
EpicycleId int64 `json:"epicycleId"`
|
|
TaskId string `json:"task_id"`
|
|
State int `json:"state"`
|
|
ErrorMsg string `json:"error_msg"`
|
|
OssFile string `json:"oss_file"`
|
|
FileType string `json:"file_type"`
|
|
}
|
|
|
|
// TriggerPromptsCallback 任务成功后的提示词回调
|
|
func TriggerPromptsCallback(ctx context.Context, t *entity.ModelGatewayTask) {
|
|
callbackURL := "prompts-core/session/callback"
|
|
headers := make(map[string]string)
|
|
if r := g.RequestFromCtx(ctx); r != nil {
|
|
for k, v := range r.Request.Header {
|
|
if len(v) > 0 {
|
|
headers[k] = v[0]
|
|
}
|
|
}
|
|
}
|
|
var resp struct{}
|
|
payload := PromptsCallbackPayload{
|
|
EpicycleId: t.EpicycleId,
|
|
TaskId: t.TaskID,
|
|
State: t.State,
|
|
ErrorMsg: t.ErrorMsg,
|
|
OssFile: t.ResultFile.OssFile,
|
|
FileType: t.ResultFile.FileType,
|
|
}
|
|
jsonData, err := json.Marshal(payload)
|
|
if err != nil {
|
|
g.Log().Warningf(ctx, "[提示词回调] JSON序列化失败 epicycleId=%d 错误=%v", t.EpicycleId, err)
|
|
return
|
|
}
|
|
g.Log().Infof(ctx, "[提示词回调] 开始发送 epicycleId=%d 回调地址=%s 请求头数量=%d 消息体大小=%d字节",
|
|
t.EpicycleId, callbackURL, len(headers), len(jsonData))
|
|
|
|
err = commonHttp.Post(ctx, callbackURL, headers, &resp, jsonData)
|
|
if err != nil {
|
|
g.Log().Warningf(ctx, "[提示词回调] 发送失败 epicycleId=%d 回调地址=%s 错误=%v", t.EpicycleId, callbackURL, err)
|
|
return
|
|
}
|
|
g.Log().Infof(ctx, "[提示词回调] 发送成功 epicycleId=%d 回调地址=%s 消息体大小=%d字节", t.EpicycleId, callbackURL, len(jsonData))
|
|
}
|
|
|
|
// BuildCallbackPayload 构建回调请求体
|
|
type BuildCallbackPayload struct {
|
|
TaskId string `json:"taskId"`
|
|
Status int `json:"status"`
|
|
Messages any `json:"messages"`
|
|
ErrorMsg string `json:"errorMsg"`
|
|
}
|
|
|
|
// CallbackBuildResult 回调构建结果
|
|
func CallbackBuildResult(ctx context.Context, record *entity.ModelGatewayBuildRecord) {
|
|
headers := make(map[string]string)
|
|
if r := g.RequestFromCtx(ctx); r != nil {
|
|
for k, v := range r.Request.Header {
|
|
if len(v) > 0 {
|
|
headers[k] = v[0]
|
|
}
|
|
}
|
|
}
|
|
payload := BuildCallbackPayload{
|
|
TaskId: record.TaskID,
|
|
Status: record.Status,
|
|
Messages: record.ResultMessages,
|
|
ErrorMsg: record.ErrorMsg,
|
|
}
|
|
jsonData, _ := json.Marshal(payload)
|
|
|
|
var resp struct{}
|
|
if err := commonHttp.Post(ctx, record.CallbackURL, headers, &resp, jsonData); err != nil {
|
|
g.Log().Warningf(ctx, "[构建回调] 发送失败 taskId=%s err=%v", record.TaskID, err)
|
|
return
|
|
}
|
|
g.Log().Infof(ctx, "[构建回调] 发送成功 taskId=%s", record.TaskID)
|
|
}
|
|
|
|
// IsSuperAdmin 调用admin-go服务检查是否是超级管理员
|
|
func IsSuperAdmin(ctx context.Context) (res bool, err error) {
|
|
//headers := util.ForwardHeaders(ctx)
|
|
headers := make(map[string]string)
|
|
if r := g.RequestFromCtx(ctx); r != nil {
|
|
for k, v := range r.Request.Header {
|
|
if len(v) > 0 {
|
|
headers[k] = v[0]
|
|
}
|
|
}
|
|
}
|
|
var r = make(map[string]bool)
|
|
if err = commonHttp.Get(ctx, "admin-go/api/v1/system/user/checkIsSuperAdmin", headers, &r); err != nil {
|
|
return false, err
|
|
}
|
|
return r["isSuperAdmin"], err
|
|
}
|
|
|
|
// SkillUserVO 技能用户视图对象
|
|
type SkillUserVO struct {
|
|
Id int64 `json:"id,string"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
FileName string `json:"fileName"`
|
|
FileUrl string `json:"fileUrl"`
|
|
CreatedAt *gtime.Time `json:"createdAt"`
|
|
UpdatedAt *gtime.Time `json:"updatedAt"`
|
|
ImgAddressPrefix string `json:"imgAddressPrefix"`
|
|
}
|
|
|
|
// GetSkillUser 获取技能用户信息
|
|
func GetSkillUser(ctx context.Context, name string) (*SkillUserVO, error) {
|
|
fullURL := fmt.Sprintf("ai-agent/skill/user/getUserOrTemplate?name=%s", name)
|
|
//headers := util.ForwardHeaders(ctx)
|
|
headers := make(map[string]string)
|
|
if r := g.RequestFromCtx(ctx); r != nil {
|
|
for k, v := range r.Request.Header {
|
|
if len(v) > 0 {
|
|
headers[k] = v[0]
|
|
}
|
|
}
|
|
}
|
|
var resp SkillUserVO
|
|
var req struct{}
|
|
if err := commonHttp.Get(ctx, fullURL, headers, &resp, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return &resp, nil
|
|
}
|
|
|
|
// SessionHistoryItem 会话历史条目
|
|
type SessionHistoryItem struct {
|
|
Role string `json:"role"`
|
|
Content string `json:"content"`
|
|
}
|
|
|
|
// GetSessionHistory 获取会话历史
|
|
func GetSessionHistory(ctx context.Context, nodeId, sessionId string) ([]SessionHistoryItem, error) {
|
|
fullURL := fmt.Sprintf("model-session/session/history?nodeId=%s&sessionId=%s", nodeId, sessionId)
|
|
headers := make(map[string]string)
|
|
if r := g.RequestFromCtx(ctx); r != nil {
|
|
for k, v := range r.Request.Header {
|
|
if len(v) > 0 {
|
|
headers[k] = v[0]
|
|
}
|
|
}
|
|
}
|
|
var req struct{}
|
|
var resp []SessionHistoryItem
|
|
if err := commonHttp.Get(ctx, fullURL, headers, &resp, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
//// callback 向回调地址 POST 任务结果(与查询接口 GetTaskRes 出参一致)
|
|
//func (s *audioTaskService) callback(ctx context.Context, taskID, status, errMsg, callbackURL string) {
|
|
// if callbackURL == "" {
|
|
// return
|
|
// }
|
|
//
|
|
// task, _ := dao.TranscribeTask.GetByTaskID(ctx, taskID)
|
|
// if task == nil {
|
|
// g.Log().Errorf(ctx, "[回调 %s] 任务不存在", taskID)
|
|
// return
|
|
// }
|
|
//
|
|
// detailList, _ := dao.TranscribeTaskDetail.ListByTaskID(ctx, taskID)
|
|
// detailItems := make([]dto.TranscribeTaskDetailItem, 0, len(detailList))
|
|
// for i := range detailList {
|
|
// detailItems = append(detailItems, dao.DetailEntityToItem(&detailList[i]))
|
|
// }
|
|
//
|
|
// // 构建与查询接口一致的 taskInfo
|
|
// taskInfo := dao.EntityToItem(task)
|
|
//
|
|
// // 兼容历史数据: 从 result 中补全 scenes 等字段
|
|
// detailItems = enrichDetailsFromResult(task.Result, detailItems)
|
|
//
|
|
// payload := dto.CallbackPayload{
|
|
// TaskInfo: taskInfo,
|
|
// DetailList: detailItems,
|
|
// }
|
|
//
|
|
// body, _ := json.Marshal(payload)
|
|
//
|
|
// // 透传调用方的用户信息
|
|
// userJSON, _ := json.Marshal(beans.User{UserName: "admin", TenantId: 1})
|
|
//
|
|
// req, _ := http.NewRequest("POST", callbackURL, bytes.NewReader(body))
|
|
// req.Header.Set("Content-Type", "application/json")
|
|
// req.Header.Set("X-User-Info", string(userJSON))
|
|
//
|
|
// resp, reqErr := http.DefaultClient.Do(req)
|
|
// if reqErr != nil {
|
|
// g.Log().Errorf(ctx, "[回调 %s] 请求失败: %v", taskID, reqErr)
|
|
// return
|
|
// }
|
|
// defer resp.Body.Close()
|
|
//
|
|
// respBody, _ := io.ReadAll(resp.Body)
|
|
// g.Log().Infof(ctx, "[回调 %s] 响应 status=%d, body=%s", taskID, resp.StatusCode, string(respBody))
|
|
//}
|