diff --git a/model/task.go b/model/task.go index a93d6339f..7bd1b9bc4 100644 --- a/model/task.go +++ b/model/task.go @@ -11,6 +11,23 @@ import ( type TaskStatus string +func (t TaskStatus) ToVideoStatus() string { + var status string + switch t { + case TaskStatusQueued, TaskStatusSubmitted: + status = commonRelay.VideoStatusQueued + case TaskStatusInProgress: + status = commonRelay.VideoStatusInProgress + case TaskStatusSuccess: + status = commonRelay.VideoStatusCompleted + case TaskStatusFailure: + status = commonRelay.VideoStatusFailed + default: + status = commonRelay.VideoStatusUnknown // Default fallback + } + return status +} + const ( TaskStatusNotStart TaskStatus = "NOT_START" TaskStatusSubmitted = "SUBMITTED" diff --git a/relay/channel/task/jimeng/adaptor.go b/relay/channel/task/jimeng/adaptor.go index 6c94a4d29..0122e88dc 100644 --- a/relay/channel/task/jimeng/adaptor.go +++ b/relay/channel/task/jimeng/adaptor.go @@ -158,7 +158,12 @@ func (a *TaskAdaptor) DoResponse(c *gin.Context, resp *http.Response, info *rela return } - c.JSON(http.StatusOK, gin.H{"task_id": jResp.Data.TaskID}) + ov := relaycommon.NewOpenAIVideo() + ov.ID = jResp.Data.TaskID + ov.TaskID = jResp.Data.TaskID + ov.CreatedAt = time.Now().Unix() + ov.Model = info.OriginModelName + c.JSON(http.StatusOK, ov) return jResp.Data.TaskID, responseBody, nil } @@ -400,6 +405,30 @@ func (a *TaskAdaptor) ParseTaskResult(respBody []byte) (*relaycommon.TaskInfo, e return &taskResult, nil } +func (a *TaskAdaptor) ConvertToOpenAIVideo(originTask *model.Task) (*relaycommon.OpenAIVideo, error) { + var jimengResp responseTask + if err := json.Unmarshal(originTask.Data, &jimengResp); err != nil { + return nil, errors.Wrap(err, "unmarshal jimeng task data failed") + } + + openAIVideo := relaycommon.NewOpenAIVideo() + openAIVideo.ID = originTask.TaskID + openAIVideo.Status = originTask.Status.ToVideoStatus() + openAIVideo.SetProgressStr(originTask.Progress) + openAIVideo.SetMetadata("url", jimengResp.Data.VideoUrl) + openAIVideo.CreatedAt = originTask.CreatedAt + openAIVideo.CompletedAt = originTask.UpdatedAt + + if jimengResp.Code != 10000 { + openAIVideo.Error = &relaycommon.OpenAIVideoError{ + Message: jimengResp.Message, + Code: fmt.Sprintf("%d", jimengResp.Code), + } + } + + return openAIVideo, nil +} + func isNewAPIRelay(apiKey string) bool { return strings.HasPrefix(apiKey, "sk-") } diff --git a/relay/channel/task/kling/adaptor.go b/relay/channel/task/kling/adaptor.go index c89f8f2e4..54f41618d 100644 --- a/relay/channel/task/kling/adaptor.go +++ b/relay/channel/task/kling/adaptor.go @@ -6,13 +6,11 @@ import ( "fmt" "io" "net/http" - "strconv" "strings" "time" "github.com/QuantumNous/new-api/model" - "github.com/bytedance/gopkg/util/logger" "github.com/samber/lo" "github.com/gin-gonic/gin" @@ -190,8 +188,12 @@ func (a *TaskAdaptor) DoResponse(c *gin.Context, resp *http.Response, info *rela taskErr = service.TaskErrorWrapperLocal(fmt.Errorf(kResp.Message), "task_failed", http.StatusBadRequest) return } - kResp.TaskId = kResp.Data.TaskId - c.JSON(http.StatusOK, kResp) + ov := relaycommon.NewOpenAIVideo() + ov.ID = kResp.Data.TaskId + ov.TaskID = kResp.Data.TaskId + ov.CreatedAt = time.Now().Unix() + ov.Model = info.OriginModelName + c.JSON(http.StatusOK, ov) return kResp.Data.TaskId, responseBody, nil } @@ -371,31 +373,17 @@ func (a *TaskAdaptor) ConvertToOpenAIVideo(originTask *model.Task) (*relaycommon return nil, errors.Wrap(err, "unmarshal kling task data failed") } - convertProgress := func(progress string) int { - progress = strings.TrimSuffix(progress, "%") - p, err := strconv.Atoi(progress) - if err != nil { - logger.Warnf("convert progress failed, progress: %s, err: %v", progress, err) - } - return p - } + openAIVideo := relaycommon.NewOpenAIVideo() + openAIVideo.ID = originTask.TaskID + openAIVideo.Status = originTask.Status.ToVideoStatus() + openAIVideo.SetProgressStr(originTask.Progress) + openAIVideo.CreatedAt = klingResp.Data.CreatedAt + openAIVideo.CompletedAt = klingResp.Data.UpdatedAt - openAIVideo := &relaycommon.OpenAIVideo{ - ID: klingResp.Data.TaskId, - Object: "video", - //Model: "kling-v1", //todo save model - Status: string(originTask.Status), - CreatedAt: klingResp.Data.CreatedAt, - CompletedAt: klingResp.Data.UpdatedAt, - Metadata: make(map[string]any), - Progress: convertProgress(originTask.Progress), - } - - // 处理视频 URL if len(klingResp.Data.TaskResult.Videos) > 0 { video := klingResp.Data.TaskResult.Videos[0] if video.Url != "" { - openAIVideo.Metadata["url"] = video.Url + openAIVideo.SetMetadata("url", video.Url) } if video.Duration != "" { openAIVideo.Seconds = video.Duration diff --git a/relay/channel/task/vidu/adaptor.go b/relay/channel/task/vidu/adaptor.go index 019352c61..6a961c7d5 100644 --- a/relay/channel/task/vidu/adaptor.go +++ b/relay/channel/task/vidu/adaptor.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "net/http" + "time" "github.com/gin-gonic/gin" @@ -135,7 +136,7 @@ func (a *TaskAdaptor) DoRequest(c *gin.Context, info *relaycommon.RelayInfo, req return channel.DoTaskApiRequest(a, c, info, requestBody) } -func (a *TaskAdaptor) DoResponse(c *gin.Context, resp *http.Response, _ *relaycommon.RelayInfo) (taskID string, taskData []byte, taskErr *dto.TaskError) { +func (a *TaskAdaptor) DoResponse(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo) (taskID string, taskData []byte, taskErr *dto.TaskError) { responseBody, err := io.ReadAll(resp.Body) if err != nil { taskErr = service.TaskErrorWrapper(err, "read_response_body_failed", http.StatusInternalServerError) @@ -154,7 +155,12 @@ func (a *TaskAdaptor) DoResponse(c *gin.Context, resp *http.Response, _ *relayco return } - c.JSON(http.StatusOK, vResp) + ov := relaycommon.NewOpenAIVideo() + ov.ID = vResp.TaskId + ov.TaskID = vResp.TaskId + ov.CreatedAt = time.Now().Unix() + ov.Model = info.OriginModelName + c.JSON(http.StatusOK, ov) return vResp.TaskId, responseBody, nil } @@ -256,3 +262,30 @@ func (a *TaskAdaptor) ParseTaskResult(respBody []byte) (*relaycommon.TaskInfo, e return taskInfo, nil } + +func (a *TaskAdaptor) ConvertToOpenAIVideo(originTask *model.Task) (*relaycommon.OpenAIVideo, error) { + var viduResp taskResultResponse + if err := json.Unmarshal(originTask.Data, &viduResp); err != nil { + return nil, errors.Wrap(err, "unmarshal vidu task data failed") + } + + openAIVideo := relaycommon.NewOpenAIVideo() + openAIVideo.ID = originTask.TaskID + openAIVideo.Status = originTask.Status.ToVideoStatus() + openAIVideo.SetProgressStr(originTask.Progress) + openAIVideo.CreatedAt = originTask.CreatedAt + openAIVideo.CompletedAt = originTask.UpdatedAt + + if len(viduResp.Creations) > 0 && viduResp.Creations[0].URL != "" { + openAIVideo.SetMetadata("url", viduResp.Creations[0].URL) + } + + if viduResp.State == "failed" && viduResp.ErrCode != "" { + openAIVideo.Error = &relaycommon.OpenAIVideoError{ + Message: viduResp.ErrCode, + Code: viduResp.ErrCode, + } + } + + return openAIVideo, nil +} diff --git a/relay/common/relay_info.go b/relay/common/relay_info.go index 35df62f80..c7c73980f 100644 --- a/relay/common/relay_info.go +++ b/relay/common/relay_info.go @@ -551,24 +551,3 @@ func RemoveDisabledFields(jsonData []byte, channelOtherSettings dto.ChannelOther } return jsonDataAfter, nil } - -type OpenAIVideo struct { - ID string `json:"id"` - TaskID string `json:"task_id,omitempty"` //兼容旧接口 待废弃 - Object string `json:"object"` - Model string `json:"model"` - Status string `json:"status"` - Progress int `json:"progress"` - CreatedAt int64 `json:"created_at"` - CompletedAt int64 `json:"completed_at,omitempty"` - ExpiresAt int64 `json:"expires_at,omitempty"` - Seconds string `json:"seconds,omitempty"` - Size string `json:"size,omitempty"` - RemixedFromVideoID string `json:"remixed_from_video_id,omitempty"` - Error *OpenAIVideoError `json:"error,omitempty"` - Metadata map[string]any `json:"metadata,omitempty"` -} -type OpenAIVideoError struct { - Message string `json:"message"` - Code string `json:"code"` -} diff --git a/relay/common/relay_video.go b/relay/common/relay_video.go new file mode 100644 index 000000000..6f7e9cd84 --- /dev/null +++ b/relay/common/relay_video.go @@ -0,0 +1,52 @@ +package common + +import ( + "strconv" + "strings" +) + +const ( + VideoStatusUnknown = "unknown" + VideoStatusQueued = "queued" + VideoStatusInProgress = "in_progress" + VideoStatusCompleted = "completed" + VideoStatusFailed = "failed" +) + +type OpenAIVideo struct { + ID string `json:"id"` + TaskID string `json:"task_id,omitempty"` //兼容旧接口 待废弃 + Object string `json:"object"` + Model string `json:"model"` + Status string `json:"status"` // Should use VideoStatus constants: VideoStatusQueued, VideoStatusInProgress, VideoStatusCompleted, VideoStatusFailed + Progress int `json:"progress"` + CreatedAt int64 `json:"created_at"` + CompletedAt int64 `json:"completed_at,omitempty"` + ExpiresAt int64 `json:"expires_at,omitempty"` + Seconds string `json:"seconds,omitempty"` + Size string `json:"size,omitempty"` + RemixedFromVideoID string `json:"remixed_from_video_id,omitempty"` + Error *OpenAIVideoError `json:"error,omitempty"` + Metadata map[string]any `json:"metadata,omitempty"` +} + +func (m *OpenAIVideo) SetProgressStr(progress string) { + progress = strings.TrimSuffix(progress, "%") + m.Progress, _ = strconv.Atoi(progress) +} +func (m *OpenAIVideo) SetMetadata(k string, v any) { + if m.Metadata == nil { + m.Metadata = make(map[string]any) + } + m.Metadata[k] = v +} +func NewOpenAIVideo() *OpenAIVideo { + return &OpenAIVideo{ + Object: "video", + } +} + +type OpenAIVideoError struct { + Message string `json:"message"` + Code string `json:"code"` +}