fix(generation): reject empty @ references
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 5m37s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 5m37s
This commit is contained in:
parent
ab790fbe65
commit
991bb6dd30
@ -1,4 +1,5 @@
|
||||
import logging
|
||||
import re
|
||||
|
||||
from rest_framework import status
|
||||
from rest_framework.decorators import api_view, permission_classes, parser_classes
|
||||
@ -90,6 +91,14 @@ def _format_prompt_for_ark(prompt, label_placeholders):
|
||||
return result
|
||||
|
||||
|
||||
_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 _get_token_price(config, model, has_video_ref, resolution):
|
||||
"""根据模型、是否含视频、分辨率选择单价。
|
||||
|
||||
@ -226,9 +235,21 @@ def video_generate_view(request):
|
||||
aspect_ratio = serializer.validated_data['aspect_ratio']
|
||||
# serializer 已设 default='720p' + choices 约束,validated_data 必有合法值
|
||||
resolution = serializer.validated_data['resolution']
|
||||
references = serializer.validated_data.get('references', [])
|
||||
search_mode = request.data.get('search_mode', 'off')
|
||||
seed = _safe_int(request.data.get('seed', -1), -1)
|
||||
|
||||
if _has_orphan_material_mention(prompt, references):
|
||||
logger.warning(
|
||||
'Blocked generate with material @mention but empty references (user=%s prompt=%s)',
|
||||
user.id,
|
||||
prompt[:120],
|
||||
)
|
||||
return Response({
|
||||
'error': 'missing_references',
|
||||
'message': '@对应的内容为空',
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 1080P 仅 Seedance 2.0 支持,Fast 不支持
|
||||
if resolution == '1080p' and model == 'seedance_2.0_fast':
|
||||
return Response({
|
||||
@ -238,7 +259,6 @@ def video_generate_view(request):
|
||||
|
||||
# ── 预估 token 和费用 ──
|
||||
config = QuotaConfig.objects.get_or_create(pk=1)[0]
|
||||
references = request.data.get('references', [])
|
||||
w, h = get_resolution(aspect_ratio, resolution)
|
||||
has_video_ref = _has_video_reference(references)
|
||||
input_video_dur = _sum_video_duration(references) if has_video_ref else 0
|
||||
@ -335,7 +355,6 @@ def video_generate_view(request):
|
||||
}, status=status.HTTP_429_TOO_MANY_REQUESTS)
|
||||
|
||||
# 构建参考素材
|
||||
references = request.data.get('references', [])
|
||||
# 火山限制最多 9 张参考图片
|
||||
image_count = sum(1 for r in references if r.get('type', 'image') == 'image')
|
||||
if image_count > 9:
|
||||
|
||||
@ -146,6 +146,16 @@ class TestVideoGenerateArkPrompt(TestCase):
|
||||
'references': references,
|
||||
}, format='json')
|
||||
|
||||
@mock.patch('apps.generation.views.create_task')
|
||||
def test_reject_material_mention_without_references(self, mock_create_task):
|
||||
"""事故回归:prompt 含 @图片 但 references 为空时,不能创建 refs=0 脏任务。"""
|
||||
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.assertFalse(mock_create_task.called)
|
||||
self.assertFalse(GenerationRecord.objects.filter(user=self.user).exists())
|
||||
|
||||
@mock.patch('apps.generation.tasks.poll_video_task')
|
||||
@mock.patch('apps.generation.views.create_task')
|
||||
def test_view_converts_prompt_for_local_assets(self, mock_create_task, mock_poll):
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user