Repository navigation
Conversation
dd362bd to
f4f4229
Compare
9e5c925 to
6d6e2da
Compare
|
Review of [P2] Please exclude literal inline-code examples from the unresolved-image failure guard.
Use `data:image/png;base64,...` to illustrate a data URI.returns true from the new guard. It is a literal code example, so the resolver has no real image to decode. The new checks in document processing and manual-content processing then mark the entire document failed and return A temporary regression using the actual helper reproduces this; the existing inline-image tests pass. Please recognize inline code (and other literal code contexts) before checking actual unresolved image payloads, and add a document-processing regression proving this example remains ingestible. Keep coverage for genuinely malformed image payloads. |
|
Thanks @lyingbug for catching this. Fixed in
Would you mind taking another look? |
lyingbug
left a comment
There was a problem hiding this comment.
感谢修复!这个 PR 解决的三个问题都是真实存在的:超过 30 张的内联图以 Base64 原样进入切分/Embedding、AI 名额因倒序遍历落到文末图片、SaveBytes 失败被静默吞掉。全部存储 + 按文档顺序分配 SkipMultimodal 名额、失败可重试并回滚本次已存图片、代码块内 Base64 不处理,这些方向都很好。不过有一个阻塞问题需要先处理。
1. 【高】解析器主动跳过的图片会被 guard 判为整篇终态失败
内联解析器在以下情况会 continue 跳过且不返回错误,Base64 保留在正文中:
- 解码失败(例如截断的 payload)
- 单张解码后超过 10MB(
maxRemoteImageSize) - 裸 data URI 按 76 列换行,凑不满
{100,}的连续字符 - 正文只是提到
data:image/png;base64,xxx(例如 PDF 抽取出的前端教程,没有反引号)
而 HasUnresolvedInlineImagePayload 的 unresolvedImageDataURI 只要求 payload ≥ 1 个字符,命中后 ProcessDocument / triggerManualProcessing 都直接标记 failed 并返回 asynq.SkipRetry。
我在 PR 分支上对这四种输入逐一验证:ResolveAndStore 均返回 err=nil, stored=0,随后 guard 均为 true。也就是说一份几百页的文档只要含一张 11MB 的内联图或一段损坏的 Base64,整篇就会永久失败,用户无法补救;而合入前这类文档是可以入库的。TestProcessDocumentBlocksUnresolvedImageDataURIBeforeChunking 也把「正文提及 data URI 即失败」固化成了预期行为。
建议:对解析器跳过的内联图,原地替换为占位符(如 [image omitted])或直接移除(与现有 icon 的处理一致),而不是让整篇失败;guard 仅作最后兜底,且至少要求 payload 能解码并像图片(与裸 Base64 分支的 looksLikeImageBase64 对齐)。
2. 【中】移除 30 张上限后,数量与改写开销都无上界
每次替换 markdown[:m[0]] + ... + markdown[m[1]:] 都会复制整篇正文,k 张图、n 字节正文是 O(n·k);例如 100MB 正文含 100 张图约复制 10GB。同时单文档可写入的对象存储/catalog 记录也不再有上限。建议改为单遍正向扫描 + strings.Builder,并为单文档内联图总数或总字节设硬上限,超出部分按第 1 点降级。
3. 【中】guard 失败时远程图片成为孤儿
guard 在 ResolveRemoteImages 之后执行,cleanupUnboundInlineImages 只清理 Inline=true 的图,已下载并上传的远程图片(以及 ImageRefs 路径存下的图片)既未绑定也未删除。建议把 guard 挪到 ResolveAndStore 之后、远程下载之前。
4. 【低】手动知识行为变化
手动路径从 ResolveDataURIImages 改为 ResolveAndStore,会顺带跑 HTML 与裸 Base64 解析器:用户手写的 <img src="data:..." width=... alt=...> 会被改写为 ,丢失属性;且每次重新发布都会重新上传全部内联图(原先最多 30 张)。建议在描述中说明。
5. 【低】可观测性不一致
手动路径的 guard 失败没有 beginStage / failStage,与 ProcessDocument 不一致,处理轨迹里看不到失败阶段。
测试缺口
- 缺少第 1 点四类「解析器跳过」输入的回归用例。
ResolveBareBase64Content内部两个解析器各有独立的 30 张名额(单文档内联图最多 120 张进入 AI 理解,与旧行为一致),但测试只覆盖了 Markdown 与 HTML 两种语法。
6055c02 to
40fbf07
Compare
40fbf07 to
11dbdbf
Compare
|
@lyingbug 感谢这轮 review。已针对上述意见继续修复,当前 HEAD 为
还需明确一个保守边界:真正无法区分编码续行与正文时,会保留原文并在切分前终止入库,避免误删正文或让残余 Base64 进入 Embedding。中文开头正文或 Markdown 标题可作为明确边界;ASCII 开头的后续行仍按歧义保护。因此,部分损坏的裸图片仍会导致文档失败,这一点也请重点复核。另外,内嵌图片采用固定的 16,777,216 像素上限,GIF 另有帧数及累计像素上限;有效但超限的图片也会被省略,属于支持范围限制,已同步到 PR 说明。 本地验证通过:docparser 全量测试、12 项相关 service 回归、变更范围内 golangci-lint、 |
Description
Inline Base64 image data could remain in document content and enter Chunking/Embedding, making chunks carry large encoded payloads or causing ingestion to fail. Because images are replaced in reverse document order, the 30-image AI budget could also be assigned to trailing images.
Save valid inline images and replace their Base64 with serving URLs before Chunking, applying the independent 30-image AI budget to each syntax's leading images. Store up to 1,000 inline images / 100 MiB decoded inline bytes per document, independently of the AI budget. Malformed, unsupported, oversized, or over-budget images with a known payload boundary are replaced with
[image omitted]. If a malformed bare multiline payload cannot be separated safely from surrounding text, preserve the original content and fail ingestion before Chunking/Embedding without retrying; storage failures remain retryable. Use one-pass Markdown substitutions to avoid quadratic copying. The final guard rejects only unresolved image-like payloads, before any remote-image downloads, and failed attempts clean up newly written unbound inline and ImageRef resources. Existing remote-image and PDF/Office processing retain their own behavior.Review follow-up / compatibility notes
<img src="data:..." width=... alt=...>becomes a Markdown image link, so HTML attributes may be lost. Publishing the same raw inline-image body again uploads new copies; this was not changed to content-addressed deduplication in this PR.Type of Change
Related Issue
N/A
Testing
Regression coverage for the Base64 guard before Chunking, document-order per-syntax AI budgets, bounded image omission, unknown image data, ambiguous-content preservation/rollback, and decode resource limits. CI results must be assessed for the current pushed HEAD separately from local validation.
Checklist
git diff --check origin/main...HEADpassesgolangci-lint run --new-from-rev=origin/main ./...)website-docs/, Swagger annotations, etc.)Screenshots / Recordings
N/A — backend processing fix.