245 lines
11 KiB
Go
245 lines
11 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"path/filepath"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
|
|
"yingce/backend/internal/model"
|
|
"yingce/backend/internal/protocol"
|
|
)
|
|
|
|
func autoDLProfile(t *testing.T, subset bool) *ModelCapabilityConfig {
|
|
t.Helper()
|
|
profile := DefaultModelCapabilityConfigForModel("autodl-comfyui", "minimax_h3_zm_u24")
|
|
profile.Video.Resolutions = []string{"480p竖", "768p竖", "480p横", "768p横", "480p(1:1)", "768p(1:1)"}
|
|
profile.Video.DefaultResolution = "768p竖"
|
|
if subset {
|
|
profile.Video.Resolutions = []string{"480p横", "768p(1:1)"}
|
|
profile.Video.DefaultResolution = "768p(1:1)"
|
|
}
|
|
return profile
|
|
}
|
|
|
|
func normalizeAutoDLProfile(t *testing.T, profile *ModelCapabilityConfig, name string) *ModelCapabilityConfig {
|
|
t.Helper()
|
|
result, err := NormalizeModelCapabilityConfigForModel("video", "autodl-comfyui", name, profile)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func TestAutoDLScreenSpecIgnoresRemovedSwitchAndDraft(t *testing.T) {
|
|
for _, oldEnabled := range []bool{false, true} {
|
|
data, _ := json.Marshal(autoDLProfile(t, false))
|
|
var raw map[string]any
|
|
if err := json.Unmarshal(data, &raw); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
video := raw["video"].(map[string]any)
|
|
video["customSizeEnabled"] = oldEnabled
|
|
video["customScreenSpec"] = map[string]any{"resolutions": []string{"invalid"}, "defaultResolution": "invalid"}
|
|
video["fixedScreenSpec"] = map[string]any{"resolutions": []string{"forged"}, "defaultResolution": "forged"}
|
|
data, _ = json.Marshal(raw)
|
|
profile, err := DecodeModelCapabilityConfig(string(data))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
result := normalizeAutoDLProfile(t, profile, "minimax_h3_zm_u24")
|
|
if result.Video.DefaultResolution != "768p竖" || len(result.Video.Resolutions) != 6 || len(result.Video.Ratios) != 0 || result.Video.DefaultRatio != "" || len(result.Video.FixedScreenSpec.Resolutions) != 6 {
|
|
t.Fatalf("selected spec = %#v", result.Video)
|
|
}
|
|
if !reflect.DeepEqual(result.Video.References, profile.Video.References) || !reflect.DeepEqual(result.Video.Duration, profile.Video.Duration) || !reflect.DeepEqual(result.Video.Operations, profile.Video.Operations) {
|
|
t.Fatal("screen-spec normalization changed unrelated parameters")
|
|
}
|
|
data, _ = json.Marshal(result)
|
|
if strings.Contains(string(data), "customSizeEnabled") || strings.Contains(string(data), "customScreenSpec") {
|
|
t.Fatalf("removed fields remain in saved JSON: %s", data)
|
|
}
|
|
if profile.Video.DefaultRatio != "16:9" || profile.Video.FixedScreenSpec.DefaultResolution != "forged" {
|
|
t.Fatal("normalization mutated the original profile")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAutoDLScreenSpecSelectedValuesSurviveJSONReload(t *testing.T) {
|
|
profile := autoDLProfile(t, true)
|
|
profile.Video.Resolutions = []string{" 480p横 ", "768p(1:1)", "480P横", ""}
|
|
profile.Video.DefaultResolution = " 768P(1:1) "
|
|
selected := normalizeAutoDLProfile(t, profile, "minimax_h3_zm_u24")
|
|
loaded, err := DecodeModelCapabilityConfig(mustEncodeModelCapabilityConfig(t, selected))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
restored := normalizeAutoDLProfile(t, loaded, "minimax_h3_zm_u24")
|
|
if !reflect.DeepEqual(restored.Video.Resolutions, []string{"480p横", "768p(1:1)"}) || restored.Video.DefaultResolution != "768p(1:1)" {
|
|
t.Fatalf("restored selected spec = %#v", restored.Video)
|
|
}
|
|
}
|
|
|
|
func TestAutoDLScreenSpecRejectsInvalidSelectionsAndUnknownWorkflow(t *testing.T) {
|
|
for _, values := range [][]string{nil, {"480p横"}, {"480p横", "768p(1:1)", "1080p横"}} {
|
|
profile := autoDLProfile(t, true)
|
|
profile.Video.Resolutions = values
|
|
if _, err := NormalizeModelCapabilityConfigForModel("video", "autodl-comfyui", "minimax_h3_zm_u24", profile); err == nil {
|
|
t.Fatal("invalid selection or default was accepted")
|
|
}
|
|
}
|
|
if _, err := NormalizeModelCapabilityConfigForModel("video", "autodl-comfyui", "unknown", autoDLProfile(t, false)); err == nil {
|
|
t.Fatal("unknown workflow invented preset values")
|
|
}
|
|
}
|
|
|
|
func TestAutoDLScreenSpecUsesEachPackagedWorkflowExactly(t *testing.T) {
|
|
dir, err := officialPluginPackageDir()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
pkg, err := inspectOfficialPluginPackage(filepath.Join(dir, "autodl-comfyui.yingce-plugin"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, workflow := range pkg.info.Manifest.Contributes.Workflows {
|
|
t.Run(workflow.ID, func(t *testing.T) {
|
|
for _, parameter := range workflow.Parameters {
|
|
if parameter.Name == "resolution" {
|
|
input := autoDLProfile(t, false)
|
|
input.Video.Resolutions = parameter.Values
|
|
input.Video.DefaultResolution = workflow.Defaults[parameter.Name].(string)
|
|
profile := normalizeAutoDLProfile(t, input, workflow.ID)
|
|
if !reflect.DeepEqual(profile.Video.Resolutions, parameter.Values) || profile.Video.DefaultResolution != workflow.Defaults[parameter.Name] {
|
|
t.Fatalf("workflow contract mismatch: %#v", profile.Video)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAutoDLScreenSpecSubmissionUsesSameValueAsValidation(t *testing.T) {
|
|
adapter, ok := loadOfficialFallbackRegistry().Resolve("autodl-comfyui")
|
|
if !ok {
|
|
t.Fatal("AutoDL adapter missing")
|
|
}
|
|
for _, subset := range []bool{false, true} {
|
|
profile := normalizeAutoDLProfile(t, autoDLProfile(t, subset), "minimax_h3_zm_u24")
|
|
input := canvasGenerationInput{Mode: "video", Prompt: "test", VideoCapability: profile.Video, Config: providerConfig{InterfaceType: "autodl-comfyui", Model: "minimax_h3_zm_u24", Size: "16:9", VQuality: "auto", VideoSeconds: "6"}}
|
|
applyAutoDLVideoScreenSpec(&input, profile.Video)
|
|
if err := validateVideoTask(profile.Video, input); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
request := protocolRequestFromInput(input)
|
|
spec, err := adapter.BuildCreate(context.Background(), protocol.RequestContext{Request: request})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
body := spec.Body.(map[string]any)
|
|
if body["resolution"] != profile.Video.DefaultResolution || body["resolution"] != input.Config.VQuality || request.AspectRatio != "" || body["duration"] != 6 {
|
|
t.Fatalf("validated input and actual request differ: %#v, %#v", input.Config, body)
|
|
}
|
|
if _, exists := body["aspect_ratio"]; exists {
|
|
t.Fatal("unsupported independent aspect ratio was sent")
|
|
}
|
|
input.Config.VQuality = "unsupported"
|
|
applyAutoDLVideoScreenSpec(&input, profile.Video)
|
|
if validateVideoTask(profile.Video, input) == nil {
|
|
t.Fatal("accepted an undeclared explicit request value")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAutoDLScreenSpecSystemSaveCatalogAndExecutionIgnoreClientOverride(t *testing.T) {
|
|
svc, db := newChannelModelTestService(t)
|
|
admin := &model.User{ID: "admin", Role: model.UserRoleAdmin}
|
|
channel := model.ModelChannel{ID: "autodl", UserID: admin.ID, Scope: model.ChannelScopeSystem, Enabled: true, Name: "AutoDL", BaseURL: "https://autodl.art", APIKey: "test", ModelsJSON: `[]`}
|
|
if err := db.Create(&channel).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
enabled := true
|
|
priceTiers := make([]ChannelModelPriceTierRequest, 0, 6)
|
|
for _, resolution := range autoDLProfile(t, false).Video.Resolutions {
|
|
sale, cost := int64(6), int64(3)
|
|
if resolution[:4] == "768p" {
|
|
sale, cost = 8, 4
|
|
}
|
|
priceTiers = append(priceTiers, ChannelModelPriceTierRequest{Resolution: resolution, BillingMode: "per_second", UnitPriceMicrocredits: sale * CreditScale, CostPricing: model.CreditCostPricing{Configured: true, UnitPriceMicrocredits: cost * CreditScale}, PriceConfigured: true, Enabled: &enabled})
|
|
}
|
|
for _, subset := range []bool{true, false} {
|
|
profile := autoDLProfile(t, subset)
|
|
id := ""
|
|
if item, err := svc.repo.ChannelModelByKey(channel.ID, "minimax_h3_zm_u24"); err == nil {
|
|
id = item.ID
|
|
}
|
|
saved, err := svc.SaveAdminChannelModel(admin, channel.ID, id, ChannelModelRequest{
|
|
ModelKey: "minimax_h3_zm_u24", ProviderModelKey: "minimax_h3_zm_u24", Capability: "video", Protocol: "autodl-comfyui", CapabilityConfig: profile, Enabled: &enabled,
|
|
PriceTiers: priceTiers,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
public, err := svc.sanitizeChannelModel(saved)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
catalogSpec, err := channelModelCapabilitySpec(*saved)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, exists := catalogSpec.Options["size"]; exists {
|
|
t.Fatal("catalog exposes an unsupported independent ratio")
|
|
}
|
|
if len(catalogSpec.Options["vquality"].Values) != len(profile.Video.Resolutions) {
|
|
t.Fatalf("catalog choices ignored the selected list: %#v", catalogSpec)
|
|
}
|
|
for _, tier := range saved.PriceTiers {
|
|
if !containsCapabilityString(profile.Video.Resolutions, tier.Resolution) {
|
|
continue
|
|
}
|
|
priceInput := map[string]any{"mode": "video", "prompt": "test", "config": map[string]any{"channelId": channel.ID, "channelModelKey": saved.ModelKey, "model": saved.ModelKey, "vquality": tier.Resolution, "videoSeconds": "6"}}
|
|
priced, err := svc.resolveSystemChannelModelSelection(priceInput, "canvas_video", "text_to_video")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
config := priced["config"].(map[string]any)
|
|
if config["priceTierId"] != tier.ID || config["vquality"] != tier.Resolution || tier.BillingMode != "per_second" || tier.UnitPriceMicrocredits != tier.CostPricing.UnitPriceMicrocredits*2 {
|
|
t.Fatalf("resolution and price diverged: %#v, %#v", config, tier)
|
|
}
|
|
}
|
|
data, _ := json.Marshal(public.CapabilityConfig)
|
|
catalog, err := DecodeModelCapabilityConfig(string(data))
|
|
if err != nil || catalog.Video.DefaultResolution != profile.Video.DefaultResolution {
|
|
t.Fatalf("catalog = %s, err = %v", data, err)
|
|
}
|
|
input := map[string]any{"mode": "video", "prompt": "test", "config": map[string]any{"channelId": channel.ID, "channelModelKey": saved.ModelKey, "model": saved.ModelKey, "interfaceType": "autodl-comfyui", "vquality": "auto", "size": "16:9", "videoSeconds": "6", "capabilityConfig": autoDLProfile(t, !subset)}}
|
|
resolved, err := svc.resolveSystemChannelModelSelection(input, "canvas_video", "text_to_video")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := svc.ValidateTaskCapability(resolved); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
encoded, _ := json.Marshal(resolved)
|
|
var execution canvasGenerationInput
|
|
if err := json.Unmarshal(encoded, &execution); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := svc.validateResolvedVideoCapability(&execution); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if execution.Config.VQuality != catalog.Video.DefaultResolution || execution.Config.Size != "" || !reflect.DeepEqual(execution.VideoCapability.Resolutions, catalog.Video.Resolutions) {
|
|
t.Fatalf("catalog and execution mismatch: %#v, %#v", catalog.Video, execution.Config)
|
|
}
|
|
if subset {
|
|
rejected := map[string]any{"mode": "video", "prompt": "test", "config": map[string]any{"channelId": channel.ID, "model": saved.ModelKey, "vquality": "768p竖", "videoSeconds": "6"}}
|
|
resolved, err = svc.resolveSystemChannelModelSelection(rejected, "canvas_video", "text_to_video")
|
|
if err == nil && svc.ValidateTaskCapability(resolved) == nil {
|
|
t.Fatal("unselected preset bypassed saved capability restrictions")
|
|
}
|
|
}
|
|
}
|
|
}
|