功能增加

This commit is contained in:
andy committed 2026-09-11 15:33:18 +08:00
1 parent b340fc7ad7
commit f1993eb388
69 files changed
+2243 -162

No files matched your search

+18 -4
View File
@@ -10,6 +10,8 @@ import (
"sort"
"strings"
"sync"
"git.nianxx.cn/wangxuming/NianAIGC/backend/internal/providers"
)
type RuntimeUpdater func(context.Context, map[string]string) error
@@ -68,6 +70,7 @@ type Services struct {
Seedance bool `json:"seedance"`
Seedream bool `json:"seedream"`
Bailian bool `json:"bailian"`
Minimax bool `json:"minimax"`
Auth bool `json:"auth"`
Organization bool `json:"organization"`
}
@@ -321,13 +324,15 @@ func (s *Service) get() (Payload, error) {
videoModel := lookup(s.database, s.environment, file, "SEEDANCE_MODEL", "doubao-seedance-2-0-260128")
if video == "bailian" {
videoModel = lookup(s.database, s.environment, file, "BAILIAN_VIDEO_MODEL", "wan2.7-i2v-2026-04-25")
} else if video == "minimax" {
videoModel = providers.MinimaxH3Model
}
imageConnected := connected(image, s.database, s.environment, file)
videoConnected := connected(video, s.database, s.environment, file)
imageField := project(fieldIndex["IMAGE_GENERATE_ENGINE"], image, s.database, s.environment, file)
videoField := project(fieldIndex["VIDEO_GENERATE_ENGINE"], video, s.database, s.environment, file)
assignments := []EngineAssignment{{ID: "image.generate", Label: "图片生成", Engine: image, EngineLabel: label(image), Connected: imageConnected, ConnectionLabel: connection(imageConnected), ReqKey: imageModel, Configurable: true, Field: &imageField}, {ID: "video.generate", Label: "视频生成", Engine: video, EngineLabel: label(video), Connected: videoConnected, ConnectionLabel: connection(videoConnected), ReqKey: videoModel, Configurable: true, Field: &videoField}}
services := Services{Visual: connected("jimeng", s.database, s.environment, file), Evolink: connected("evolink", s.database, s.environment, file), Seedance: connected("seedance", s.database, s.environment, file), Seedream: connected("seedream", s.database, s.environment, file), Bailian: connected("bailian", s.database, s.environment, file), Auth: lookup(s.database, s.environment, file, "ZHINIAN_AUTH_SESSION_SECRET", "") != "", Organization: lookup(s.database, s.environment, file, "DATABASE_URL", "") != "" || lookup(s.database, s.environment, file, "ZHINIAN_AUTH_SESSION_SECRET", "") != ""}
services := Services{Visual: connected("jimeng", s.database, s.environment, file), Evolink: connected("evolink", s.database, s.environment, file), Seedance: connected("seedance", s.database, s.environment, file), Seedream: connected("seedream", s.database, s.environment, file), Bailian: connected("bailian", s.database, s.environment, file), Minimax: connected("minimax", s.database, s.environment, file), Auth: lookup(s.database, s.environment, file, "ZHINIAN_AUTH_SESSION_SECRET", "") != "", Organization: lookup(s.database, s.environment, file, "DATABASE_URL", "") != "" || lookup(s.database, s.environment, file, "ZHINIAN_AUTH_SESSION_SECRET", "") != ""}
imageLabel := "图片生成 4.6"
if image == "seedream" {
imageLabel = "Seedream 5.0 Pro 图片生成"
@@ -546,10 +551,14 @@ func normalizeImage(value string) string {
return "jimeng"
}
func normalizeVideo(value string) string {
if strings.ToLower(strings.TrimSpace(value)) == "bailian" {
switch strings.ToLower(strings.TrimSpace(value)) {
case "bailian":
return "bailian"
case "minimax":
return "minimax"
default:
return "seedance"
}
return "seedance"
}
func label(engine string) string {
switch engine {
@@ -561,6 +570,8 @@ func label(engine string) string {
return "Seedance"
case "seedream":
return "Seedream 5.0 Pro"
case "minimax":
return "MiniMax H3"
default:
return "即梦"
}
@@ -579,6 +590,8 @@ func connected(engine string, database, environment, file map[string]string) boo
return strings.TrimSpace(lookup(database, environment, file, "SEEDANCE_API_KEY", "")) != ""
case "bailian":
return strings.TrimSpace(lookup(database, environment, file, "BAILIAN_API_KEY", "")) != "" || strings.TrimSpace(lookup(database, environment, file, "DASHSCOPE_API_KEY", "")) != ""
case "minimax":
return strings.TrimSpace(lookup(database, environment, file, "MINIMAX_API_KEY", "")) != ""
default:
return strings.TrimSpace(lookup(database, environment, file, "VOLCENGINE_ACCESS_KEY_ID", "")) != "" && strings.TrimSpace(lookup(database, environment, file, "VOLCENGINE_SECRET_ACCESS_KEY", "")) != ""
}
@@ -592,6 +605,7 @@ func definitions() []Group {
{ID: "evolink", Title: "EvoLink 图片 API", Description: "GPT Image 2 图片生成。", Fields: []Field{{Key: "EVOLINK_API_KEY", Label: "EvoLink API Key", Secret: true, Type: "password"}, {Key: "EVOLINK_BASE_URL", Label: "Base URL", DefaultValue: "https://api.evolink.ai"}, {Key: "EVOLINK_IMAGE_MODEL", Label: "图片模型", DefaultValue: "gpt-image-2"}, {Key: "EVOLINK_IMAGE_QUALITY", Label: "质量", DefaultValue: "medium"}}},
{ID: "seedance", Title: "火山方舟 API", Description: "Seedance 视频与 Seedream 5.0 Pro 图片共用此 API Key。", Fields: []Field{{Key: "SEEDANCE_API_KEY", Label: "方舟 API Key", Secret: true, Type: "password"}}},
{ID: "bailian", Title: "阿里云百炼 API", Description: "万相图片与视频。", Fields: []Field{{Key: "BAILIAN_API_KEY", Label: "百炼 API Key", Secret: true, Type: "password"}, {Key: "BAILIAN_BASE_URL", Label: "Base URL", DefaultValue: "https://llm-126wneubbdo6dbr5.cn-beijing.maas.aliyuncs.com/compatible-mode/v1"}, {Key: "BAILIAN_IMAGE_MODEL", Label: "图片模型", DefaultValue: "wan2.7-image-pro"}, {Key: "BAILIAN_VIDEO_MODEL", Label: "视频模型", DefaultValue: "wan2.7-i2v-2026-04-25"}}},
{ID: "minimax", Title: "MiniMax API", Description: "MiniMax H3 视频生成。", Fields: []Field{{Key: "MINIMAX_API_KEY", Label: "MiniMax API Key", Secret: true, Type: "password"}, {Key: "MINIMAX_BASE_URL", Label: "Base URL", DefaultValue: "https://api.minimax.cn"}}},
{ID: "oss", Title: "OSS 资产存储", Description: "私有桶通过后端签名访问。", Fields: []Field{{Key: "ALI_OSS_ENDPOINT", Label: "Endpoint"}, {Key: "ALI_OSS_BUCKET", Label: "Bucket"}, {Key: "ALI_OSS_ACCESS_KEY_ID", Label: "Access Key ID", Secret: true, Type: "password"}, {Key: "ALI_OSS_ACCESS_KEY_SECRET", Label: "Access Key Secret", Secret: true, Type: "password"}, {Key: "ALI_OSS_PUBLIC_BASE_URL", Label: "Bucket Base URL(无需公共读)"}}},
}
}
@@ -604,7 +618,7 @@ var fieldIndex = func() map[string]Field {
}
}
result["IMAGE_GENERATE_ENGINE"] = Field{Key: "IMAGE_GENERATE_ENGINE", Label: "图片生成", Type: "select", DefaultValue: "jimeng", Options: []Option{{Label: "即梦 4.6 / 火山视觉", Value: "jimeng"}, {Label: "Seedream 5.0 Pro / 火山方舟", Value: "seedream"}, {Label: "EvoLink GPT Image 2", Value: "evolink"}, {Label: "阿里云百炼 Wan 2.7", Value: "bailian"}}}
result["VIDEO_GENERATE_ENGINE"] = Field{Key: "VIDEO_GENERATE_ENGINE", Label: "视频生成", Type: "select", DefaultValue: "bailian", Options: []Option{{Label: "Seedance", Value: "seedance"}, {Label: "阿里云百炼 Wan 2.7", Value: "bailian"}}}
result["VIDEO_GENERATE_ENGINE"] = Field{Key: "VIDEO_GENERATE_ENGINE", Label: "视频生成", Type: "select", DefaultValue: "bailian", Options: []Option{{Label: "Seedance", Value: "seedance"}, {Label: "MiniMax H3", Value: "minimax"}, {Label: "阿里云百炼 Wan 2.7", Value: "bailian"}}}
return result
}()
+20 -1
View File
@@ -10,6 +10,8 @@ import (
"sort"
"strings"
"testing"
"git.nianxx.cn/wangxuming/NianAIGC/backend/internal/providers"
)
func TestFixtureIsConsumedByGo(t *testing.T) {
@@ -27,7 +29,7 @@ func TestFixtureIsConsumedByGo(t *testing.T) {
if err := json.Unmarshal(data, &fixture); err != nil {
t.Fatal(err)
}
if fixture.Version != 1 || fixture.FileName != ".env.local" || len(fixture.AllowedKeys) != 25 || len(fixture.SecretKeys) != 8 {
if fixture.Version != 1 || fixture.FileName != ".env.local" || len(fixture.AllowedKeys) != 27 || len(fixture.SecretKeys) != 9 {
t.Fatalf("fixture = %#v", fixture)
}
wantDatabaseKeys := RuntimeSettingKeys()
@@ -38,6 +40,23 @@ func TestFixtureIsConsumedByGo(t *testing.T) {
}
}
func TestMinimaxSettingsAreDatabaseBackedAndReportedConnected(t *testing.T) {
repository := &runtimeSettingsRepositoryStub{values: map[string]string{
"MINIMAX_API_KEY": "secret",
"MINIMAX_BASE_URL": "https://api.minimax.test",
"VIDEO_GENERATE_ENGINE": "minimax",
}}
service := NewWithRuntimeRepository(filepath.Join(t.TempDir(), ".env.local"), nil, repository, nil)
value, err := service.Get(context.Background())
if err != nil {
t.Fatal(err)
}
payload := value.(Payload)
if !payload.Services.Minimax || payload.EngineAssignments[1].Engine != "minimax" || payload.EngineAssignments[1].ReqKey != providers.MinimaxH3Model {
t.Fatalf("payload=%#v", payload)
}
}
func TestServiceSavePreservesSecretsAndUnrelatedEnvLines(t *testing.T) {
path := filepath.Join(t.TempDir(), ".env.local")
original := "# operator note\nDATABASE_URL=postgres://untouched\nZHINIAN_AUTH_SESSION_SECRET=keep-me\nZHINIAN_BILLING_CONTACT=old # prior\nCUSTOM_QUOTED=\"a b\"\n"