market-assistant/backend/pipeline/tests/test_marketing_detail_pack.py
hub-gif 6470d0d56c feat(marketing): 营销内容命名、文生图/视频提示词与结果规范化
两步 LLM 增加可复制文生图/文生视频提示词并强化卖点可视化;normalize_detail_page_pack 补全键;产品用语由商详包改为营销内容;前端导出 Markdown 与策略预览区展示一致;营销包落盘模块入库。

Made-with: Cursor
2026-04-22 15:35:35 +08:00

96 lines
4.6 KiB
Python
Raw 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.

"""营销内容包:两步 JSON LLM 与解析。"""
from __future__ import annotations
import json
import tempfile
from unittest.mock import patch
from django.test import SimpleTestCase
from pipeline.llm.generate_marketing_detail import (
_parse_llm_json,
generate_marketing_detail_pack,
normalize_detail_page_pack,
)
from pipeline.reporting.marketing_pack_persist import persist_marketing_detail_pack_v1
class MarketingDetailPackTests(SimpleTestCase):
def test_normalize_fills_missing_keys_including_aigc(self) -> None:
"""旧结果或模型漏键时补齐文生图/文生视频等字段。"""
slim = {
"traceability_note": "x",
"main_image_three_points": ["a", "b", "c"],
"live_or_short_hook": "h",
"customer_service_opening": "c",
}
n = normalize_detail_page_pack(slim)
self.assertEqual(n["text_to_image_prompt_main"], "")
self.assertEqual(n["text_to_image_prompt_scene"], "")
self.assertEqual(n["text_to_video_prompt"], "")
self.assertEqual(n["listing_titles"], [])
self.assertEqual(n["traceability_note"], "x")
def test_parse_llm_json_strips_wrapped(self) -> None:
raw = '前缀 {"a": 1, "b": "x"} 后缀'
d = _parse_llm_json(raw)
self.assertEqual(d, {"a": 1, "b": "x"})
def test_parse_llm_json_rejects_non_object(self) -> None:
with self.assertRaises(ValueError):
_parse_llm_json("[1,2]")
def test_generate_marketing_detail_pack_two_calls(self) -> None:
core = {
"what_we_sell": "低GI方向早餐饼干监测关键词语境待业务定主推款",
"one_liner_value": "低负担早餐选择",
"buyer_job_to_be_done": "控糖加餐",
"key_pain_or_desire": "怕升糖",
"why_this_product": "配方可核对",
"proof_or_trust_angle": "输入未体现",
"differentiation_vs_alternatives": "同价带更少添加糖",
"price_value_framing": "中端",
"compliance_taboos": "不涉疗效",
"open_points_for_business": "",
}
pack = {
"listing_titles": ["标题A", "标题B"],
"listing_subtitle": "副文案",
"detail_headline": "首屏一句",
"selling_bullets": ["卖点1"],
"spec_sidebar_lines": [],
"faq": [{"question": "是否低GI", "answer": "以包装与检测为准。"}],
"traceability_note": "与策略方向一致;具体宣称以包装为准。",
"main_image_three_points": ["低GI早餐", "独立小包", "配料可核对"],
"live_or_short_hook": "控糖早餐怎么选?先看配料表。",
"customer_service_opening": "您好,这款饼干适合关注血糖管理的早餐场景,需要我帮您对比规格吗?",
"text_to_image_prompt_main": "电商主图白底居中摆放一盘低GI早餐饼干柔和棚拍光写实无品牌logo健康清爽风格",
"text_to_image_prompt_scene": "早餐餐桌场景,牛奶与饼干搭配,自然窗光,生活感,无文字贴片",
"text_to_video_prompt": "竖屏9:165秒从俯拍早餐桌缓慢推近至饼干包装无对白干净色调无疗效字幕",
}
with patch(
"pipeline.llm.generate_marketing_detail.call_llm",
side_effect=[json.dumps(core, ensure_ascii=False), json.dumps(pack, ensure_ascii=False)],
):
out = generate_marketing_detail_pack(
keyword="低GI",
strategy_markdown="# 策略\n\n- 要点",
strategy_decisions={"product_role": "新品"},
business_notes="",
)
self.assertEqual(out["core_info_card"]["one_liner_value"], "低负担早餐选择")
self.assertEqual(out["detail_page_pack"]["listing_titles"][0], "标题A")
self.assertIn("竖屏", out["detail_page_pack"]["text_to_video_prompt"])
def test_persist_marketing_detail_pack_v1_writes_file(self) -> None:
with tempfile.TemporaryDirectory() as td:
payload = {"schema_version": 1, "job_id": 1, "x": "y"}
path = persist_marketing_detail_pack_v1(td, payload)
self.assertIsNotNone(path)
assert path is not None
self.assertTrue(path.is_file())
self.assertEqual(path.parent.name, "marketing")
self.assertIn("marketing_detail_pack_v1.json", path.name)
loaded = json.loads(path.read_text(encoding="utf-8"))
self.assertEqual(loaded["job_id"], 1)