mirror of
https://github.com/primedigitaltech/market-assistant.git
synced 2026-07-24 09:11:37 +08:00
feat(report): remove §5 competitor matrix table, keep per-group charts
Made-with: Cursor
This commit is contained in:
parent
a1d0fa6686
commit
c45ec66d4c
@ -3,7 +3,7 @@
|
|||||||
关键词 → 调用 ``jd_keyword_pipeline`` 全链路采集 → 生成 **标准化竞品分析报告**(Markdown)。
|
关键词 → 调用 ``jd_keyword_pipeline`` 全链路采集 → 生成 **标准化竞品分析报告**(Markdown)。
|
||||||
|
|
||||||
报告结构对齐常见竞品分析框架:研究范围与方法、执行摘要、**整体市场观察(列表可见度 proxy)**、
|
报告结构对齐常见竞品分析框架:研究范围与方法、执行摘要、**整体市场观察(列表可见度 proxy)**、
|
||||||
市场与竞争结构、**按细分类目分组的竞品对比矩阵**、价格分析、产品与宣称、**按细分类目的消费者反馈与用户画像**、策略提示与附录;并明确数据边界。
|
市场与竞争结构、**按细分类目分组的竞品结构(统计图 + 合并表外置)**、价格分析、产品与宣称、**按细分类目的消费者反馈与用户画像**、策略提示与附录;并明确数据边界。
|
||||||
若运行配置中提供了外部市场规模摘录(``EXTERNAL_MARKET_TABLE_ROWS``),则追加对应表格小节;否则不输出占位行。
|
若运行配置中提供了外部市场规模摘录(``EXTERNAL_MARKET_TABLE_ROWS``),则追加对应表格小节;否则不输出占位行。
|
||||||
|
|
||||||
依赖:全量抓取时与 ``jd_keyword_pipeline.py`` 相同(Node、h5st、Playwright、``common/jd_cookie.txt``)。
|
依赖:全量抓取时与 ``jd_keyword_pipeline.py`` 相同(Node、h5st、Playwright、``common/jd_cookie.txt``)。
|
||||||
@ -1655,7 +1655,7 @@ def _lines_4_reading_category(
|
|||||||
"",
|
"",
|
||||||
f"- 列表侧可读类目/简称共 **{len(cm_structure)}** 种取值,合计 **{total}** 行;"
|
f"- 列表侧可读类目/简称共 **{len(cm_structure)}** 种取值,合计 **{total}** 行;"
|
||||||
f"其中「{_md_cell(top_lbl, 40)}」行数最多,约占 **{100 * share:.1f}%**。",
|
f"其中「{_md_cell(top_lbl, 40)}」行数最多,约占 **{100 * share:.1f}%**。",
|
||||||
"- 若头部类目占比极高,说明当前关键词下货架被少数品类定义;跨品类机会需结合商详矩阵(§5)再核对。",
|
"- 若头部类目占比极高,说明当前关键词下货架被少数品类定义;跨品类机会需结合 §5 细类结构与合并表再核对。",
|
||||||
"",
|
"",
|
||||||
"| 类目/简称(Top 5) | 列表行数 | 占本章结构样本 |",
|
"| 类目/简称(Top 5) | 列表行数 | 占本章结构样本 |",
|
||||||
"| --- | ---: | ---: |",
|
"| --- | ---: | ---: |",
|
||||||
@ -1800,7 +1800,7 @@ def build_competitor_markdown(
|
|||||||
"- **用途/场景**:对每条评价独立判断是否命中预设场景词;一条可计入多个场景,统计的是「提及该场景的评价条数」而非用户数。",
|
"- **用途/场景**:对每条评价独立判断是否命中预设场景词;一条可计入多个场景,统计的是「提及该场景的评价条数」而非用户数。",
|
||||||
"- **用户画像(第八章)**:正负面粗判含**口语短语**级摘录;关注词与场景**仅按细类**以条形图展示(场景图为**占该细类有效文本比例 %**);见 §8.3~8.4。",
|
"- **用户画像(第八章)**:正负面粗判含**口语短语**级摘录;关注词与场景**仅按细类**以条形图展示(场景图为**占该细类有效文本比例 %**);见 §8.3~8.4。",
|
||||||
"- **各章衔接(可选)**:若任务配置 ``llm_section_bridges``(或部署侧环境变量启用),则在「## 一」至「## 九」各章二级标题后插入大模型撰写的**衔接分析**段落,便于阅读过渡;**定量结论仍以正文表格与摘要 JSON 为准**。",
|
"- **各章衔接(可选)**:若任务配置 ``llm_section_bridges``(或部署侧环境变量启用),则在「## 一」至「## 九」各章二级标题后插入大模型撰写的**衔接分析**段落,便于阅读过渡;**定量结论仍以正文表格与摘要 JSON 为准**。",
|
||||||
"- **细类大模型归纳(可选)**:若任务配置 ``llm_matrix_group_summaries`` / ``llm_price_group_summaries`` / ``llm_comment_group_summaries``(或对应 ``MA_ENABLE_LLM_*`` 环境变量),则在 **§5.1、§6.2、§8.6** 分别插入卖点/价盘/评论关注词的细类归纳;**仍以同章表格与 CSV 为准**。",
|
"- **细类大模型归纳(可选)**:若任务配置 ``llm_price_group_summaries`` / ``llm_comment_group_summaries``(或对应 ``MA_ENABLE_LLM_*`` 环境变量),则在 **§6.2、§8.6** 插入价盘/评论关注词的细类归纳;**§5 不再输出矩阵表**,卖点/配料等仍以 ``keyword_pipeline_merged.csv`` 与 JSON 为准。",
|
||||||
"- **检索结果规模**:来自京东 PC 搜索返回的「结果条数」类指标,表示平台侧申报的匹配数量级,**不等于**动销、库存或独立 SKU 数。",
|
"- **检索结果规模**:来自京东 PC 搜索返回的「结果条数」类指标,表示平台侧申报的匹配数量级,**不等于**动销、库存或独立 SKU 数。",
|
||||||
"",
|
"",
|
||||||
"### 1.4 主要局限",
|
"### 1.4 主要局限",
|
||||||
@ -1863,7 +1863,7 @@ def build_competitor_markdown(
|
|||||||
)
|
)
|
||||||
elif list_export and cr1_deep is not None and top_brand_deep and not brands_s:
|
elif list_export and cr1_deep is not None and top_brand_deep and not brands_s:
|
||||||
exec_bullets.append(
|
exec_bullets.append(
|
||||||
f"列表导出缺少品牌标题字段,**深入 {n_sku} SKU** 商详品牌第一大品牌份额 ≈ **{100 * cr1_deep:.1f}%**(「{top_brand_deep}」),供与 §5 矩阵对照。"
|
f"列表导出缺少品牌标题字段,**深入 {n_sku} SKU** 商详品牌第一大品牌份额 ≈ **{100 * cr1_deep:.1f}%**(「{top_brand_deep}」),供与 §5 细类结构对照。"
|
||||||
)
|
)
|
||||||
if pst:
|
if pst:
|
||||||
price_src_short = (
|
price_src_short = (
|
||||||
@ -2053,7 +2053,7 @@ def build_competitor_markdown(
|
|||||||
lines.append(
|
lines.append(
|
||||||
f"*列表导出中店铺/品牌标题有效 **{brand_rows_n}** 条,"
|
f"*列表导出中店铺/品牌标题有效 **{brand_rows_n}** 条,"
|
||||||
f"低于建议阈值(≥{min_brand_rows}),品牌集中度未展开。**店铺结构见 §4.2**;"
|
f"低于建议阈值(≥{min_brand_rows}),品牌集中度未展开。**店铺结构见 §4.2**;"
|
||||||
f"商详品牌在 **§5**。*"
|
f"商详品牌在 **§5 细类结构**。*"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
lines.append("*深入子样本无可用品牌字段。*")
|
lines.append("*深入子样本无可用品牌字段。*")
|
||||||
@ -2116,24 +2116,17 @@ def build_competitor_markdown(
|
|||||||
[
|
[
|
||||||
"---",
|
"---",
|
||||||
"",
|
"",
|
||||||
"## 五、竞品对比矩阵(按细分类目分组)",
|
"## 五、竞品结构(按细分类目分组)",
|
||||||
"",
|
"",
|
||||||
"优先按商详**类目路径**列分组:**三级路径**取中间一段(如 … > **饼干** > 粗粮饼干),"
|
"SKU 依商详**类目路径**聚合为细类:**三级路径**取中间一段(如 … > **饼干** > 粗粮饼干),"
|
||||||
"**四级及以上**取倒数第二段(如 … > **面条** > 挂面)。若该列为空,退化为搜索列表中的类目或规格属性;仍无则「未归类」。全量合并模式下另有更多商详字段可供核对。",
|
"**四级及以上**取倒数第二段(如 … > **面条** > 挂面);类目列为空时退化为列表类目或规格,仍无则「未归类」。",
|
||||||
"",
|
"",
|
||||||
"维度说明:**产品**(标题/规格)、**价格**(列表展示)、**渠道**(京东店铺)、**推广**(卖点/榜单文案)、"
|
"**本版不再在正文打印细类矩阵表**(宽表影响阅读);各 SKU 的标题、品牌、店铺、标价/详情价、卖点、配料、评价量与摘要等,"
|
||||||
"**类目**、**配料表**(见下)、**声量**(评价量与摘要)。",
|
"请直接查看本批次目录下 ``keyword_pipeline_merged.csv``,或调用 API 结构化字段 ``matrix_by_group``。",
|
||||||
"",
|
"下列按细类给出 **SKU 款数** 及 **展示价 / 评价量** 统计图(与合并表、``matrix_by_group`` 同源)。",
|
||||||
"**配料表**:优先使用配料正文列(开启配料视觉解析时为识别出的文字);"
|
|
||||||
"仅有详情长图链接时列内会提示;若商详参数含「配料/配料表:」则摘录该段。"
|
|
||||||
"均为页面信息摘录,**以包装实物与法规标签为准**。",
|
|
||||||
"",
|
"",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
matrix_header = [
|
|
||||||
"| SKU | 产品(标题) | 品牌 | 标价 | 详情价 | 渠道(店铺) | 推广(卖点) | 榜单/标签 | 类目 | 配料表 | 评价量(搜索) | 消费者反馈摘要 |",
|
|
||||||
"| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |",
|
|
||||||
]
|
|
||||||
grouped_matrix = _merged_rows_grouped_for_matrix(merged_rows)
|
grouped_matrix = _merged_rows_grouped_for_matrix(merged_rows)
|
||||||
if not grouped_matrix:
|
if not grouped_matrix:
|
||||||
lines.append("*无合并表 SKU。*")
|
lines.append("*无合并表 SKU。*")
|
||||||
@ -2141,39 +2134,20 @@ def build_competitor_markdown(
|
|||||||
for gi, (gname, grows) in enumerate(grouped_matrix):
|
for gi, (gname, grows) in enumerate(grouped_matrix):
|
||||||
lines.append(f"### {gname}(**{len(grows)}** 款)")
|
lines.append(f"### {gname}(**{len(grows)}** 款)")
|
||||||
lines.append("")
|
lines.append("")
|
||||||
lines.extend(matrix_header)
|
lines.append(
|
||||||
grows_sorted = sorted(grows, key=lambda r: _cell(r, sku_header) or "")
|
"*SKU 级字段明细见 ``keyword_pipeline_merged.csv``(本细类 SKU 与上节分组规则一致)。*"
|
||||||
for row in grows_sorted:
|
)
|
||||||
lines.append(
|
|
||||||
_competitor_matrix_md_line(
|
|
||||||
row, sku_header=sku_header, title_h=title_h
|
|
||||||
)
|
|
||||||
)
|
|
||||||
lines.append("")
|
lines.append("")
|
||||||
slug_mx = _scenario_group_asset_slug(gname, gi)
|
slug_mx = _scenario_group_asset_slug(gname, gi)
|
||||||
lines.extend(
|
lines.extend(
|
||||||
_embed_chart(
|
_embed_chart(
|
||||||
run_dir,
|
run_dir,
|
||||||
f"chart_matrix_prices_reviews__{slug_mx}.png",
|
f"chart_matrix_prices_reviews__{slug_mx}.png",
|
||||||
f"「{_md_cell(gname, 24)}」细类 · **展示价与评价量**(条形图;与上表同源:"
|
f"「{_md_cell(gname, 24)}」细类 · **展示价与评价量**(条形图;与合并表及 ``matrix_by_group`` 同源:"
|
||||||
f"价取 detail_price_final→标价→券后 优先可解析数值;评价量为搜索侧「评价量」字段摘录)",
|
f"价取 detail_price_final→标价→券后 优先可解析数值;评价量为搜索侧「评价量」字段摘录)",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
_mx_llm = (llm_matrix_section_md or "").strip()
|
|
||||||
if _mx_llm:
|
|
||||||
lines.extend(
|
|
||||||
[
|
|
||||||
"",
|
|
||||||
"### 5.1 细类要点归纳(大模型)",
|
|
||||||
"",
|
|
||||||
"> **说明**:模型按 §5 同细类拆分,仅基于上表矩阵摘录(标题/卖点/配料等)与每细类 ``price_stats``(与 §6 分位数同源对象)归纳;**不含**医学或功效结论。配料与宣称以页面为准。",
|
|
||||||
"",
|
|
||||||
_mx_llm,
|
|
||||||
"",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
ch6_price_title = (
|
ch6_price_title = (
|
||||||
"## 六、价格分析(PC 搜索列表全量)"
|
"## 六、价格分析(PC 搜索列表全量)"
|
||||||
if list_export and pst_list.get("n", 0) > 0
|
if list_export and pst_list.get("n", 0) > 0
|
||||||
@ -2237,7 +2211,7 @@ def build_competitor_markdown(
|
|||||||
"### 6.2 细类价盘要点归纳(大模型)",
|
"### 6.2 细类价盘要点归纳(大模型)",
|
||||||
"",
|
"",
|
||||||
"> **说明**:以下为模型按 §5 同细类拆分、仅基于上文本节价统计与价字段摘录的归纳(价带与价差);"
|
"> **说明**:以下为模型按 §5 同细类拆分、仅基于上文本节价统计与价字段摘录的归纳(价带与价差);"
|
||||||
"不含配料/宣称/场景关键词分析——见 §5「细类要点归纳(大模型)」。具体数值仍以正文表格及批次 CSV 为准。",
|
"不含配料/宣称/场景关键词分析。具体数值仍以 **§6** 表格及 ``keyword_pipeline_merged.csv`` 为准。",
|
||||||
"",
|
"",
|
||||||
_pr_llm,
|
_pr_llm,
|
||||||
"",
|
"",
|
||||||
@ -2265,7 +2239,7 @@ def build_competitor_markdown(
|
|||||||
"",
|
"",
|
||||||
"### 8.1 方法",
|
"### 8.1 方法",
|
||||||
"",
|
"",
|
||||||
"- **细类划分**:与 **§5 竞品矩阵** 相同,依据商详类目路径解析为「饼干 / 西式糕点 / …」等(规则见 §5 章首说明)。",
|
"- **细类划分**:与 **§5** 相同的商详类目路径规则(见 §5 章首)。",
|
||||||
"- **归因**:每条评价按其 SKU 对应到深入样本,再映射到该 SKU 所属细类;SKU 不在合并表中的评价单独归入说明性分组。",
|
"- **归因**:每条评价按其 SKU 对应到深入样本,再映射到该 SKU 所属细类;SKU 不在合并表中的评价单独归入说明性分组。",
|
||||||
"- **正负面粗判(§8.2)**:先以关键词规则与图表做粗分;若任务开启 **llm_comment_sentiment**,可附**大模型对抽样原文的主题归因**(尤其负向「用户在抱怨什么」),与词频条形图互补。",
|
"- **正负面粗判(§8.2)**:先以关键词规则与图表做粗分;若任务开启 **llm_comment_sentiment**,可附**大模型对抽样原文的主题归因**(尤其负向「用户在抱怨什么」),与词频条形图互补。",
|
||||||
"- **关注词按细类(§8.3)**:对组内评价正文做子串计数并出条形图;若无逐条正文则用该细类下评价摘要列拼接兜底;与配置关注词及联想扩展同源。",
|
"- **关注词按细类(§8.3)**:对组内评价正文做子串计数并出条形图;若无逐条正文则用该细类下评价摘要列拼接兜底;与配置关注词及联想扩展同源。",
|
||||||
|
|||||||
@ -431,24 +431,8 @@ def write_competitor_analysis_for_run_dir(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if want_mx and not skip_mx and merged_rows:
|
if want_mx and not skip_mx and merged_rows:
|
||||||
pl_mx = jcr.build_matrix_groups_llm_payload(
|
# §5 正文已取消细类矩阵表,不再向报告嵌入矩阵要点 LLM 段落。
|
||||||
merged_rows, sku_header=sku_h, title_h=title_h
|
matrix_llm_rec["skipped"] = "matrix_table_removed_from_report"
|
||||||
)
|
|
||||||
if pl_mx:
|
|
||||||
matrix_llm_rec["attempted"] = True
|
|
||||||
try:
|
|
||||||
from .llm_generate import generate_matrix_group_summaries_llm
|
|
||||||
|
|
||||||
llm_matrix_md = generate_matrix_group_summaries_llm(
|
|
||||||
pl_mx, keyword=kw
|
|
||||||
)
|
|
||||||
matrix_llm_rec["ok"] = True
|
|
||||||
matrix_llm_rec["chars"] = len(llm_matrix_md)
|
|
||||||
except Exception as e:
|
|
||||||
matrix_llm_rec["ok"] = False
|
|
||||||
matrix_llm_rec["error"] = str(e)
|
|
||||||
else:
|
|
||||||
matrix_llm_rec["skipped"] = "empty_matrix_payload"
|
|
||||||
elif skip_mx:
|
elif skip_mx:
|
||||||
matrix_llm_rec["skipped"] = "MA_SKIP_LLM_MATRIX_GROUP_SUMMARIES"
|
matrix_llm_rec["skipped"] = "MA_SKIP_LLM_MATRIX_GROUP_SUMMARIES"
|
||||||
elif not want_mx:
|
elif not want_mx:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user