market-assistant/backend/pipeline/tests/test_marketing_detail_pack.py
hub-gif 31e8482442 feat(marketing): 扩展营销内容条数与中长文案(仍禁止编造)
第二步提高标题/卖点/FAQ 等上限;新增详情中段叙事、食用搭配、短图文变体、直播要点提纲;提示词强调更丰富≠编造;normalize 与导出、策略预览 JSON 分区同步;alignment 留痕更新。

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

102 lines
5.1 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.

"""营销内容包:两步 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["detail_mid_story_paragraphs"], [])
self.assertEqual(n["live_script_bullets"], [])
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秒从俯拍早餐桌缓慢推近至饼干包装无对白干净色调无疗效字幕",
"detail_mid_story_paragraphs": ["段落一适合控糖早餐。", "段落二配料可核对。"],
"usage_and_pairing_tips": ["配无糖酸奶", "开封后密封防潮"],
"short_graphic_post_variants": ["低GI早餐饼干小包装方便。"],
"live_script_bullets": ["大家好看配料表", "独立小包控量", "适合加餐"],
}
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)