fix: clarify seedance reference video failures

This commit is contained in:
stupid-h4er
2026-05-27 22:34:46 +08:00
parent 6d185a6d93
commit 76461e6dba
6 changed files with 58 additions and 2 deletions
+11
View File
@@ -263,6 +263,9 @@ func aiUpstreamErrorDetail(body []byte) string {
}
if err := json.Unmarshal(body, &payload); err == nil {
if payload.Error.Message != "" {
if detail := friendlyUpstreamError(payload.Error.Code, payload.Error.Message); detail != "" {
return safeUpstreamText(detail)
}
if payload.Error.Code != "" {
return safeUpstreamText(payload.Error.Code + " " + payload.Error.Message)
}
@@ -278,6 +281,14 @@ func aiUpstreamErrorDetail(body []byte) string {
return safeUpstreamText(text)
}
func friendlyUpstreamError(code string, message string) string {
lowerCode := strings.ToLower(strings.TrimSpace(code))
if strings.Contains(lowerCode, "inputvideosensitivecontentdetected") || strings.Contains(lowerCode, "privacyinformation") {
return strings.TrimSpace(code + " 参考视频疑似包含真人或隐私信息,火山方舟拒绝使用普通 URL 作为真人视频参考;请改用不含真人的视频、官方允许的模型产物,或已授权的 asset:// 素材。原始错误:" + message)
}
return ""
}
func safeUpstreamText(text string) string {
text = strings.Join(strings.Fields(strings.TrimSpace(text)), " ")
runes := []rune(text)
+7
View File
@@ -12,6 +12,13 @@ func TestAIUpstreamErrorDetail(t *testing.T) {
}
}
func TestAIUpstreamErrorDetailExplainsSensitiveVideo(t *testing.T) {
got := aiUpstreamErrorDetail([]byte(`{"error":{"code":"InputVideoSensitiveContentDetected.PrivacyInformation","message":"The request failed because the input video may contain real person."}}`))
if !strings.Contains(got, "参考视频疑似包含真人") || !strings.Contains(got, "asset://") {
t.Fatalf("detail = %q", got)
}
}
func TestSafeUpstreamTextTruncates(t *testing.T) {
got := safeUpstreamText(strings.Repeat("错", 320))
if len([]rune(got)) != 303 {
+19 -1
View File
@@ -117,7 +117,25 @@ func ReferenceMedia(w http.ResponseWriter, r *http.Request, id string) {
}
func referenceMediaDir() string {
return filepath.Join("data", "reference-media")
return filepath.Join(referenceDataDir(), "reference-media")
}
func referenceDataDir() string {
driver := strings.ToLower(strings.TrimSpace(config.Cfg.StorageDriver))
dsn := strings.TrimSpace(config.Cfg.DatabaseDSN)
if (driver == "" || driver == "sqlite") && dsn != "" && dsn != ":memory:" && !strings.HasPrefix(dsn, "file:") {
pathPart := dsn
if index := strings.Index(dsn, "?"); index >= 0 {
pathPart = dsn[:index]
}
if filepath.IsAbs(pathPart) {
return filepath.Dir(pathPart)
}
}
if _, err := os.Stat("/app/data"); err == nil {
return "/app/data"
}
return "data"
}
func normalizeReferenceMediaType(contentType string, ext string) (string, string, bool) {
+17 -1
View File
@@ -1,6 +1,11 @@
package handler
import "testing"
import (
"path/filepath"
"testing"
"github.com/basketikun/infinite-canvas/config"
)
func TestNormalizeReferenceMediaTypeSupportsAudio(t *testing.T) {
tests := []struct {
@@ -38,3 +43,14 @@ func TestReferenceMediaTypeMaxBytes(t *testing.T) {
t.Fatalf("image max bytes = %d, want %d", got, referenceImageMaxBytes)
}
}
func TestReferenceMediaDirUsesAbsoluteSQLiteDataDir(t *testing.T) {
previous := config.Cfg
t.Cleanup(func() { config.Cfg = previous })
root := t.TempDir()
config.Cfg = config.Config{StorageDriver: "sqlite", DatabaseDSN: filepath.Join(root, "infinite-canvas.db")}
if got := referenceMediaDir(); got != filepath.Join(root, "reference-media") {
t.Fatalf("referenceMediaDir = %q", got)
}
}