From f994555f9f9d0a0c082a3aaf96aa7d5291bc96f6 Mon Sep 17 00:00:00 2001 From: hub-gif <2487812171@qq.com> Date: Tue, 14 Apr 2026 15:48:23 +0800 Subject: [PATCH] feat(pipeline): remove llm section bridges from report generation Made-with: Cursor --- .env.example | 3 - .../jd_pc_search/jd_competitor_report.py | 1 - backend/pipeline/jd_runner.py | 63 ------------------- .../pipeline/run_report_llm_chapters_demo.py | 42 +------------ backend/pipeline/serializers.py | 7 +-- .../src/composables/useReportConfigForm.js | 1 - frontend/src/views/jd/JdAnalysisBuildView.vue | 4 +- 7 files changed, 7 insertions(+), 114 deletions(-) diff --git a/.env.example b/.env.example index 19153bb..b19a7fa 100644 --- a/.env.example +++ b/.env.example @@ -33,6 +33,3 @@ CSRF_TRUSTED_ORIGINS=http://localhost:5173,http://127.0.0.1:5173 # MA_SKIP_LLM_KEYWORD_SUGGEST=1 # MA_ENABLE_LLM_COMMENT_SENTIMENT=1 # MA_SKIP_LLM_COMMENT_SENTIMENT=1 -# 各章标题后插入大模型「衔接分析」(任务 report_config.llm_section_bridges 或本项设为 1) -# MA_ENABLE_LLM_SECTION_BRIDGES=1 -# MA_SKIP_LLM_SECTION_BRIDGES=1 diff --git a/backend/crawler_copy/jd_pc_search/jd_competitor_report.py b/backend/crawler_copy/jd_pc_search/jd_competitor_report.py index be30f9b..616f60b 100644 --- a/backend/crawler_copy/jd_pc_search/jd_competitor_report.py +++ b/backend/crawler_copy/jd_pc_search/jd_competitor_report.py @@ -1787,7 +1787,6 @@ def build_competitor_markdown( "- **用途/场景**:对每条评价独立判断是否命中预设场景词;一条可计入多个场景,统计的是「提及该场景的评价条数」而非用户数。", "- **用户画像(第八章)**:正负面粗判含**口语短语**级摘录;关注词与场景**仅按细类**以条形图展示(场景图为**占该细类有效文本比例 %**);见 §8.3~8.4。", "- **细类划分(§5~§8)**:**仅**依据合并表 ``detail_category_path``;该列为空或无法解析出可读细类段的 SKU **不参与**竞品矩阵与按细类评价统计(相关评价条亦**不进入**按细类图表)。", - "- **各章衔接(可选)**:若任务配置 ``llm_section_bridges``(或部署侧环境变量启用),则在「## 一」至「## 九」各章二级标题后插入大模型撰写的**衔接分析**段落,便于阅读过渡;**定量结论仍以正文表格与摘要 JSON 为准**。", "- **检索结果规模**:来自京东 PC 搜索返回的「结果条数」类指标,表示平台侧申报的匹配数量级,**不等于**动销、库存或独立 SKU 数。", "", "### 1.4 主要局限", diff --git a/backend/pipeline/jd_runner.py b/backend/pipeline/jd_runner.py index 1a4eb9d..b6cb96b 100644 --- a/backend/pipeline/jd_runner.py +++ b/backend/pipeline/jd_runner.py @@ -6,7 +6,6 @@ from __future__ import annotations import json import os -import re import sys from pathlib import Path from typing import Any @@ -71,25 +70,6 @@ def merge_llm_report_with_rules_charts(llm_md: str, rules_md: str) -> str: return merge_llm_supplement_with_rules_report(llm_md, rules_md) -def inject_section_bridges_into_markdown(md: str, bridges: dict[str, str]) -> str: - """ - 在「## 一、」…「## 九、」各章标题行之后插入 ``#### 衔接分析(大模型)`` 段落。 - 自第九章向前替换,避免多次插入导致偏移错位。 - """ - out = md - for key in "九八七六五四三二一": - content = (bridges.get(key) or "").strip() - if not content: - continue - pat = re.compile(rf"^(## {key}、[^\n]*)\n", re.MULTILINE) - - def _repl(m: re.Match[str], _c: str = content) -> str: - return m.group(0) + "\n#### 衔接分析(大模型)\n\n" + _c + "\n\n" - - out = pat.sub(_repl, out, count=1) - return out - - def _flat_comment_texts(comment_rows: list[dict[str, str]]) -> list[str]: """全部非空评价正文(与报告统计同源)。""" out: list[str] = [] @@ -169,7 +149,6 @@ def get_default_report_config() -> dict[str, Any]: jcr, _ = _jd_crawler_modules() return { "llm_comment_sentiment": True, - "llm_section_bridges": True, "llm_matrix_group_summaries": True, "llm_comment_group_summaries": True, "llm_price_group_summaries": True, @@ -528,48 +507,6 @@ def write_competitor_analysis_for_run_dir( llm_comment_groups_section_md=llm_comment_gr_md or None, ) - bridge_record: dict[str, Any] = { - "schema_version": 1, - "attempted": False, - } - skip_bridge = os.environ.get( - "MA_SKIP_LLM_SECTION_BRIDGES", "" - ).strip().lower() in ("1", "true", "yes") - env_bridge = os.environ.get( - "MA_ENABLE_LLM_SECTION_BRIDGES", "" - ).strip().lower() in ("1", "true", "yes") - want_bridge = bool(eff_rc.get("llm_section_bridges")) or env_bridge - if want_bridge and not skip_bridge: - from .llm_generate import ( - generate_section_bridges_llm, - split_competitor_report_for_bridges, - ) - - parts = split_competitor_report_for_bridges(md) - if parts: - bridge_record["attempted"] = True - try: - bridges = generate_section_bridges_llm( - keyword=kw, brief=brief_final, sections=parts - ) - bridge_record["keys_received"] = sorted(bridges.keys()) - md = inject_section_bridges_into_markdown(md, bridges) - bridge_record["ok"] = True - except Exception as e: - bridge_record["ok"] = False - bridge_record["error"] = str(e) - else: - bridge_record["skipped"] = "no_h2_sections_matched" - elif skip_bridge: - bridge_record["skipped"] = "MA_SKIP_LLM_SECTION_BRIDGES" - elif not want_bridge: - bridge_record["skipped"] = "not_enabled" - - (run_dir / "section_bridge_llm.json").write_text( - json.dumps(bridge_record, ensure_ascii=False, indent=2), - encoding="utf-8", - ) - out_md = run_dir / "competitor_analysis.md" out_md.write_text(md, encoding="utf-8") return run_dir diff --git a/backend/pipeline/run_report_llm_chapters_demo.py b/backend/pipeline/run_report_llm_chapters_demo.py index 9fdb1a2..04007ea 100644 --- a/backend/pipeline/run_report_llm_chapters_demo.py +++ b/backend/pipeline/run_report_llm_chapters_demo.py @@ -5,7 +5,6 @@ - §6 后:``generate_price_group_summaries_llm`` - §8.2:``generate_comment_sentiment_analysis_llm`` - §8末细类评价:``generate_comment_group_summaries_llm`` -- 各章衔接(一~九):``generate_section_bridges_llm``(基于无 LLM 插入的规则稿切分) - §8.5 类全文补充(独立长文):``generate_competitor_report_markdown_llm`` cd backend @@ -124,7 +123,7 @@ def main() -> None: "--only", type=str, default="", - help="逗号分隔子集:sentiment,matrix,price,comment_groups,bridges,report_supplement", + help="逗号分隔子集:sentiment,matrix,price,comment_groups,report_supplement", ) parser.add_argument( "--preview-chars", @@ -144,7 +143,6 @@ def main() -> None: "matrix", "price", "comment_groups", - "bridges", "report_supplement", } if not only: @@ -166,8 +164,6 @@ def main() -> None: generate_competitor_report_markdown_llm, generate_matrix_group_summaries_llm, generate_price_group_summaries_llm, - generate_section_bridges_llm, - split_competitor_report_for_bridges, ) if "sentiment" in only: @@ -256,18 +252,8 @@ def main() -> None: if not args.live: print(f" payload groups={len(pl_cg)}", flush=True) - brief = jcr.build_competitor_brief( - run_dir=run_dir, - keyword=keyword, - merged_rows=merged, - search_export_rows=search_rows, - comment_rows=comment_rows, - meta=meta, - report_config=eff_rc, - ) - - if "bridges" in only: - md_base = jcr.build_competitor_markdown( + if "report_supplement" in only: + brief = jcr.build_competitor_brief( run_dir=run_dir, keyword=keyword, merged_rows=merged, @@ -275,29 +261,7 @@ def main() -> None: comment_rows=comment_rows, meta=meta, report_config=eff_rc, - llm_sentiment_section_md=None, - llm_matrix_section_md=None, - llm_price_groups_section_md=None, - llm_comment_groups_section_md=None, ) - parts = split_competitor_report_for_bridges(md_base) - - def _br() -> str: - m = generate_section_bridges_llm( - keyword=keyword, brief=brief, sections=parts - ) - return json.dumps(m, ensure_ascii=False, indent=2) - - _run_one( - "各章衔接 bridges(JSON 键一~九)", - _br, - live=args.live, - preview_chars=min(args.preview_chars, 1200), - ) - if not args.live: - print(f" sections keys={sorted(parts.keys())}", flush=True) - - if "report_supplement" in only: def _rp() -> str: return generate_competitor_report_markdown_llm(brief, keyword) diff --git a/backend/pipeline/serializers.py b/backend/pipeline/serializers.py index 7d9a098..6ee92ea 100644 --- a/backend/pipeline/serializers.py +++ b/backend/pipeline/serializers.py @@ -17,7 +17,6 @@ from .models import ( _REPORT_CONFIG_ALLOWED_KEYS = frozenset( { "llm_comment_sentiment", - "llm_section_bridges", "llm_matrix_group_summaries", "llm_price_group_summaries", "llm_comment_group_summaries", @@ -31,6 +30,8 @@ _REPORT_CONFIG_ALLOWED_KEYS = frozenset( def validate_report_config_body(value: dict) -> dict: if not isinstance(value, dict): raise serializers.ValidationError("须为 JSON 对象") + value = dict(value) + value.pop("llm_section_bridges", None) extra = set(value.keys()) - _REPORT_CONFIG_ALLOWED_KEYS if extra: raise serializers.ValidationError( @@ -39,9 +40,6 @@ def validate_report_config_body(value: dict) -> dict: if "llm_comment_sentiment" in value and value["llm_comment_sentiment"] is not None: if not isinstance(value["llm_comment_sentiment"], bool): raise serializers.ValidationError("llm_comment_sentiment 须为 true 或 false") - if "llm_section_bridges" in value and value["llm_section_bridges"] is not None: - if not isinstance(value["llm_section_bridges"], bool): - raise serializers.ValidationError("llm_section_bridges 须为 true 或 false") for k in ( "llm_matrix_group_summaries", "llm_price_group_summaries", @@ -61,7 +59,6 @@ _ARTIFACT_FILES: tuple[tuple[str, str], ...] = ( ("comments", "comments_flat.csv"), ("detail_ware", "detail_ware_export.csv"), ("report", "competitor_analysis.md"), - ("section_bridge_llm", "section_bridge_llm.json"), ) diff --git a/frontend/src/composables/useReportConfigForm.js b/frontend/src/composables/useReportConfigForm.js index eb63c3a..09a6388 100644 --- a/frontend/src/composables/useReportConfigForm.js +++ b/frontend/src/composables/useReportConfigForm.js @@ -17,7 +17,6 @@ function splitTriggers(text) { */ const REPORT_CONFIG_PASSTHROUGH_BOOL_KEYS = [ 'llm_comment_sentiment', - 'llm_section_bridges', 'llm_matrix_group_summaries', 'llm_price_group_summaries', 'llm_comment_group_summaries', diff --git a/frontend/src/views/jd/JdAnalysisBuildView.vue b/frontend/src/views/jd/JdAnalysisBuildView.vue index 492dd87..7ae1937 100644 --- a/frontend/src/views/jd/JdAnalysisBuildView.vue +++ b/frontend/src/views/jd/JdAnalysisBuildView.vue @@ -278,7 +278,7 @@ watch(
关注词、场景词组、外部市场表等可以不改:留空并保存即沿用内置规则。大模型相关布尔项(如
- llm_comment_sentiment、llm_section_bridges)不再单独占勾选框:若任务里已有,会在保存时保留;要改请展开「高级 JSON」。
+ llm_comment_sentiment)不再单独占勾选框:若任务里已有,会在保存时保留;要改请展开「高级 JSON」。