Files
xiaoxia-saas/tests/unit/test_viral_parser_field_mapping.py
xiaoxia 6cfab71d6e
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Check push changed paths (push) Successful in 4s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 4s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 5s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m43s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m16s
CI/CD Pipeline / Build Staging Web Image (push) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 56s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 4m35s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m25s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m1s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m8s
CI/CD Pipeline / Integration Tests (push) Successful in 3m53s
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 5s
CI/CD Pipeline / Retag skipped Staging Web Image (push) Successful in 24s
CI/CD Pipeline / Validate - Style (push) Successful in 5m33s
AI Code Review / AI Code Review (pull_request) Successful in 6m54s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m42s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m49s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m15s
CI/CD Pipeline / Validate - Security (push) Successful in 9m17s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m5s
CI/CD Pipeline / Unit Tests (push) Successful in 12m12s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
fix(viral-parser): #2308 分镜字段映射修复——<shot>/<visual>/<action_details>三字段拆分 (#2308)
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-10-15 12:07:38 +08:00

166 lines
6.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""#2308 parser字段映射单测:
1. 新schema XML(<shot>+<visual>+<action_details>)字段正确映射
2. 旧schema XML(<visual>混写)能拆分出cam/visual/action
3. markdown中文分镜字段正确提取
"""
from __future__ import annotations
import sys
from unittest.mock import MagicMock
import pytest
@pytest.fixture
def mock_job():
job = MagicMock()
job.duration = 15
job.video_ratio = "9:16"
job.marketing_purpose = "品牌推广"
job.image_analysis = {"images": []}
job.images = []
job.user_copy_text = ""
job.fusion_level = "ai_polish"
return job
def _import_wv(monkeypatch):
for mod in ["worker_app.celery_app", "worker_app.db"]:
monkeypatch.setitem(sys.modules, mod, MagicMock())
import celery
monkeypatch.setattr(celery, "shared_task", lambda **kw: (lambda f: f))
from worker_app.tasks import viral_video as wv
return wv
# === 1. 新schema(v3.1+):独立 <shot>/<visual>/<action_details> ===
NEW_SCHEMA_XML = """<script>
<copy_display_markdown><![CDATA[来御众堂放松一下]]></copy_display_markdown>
<clips>
<clip index="1">
<time_range>0-4秒</time_range>
<voiceover>生完娃,是不是连照镜子都没勇气了?</voiceover>
<shot>中近景平视,50mm f/2.0,缓慢推镜</shot>
<visual>暖光浴室镜前,妈妈略显疲惫地看向镜中自己,镜灯打在侧脸</visual>
<action_details>妈妈手扶洗手台,微微低头再抬眼看镜,眼眶微红</action_details>
<reference_image_index>0</reference_image_index>
</clip>
<clip index="2">
<time_range>4-10秒</time_range>
<voiceover>推开门,暖光和一杯热茶先接住了你。</voiceover>
<shot>中景平视,35mm f/2.8,缓慢平移</shot>
<visual>门店前台暖光木色装修,茶水冒热气,背景柔和虚化</visual>
<action_details>店员微笑双手递上茶杯,妈妈伸手接过,指尖轻触杯沿</action_details>
<reference_image_index>1</reference_image_index>
</clip>
</clips>
<voiceover_script>生完娃,是不是连照镜子都没勇气了?推开门,暖光和一杯热茶先接住了你。</voiceover_script>
<theme>产后妈妈走进御众堂</theme>
</script>"""
def test_new_schema_xml_field_mapping(monkeypatch, mock_job):
wv = _import_wv(monkeypatch)
r = wv._parse_script(NEW_SCHEMA_XML, mock_job)
assert r is not None
assert len(r["shots"]) == 2
s0 = r["shots"][0]
# shot_type 应是纯摄影参数
assert "缓慢推镜" in s0["shot_type_angle_movement"]
assert "妈妈" not in s0["shot_type_angle_movement"]
# scene_and_dialogue 只放对白
assert s0["scene_and_dialogue"] == "生完娃,是不是连照镜子都没勇气了?"
# action_details 有内容
assert "手扶洗手台" in s0["action_details"]
# visual 字段有画面
assert "暖光" in s0["visual"]
assert "推镜" not in s0["visual"]
# === 2. 旧schema(无<shot>/<action_details>标签,<visual>混写):兼容拆分 ===
OLD_SCHEMA_XML = """<script>
<clips>
<clip index="1">
<time_range>0-4秒</time_range>
<voiceover>生完娃,是不是连照镜子都没勇气了?</voiceover>
<visual>中近景平视,暖光下妈妈略显疲惫地看向镜中,镜头缓缓推近,妈妈手扶洗手台微微低头</visual>
<reference_image_index>0</reference_image_index>
</clip>
</clips>
<voiceover_script>生完娃,是不是连照镜子都没勇气了?</voiceover_script>
<theme>测试</theme>
</script>"""
def test_old_schema_xml_splits_visual(monkeypatch, mock_job):
wv = _import_wv(monkeypatch)
r = wv._parse_script(OLD_SCHEMA_XML, mock_job)
assert r is not None
s0 = r["shots"][0]
# 摄影参数段应含景别/运镜关键词
assert "中近景" in s0["shot_type_angle_movement"] or "推" in s0["shot_type_angle_movement"]
# action_details 应含动作动词
assert s0["action_details"], "action_details不应为空(旧schema兼容应从<visual>拆出动作)"
assert "手扶" in s0["action_details"] or "低头" in s0["action_details"]
# scene_and_dialogue 只放对白,不重复画面
assert s0["scene_and_dialogue"] == "生完娃,是不是连照镜子都没勇气了?"
# === 3. markdown 中文分镜字段 ===
MARKDOWN_INPUT = """## 视频主题:御众堂探店
### 镜头1
- 时间范围:0-4秒
- 景别/角度与运镜:中近景平视,缓慢推镜
- 画面:暖光下妈妈看向镜中,镜灯打在侧脸
- 动作与真人细节:妈妈手扶洗手台,微微低头
- 口播:"生完娃,是不是连照镜子都没勇气了?"
### 镜头2
- 时间范围:4-10秒
- 景别:中景平视
- 运镜:缓慢平移
- 画面:门店前台暖光木色装修
- 动作:店员递茶,妈妈伸手接过
- 口播:"推开门,暖光和一杯热茶先接住了你"
"""
def test_markdown_field_extraction(monkeypatch, mock_job):
wv = _import_wv(monkeypatch)
r = wv._parse_script(MARKDOWN_INPUT, mock_job)
assert r is not None
assert len(r["shots"]) == 2
s0 = r["shots"][0]
assert "中近景" in s0["shot_type_angle_movement"]
assert "妈妈手扶洗手台" in s0["action_details"]
assert s0["scene_and_dialogue"] == "生完娃,是不是连照镜子都没勇气了?"
# === 4. _split_visual_field 单元测试 ===
def test_split_visual_field(monkeypatch):
wv = _import_wv(monkeypatch)
# 典型旧schema混写:"中近景平视,暖光下一位妈妈略显疲惫地看向镜中,镜头缓缓推近,妈妈手扶洗手台微微低头"
cam, vis, act = wv._split_visual_field(
"中近景平视,暖光下妈妈略显疲惫地看向镜中,镜头缓缓推近,妈妈手扶洗手台微微低头"
)
assert cam and "中近景" in cam
# 动作/表情段应被拆到 act(含"妈妈"主语+动词)
assert act and ("手扶" in act or "疲惫" in act or "看向" in act)
# 画面描述允许为空(当动作段本身承载了主要画面信息时),或含"暖光"
assert (not vis) or ("暖光" in vis) or ("妈妈" in vis)
def test_split_visual_short(monkeypatch):
wv = _import_wv(monkeypatch)
cam, vis, act = wv._split_visual_field("特写固定镜头")
# 切不开时整体归camera/visual,action为空
assert "特写" in cam
if __name__ == "__main__":
pytest.main([__file__, "-v"])