feat: add seedance media params and model visibility

This commit is contained in:
stupid-h4er
2026-05-27 13:02:36 +08:00
parent 871bedc072
commit 4bffb55695
25 changed files with 873 additions and 140 deletions
+53 -5
View File
@@ -12,7 +12,16 @@ import (
"github.com/google/uuid"
)
const referenceMediaMaxBytes = 80 << 20
const (
referenceMediaMaxBytes = 80 << 20
referenceImageMaxBytes = 30 << 20
referenceVideoMaxBytes = 50 << 20
referenceAudioMaxBytes = 15 << 20
referenceImageAllowedText = "jpeg/png/webp/bmp/gif/heic/heif 图片"
referenceVideoAllowedText = "mp4/mov 视频"
referenceAudioAllowedText = "mp3/wav 音频"
referenceMediaAllowedText = referenceImageAllowedText + "、" + referenceVideoAllowedText + "或" + referenceAudioAllowedText
)
type referenceMediaUploadResult struct {
ID string `json:"id"`
@@ -24,7 +33,7 @@ type referenceMediaUploadResult struct {
func UploadReferenceMedia(w http.ResponseWriter, r *http.Request) {
publicBaseURL := strings.TrimRight(strings.TrimSpace(config.Cfg.PublicBaseURL), "/")
if publicBaseURL == "" {
Fail(w, "未配置 PUBLIC_BASE_URL,无法把本地参考视频提供给火山方舟访问")
Fail(w, "未配置 PUBLIC_BASE_URL,无法把本地参考素材提供给火山方舟访问")
return
}
r.Body = http.MaxBytesReader(w, r.Body, referenceMediaMaxBytes+1)
@@ -44,7 +53,7 @@ func UploadReferenceMedia(w http.ResponseWriter, r *http.Request) {
mimeType, ext, ok := normalizeReferenceMediaType(header.Header.Get("Content-Type"), filepath.Ext(header.Filename))
if !ok {
Fail(w, "参考素材格式不支持,请使用 jpeg/png/webp/bmp/gif/heic/heif 图片或 mp4/mov 视频")
Fail(w, "参考素材格式不支持,请使用 "+referenceMediaAllowedText)
return
}
if err := os.MkdirAll(referenceMediaDir(), 0o755); err != nil {
@@ -65,9 +74,14 @@ func UploadReferenceMedia(w http.ResponseWriter, r *http.Request) {
Fail(w, "参考素材保存失败")
return
}
if bytes <= 0 || bytes > referenceMediaMaxBytes {
if bytes <= 0 {
_ = os.Remove(targetPath)
Fail(w, "参考素材为空或超过大小限制")
Fail(w, "参考素材为空")
return
}
if limit := referenceMediaTypeMaxBytes(mimeType); limit > 0 && bytes > limit {
_ = os.Remove(targetPath)
Fail(w, referenceMediaSizeMessage(mimeType))
return
}
OK(w, referenceMediaUploadResult{
@@ -141,6 +155,10 @@ func referenceMediaExtByMimeType(mimeType string) string {
return ".mp4"
case "video/quicktime", "video/mov":
return ".mov"
case "audio/mpeg", "audio/mp3":
return ".mp3"
case "audio/wav", "audio/x-wav", "audio/wave":
return ".wav"
default:
return ""
}
@@ -166,7 +184,37 @@ func mimeTypeByReferenceMediaExt(ext string) string {
return "video/mp4"
case ".mov":
return "video/quicktime"
case ".mp3":
return "audio/mpeg"
case ".wav":
return "audio/wav"
default:
return ""
}
}
func referenceMediaTypeMaxBytes(mimeType string) int64 {
if strings.HasPrefix(mimeType, "image/") {
return referenceImageMaxBytes
}
if strings.HasPrefix(mimeType, "video/") {
return referenceVideoMaxBytes
}
if strings.HasPrefix(mimeType, "audio/") {
return referenceAudioMaxBytes
}
return referenceMediaMaxBytes
}
func referenceMediaSizeMessage(mimeType string) string {
if strings.HasPrefix(mimeType, "image/") {
return "参考图片超过大小限制,请使用 30MB 以内的图片"
}
if strings.HasPrefix(mimeType, "video/") {
return "参考视频超过大小限制,请使用 50MB 以内的 mp4/mov 视频"
}
if strings.HasPrefix(mimeType, "audio/") {
return "参考音频超过大小限制,请使用 15MB 以内的 mp3/wav 音频"
}
return "参考素材超过大小限制"
}
+40
View File
@@ -0,0 +1,40 @@
package handler
import "testing"
func TestNormalizeReferenceMediaTypeSupportsAudio(t *testing.T) {
tests := []struct {
name string
contentType string
ext string
wantMime string
wantExt string
}{
{name: "mp3 mime", contentType: "audio/mpeg", ext: ".bin", wantMime: "audio/mpeg", wantExt: ".mp3"},
{name: "wav ext fallback", contentType: "application/octet-stream", ext: ".wav", wantMime: "audio/wav", wantExt: ".wav"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mimeType, ext, ok := normalizeReferenceMediaType(tt.contentType, tt.ext)
if !ok {
t.Fatal("expected media type to be accepted")
}
if mimeType != tt.wantMime || ext != tt.wantExt {
t.Fatalf("got (%q, %q), want (%q, %q)", mimeType, ext, tt.wantMime, tt.wantExt)
}
})
}
}
func TestReferenceMediaTypeMaxBytes(t *testing.T) {
if got := referenceMediaTypeMaxBytes("audio/mpeg"); got != referenceAudioMaxBytes {
t.Fatalf("audio max bytes = %d, want %d", got, referenceAudioMaxBytes)
}
if got := referenceMediaTypeMaxBytes("video/mp4"); got != referenceVideoMaxBytes {
t.Fatalf("video max bytes = %d, want %d", got, referenceVideoMaxBytes)
}
if got := referenceMediaTypeMaxBytes("image/png"); got != referenceImageMaxBytes {
t.Fatalf("image max bytes = %d, want %d", got, referenceImageMaxBytes)
}
}