Przeglądaj źródła

Merge pull request #2018 from feitianbubu/pr/add-jimeng-vidu-openai-sdk

即梦和vidu支持 OpenAI sdk生成和查询视频
Seefs 2 miesięcy temu
rodzic
commit
77f8e51b56

+ 17 - 0
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"

+ 30 - 1
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-")
 }

+ 13 - 25
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.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),
-	}
+	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
 
-	// 处理视频 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

+ 35 - 2
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
+}

+ 0 - 21
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"`
-}

+ 52 - 0
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"`
+}