fix(generation): include missing @ mention in error
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 6m25s

This commit is contained in:
zyc 2026-05-25 14:09:39 +08:00
parent 540f8ef4bb
commit ac12c0fbd4
3 changed files with 19 additions and 13 deletions

View File

@ -91,12 +91,15 @@ def _format_prompt_for_ark(prompt, label_placeholders):
return result
_ORPHAN_MATERIAL_MENTION_RE = re.compile(r'@(?:图片|视频|音频|素材)\S*')
_ORPHAN_MATERIAL_MENTION_RE = re.compile(r'@(?:图片|视频|音频|素材)[^\s,.!?;:)]*')
def _has_orphan_material_mention(prompt, references):
"""Detect a material @mention in prompt when no reference payload arrived."""
return bool(prompt and not references and _ORPHAN_MATERIAL_MENTION_RE.search(prompt))
def _find_orphan_material_mention(prompt, references):
"""Return a material @mention in prompt when no reference payload arrived."""
if not prompt or references:
return None
match = _ORPHAN_MATERIAL_MENTION_RE.search(prompt)
return match.group(0) if match else None
def _get_token_price(config, model, has_video_ref, resolution):
@ -239,7 +242,8 @@ def video_generate_view(request):
search_mode = request.data.get('search_mode', 'off')
seed = _safe_int(request.data.get('seed', -1), -1)
if _has_orphan_material_mention(prompt, references):
orphan_mention = _find_orphan_material_mention(prompt, references)
if orphan_mention:
logger.warning(
'Blocked generate with material @mention but empty references (user=%s prompt=%s)',
user.id,
@ -247,7 +251,7 @@ def video_generate_view(request):
)
return Response({
'error': 'missing_references',
'message': '@对应的内容为空',
'message': f'{orphan_mention} 对应的内容为空',
}, status=status.HTTP_400_BAD_REQUEST)
# 1080P 仅 Seedance 2.0 支持Fast 不支持

View File

@ -152,7 +152,7 @@ class TestVideoGenerateArkPrompt(TestCase):
resp = self._post_generate('@图片1 走过来', [])
self.assertEqual(resp.status_code, 400, resp.content)
self.assertEqual(resp.json().get('error'), 'missing_references')
self.assertEqual(resp.json().get('message'), '@对应的内容为空')
self.assertEqual(resp.json().get('message'), '@图片1 对应的内容为空')
self.assertFalse(mock_create_task.called)
self.assertFalse(GenerationRecord.objects.filter(user=self.user).exists())

View File

@ -54,13 +54,14 @@ function mapProgress(backendStatus: string): number {
return 50;
}
const ORPHAN_MATERIAL_MENTION_RE = /@(?:图片|视频|音频|素材)\S*/;
const ORPHAN_MATERIAL_MENTION_RE = /@(?:图片|视频|音频|素材)[^\s,.!?;:)]*/;
function hasOrphanMaterialMention(input: ReturnType<typeof useInputBarStore.getState>): boolean {
if (input.mode !== 'universal') return false;
function findOrphanMaterialMention(input: ReturnType<typeof useInputBarStore.getState>): string | null {
if (input.mode !== 'universal') return null;
const hasDirectRefs = input.references.length > 0;
const hasAssetMentions = (input.assetMentions || []).length > 0;
return !hasDirectRefs && !hasAssetMentions && ORPHAN_MATERIAL_MENTION_RE.test(input.prompt);
if (hasDirectRefs || hasAssetMentions) return null;
return input.prompt.match(ORPHAN_MATERIAL_MENTION_RE)?.[0] || null;
}
/** Check if a URL is an asset library reference (case-insensitive protocol). */
@ -323,8 +324,9 @@ export const useGenerationStore = create<GenerationState>((set, get) => ({
addTask: async () => {
const input = useInputBarStore.getState();
if (hasOrphanMaterialMention(input)) {
showToast('@对应的内容为空');
const orphanMention = findOrphanMaterialMention(input);
if (orphanMention) {
showToast(`${orphanMention} 对应的内容为空`);
return null;
}
if (!input.canSubmit()) return null;