Restore MiniMax media routing parity across image and video flows
The server now keeps portable image ratio normalization, enforces documented Seedream size presets, routes MiniMax img2img through generations-style payloads, and submits Hailuo video variants through the video generations API with proper reference-image handling. Constraint: The deployed test chain relies on popiartServer as the lowest-risk place to adapt provider-specific routing without broad newapi changes Rejected: Expand newapi relay modes for every MiniMax image/video branch | larger blast radius than needed for the verified server-managed flows Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep MiniMax-specific media routing in popiartServer unless upstream newapi adapters are upgraded to the same contract Tested: go test ./internal/server -run TestInferRouteKeyForModelRecognizesViduAsVideo|TestGenerate|TestResolve|TestSubmitMiniMaxVideoTask|TestExecuteImageToImageJobUsesGenerationsPathForMiniMax|TestExecuteImageToVideoJob|TestResolveVideoReferencesSupportsImagesArray Not-tested: Full PopiNewAPI unit suite (blocked earlier by external module checksum drift in local checkout)
This commit is contained in:
@@ -138,6 +138,110 @@ func TestSubmitImageToVideoTaskUsesURLImagesForViduModels(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubmitMiniMaxVideoTaskUsesVideoGenerationsEndpoint(t *testing.T) {
|
||||
var gotPath string
|
||||
var gotBody map[string]any
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gotPath = r.URL.Path
|
||||
if err := json.NewDecoder(r.Body).Decode(&gotBody); err != nil {
|
||||
t.Fatalf("decode request body: %v", err)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"task_id":"task_minimax_video_123","status":"submitted"}`))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
client := newNewAPIClient(Config{NewAPIBaseURL: srv.URL})
|
||||
taskID, err := client.submitMiniMaxVideoTask(context.Background(), "sk-test", "I2V-01", map[string]any{
|
||||
"prompt": "animate this portrait gently",
|
||||
"size": "720x1280",
|
||||
}, []imageEditReference{{
|
||||
URL: "https://example.com/reference.png",
|
||||
}})
|
||||
if err != nil {
|
||||
t.Fatalf("submitMiniMaxVideoTask: %v", err)
|
||||
}
|
||||
if taskID != "task_minimax_video_123" {
|
||||
t.Fatalf("unexpected task id: %q", taskID)
|
||||
}
|
||||
if gotPath != "/v1/video/generations" {
|
||||
t.Fatalf("expected /v1/video/generations, got %q", gotPath)
|
||||
}
|
||||
if gotBody["model"] != "I2V-01" {
|
||||
t.Fatalf("unexpected model: %#v", gotBody["model"])
|
||||
}
|
||||
images, ok := gotBody["images"].([]any)
|
||||
if !ok || len(images) != 1 || images[0] != "https://example.com/reference.png" {
|
||||
t.Fatalf("unexpected images payload: %#v", gotBody["images"])
|
||||
}
|
||||
if gotBody["size"] != "720P" {
|
||||
t.Fatalf("expected 720P resolution, got %#v", gotBody["size"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubmitMiniMaxVideoTaskKeepsS2VImagesArray(t *testing.T) {
|
||||
var gotBody map[string]any
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := json.NewDecoder(r.Body).Decode(&gotBody); err != nil {
|
||||
t.Fatalf("decode request body: %v", err)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"task_id":"task_s2v_123","status":"submitted"}`))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
client := newNewAPIClient(Config{NewAPIBaseURL: srv.URL})
|
||||
taskID, err := client.submitMiniMaxVideoTask(context.Background(), "sk-test", "S2V-01", map[string]any{
|
||||
"prompt": "animate the subject gently",
|
||||
}, []imageEditReference{{
|
||||
URL: "https://example.com/reference.png",
|
||||
}})
|
||||
if err != nil {
|
||||
t.Fatalf("submitMiniMaxVideoTask: %v", err)
|
||||
}
|
||||
if taskID != "task_s2v_123" {
|
||||
t.Fatalf("unexpected task id: %q", taskID)
|
||||
}
|
||||
images, ok := gotBody["images"].([]any)
|
||||
if !ok || len(images) != 1 || images[0] != "https://example.com/reference.png" {
|
||||
t.Fatalf("unexpected images payload for S2V: %#v", gotBody["images"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveVideoReferencesSupportsImagesArray(t *testing.T) {
|
||||
cfg := Config{
|
||||
SQLitePath: filepath.Join(t.TempDir(), "popiart.db"),
|
||||
SkillhubDir: makeEmptySkillhub(t),
|
||||
SessionSecret: "test-secret",
|
||||
}
|
||||
server, err := NewWithConfig(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("NewWithConfig: %v", err)
|
||||
}
|
||||
|
||||
imageBytes := tinyPNG(t)
|
||||
refSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "image/png")
|
||||
_, _ = w.Write(imageBytes)
|
||||
}))
|
||||
defer refSrv.Close()
|
||||
|
||||
refs, err := server.resolveVideoReferences(context.Background(), &job{
|
||||
UserID: "user_test",
|
||||
UpstreamKey: "sk-upstream",
|
||||
}, map[string]any{
|
||||
"images": []any{refSrv.URL + "/a.png", refSrv.URL + "/b.png"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("resolveVideoReferences: %v", err)
|
||||
}
|
||||
if len(refs) != 2 {
|
||||
t.Fatalf("expected 2 refs, got %#v", refs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchVideoTaskFallsBackToGenericTaskEnvelope(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
|
||||
Reference in New Issue
Block a user