2026-05-21 10:41:37 +08:00
|
|
|
package gateway
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"context"
|
|
|
|
|
"encoding/json"
|
2026-05-27 09:36:25 +08:00
|
|
|
"errors"
|
2026-05-21 10:41:37 +08:00
|
|
|
"fmt"
|
|
|
|
|
"mime/multipart"
|
|
|
|
|
"model-gateway/common/util"
|
|
|
|
|
"model-gateway/model/entity"
|
|
|
|
|
"time"
|
|
|
|
|
|
2026-06-10 16:16:05 +08:00
|
|
|
commonHttp "gitea.redpowerfuture.com/red-future/common/http"
|
2026-05-21 10:41:37 +08:00
|
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
|
|
|
"github.com/gogf/gf/v2/util/guid"
|
|
|
|
|
)
|
|
|
|
|
|
2026-05-27 09:36:25 +08:00
|
|
|
type UploadFileResponse struct {
|
2026-05-21 10:41:37 +08:00
|
|
|
FileURL string `json:"fileURL"` // 文件 URL
|
|
|
|
|
FileSize int `json:"fileSize"` // 文件大小(字节)
|
|
|
|
|
FileName string `json:"fileName"` // 文件名
|
|
|
|
|
FileFormat string `json:"fileFormat"` // 文件格式
|
|
|
|
|
FileAddressPrefix string `json:"fileAddressPrefix"` // 文件地址前缀
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-27 09:36:25 +08:00
|
|
|
func UploadByTask(ctx context.Context, data []byte, fileExt string) (oss *UploadFileResponse, err error) {
|
2026-05-21 10:41:37 +08:00
|
|
|
// 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 {
|
2026-05-27 09:36:25 +08:00
|
|
|
return nil, err
|
2026-05-21 10:41:37 +08:00
|
|
|
}
|
2026-05-21 11:18:39 +08:00
|
|
|
if _, err := part.Write(data); err != nil {
|
2026-05-27 09:36:25 +08:00
|
|
|
return nil, err
|
2026-05-21 10:41:37 +08:00
|
|
|
}
|
2026-05-21 11:18:39 +08:00
|
|
|
contentType := writer.FormDataContentType()
|
2026-05-21 14:23:34 +08:00
|
|
|
if err = writer.Close(); err != nil {
|
2026-05-27 09:36:25 +08:00
|
|
|
return nil, err
|
2026-05-21 11:18:39 +08:00
|
|
|
}
|
|
|
|
|
|
2026-05-21 10:41:37 +08:00
|
|
|
headers := util.ForwardHeaders(ctx)
|
2026-05-21 11:18:39 +08:00
|
|
|
headers["Content-Type"] = contentType
|
2026-05-21 10:41:37 +08:00
|
|
|
fullURL := "oss/file/uploadFile"
|
|
|
|
|
g.Log().Infof(ctx, "[OSS] upload start url=%s filename=%s size=%d", fullURL, filename, len(data))
|
|
|
|
|
|
2026-05-27 09:36:25 +08:00
|
|
|
var resp UploadFileResponse
|
2026-05-21 10:41:37 +08:00
|
|
|
if err = commonHttp.Post(ctx, fullURL, headers, &resp, body.Bytes()); err != nil {
|
2026-05-27 09:36:25 +08:00
|
|
|
return nil, err
|
2026-05-21 10:41:37 +08:00
|
|
|
}
|
2026-05-27 09:36:25 +08:00
|
|
|
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
|
2026-05-21 10:41:37 +08:00
|
|
|
}
|
|
|
|
|
|
2026-05-23 18:08:08 +08:00
|
|
|
// CallbackPayload 回调请求体
|
|
|
|
|
type CallbackPayload struct {
|
2026-05-27 09:36:25 +08:00
|
|
|
TaskId string `json:"task_id"`
|
|
|
|
|
State int `json:"state"`
|
|
|
|
|
OssFile string `json:"oss_file"`
|
|
|
|
|
FileType string `json:"file_type"`
|
|
|
|
|
Messages map[string]any `json:"messages"`
|
|
|
|
|
ErrorMsg string `json:"error_msg"`
|
2026-05-23 18:08:08 +08:00
|
|
|
}
|
|
|
|
|
|
2026-05-27 09:36:25 +08:00
|
|
|
// TriggerCallback 任务的回调
|
2026-05-21 10:41:37 +08:00
|
|
|
func TriggerCallback(ctx context.Context, t *entity.AsynchTask) {
|
|
|
|
|
headers := util.ForwardHeaders(ctx)
|
2026-05-23 18:08:08 +08:00
|
|
|
var resp struct{}
|
|
|
|
|
payload := CallbackPayload{
|
|
|
|
|
TaskId: t.TaskID,
|
|
|
|
|
State: t.State,
|
|
|
|
|
OssFile: t.OssFile,
|
|
|
|
|
FileType: t.FileType,
|
2026-05-27 09:36:25 +08:00
|
|
|
Messages: t.TextResult,
|
2026-05-23 18:08:08 +08:00
|
|
|
ErrorMsg: t.ErrorMsg,
|
2026-05-21 10:41:37 +08:00
|
|
|
}
|
|
|
|
|
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))
|
|
|
|
|
|
2026-05-23 18:08:08 +08:00
|
|
|
err = commonHttp.Post(ctx, t.CallbackURL, headers, &resp, jsonData)
|
2026-05-21 10:41:37 +08:00
|
|
|
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))
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-23 18:08:08 +08:00
|
|
|
// PromptsCallbackPayload 提示词回调请求体
|
|
|
|
|
type PromptsCallbackPayload struct {
|
2026-05-27 09:36:25 +08:00
|
|
|
EpicycleId int64 `json:"epicycleId"`
|
|
|
|
|
Messages map[string]any `json:"messages"`
|
2026-05-23 18:08:08 +08:00
|
|
|
}
|
|
|
|
|
|
2026-05-21 10:41:37 +08:00
|
|
|
// TriggerPromptsCallback 任务成功后的提示词回调
|
|
|
|
|
func TriggerPromptsCallback(ctx context.Context, t *entity.AsynchTask, epicycleId int64) {
|
2026-06-10 14:51:24 +08:00
|
|
|
callbackURL := "prompts-core/session/callback"
|
2026-05-21 10:41:37 +08:00
|
|
|
headers := util.ForwardHeaders(ctx)
|
2026-05-23 18:08:08 +08:00
|
|
|
var resp struct{}
|
|
|
|
|
payload := PromptsCallbackPayload{
|
|
|
|
|
EpicycleId: epicycleId,
|
2026-05-27 09:36:25 +08:00
|
|
|
Messages: t.TextResult,
|
2026-05-21 10:41:37 +08:00
|
|
|
}
|
|
|
|
|
jsonData, err := json.Marshal(payload)
|
|
|
|
|
if err != nil {
|
|
|
|
|
g.Log().Warningf(ctx, "[提示词回调] JSON序列化失败 epicycleId=%d 错误=%v", epicycleId, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
g.Log().Infof(ctx, "[提示词回调] 开始发送 epicycleId=%d 回调地址=%s 请求头数量=%d 消息体大小=%d字节",
|
|
|
|
|
t.EpicycleId, callbackURL, len(headers), len(jsonData))
|
|
|
|
|
|
2026-05-23 18:08:08 +08:00
|
|
|
err = commonHttp.Post(ctx, callbackURL, headers, &resp, jsonData)
|
2026-05-21 10:41:37 +08:00
|
|
|
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))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// IsSuperAdmin 调用admin-go服务检查是否是超级管理员
|
|
|
|
|
func IsSuperAdmin(ctx context.Context) (res bool, err error) {
|
|
|
|
|
headers := util.ForwardHeaders(ctx)
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//// 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))
|
|
|
|
|
//}
|