From 28fe59a1afe88efba592a33a08990525217b32f2 Mon Sep 17 00:00:00 2001 From: chiyi Date: Sun, 5 Jul 2026 14:35:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=A7=86=E9=A2=91=E5=88=86?= =?UTF-8?q?=E8=BE=A8=E7=8E=87=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/service/v1.go | 34 ++++++++++++++++++++++++++- frontend/src/views/PlaygroundView.vue | 6 +++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/backend/internal/service/v1.go b/backend/internal/service/v1.go index c464b29..4e194b3 100644 --- a/backend/internal/service/v1.go +++ b/backend/internal/service/v1.go @@ -1893,7 +1893,7 @@ func (s *V1Service) generateCustomVideo(ctx context.Context, eventID string, mod if len(active) == 0 { return nil, "", ErrNoProviderAccount } - size := upstreamSize(aspectRatio, resolution) + size := upstreamVideoSize(aspectRatio, resolution) var lastErr error var videoURL string busy := 0 @@ -1974,6 +1974,38 @@ func upstreamSize(aspectRatio, resolution string) string { return fmt.Sprintf("%dx%d", base*w/h, base) } +// upstreamVideoSize maps our (ratio, resolution) to a "WxH" size for video +// upstreams. Video "Np" tiers set the SHORT edge in pixels (like grok: +// 720p 1:1 → 720x720, 720p 16:9 → 1280x720); 2K/4K fall back to the +// long-edge mapping shared with images. +func upstreamVideoSize(aspectRatio, resolution string) string { + short := 0 + switch res := strings.ToLower(strings.TrimSpace(resolution)); res { + case "540p": + short = 540 + case "720p", "": + short = 720 + case "1080p": + short = 1080 + } + if short == 0 { + return upstreamSize(aspectRatio, resolution) + } + w, h := 1, 1 + parts := strings.Split(strings.ReplaceAll(strings.TrimSpace(aspectRatio), "x", ":"), ":") + if len(parts) == 2 { + if a, e1 := strconv.Atoi(strings.TrimSpace(parts[0])); e1 == nil && a > 0 { + if b, e2 := strconv.Atoi(strings.TrimSpace(parts[1])); e2 == nil && b > 0 { + w, h = a, b + } + } + } + if w >= h { + return fmt.Sprintf("%dx%d", short*w/h, short) + } + return fmt.Sprintf("%dx%d", short, short*h/w) +} + // upstreamQuality maps a resolution tier to the OpenAI quality enum. func upstreamQuality(resolution string) string { switch strings.ToUpper(strings.TrimSpace(resolution)) { diff --git a/frontend/src/views/PlaygroundView.vue b/frontend/src/views/PlaygroundView.vue index d0ce0f5..816f583 100644 --- a/frontend/src/views/PlaygroundView.vue +++ b/frontend/src/views/PlaygroundView.vue @@ -303,7 +303,13 @@ async function copyImage(url) { const count = ref(1) const batchCount = computed(() => (mode.value === 'image' ? Math.max(1, Math.min(4, count.value)) : 1)) +// Guard against accidental double-clicks: a second run() within 600ms is +// ignored (each click otherwise fires an independent, charged generation). +let lastRunAt = 0 async function run() { + const now = Date.now() + if (now - lastRunAt < 600) return + lastRunAt = now if (!modelId.value) { error.value = '请选择模型'; return } if (!prompt.value.trim()) { error.value = '请输入提示词'; return } if (refsRequired.value && refImages.value.length < 1) {