diff --git a/web/src/components/Toolbar.tsx b/web/src/components/Toolbar.tsx index 5bda6e9..2f431a5 100644 --- a/web/src/components/Toolbar.tsx +++ b/web/src/components/Toolbar.tsx @@ -3,6 +3,7 @@ import { useInputBarStore } from '../store/inputBar'; import { useGenerationStore } from '../store/generation'; import { useAuthStore } from '../store/auth'; import { Dropdown } from './Dropdown'; +import { showToast } from './Toast'; import type { CreationMode, AspectRatio, Duration, GenerationType, ModelOption } from '../types'; import styles from './Toolbar.module.css'; @@ -145,7 +146,14 @@ export function Toolbar() { }, [estimatedTokens, model, references, team]); const handleSend = useCallback(() => { - if (!isSubmittable) return; + if (!isSubmittable) { + const s = useInputBarStore.getState(); + if (s.mode === 'universal' && s.references.some((r) => r.type === 'audio') + && !s.references.some((r) => r.type === 'image' || r.type === 'video')) { + showToast('音频不能作为唯一的参考素材,请同时添加图片或视频'); + } + return; + } addTask(); }, [isSubmittable, addTask]); diff --git a/web/src/store/inputBar.ts b/web/src/store/inputBar.ts index dc3900d..b434f51 100644 --- a/web/src/store/inputBar.ts +++ b/web/src/store/inputBar.ts @@ -285,10 +285,19 @@ export const useInputBarStore = create((set, get) => ({ ? state.references.length > 0 : state.firstFrame !== null || state.lastFrame !== null; if (!hasText && !hasFiles) return false; - // Audio cannot be sent alone — must have image or video - if (state.mode === 'universal' && state.references.length > 0) { - const hasImageOrVideo = state.references.some((r) => r.type === 'image' || r.type === 'video'); - if (!hasImageOrVideo && !hasText) return false; + // Audio cannot be the only reference — Seedance API requires image or video alongside + if (state.mode === 'universal') { + const hasAudioRef = state.references.some((r) => r.type === 'audio'); + const hasAudioAsset = (state.assetMentions || []).some((m: Record) => + (m.assetType || '').toLowerCase() === 'audio'); + if (hasAudioRef || hasAudioAsset) { + const hasImageOrVideoRef = state.references.some((r) => r.type === 'image' || r.type === 'video'); + const hasImageOrVideoAsset = (state.assetMentions || []).some((m: Record) => { + const t = (m.assetType || '').toLowerCase(); + return t === 'image' || t === 'video'; + }); + if (!hasImageOrVideoRef && !hasImageOrVideoAsset) return false; + } } // Block submit if any reference is still uploading or failed if (state.references.some((r) => r.uploading || r.uploadError)) return false;