feat: publish v1.0.0-rc.36-custom.1
This commit is contained in:
commit
3a7e8f3b54
2381 files changed
+551494
No files matched your search
@@ -0,0 +1,115 @@
|
||||
package dto
|
||||
|
||||
type ChannelPinSource string
|
||||
|
||||
const (
|
||||
PinSourceToken ChannelPinSource = "token" // Rank 0, highest
|
||||
PinSourceOriginTask ChannelPinSource = "origin_task" // Rank 10
|
||||
)
|
||||
|
||||
const (
|
||||
PinRankToken = 0
|
||||
PinRankOriginTask = 10
|
||||
)
|
||||
|
||||
type PinRetryMode int
|
||||
|
||||
const (
|
||||
PinRetrySameChannel PinRetryMode = iota
|
||||
PinRetrySingleAttempt
|
||||
)
|
||||
|
||||
func (m PinRetryMode) Stricter(other PinRetryMode) PinRetryMode {
|
||||
if m == PinRetrySingleAttempt || other == PinRetrySingleAttempt {
|
||||
return PinRetrySingleAttempt
|
||||
}
|
||||
return PinRetrySameChannel
|
||||
}
|
||||
|
||||
type ChannelPin struct {
|
||||
ChannelId int
|
||||
Source ChannelPinSource
|
||||
Rank int
|
||||
RetryMode PinRetryMode
|
||||
}
|
||||
|
||||
type ChannelFilterKind string
|
||||
|
||||
const (
|
||||
FilterRequestPath ChannelFilterKind = "request_path"
|
||||
FilterTaskPluginIdentity ChannelFilterKind = "task_plugin_identity"
|
||||
)
|
||||
|
||||
type ChannelFilter struct {
|
||||
Kind ChannelFilterKind
|
||||
RequestPath string
|
||||
TaskPluginKey string
|
||||
TaskPluginChannelTypes []int
|
||||
}
|
||||
|
||||
type ChannelConstraints struct {
|
||||
Pins []ChannelPin
|
||||
Filters []ChannelFilter
|
||||
}
|
||||
|
||||
func (cc *ChannelConstraints) AddPin(p ChannelPin) {
|
||||
if cc == nil {
|
||||
return
|
||||
}
|
||||
cc.Pins = append(cc.Pins, p)
|
||||
}
|
||||
|
||||
func (cc *ChannelConstraints) AddFilter(f ChannelFilter) {
|
||||
if cc == nil {
|
||||
return
|
||||
}
|
||||
cc.Filters = append(cc.Filters, f)
|
||||
}
|
||||
|
||||
// ResolvedPin returns the winning pin after priority resolution.
|
||||
// Lowest Rank wins. Pins that name the same channel are merged (stricter RetryMode).
|
||||
// overridden lists pins that lost to a different channel (for warn logging).
|
||||
func (cc *ChannelConstraints) ResolvedPin() (ChannelPin, bool, []ChannelPin) {
|
||||
if cc == nil || len(cc.Pins) == 0 {
|
||||
return ChannelPin{}, false, nil
|
||||
}
|
||||
|
||||
merged := make(map[int]ChannelPin, len(cc.Pins))
|
||||
order := make([]int, 0, len(cc.Pins))
|
||||
for _, pin := range cc.Pins {
|
||||
existing, seen := merged[pin.ChannelId]
|
||||
if !seen {
|
||||
merged[pin.ChannelId] = pin
|
||||
order = append(order, pin.ChannelId)
|
||||
continue
|
||||
}
|
||||
existing.RetryMode = existing.RetryMode.Stricter(pin.RetryMode)
|
||||
if pin.Rank < existing.Rank {
|
||||
existing.Rank = pin.Rank
|
||||
existing.Source = pin.Source
|
||||
}
|
||||
merged[pin.ChannelId] = existing
|
||||
}
|
||||
|
||||
winner := merged[order[0]]
|
||||
for _, channelID := range order[1:] {
|
||||
candidate := merged[channelID]
|
||||
if candidate.Rank < winner.Rank {
|
||||
winner = candidate
|
||||
}
|
||||
}
|
||||
|
||||
var overridden []ChannelPin
|
||||
for _, channelID := range order {
|
||||
candidate := merged[channelID]
|
||||
if candidate.ChannelId != winner.ChannelId {
|
||||
overridden = append(overridden, candidate)
|
||||
}
|
||||
}
|
||||
return winner, true, overridden
|
||||
}
|
||||
|
||||
func (cc *ChannelConstraints) SuppressesRetry() bool {
|
||||
pin, found, _ := cc.ResolvedPin()
|
||||
return found && pin.RetryMode == PinRetrySingleAttempt
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestResolvedPinPriorityAndMerge(t *testing.T) {
|
||||
t.Run("token pin beats origin pin on a different channel", func(t *testing.T) {
|
||||
constraints := &ChannelConstraints{}
|
||||
constraints.AddPin(ChannelPin{ChannelId: 10, Source: PinSourceOriginTask, Rank: PinRankOriginTask, RetryMode: PinRetrySameChannel})
|
||||
constraints.AddPin(ChannelPin{ChannelId: 1, Source: PinSourceToken, Rank: PinRankToken, RetryMode: PinRetrySingleAttempt})
|
||||
|
||||
pin, found, overridden := constraints.ResolvedPin()
|
||||
require.True(t, found)
|
||||
assert.Equal(t, 1, pin.ChannelId)
|
||||
assert.Equal(t, PinSourceToken, pin.Source)
|
||||
assert.Equal(t, PinRetrySingleAttempt, pin.RetryMode)
|
||||
require.Len(t, overridden, 1)
|
||||
assert.Equal(t, PinSourceOriginTask, overridden[0].Source)
|
||||
assert.Equal(t, 10, overridden[0].ChannelId)
|
||||
})
|
||||
|
||||
t.Run("same channel pins merge to the stricter retry mode", func(t *testing.T) {
|
||||
constraints := &ChannelConstraints{}
|
||||
constraints.AddPin(ChannelPin{ChannelId: 7, Source: PinSourceOriginTask, Rank: PinRankOriginTask, RetryMode: PinRetrySameChannel})
|
||||
constraints.AddPin(ChannelPin{ChannelId: 7, Source: PinSourceToken, Rank: PinRankToken, RetryMode: PinRetrySingleAttempt})
|
||||
|
||||
pin, found, overridden := constraints.ResolvedPin()
|
||||
require.True(t, found)
|
||||
assert.Equal(t, 7, pin.ChannelId)
|
||||
assert.Equal(t, PinSourceToken, pin.Source)
|
||||
assert.Equal(t, PinRetrySingleAttempt, pin.RetryMode)
|
||||
assert.Empty(t, overridden)
|
||||
assert.True(t, constraints.SuppressesRetry())
|
||||
})
|
||||
|
||||
t.Run("empty set has no pin", func(t *testing.T) {
|
||||
pin, found, overridden := (*ChannelConstraints)(nil).ResolvedPin()
|
||||
assert.False(t, found)
|
||||
assert.Zero(t, pin.ChannelId)
|
||||
assert.Nil(t, overridden)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package dto
|
||||
|
||||
//type SimpleMjRequest struct {
|
||||
// Prompt string `json:"prompt"`
|
||||
// CustomId string `json:"customId"`
|
||||
// Action string `json:"action"`
|
||||
// Content string `json:"content"`
|
||||
//}
|
||||
|
||||
type SwapFaceRequest struct {
|
||||
SourceBase64 string `json:"sourceBase64"`
|
||||
TargetBase64 string `json:"targetBase64"`
|
||||
}
|
||||
|
||||
type MidjourneyRequest struct {
|
||||
Prompt string `json:"prompt"`
|
||||
CustomId string `json:"customId"`
|
||||
BotType string `json:"botType"`
|
||||
NotifyHook string `json:"notifyHook"`
|
||||
Action string `json:"action"`
|
||||
Index int `json:"index"`
|
||||
State string `json:"state"`
|
||||
TaskId string `json:"taskId"`
|
||||
Base64Array []string `json:"base64Array"`
|
||||
Content string `json:"content"`
|
||||
MaskBase64 string `json:"maskBase64"`
|
||||
}
|
||||
|
||||
type MidjourneyResponse struct {
|
||||
Code int `json:"code"`
|
||||
Description string `json:"description"`
|
||||
Properties any `json:"properties"`
|
||||
Result string `json:"result"`
|
||||
}
|
||||
|
||||
type MidjourneyUploadResponse struct {
|
||||
Code int `json:"code"`
|
||||
Description string `json:"description"`
|
||||
Result []string `json:"result"`
|
||||
}
|
||||
|
||||
type MidjourneyResponseWithStatusCode struct {
|
||||
StatusCode int `json:"statusCode"`
|
||||
Response MidjourneyResponse
|
||||
}
|
||||
|
||||
type MidjourneyDto struct {
|
||||
MjId string `json:"id"`
|
||||
Action string `json:"action"`
|
||||
CustomId string `json:"customId"`
|
||||
BotType string `json:"botType"`
|
||||
Prompt string `json:"prompt"`
|
||||
PromptEn string `json:"promptEn"`
|
||||
Description string `json:"description"`
|
||||
State string `json:"state"`
|
||||
SubmitTime int64 `json:"submitTime"`
|
||||
StartTime int64 `json:"startTime"`
|
||||
FinishTime int64 `json:"finishTime"`
|
||||
ImageUrl string `json:"imageUrl"`
|
||||
VideoUrl string `json:"videoUrl"`
|
||||
VideoUrls []ImgUrls `json:"videoUrls"`
|
||||
Status string `json:"status"`
|
||||
Progress string `json:"progress"`
|
||||
FailReason string `json:"failReason"`
|
||||
Buttons any `json:"buttons"`
|
||||
MaskBase64 string `json:"maskBase64"`
|
||||
Properties *Properties `json:"properties"`
|
||||
}
|
||||
|
||||
type ImgUrls struct {
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type MidjourneyStatus struct {
|
||||
Status int `json:"status"`
|
||||
}
|
||||
type MidjourneyWithoutStatus struct {
|
||||
Id int `json:"id"`
|
||||
Code int `json:"code"`
|
||||
UserId int `json:"user_id" gorm:"index"`
|
||||
Action string `json:"action"`
|
||||
MjId string `json:"mj_id" gorm:"index"`
|
||||
Prompt string `json:"prompt"`
|
||||
PromptEn string `json:"prompt_en"`
|
||||
Description string `json:"description"`
|
||||
State string `json:"state"`
|
||||
SubmitTime int64 `json:"submit_time"`
|
||||
StartTime int64 `json:"start_time"`
|
||||
FinishTime int64 `json:"finish_time"`
|
||||
ImageUrl string `json:"image_url"`
|
||||
Progress string `json:"progress"`
|
||||
FailReason string `json:"fail_reason"`
|
||||
ChannelId int `json:"channel_id"`
|
||||
}
|
||||
|
||||
type ActionButton struct {
|
||||
CustomId any `json:"customId"`
|
||||
Emoji any `json:"emoji"`
|
||||
Label any `json:"label"`
|
||||
Type any `json:"type"`
|
||||
Style any `json:"style"`
|
||||
}
|
||||
|
||||
type Properties struct {
|
||||
FinalPrompt string `json:"finalPrompt"`
|
||||
FinalZhPrompt string `json:"finalZhPrompt"`
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package dto
|
||||
|
||||
// PluginResponsesResponse is the host-owned Responses facade used for stream
|
||||
// snapshots and sanitized terminal failures. Non-stream success objects may
|
||||
// retain additional validated plugin fields, but identifiers, lifecycle state,
|
||||
// and retrieval metadata are always populated by the host.
|
||||
type PluginResponsesResponse struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
Status string `json:"status"`
|
||||
Error *PluginResponsesError `json:"error"`
|
||||
IncompleteDetails *PluginResponsesIncompleteDetail `json:"incomplete_details"`
|
||||
Instructions any `json:"instructions"`
|
||||
Model string `json:"model"`
|
||||
Output []PluginResponsesOutput `json:"output"`
|
||||
ParallelToolCalls bool `json:"parallel_tool_calls"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
ToolChoice any `json:"tool_choice"`
|
||||
Tools []any `json:"tools"`
|
||||
TopP float64 `json:"top_p"`
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
Usage *PluginResponsesUsage `json:"usage"`
|
||||
}
|
||||
|
||||
type PluginResponsesError struct {
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type PluginResponsesIncompleteDetail struct {
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
type PluginResponsesUsage struct {
|
||||
InputTokens int `json:"input_tokens"`
|
||||
InputTokensDetails PluginResponsesInputTokenDetails `json:"input_tokens_details"`
|
||||
OutputTokens int `json:"output_tokens"`
|
||||
OutputTokensDetails PluginResponsesOutputTokenDetails `json:"output_tokens_details"`
|
||||
TotalTokens int `json:"total_tokens"`
|
||||
}
|
||||
|
||||
type PluginResponsesInputTokenDetails struct {
|
||||
CachedTokens int `json:"cached_tokens"`
|
||||
}
|
||||
|
||||
type PluginResponsesOutputTokenDetails struct {
|
||||
ReasoningTokens int `json:"reasoning_tokens"`
|
||||
}
|
||||
|
||||
type PluginResponsesOutput struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Status string `json:"status"`
|
||||
Role string `json:"role"`
|
||||
Content []PluginResponsesContent `json:"content"`
|
||||
}
|
||||
|
||||
type PluginResponsesContent struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Text string `json:"text"`
|
||||
Annotations []any `json:"annotations"`
|
||||
Logprobs []any `json:"logprobs"`
|
||||
}
|
||||
|
||||
// PluginResponsesStreamEvent contains the exact event-specific fields used by
|
||||
// the host Responses state machine. Pointer fields preserve required empty
|
||||
// strings and arrays on delta/done events while omitting unrelated fields.
|
||||
type PluginResponsesStreamEvent struct {
|
||||
Type string `json:"type"`
|
||||
SequenceNumber int `json:"sequence_number"`
|
||||
Response *PluginResponsesResponse `json:"response,omitempty"`
|
||||
OutputIndex *int `json:"output_index,omitempty"`
|
||||
ContentIndex *int `json:"content_index,omitempty"`
|
||||
ItemID string `json:"item_id,omitempty"`
|
||||
Item *PluginResponsesOutput `json:"item,omitempty"`
|
||||
Part *PluginResponsesContent `json:"part,omitempty"`
|
||||
Delta *string `json:"delta,omitempty"`
|
||||
Text *string `json:"text,omitempty"`
|
||||
Logprobs *[]any `json:"logprobs,omitempty"`
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
type SunoSubmitReq struct {
|
||||
GptDescriptionPrompt string `json:"gpt_description_prompt,omitempty"`
|
||||
Prompt string `json:"prompt,omitempty"`
|
||||
Mv string `json:"mv,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Tags string `json:"tags,omitempty"`
|
||||
ContinueAt float64 `json:"continue_at,omitempty"`
|
||||
TaskID string `json:"task_id,omitempty"`
|
||||
ContinueClipId string `json:"continue_clip_id,omitempty"`
|
||||
MakeInstrumental bool `json:"make_instrumental"`
|
||||
}
|
||||
|
||||
type SunoDataResponse struct {
|
||||
TaskID string `json:"task_id" gorm:"type:varchar(50);index"`
|
||||
Action string `json:"action" gorm:"type:varchar(40);index"` // 任务类型, song, lyrics, description-mode
|
||||
Status string `json:"status" gorm:"type:varchar(20);index"` // 任务状态, submitted, queueing, processing, success, failed
|
||||
FailReason string `json:"fail_reason"`
|
||||
SubmitTime int64 `json:"submit_time" gorm:"index"`
|
||||
StartTime int64 `json:"start_time" gorm:"index"`
|
||||
FinishTime int64 `json:"finish_time" gorm:"index"`
|
||||
Data json.RawMessage `json:"data" gorm:"type:json"`
|
||||
}
|
||||
|
||||
type SunoSong struct {
|
||||
ID string `json:"id"`
|
||||
VideoURL string `json:"video_url"`
|
||||
AudioURL string `json:"audio_url"`
|
||||
ImageURL string `json:"image_url"`
|
||||
ImageLargeURL string `json:"image_large_url"`
|
||||
MajorModelVersion string `json:"major_model_version"`
|
||||
ModelName string `json:"model_name"`
|
||||
Status string `json:"status"`
|
||||
Title string `json:"title"`
|
||||
Text string `json:"text"`
|
||||
Metadata SunoMetadata `json:"metadata"`
|
||||
}
|
||||
|
||||
type SunoMetadata struct {
|
||||
Tags string `json:"tags"`
|
||||
Prompt string `json:"prompt"`
|
||||
GPTDescriptionPrompt any `json:"gpt_description_prompt"`
|
||||
AudioPromptID any `json:"audio_prompt_id"`
|
||||
Duration any `json:"duration"`
|
||||
ErrorType any `json:"error_type"`
|
||||
ErrorMessage any `json:"error_message"`
|
||||
}
|
||||
|
||||
type SunoLyrics struct {
|
||||
ID string `json:"id"`
|
||||
Status string `json:"status"`
|
||||
Title string `json:"title"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
type SunoGoAPISubmitReq struct {
|
||||
CustomMode bool `json:"custom_mode"`
|
||||
|
||||
Input SunoGoAPISubmitReqInput `json:"input"`
|
||||
|
||||
NotifyHook string `json:"notify_hook,omitempty"`
|
||||
}
|
||||
|
||||
type SunoGoAPISubmitReqInput struct {
|
||||
GptDescriptionPrompt string `json:"gpt_description_prompt"`
|
||||
Prompt string `json:"prompt"`
|
||||
Mv string `json:"mv"`
|
||||
Title string `json:"title"`
|
||||
Tags string `json:"tags"`
|
||||
ContinueAt float64 `json:"continue_at"`
|
||||
TaskID string `json:"task_id"`
|
||||
ContinueClipId string `json:"continue_clip_id"`
|
||||
MakeInstrumental bool `json:"make_instrumental"`
|
||||
}
|
||||
|
||||
type GoAPITaskResponse[T any] struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data T `json:"data"`
|
||||
ErrorMessage string `json:"error_message,omitempty"`
|
||||
}
|
||||
|
||||
type GoAPITaskResponseData struct {
|
||||
TaskID string `json:"task_id"`
|
||||
}
|
||||
|
||||
type GoAPIFetchResponseData struct {
|
||||
TaskID string `json:"task_id"`
|
||||
Status string `json:"status"`
|
||||
Input string `json:"input"`
|
||||
Clips map[string]SunoSong `json:"clips"`
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
type TaskError struct {
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data any `json:"data"`
|
||||
StatusCode int `json:"-"`
|
||||
LocalError bool `json:"-"`
|
||||
Error error `json:"-"`
|
||||
}
|
||||
|
||||
type TaskData interface {
|
||||
SunoDataResponse | []SunoDataResponse | string | any
|
||||
}
|
||||
|
||||
const TaskSuccessCode = "success"
|
||||
|
||||
type TaskResponse[T TaskData] struct {
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data T `json:"data"`
|
||||
}
|
||||
|
||||
func (t *TaskResponse[T]) IsSuccess() bool {
|
||||
return t.Code == TaskSuccessCode
|
||||
}
|
||||
|
||||
type TaskDto struct {
|
||||
ID int64 `json:"id"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
TaskID string `json:"task_id"`
|
||||
Platform string `json:"platform"`
|
||||
UserId int `json:"user_id"`
|
||||
Group string `json:"group"`
|
||||
ChannelId int `json:"channel_id"`
|
||||
Quota int `json:"quota"`
|
||||
Action string `json:"action"`
|
||||
Status string `json:"status"`
|
||||
FailReason string `json:"fail_reason"`
|
||||
ResultURL string `json:"result_url,omitempty"` // 任务结果 URL(视频地址等)
|
||||
LegacyVideoAvailable bool `json:"legacy_video_available,omitempty"`
|
||||
SubmitTime int64 `json:"submit_time"`
|
||||
StartTime int64 `json:"start_time"`
|
||||
FinishTime int64 `json:"finish_time"`
|
||||
Progress string `json:"progress"`
|
||||
Properties any `json:"properties"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
AdminInfo *TaskAdminInfo `json:"admin_info,omitempty"`
|
||||
RootInfo *TaskRootInfo `json:"root_info,omitempty"`
|
||||
}
|
||||
|
||||
type TaskPluginInfo struct {
|
||||
Key string `json:"key"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version,omitempty"`
|
||||
Author *TaskPluginAuthorInfo `json:"author,omitempty"`
|
||||
}
|
||||
|
||||
type TaskPluginAuthorInfo struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
type TaskPluginRuntimeInfo struct {
|
||||
Key string `json:"key"`
|
||||
Version string `json:"version"`
|
||||
APIVersion int `json:"api_version"`
|
||||
Generation uint64 `json:"generation"`
|
||||
}
|
||||
|
||||
type TaskAdminInfo struct {
|
||||
RequestID string `json:"request_id,omitempty"`
|
||||
RequestPath string `json:"request_path,omitempty"`
|
||||
TaskPlugin *TaskPluginInfo `json:"task_plugin,omitempty"`
|
||||
}
|
||||
|
||||
type TaskRootInfo struct {
|
||||
TaskPlugin *TaskPluginRuntimeInfo `json:"task_plugin,omitempty"`
|
||||
UpstreamTaskID string `json:"upstream_task_id,omitempty"`
|
||||
NodeName string `json:"node_name,omitempty"`
|
||||
}
|
||||
|
||||
type FetchReq struct {
|
||||
IDs []string `json:"ids"`
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package dto
|
||||
|
||||
type TaskPluginError struct {
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
HTTPStatus int `json:"httpStatus"`
|
||||
Retryable bool `json:"retryable"`
|
||||
}
|
||||
|
||||
// TaskView is the only persisted-task shape exposed to JavaScript plugins.
|
||||
// It deliberately excludes ownership, channel, quota, properties, and private
|
||||
// upstream identifiers.
|
||||
type TaskView struct {
|
||||
TaskID string `json:"task_id"`
|
||||
Platform string `json:"platform"`
|
||||
Status string `json:"status"`
|
||||
Progress string `json:"progress"`
|
||||
FailReason string `json:"fail_reason"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at,omitempty"`
|
||||
FinishedAt int64 `json:"finished_at,omitempty"`
|
||||
Data any `json:"data,omitempty"`
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package dto
|
||||
|
||||
type VideoRequest struct {
|
||||
Model string `json:"model,omitempty" example:"kling-v1"` // Model/style ID
|
||||
Prompt string `json:"prompt,omitempty" example:"宇航员站起身走了"` // Text prompt
|
||||
Image string `json:"image,omitempty" example:"https://h2.inkwai.com/bs2/upload-ylab-stunt/se/ai_portal_queue_mmu_image_upscale_aiweb/3214b798-e1b4-4b00-b7af-72b5b0417420_raw_image_0.jpg"` // Image input (URL/Base64)
|
||||
Duration float64 `json:"duration" example:"5.0"` // Video duration (seconds)
|
||||
Width int `json:"width" example:"512"` // Video width
|
||||
Height int `json:"height" example:"512"` // Video height
|
||||
Fps int `json:"fps,omitempty" example:"30"` // Video frame rate
|
||||
Seed int `json:"seed,omitempty" example:"20231234"` // Random seed
|
||||
N int `json:"n,omitempty" example:"1"` // Number of videos to generate
|
||||
ResponseFormat string `json:"response_format,omitempty" example:"url"` // Response format
|
||||
User string `json:"user,omitempty" example:"user-1234"` // User identifier
|
||||
Metadata map[string]any `json:"metadata,omitempty"` // Vendor-specific/custom params (e.g. negative_prompt, style, quality_level, etc.)
|
||||
}
|
||||
|
||||
// VideoResponse 视频生成提交任务后的响应
|
||||
type VideoResponse struct {
|
||||
TaskId string `json:"task_id"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// VideoTaskResponse 查询视频生成任务状态的响应
|
||||
type VideoTaskResponse struct {
|
||||
TaskId string `json:"task_id" example:"abcd1234efgh"` // 任务ID
|
||||
Status string `json:"status" example:"succeeded"` // 任务状态
|
||||
Url string `json:"url,omitempty"` // 视频资源URL(成功时)
|
||||
Format string `json:"format,omitempty" example:"mp4"` // 视频格式
|
||||
Metadata *VideoTaskMetadata `json:"metadata,omitempty"` // 结果元数据
|
||||
Error *VideoTaskError `json:"error,omitempty"` // 错误信息(失败时)
|
||||
}
|
||||
|
||||
// VideoTaskMetadata 视频任务元数据
|
||||
type VideoTaskMetadata struct {
|
||||
Duration float64 `json:"duration" example:"5.0"` // 实际生成的视频时长
|
||||
Fps int `json:"fps" example:"30"` // 实际帧率
|
||||
Width int `json:"width" example:"512"` // 实际宽度
|
||||
Height int `json:"height" example:"512"` // 实际高度
|
||||
Seed int `json:"seed" example:"20231234"` // 使用的随机种子
|
||||
}
|
||||
|
||||
// VideoTaskError 视频任务错误信息
|
||||
type VideoTaskError struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
Reference in new issue
Block a user