mirror of
https://github.com/primedigitaltech/market-assistant.git
synced 2026-07-23 00:21:41 +08:00
第二步提高标题/卖点/FAQ 等上限;新增详情中段叙事、食用搭配、短图文变体、直播要点提纲;提示词强调更丰富≠编造;normalize 与导出、策略预览 JSON 分区同步;alignment 留痕更新。 Made-with: Cursor
102 lines
5.1 KiB
Python
102 lines
5.1 KiB
Python
"""营销内容包:两步 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:16,5秒:从俯拍早餐桌缓慢推近至饼干包装,无对白,干净色调,无疗效字幕",
|
||
"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)
|