diff --git a/relay/channel/task/doubao/adaptor.go b/relay/channel/task/doubao/adaptor.go index 8f1d748c..e760e4c9 100644 --- a/relay/channel/task/doubao/adaptor.go +++ b/relay/channel/task/doubao/adaptor.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "net/http" + "strconv" "time" "github.com/QuantumNous/new-api/common" @@ -13,12 +14,13 @@ import ( "github.com/QuantumNous/new-api/dto" "github.com/QuantumNous/new-api/model" "github.com/QuantumNous/new-api/relay/channel" - taskcommon "github.com/QuantumNous/new-api/relay/channel/task/taskcommon" + "github.com/QuantumNous/new-api/relay/channel/task/taskcommon" relaycommon "github.com/QuantumNous/new-api/relay/common" "github.com/QuantumNous/new-api/service" "github.com/gin-gonic/gin" "github.com/pkg/errors" + "github.com/samber/lo" ) // ============================ @@ -26,37 +28,37 @@ import ( // ============================ type ContentItem struct { - Type string `json:"type"` // "text", "image_url" or "video" - Text string `json:"text,omitempty"` // for text type - ImageURL *ImageURL `json:"image_url,omitempty"` // for image_url type - Video *VideoReference `json:"video,omitempty"` // for video (sample) type - Role string `json:"role,omitempty"` // reference_image / first_frame / last_frame + Type string `json:"type,omitempty"` + Text string `json:"text,omitempty"` + ImageURL *MediaURL `json:"image_url,omitempty"` + VideoURL *MediaURL `json:"video_url,omitempty"` + AudioURL *MediaURL `json:"audio_url,omitempty"` + Role string `json:"role,omitempty"` } -type ImageURL struct { - URL string `json:"url"` -} - -type VideoReference struct { - URL string `json:"url"` // Draft video URL +type MediaURL struct { + URL string `json:"url,omitempty"` } type requestPayload struct { Model string `json:"model"` - Content []ContentItem `json:"content"` + Content []ContentItem `json:"content,omitempty"` CallbackURL string `json:"callback_url,omitempty"` ReturnLastFrame *dto.BoolValue `json:"return_last_frame,omitempty"` ServiceTier string `json:"service_tier,omitempty"` - ExecutionExpiresAfter dto.IntValue `json:"execution_expires_after,omitempty"` + ExecutionExpiresAfter *dto.IntValue `json:"execution_expires_after,omitempty"` GenerateAudio *dto.BoolValue `json:"generate_audio,omitempty"` Draft *dto.BoolValue `json:"draft,omitempty"` - Resolution string `json:"resolution,omitempty"` - Ratio string `json:"ratio,omitempty"` - Duration dto.IntValue `json:"duration,omitempty"` - Frames dto.IntValue `json:"frames,omitempty"` - Seed dto.IntValue `json:"seed,omitempty"` - CameraFixed *dto.BoolValue `json:"camera_fixed,omitempty"` - Watermark *dto.BoolValue `json:"watermark,omitempty"` + Tools []struct { + Type string `json:"type,omitempty"` + } `json:"tools,omitempty"` + Resolution string `json:"resolution,omitempty"` + Ratio string `json:"ratio,omitempty"` + Duration *dto.IntValue `json:"duration,omitempty"` + Frames *dto.IntValue `json:"frames,omitempty"` + Seed *dto.IntValue `json:"seed,omitempty"` + CameraFixed *dto.BoolValue `json:"camera_fixed,omitempty"` + Watermark *dto.BoolValue `json:"watermark,omitempty"` } type responsePayload struct { @@ -76,10 +78,20 @@ type responseTask struct { Ratio string `json:"ratio"` FramesPerSecond int `json:"framespersecond"` ServiceTier string `json:"service_tier"` - Usage struct { + Tools []struct { + Type string `json:"type"` + } `json:"tools"` + Usage struct { CompletionTokens int `json:"completion_tokens"` TotalTokens int `json:"total_tokens"` + ToolUsage struct { + WebSearch int `json:"web_search"` + } `json:"tool_usage"` } `json:"usage"` + Error struct { + Code string `json:"code"` + Message string `json:"message"` + } `json:"error"` CreatedAt int64 `json:"created_at"` UpdatedAt int64 `json:"updated_at"` } @@ -108,12 +120,12 @@ func (a *TaskAdaptor) ValidateRequestAndSetAction(c *gin.Context, info *relaycom } // BuildRequestURL constructs the upstream URL. -func (a *TaskAdaptor) BuildRequestURL(info *relaycommon.RelayInfo) (string, error) { +func (a *TaskAdaptor) BuildRequestURL(_ *relaycommon.RelayInfo) (string, error) { return fmt.Sprintf("%s/api/v3/contents/generations/tasks", a.baseURL), nil } // BuildRequestHeader sets required headers. -func (a *TaskAdaptor) BuildRequestHeader(c *gin.Context, req *http.Request, info *relaycommon.RelayInfo) error { +func (a *TaskAdaptor) BuildRequestHeader(_ *gin.Context, req *http.Request, _ *relaycommon.RelayInfo) error { req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", "Bearer "+a.apiKey) @@ -218,20 +230,12 @@ func (a *TaskAdaptor) convertToRequestPayload(req *relaycommon.TaskSubmitReq) (* Content: []ContentItem{}, } - // Add text prompt - if req.Prompt != "" { - r.Content = append(r.Content, ContentItem{ - Type: "text", - Text: req.Prompt, - }) - } - // Add images if present if req.HasImage() { for _, imgURL := range req.Images { r.Content = append(r.Content, ContentItem{ Type: "image_url", - ImageURL: &ImageURL{ + ImageURL: &MediaURL{ URL: imgURL, }, }) @@ -243,6 +247,16 @@ func (a *TaskAdaptor) convertToRequestPayload(req *relaycommon.TaskSubmitReq) (* return nil, errors.Wrap(err, "unmarshal metadata failed") } + if sec, _ := strconv.Atoi(req.Seconds); sec > 0 { + r.Duration = lo.ToPtr(dto.IntValue(sec)) + } + + r.Content = lo.Reject(r.Content, func(c ContentItem, _ int) bool { return c.Type == "text" }) + r.Content = append(r.Content, ContentItem{ + Type: "text", + Text: req.Prompt, + }) + return &r, nil } @@ -274,7 +288,7 @@ func (a *TaskAdaptor) ParseTaskResult(respBody []byte) (*relaycommon.TaskInfo, e case "failed": taskResult.Status = model.TaskStatusFailure taskResult.Progress = "100%" - taskResult.Reason = "task failed" + taskResult.Reason = resTask.Error.Message default: // Unknown status, treat as processing taskResult.Status = model.TaskStatusInProgress @@ -302,8 +316,8 @@ func (a *TaskAdaptor) ConvertToOpenAIVideo(originTask *model.Task) ([]byte, erro if dResp.Status == "failed" { openAIVideo.Error = &dto.OpenAIVideoError{ - Message: "task failed", - Code: "failed", + Message: dResp.Error.Message, + Code: dResp.Error.Code, } } diff --git a/relay/channel/task/doubao/constants.go b/relay/channel/task/doubao/constants.go index 13b1b1d9..417fd587 100644 --- a/relay/channel/task/doubao/constants.go +++ b/relay/channel/task/doubao/constants.go @@ -5,6 +5,8 @@ var ModelList = []string{ "doubao-seedance-1-0-lite-t2v", "doubao-seedance-1-0-lite-i2v", "doubao-seedance-1-5-pro-251215", + "doubao-seedance-2-0-260128", + "doubao-seedance-2-0-fast-260128", } var ChannelName = "doubao-video"