fix(pipeline): 8.3情感子标题降为五级以便细类报告摘录命中

strategy 侧 load_report_matrix_group_evidence 按 #### 细类 抽取时在下一行 #### 即截断,导致正/负向主题正文丢失;在 matrix_group_focus 成稿后对四个固定小节做 ####→##### 后处理,并补充单测。

Made-with: Cursor
This commit is contained in:
hub-gif 2026-04-21 11:43:50 +08:00
parent 30f1b038fa
commit 50a9867d02
3 changed files with 53 additions and 1 deletions

View File

@ -34,6 +34,31 @@ SENTIMENT_LLM_SYSTEM = """你是电商/食品类用户研究助手。输入 JSON
**篇幅** JSON ``matrix_group_focus``单细类范围本节总字数约 **5001200 **勿再按全关键词池写全行业泛化**不含**该字段全量池总字数约 **7001600 **简体中文语气客观"""
# 嵌入报告 8.3 时外层为 ``#### {细类名}``;若内文仍用同级 ``#### 正向体验主题``
# ``extract_level4_sections_by_group_title`` 会在第一个子 ``####`` 处截断,导致策略摘录/心得侧「同细类报告摘录」拿不到正文。
_SENTIMENT_INNER_H4_TITLES: frozenset[str] = frozenset(
{
"正向体验主题",
"负向评价主题归因",
"混合评价中的典型张力",
"使用注意",
}
)
def demote_sentiment_inner_h4_to_h5_for_matrix_group(md: str) -> str:
"""将情感归纳四个固定小节从 ``####`` 降为 ``#####``,以便嵌在 ``#### 细类`` 下仍能被按细类抽取。"""
out_lines: list[str] = []
for line in (md or "").splitlines():
m = re.match(r"^####\s+(.+)$", line)
if m:
title = m.group(1).strip()
if title in _SENTIMENT_INNER_H4_TITLES:
out_lines.append(f"##### {title}")
continue
out_lines.append(line)
return "\n".join(out_lines)
def generate_comment_sentiment_analysis_llm(payload: dict[str, Any]) -> str:
"""基于 lexicon 统计 + 语义池与按词表归类的抽样生成评价情感归纳段落Markdown**默认不**嵌入竞品报告正文。"""
@ -60,7 +85,10 @@ def generate_comment_sentiment_analysis_llm(payload: dict[str, Any]) -> str:
if len(raw) > 88_000:
raw = raw[:82_000] + "\n\n…(输入过长已截断,请勿编造截断外内容)\n"
user = "请根据以下 JSON 按系统说明输出 Markdown" + scope_note + "\n\n" + raw
return call_llm(SENTIMENT_LLM_SYSTEM, user)
out = call_llm(SENTIMENT_LLM_SYSTEM, user)
if isinstance(mg, str) and mg.strip():
out = demote_sentiment_inner_h4_to_h5_for_matrix_group(out)
return out
def split_competitor_report_for_bridges(

View File

@ -4,6 +4,8 @@
报告生成侧约定矩阵/价盘/促销/评论/场景等 LLM 小节均以 ``#### `` + 与矩阵一致的细类名为小节标题
``generate_group_summaries`` 系统提示
**8.3 评价正/负向主题**细类下内层小节使用 ``#####``(由 ``demote_sentiment_inner_h4_to_h5_for_matrix_group`` 处理),
避免与外层 ``#### 细类名`` 同级导致本节正文抽取为空。
"""
from __future__ import annotations

View File

@ -3,6 +3,7 @@ from __future__ import annotations
from django.test import SimpleTestCase
from pipeline.llm.generate_sections import demote_sentiment_inner_h4_to_h5_for_matrix_group
from pipeline.reporting.report_matrix_group_evidence import (
extract_level4_sections_by_group_title,
)
@ -37,3 +38,24 @@ B 段评论归纳。
extract_level4_sections_by_group_title("## 二\n", "饼干"),
[],
)
def test_extract_8_3_sentiment_when_inner_subsections_are_h5(self) -> None:
"""8.3 在 #### 细类 下须用 ##### 子标题,否则抽取在首个 #### 子节处断开。"""
inner = demote_sentiment_inner_h4_to_h5_for_matrix_group(
"#### 正向体验主题\n\n正文A\n\n#### 负向评价主题归因\n\n正文B\n"
)
md = (
"### 8.3 评价正/负向主题\n\n"
"#### 饼干\n\n"
f"{inner}\n"
)
parts = extract_level4_sections_by_group_title(md, "饼干")
self.assertEqual(len(parts), 1)
self.assertIn("正文A", parts[0])
self.assertIn("正文B", parts[0])
def test_demote_known_h4_titles_only(self) -> None:
raw = "#### 正向体验主题\nx\n#### 饼干\ny\n"
out = demote_sentiment_inner_h4_to_h5_for_matrix_group(raw)
self.assertIn("##### 正向体验主题", out)
self.assertIn("#### 饼干", out)