132 lines
4.0 KiB
Go
132 lines
4.0 KiB
Go
package providers
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
const MinimaxH3Model = "MiniMax-H3"
|
|
|
|
// Minimax adapts the MiniMax H3 V2 asynchronous video API to the common
|
|
// provider contract. Request validation for first-frame and multi-reference
|
|
// modes lives in jobs.
|
|
type Minimax struct{ *httpAdapter }
|
|
|
|
func NewMinimax(c Config, client HTTPClient) *Minimax {
|
|
if client == nil {
|
|
client = http.DefaultClient
|
|
}
|
|
if strings.TrimSpace(c.Model) == "" {
|
|
c.Model = MinimaxH3Model
|
|
}
|
|
a := &httpAdapter{
|
|
name: "minimax",
|
|
config: c,
|
|
client: client,
|
|
submitPath: func(Request) string { return "/v2/video_generation" },
|
|
queryPath: func(id string) string { return "/v2/query/video_generation/" + id },
|
|
payload: func(r Request) any {
|
|
content := []any{map[string]any{"type": "text", "text": r.Prompt}}
|
|
materials := r.Materials
|
|
if len(materials) == 0 && len(r.InputURLs) > 0 {
|
|
materials = make([]Material, 0, len(r.InputURLs))
|
|
for _, inputURL := range r.InputURLs {
|
|
materials = append(materials, Material{URL: inputURL, Type: MaterialImage})
|
|
}
|
|
}
|
|
role := "first_frame"
|
|
if r.Settings["inputMode"] == "reference" {
|
|
role = "reference_image"
|
|
}
|
|
for _, material := range materials {
|
|
content = append(content, map[string]any{
|
|
"type": "image_url",
|
|
"image_url": map[string]any{"url": material.URL},
|
|
"role": role,
|
|
})
|
|
}
|
|
return map[string]any{
|
|
"model": requestModel(r, c.Model),
|
|
"content": content,
|
|
"resolution": r.Settings["resolution"],
|
|
"duration": r.Settings["duration"],
|
|
"ratio": r.Settings["ratio"],
|
|
"aigc_watermark": false,
|
|
}
|
|
},
|
|
decode: decodeMinimax,
|
|
failureDetail: func(responseBody, requestBody []byte) string {
|
|
return minimaxSafeFailureDetail(responseBody, requestBody, c.APIKey)
|
|
},
|
|
}
|
|
return &Minimax{a}
|
|
}
|
|
|
|
func (a *Minimax) Submit(ctx context.Context, request Request) (Result, error) {
|
|
result, err := a.submit(ctx, request)
|
|
if err != nil {
|
|
logMinimaxFailedRequest(request, a.config, err)
|
|
}
|
|
return result, err
|
|
}
|
|
|
|
func (a *Minimax) Query(ctx context.Context, id string) (Result, error) {
|
|
return a.query(ctx, id)
|
|
}
|
|
|
|
func decodeMinimax(raw []byte) Result {
|
|
root := record(raw)
|
|
task := object(root["task"])
|
|
if len(task) == 0 {
|
|
return Result{TaskID: stringValue(root["task_id"]), Status: StatusQueued}
|
|
}
|
|
outputURLs := []string{}
|
|
collectURLs(object(task["content"])["url"], &outputURLs)
|
|
usage := map[string]int{}
|
|
for source, target := range map[string]string{
|
|
"total_seconds": "totalSeconds",
|
|
"input_seconds": "inputSeconds",
|
|
"output_seconds": "outputSeconds",
|
|
"input_image_count": "inputImageCount",
|
|
"input_audio_seconds": "inputAudioSeconds",
|
|
"total_tokens": "totalTokens",
|
|
"prompt_tokens": "promptTokens",
|
|
"completion_tokens": "completionTokens",
|
|
} {
|
|
if number, ok := object(task["usage"])[source].(float64); ok && number >= 0 {
|
|
usage[target] = int(number)
|
|
}
|
|
}
|
|
providerError := object(task["error"])
|
|
resultStatus := status(task["status"])
|
|
errorMessage := minimaxTaskFailureMessage(safeHTTPProviderDiagnosticToken(providerError["code"], 16), stringValue(providerError["message"]))
|
|
if resultStatus == StatusFailed && errorMessage == "" {
|
|
errorMessage = "MiniMax 视频生成失败,请调整提示词或素材后重试。"
|
|
}
|
|
return Result{
|
|
TaskID: stringValue(task["id"], root["task_id"]),
|
|
Status: resultStatus,
|
|
OutputURLs: outputURLs,
|
|
ErrorMessage: errorMessage,
|
|
Usage: usage,
|
|
}
|
|
}
|
|
|
|
func minimaxTaskFailureMessage(code, message string) string {
|
|
switch strings.TrimSpace(code) {
|
|
case "1008":
|
|
return "MiniMax API 账户余额不足,请充值后重试。"
|
|
case "1026":
|
|
return "视频描述或输入素材触发内容安全审核,请调整后重试。"
|
|
case "1002":
|
|
return "MiniMax 请求频率过高,请稍后重试。"
|
|
}
|
|
if strings.TrimSpace(message) != "" {
|
|
return "MiniMax 视频生成失败,请调整提示词或素材后重试。"
|
|
}
|
|
return ""
|
|
}
|
|
|
|
var _ Adapter = (*Minimax)(nil)
|