From e2de75c9f6bef6d8f2a6836702a5318ee2314688 Mon Sep 17 00:00:00 2001 From: Xiaoxia Agent Date: Mon, 5 Oct 2026 21:55:57 +0800 Subject: [PATCH] =?UTF-8?q?fix(test):=20=E9=80=82=E9=85=8D#2200/#2207=20V2?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E5=88=86=E6=9E=90=E6=89=B9=E5=A4=84=E7=90=86?= =?UTF-8?q?=E6=9E=B6=E6=9E=84=EF=BC=88=E7=A7=BB=E9=99=A4=5Fanalyze=5Fsingl?= =?UTF-8?q?e=5Fimage=E6=96=AD=E8=A8=80=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/unit/test_viral_video_wiring.py | 69 ++++++++++++++++++++------- 1 file changed, 51 insertions(+), 18 deletions(-) diff --git a/tests/unit/test_viral_video_wiring.py b/tests/unit/test_viral_video_wiring.py index fe5ada00e..81d2bfb12 100644 --- a/tests/unit/test_viral_video_wiring.py +++ b/tests/unit/test_viral_video_wiring.py @@ -97,21 +97,43 @@ def invalidate_loader_cache(): class TestImageAnalysisWiring: - def test_uses_loader_template_and_xml_parse(self, job): + def test_step_image_analysis_uses_v2_batch_path(self, job): + """#2200/#2207 后图片分析走 V2 批处理(OCR+lite JSON 并行), + _step_image_analysis 归一化 URL 后调用 analyze_images_v2。""" from apps.worker.worker_app.tasks import viral_video as vv - with patch("packages.shared.ai_service.call_vision", return_value=IMAGE_XML) as mock_v: - result = vv._analyze_single_image(0, "https://img/1.jpg", "vlm-lite", 15) + fake_product = { + "name": "lipstick", + "brand": "品牌X", + "category": "唇部彩妆", + "key_features": ["显白", "持久"], + "text_on_package": ["品牌X", "211"], + "_source": "v2", + } + with patch.object(vv, "_normalize_image_url", side_effect=lambda raw, idx: raw): + with patch( + "worker_app.tasks.vision.analyze_images_v2", + return_value=[fake_product, fake_product], + create=True, + ) as mock_v2: + result = vv._step_image_analysis(job) - mock_v.assert_called_once() - # 验证调用时传入了 system_prompt(说明走了 loader 渲染的模板) - call_kwargs = mock_v.call_args.kwargs - assert "system_prompt" in call_kwargs and call_kwargs["system_prompt"] - # 结果包含从 XML 解析出的产品信息 - assert result["name"] == "lipstick" - assert result["brand"] == "品牌X" - assert "显白" in result["key_features"] - assert result["text_on_package"] == ["品牌X", "211"] + mock_v2.assert_called_once() + # 传入的是归一化后的图片 URL 列表 + assert mock_v2.call_args.args[0] == job.images + products = result["products"] + assert len(products) == 2 + assert products[0]["name"] == "lipstick" + assert products[0]["brand"] == "品牌X" + assert "显白" in products[0]["key_features"] + assert products[0]["text_on_package"] == ["品牌X", "211"] + + def test_step_image_analysis_empty_images(self, job): + from apps.worker.worker_app.tasks import viral_video as vv + + job.images = [] + result = vv._step_image_analysis(job) + assert result == {"products": []} # ── 2) 意图解析走模板 ─────────────────────────────────────────────── @@ -252,18 +274,29 @@ class TestEndToEndLoaderUsed: called_types.append(prompt_type) return real_get(prompt_type, **kwargs) + v2_product = { + "name": "lipstick", + "brand": "品牌X", + "key_features": ["显白", "持久"], + } with ( patch.object(pl, "get_template", side_effect=spy_get), - patch("packages.shared.ai_service.call_vision", return_value=IMAGE_XML), + patch.object(vv, "_normalize_image_url", side_effect=lambda raw, idx: raw), + patch( + "worker_app.tasks.vision.analyze_images_v2", + return_value=[v2_product], + create=True, + ), patch("packages.shared.ai_service.call_llm", return_value=INTENT_XML), ): - # 1) image - img_res = vv._analyze_single_image(0, "https://img/1.jpg", "vlm", 15) - # 2) intent + # 1) image(V2 路径,不再经过 prompt_loader) + img_step = vv._step_image_analysis(job) + img_res = img_step["products"][0] + # 2) intent(走 loader image_analysis? 否——intent_parsing 模板) intent_res = vv._step_intent_parsing(job, {"products": [img_res]}) - # 前两步分别调用了 image_analysis 和 intent_parsing - assert "image_analysis" in called_types + # V2 图片分析不再调用 loader;意图解析调用 intent_parsing 模板 + assert "image_analysis" not in called_types assert "intent_parsing" in called_types # script 和 review 单独验证(需要不同的 LLM 返回)