完善生图5.0的功能
This commit is contained in:
1 parent
88a4268d40
commit
678d213f40
31 files changed
+3281
-107
No files matched your search
@@ -458,10 +458,22 @@ func writeJobError(w http.ResponseWriter, err error, public bool) {
|
||||
message := "生成任务计费失败。"
|
||||
if public {
|
||||
message = "Generation job billing failed."
|
||||
} else if errors.Is(err, billing.ErrInsufficientBalance) {
|
||||
message = "余额不足,请先充值。"
|
||||
} else if errors.Is(err, billing.ErrOrganizationUnavailable) {
|
||||
message = "账号未绑定有效组织,请联系管理员。"
|
||||
}
|
||||
writeJSON(w, billingStatus.Status, map[string]string{"error": message})
|
||||
return
|
||||
}
|
||||
if errors.Is(err, billing.ErrProviderUnavailable) {
|
||||
message := "计费服务暂不可用,请稍后重试。"
|
||||
if public {
|
||||
message = "Generation billing is temporarily unavailable."
|
||||
}
|
||||
writeJSON(w, http.StatusServiceUnavailable, map[string]string{"error": message})
|
||||
return
|
||||
}
|
||||
writeJSON(w, 500, map[string]string{"error": "Internal server error."})
|
||||
}
|
||||
func randomJobID() string {
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
@@ -231,7 +232,7 @@ func TestJobsHTTPMapsBillingChargeErrorsAndPublicUsesPublicCreation(t *testing.T
|
||||
h, _ := NewJobsHandler(JobsDependencies{Service: jobs.NewService(store, time.Now), Platform: platform, Public: publicapi.NewAuthenticator(publicapi.Config{APIKeys: "agent-a:secret"}), Builder: &jobBuilderStub{}, Creation: creation}, JobsConfig{})
|
||||
w := httptest.NewRecorder()
|
||||
h.ServeHTTP(w, httptest.NewRequest(http.MethodPost, "/api/generations/image", bytes.NewBufferString(`{"prompt":"hello"}`)))
|
||||
if w.Code != 402 || w.Body.String() != "{\"error\":\"生成任务计费失败。\"}\n" {
|
||||
if w.Code != 402 || w.Body.String() != "{\"error\":\"余额不足,请先充值。\"}\n" {
|
||||
t.Fatalf("platform=%d %s", w.Code, w.Body.String())
|
||||
}
|
||||
creation.err = nil
|
||||
@@ -246,13 +247,16 @@ func TestJobsHTTPMapsBillingChargeErrorsAndPublicUsesPublicCreation(t *testing.T
|
||||
|
||||
func TestJobsHTTPMapsAllCreationBillingOutcomesWithoutLeakingErrors(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
err error
|
||||
want int
|
||||
name string
|
||||
err error
|
||||
want int
|
||||
message string
|
||||
}{
|
||||
{name: "insufficient", err: &billing.StatusError{Status: 402, Err: billing.ErrInsufficientBalance}, want: 402},
|
||||
{name: "idempotency", err: &billing.StatusError{Status: 409, Err: billing.ErrIdempotencyConflict}, want: 409},
|
||||
{name: "unknown", err: errors.New("postgres password leaked"), want: 500},
|
||||
{name: "insufficient", err: &billing.StatusError{Status: 402, Err: billing.ErrInsufficientBalance}, want: 402, message: "余额不足,请先充值。"},
|
||||
{name: "organization", err: &billing.StatusError{Status: 409, Err: billing.ErrOrganizationUnavailable}, want: 409, message: "账号未绑定有效组织,请联系管理员。"},
|
||||
{name: "idempotency", err: &billing.StatusError{Status: 409, Err: billing.ErrIdempotencyConflict}, want: 409, message: "生成任务计费失败。"},
|
||||
{name: "unavailable", err: billing.ErrProviderUnavailable, want: 503, message: "计费服务暂不可用,请稍后重试。"},
|
||||
{name: "unknown", err: errors.New("postgres password leaked"), want: 500, message: "Internal server error."},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
@@ -262,7 +266,7 @@ func TestJobsHTTPMapsAllCreationBillingOutcomesWithoutLeakingErrors(t *testing.T
|
||||
h, _ := NewJobsHandler(JobsDependencies{Service: jobs.NewService(store, time.Now), Platform: platform, Public: publicapi.NewAuthenticator(publicapi.Config{APIKeys: "agent-a:secret"}), Builder: &jobBuilderStub{}, Creation: creation}, JobsConfig{})
|
||||
w := httptest.NewRecorder()
|
||||
h.ServeHTTP(w, httptest.NewRequest(http.MethodPost, "/api/generations/image", bytes.NewBufferString(`{"prompt":"hello"}`)))
|
||||
if w.Code != test.want || strings.Contains(w.Body.String(), "postgres") {
|
||||
if w.Code != test.want || w.Body.String() != fmt.Sprintf("{\"error\":%q}\n", test.message) || strings.Contains(w.Body.String(), "postgres") {
|
||||
t.Fatalf("status=%d body=%s", w.Code, w.Body.String())
|
||||
}
|
||||
})
|
||||
|
||||
@@ -96,7 +96,7 @@ func openAPISchemas() map[string]any {
|
||||
"capability": openAPIRef("GenerationCapability"),
|
||||
"engine": map[string]any{"type": "string", "enum": []string{"jimeng", "seedream", "evolink", "bailian", "seedance"}},
|
||||
"model": map[string]any{"type": "string", "enum": []string{"doubao-seedance-2-0-260128", "doubao-seedance-2-5-260628"}, "description": "Optional allow-listed Seedance model for video.generate."},
|
||||
"prompt": map[string]any{"type": "string", "description": "Prompt text. Required for image.generate unless promptAssembly is supplied."},
|
||||
"prompt": map[string]any{"type": "string", "description": "Prompt text. Required for generation except Seedream layer decomposition, where an empty prompt triggers automatic decomposition."},
|
||||
"inputUrls": map[string]any{"type": "array", "items": map[string]any{"type": "string", "format": "uri"}, "description": "Reference image URLs for image capabilities."},
|
||||
"imageUrls": map[string]any{"type": "array", "items": map[string]any{"type": "string", "format": "uri"}, "description": "Alias for image input URLs."},
|
||||
"inputAssetIds": openAPIStringArray(),
|
||||
@@ -104,12 +104,14 @@ func openAPISchemas() map[string]any {
|
||||
"settings": map[string]any{
|
||||
"type": "object", "description": "Provider-specific image or video settings.",
|
||||
"properties": map[string]any{
|
||||
"ratio": map[string]any{"type": "string", "enum": []string{"16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"}},
|
||||
"duration": map[string]any{"type": "integer", "minimum": 4, "maximum": 30, "description": "Seedance 2.0 supports up to 15 seconds; Seedance 2.5 supports up to 30 seconds."},
|
||||
"resolution": map[string]any{"type": "string", "enum": []string{"480p", "720p", "1080p"}},
|
||||
"size": map[string]any{"type": "string", "enum": []string{"1K", "1.5K", "2K"}, "description": "Seedream 5.0 Pro output size."},
|
||||
"outputFormat": map[string]any{"type": "string", "enum": []string{"png", "jpeg"}},
|
||||
"optimizeMode": map[string]any{"type": "string", "enum": []string{"standard", "fast"}},
|
||||
"ratio": map[string]any{"type": "string", "enum": []string{"16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"}},
|
||||
"duration": map[string]any{"type": "integer", "minimum": 4, "maximum": 30, "description": "Seedance 2.0 supports up to 15 seconds; Seedance 2.5 supports up to 30 seconds."},
|
||||
"resolution": map[string]any{"type": "string", "enum": []string{"480p", "720p", "1080p"}},
|
||||
"size": map[string]any{"type": "string", "enum": []string{"auto", "1K", "1.5K", "2K"}, "description": "Seedream 5.0 Pro output size. auto is available for layer decomposition only."},
|
||||
"outputFormat": map[string]any{"type": "string", "enum": []string{"png", "jpeg"}},
|
||||
"optimizeMode": map[string]any{"type": "string", "enum": []string{"standard", "fast"}},
|
||||
"creationMode": map[string]any{"type": "string", "enum": []string{"basic", "interactive", "layers"}, "description": "Seedream 5.0 Pro image workflow."},
|
||||
"layerDecomposition": map[string]any{"type": "boolean", "description": "Enables Seedream 5.0 Pro layer decomposition; exactly one image is required."},
|
||||
},
|
||||
},
|
||||
"width": map[string]any{"type": "integer", "example": 1440},
|
||||
|
||||
Reference in new issue
Block a user