Skip to content

feat(docreader): 上传 HTML 只索引正文,与 URL 导入路径对齐(开关,默认关) - #4424

Merged
lyingbug merged 3 commits into
Tencent:mainfrom
linus-liu-web:feat/docreader-html-main-content
Oct 17, 2026
Merged

lyingbug merged 3 commits into
Tencent:mainfrom
linus-liu-web:feat/docreader-html-main-content

Conversation

@linus-liu-web

Copy link
Copy Markdown
Contributor

问题:同一个 docreader 里,「上传 HTML」和「URL 导入」两条路径行为不一致

  • URL 导入(docreader/parser/web_parser.py):Playwright 抓取 → trafilatura.extract() 抽正文 → 抽取为空时回退可见文本;
  • 上传 HTML 文件(docreader/parser/html_parser.py):MHTMLParser.html_to_markdown() 整页转换 → 导航栏、侧栏、页脚、搜索框、Cookie 提示全部进入索引,检索时被当正文召回。

docreader 本来就依赖 trafilatura(pyproject.toml / uv.lock 钉 2.0.0),URL 路径一直在用,只是文件路径没用上。

改动

新增 DOCREADER_HTML_MAIN_CONTENT(DocReaderConfig,默认 false),沿用仓库既有开关模式(与 DOCREADER_ODL_MARKDOWN_WITH_HTML 同形):

  • 关闭(默认):完全走原路径,索引输出与现在逐字节相同
  • 开启:用 trafilatura 抽正文,不满足阈值时回退整页转换
_MIN_EXTRACTED_CHARS = 250   # 抽取结果短于此视为失败
_MIN_KEEP_RATIO = 0.15       # 且至少要有全量转换的这个比例

回退策略(两层):表单页/纯列表页/短公告没有明确主体 → 抽取结果过短 → 回退整页转换;长页只抽到一小段 → 不足全量转换的 15% → 回退整页转换。回退即完整保留旧行为,不丢内容。

为什么下限取 250:trafilatura 在自己的 MIN_EXTRACTED_SIZE(250)以下会退化成纯文本渲染,那会丢掉标题层级、表格和链接目标 —— 落在两个阈值之间的页面就不是"少掉 chrome"而是"丢掉结构"。把下限卡在 trafilatura 自己的地板上,让整页转换在那一段接管。(实测:仓库自带的 docreader/testdata/test.html 抽取只有 151 字符,取 120 时会丢表格和全部 <h2>;取 250 时回退整页转换、结构完整。)

为什么是开关,而不是"两条路径共用一个函数":

  • URL 路径的失败回退依赖 Playwright 的可见文本,上传路径没有浏览器,它天然的回退是已有的整页转换 —— 一个共享函数无法同时服务两种回退;
  • URL 路径的 extract_markdown_from_html() 用 with_metadata=True, include_images=True:元数据头(title:/url:/date:)会被当正文索引,而本地上传文件没有 URL;上传路径一直 extract_images=False(图片交给 Go 侧 image_resolver.go)。直接复用会改变上传路径的语义;
  • 这个开关会改变所有上传 HTML 的索引内容、分块与检索结果。仓库对这类改动的既有原则是"默认关"(见 internal/types/knowledgebase.go 的 ImageAttrsEnabled 注释),docreader 侧的同形实现就是 DOCREADER_* 环境变量。

真正该共用的是策略(抽正文 + 失败回退),不是函数。

测试

docreader/tests/test_html_parser.py(新增 HTMLMainContentTest,6 例)+ test_config.py(3 例),夹具 docreader/testdata/html_main_content/*.html。

  • 默认关:整页转换,页脚/导航仍在索引里(回归用例,改前也绿)
  • 开启:导航/侧栏/页脚文字不进索引,正文(含表格与正文内链接)完整保留
  • 无明确主体的页面:输出与整页转换逐字节相同
  • 长页只抽到一小段:比例阈值触发回退,输出与整页转换逐字节相同
  • 一句话公告不被吃掉;空 HTML 仍是空文档

逐字节一致性:把 origin/main 的解析器与改后默认解析器分别跑 20 个构造 HTML(空/纯脚本/表格/实体/BOM/UTF-16/windows-1252/畸形/深嵌套/大导航/长文…)+ 全部仓库夹具,SHA-256 全等;完整测试套件 296 → 305 例,失败面不变。

改前 (pristine): 上传一路索引整页 → AssertionError: page chrome reached the index: '产品定价'
改后 (开关开启): 导航/侧栏/页脚不在索引里,正文完整

已知限制(本 PR 不处理,欢迎维护者定夺)

  1. trafilatura 2.0.0 对"短文章页"(<h1> + 单个约 250–400 字段落)会把正文输出两遍(fast / no_fallback / favor_precision / deduplicate 均无效),开启后这类页面会索引重复正文,且虚高的长度可能绕过比例阈值;
  2. 为与上传路径既有行为一致,抽取用 include_images=False(URL 路径是 True),开启后正文内的图片引用不进 Markdown(远程图片仍由 Go 侧解析)。

兼容性

默认关闭 → 升级后索引内容不变。开启方式:DOCREADER_HTML_MAIN_CONTENT=true(已加入 docker-compose.yml / .env.example / docreader/README.md / website-docs)。后续如需 per-upload override,可按 pdf_force_scanned / odl_markdown_with_html 的先例加 parser_engine_overrides(本 PR 不含)。

docreader 的「上传 HTML 文件」路径(html_parser.py)把整页转 Markdown,
导航栏、侧栏、页脚都会进入索引并被当正文召回;而「URL 导入」路径
(web_parser.py)早已用 trafilatura 抽正文。同一产品两条路径行为不一致。

按仓库既有开关模式(DocReaderConfig + DOCREADER_* 环境变量)新增
DOCREADER_HTML_MAIN_CONTENT,默认 false:默认仍整页转换,索引输出逐字节
不变,升级不改变既有文档的解析结果。开启后改用 trafilatura 抽正文;
抽取结果 < 120 字符、或不足整页转换的 15% 时回退整页转换,表单页、
纯列表页、短公告等没有明确主体的页面不会被吃掉。

- docreader/config.py:新增 DOCREADER_HTML_MAIN_CONTENT(默认 false),
  并进入 dump_config
- docreader/parser/html_parser.py:关闭时走原路径;开启时抽正文 + 双阈值回退
- docreader/tests:新增 6 个正文抽取用例、3 个配置用例,夹具见
  docreader/testdata/html_main_content/
- docker-compose.yml / .env.example / docreader/README.md / website-docs:
  登记该开关
@linus-liu-web

Copy link
Copy Markdown
Contributor Author

关于合并顺序(和兄弟 PR #4423 的关系):

本 PR 与 #4423(Excel 百分比)都改 docker-compose.yml 和 .env.example,都只是各加一行 DOCREADER_* 透传;另外两边都动了 website-docs 下的文档(#4423 改 03-document-parsing.md,本 PR 也改它 + 04-configuration.md)。

建议顺序:#4423 → #4424,冲突只是相邻行。

@lyingbug lyingbug left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已复核此前评审结论及最新提交,相关 CI 检查全部通过,同意合入。

@lyingbug lyingbug left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已复核与最新 main 的合并:冲突仅为 .env.example 和 docker-compose.yml 中相邻配置项,已完整保留 HTML 正文抽取与 XLSX 百分比开关。Compose 配置校验及 65 项相关 Python 回归测试通过,等待本次提交的 CI 完成后合入。

@lyingbug
lyingbug merged commit 44d90be into Tencent:main Oct 17, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants