issue: .md uploaded as application/octet-stream is sent to the extraction engine (Docling/Tika) instead of TextLoader

当 CONTENT_EXTRACTION_ENGINE 设为 docling 或 tika 时,以 application/octet-stream 上传的 .md / .markdown / .txt / .rst 文件会被送进 Docling/Tika 重新解析,而不是用 TextLoader

快速结论:CONTENT_EXTRACTION_ENGINE 设为 doclingtika 时,以 application/octet-stream 上传的 .md / .markdown / .txt / .rst 文件会被送进 Docling/Tika 重新解析,而不是用 TextLoader 原样读取,导致 Markdown 结构(尤其是表格和行内代码)被破坏。优先排查客户端的 multipart content type 及引擎分支中的 _is_text_file 扩展名白名单。

适用环境:Open WebUI v0.11.4;dev 分支(24c01bd)代码路径未变但未实际运行;安装方式为 Docker;macOS 15(Colima),Kubernetes 上也有出现;内容提取引擎为 docling-serve 1.34.0 或 Tika。Issue 未提供 Python、CUDA、显卡等信息。

最快修复方案:暂无确认的一步修复方案。Issue 中给出的方向是把 mdmarkdowntxtrst 加入 _is_text_file 的扩展名检查(与 slim 路径使用同一份列表),可优先尝试;客户端侧修复见 open-webui/oikb#128(Issue 未说明其状态)。

注意事项:上述代码改动只是 Issue 作者提出的思路,Issue 关闭时未确认是否已合并;在上游修复前,规避手段是让客户端以 text/markdown 上传,而不是 application/octet-stream。若 Markdown 已被 Docling/Tika 重新渲染并入库,已存储的 file.data.content 是引擎输出而非原文,需要重新上传才能恢复。

问题场景

在 Open WebUI 中把内容提取引擎配置为 Docling 或 Tika,然后上传 Markdown 文件。当上传请求的 multipart 类型是 application/octet-stream 时,文件不会走文本加载路径,而是被送到 Docling/Tika 做转换,最终存进 file.data.content 的是引擎重新渲染后的文本。Python 3.11 的 mimetypes 没有 .md 条目,slim 镜像也不带 /etc/mime.types,因此官方 oikb 镜像上传的每个 .md 都会以 octet-stream 发送,触发该问题。在知识库预览和引用中表现为 Markdown 格式、表格内容丢失或错位。

报错原文

issue: .md uploaded as application/octet-stream is sent to the extraction engine (Docling/Tika) instead of TextLoader

_is_text_file only checks the content type and known_source_ext, and `md` is not in that list.

The default and slim paths already treat `md`/`markdown`/`txt` as text by extension (loaders/main.py:705); the engine branches (:561, :614) do not.

POST /v1/convert/file

原因分析

最可能的原因是引擎分支中的文件类型判断只看 multipart content type 和 known_source_ext 列表,而 md 不在该列表中。默认路径和 slim 路径已按扩展名把 md / markdown / txt 当作纯文本处理(loaders/main.py:705),但 Docling 分支(:561)和 Tika 分支(:614)没有同样的扩展名判断。因此当客户端把 .md 标为 application/octet-stream 时,文件被误判为需要提取引擎处理的二进制文档。复现实验显示,Docling 会重新渲染 Markdown,含行内代码或单元格内 <br> 的表格会被拆散、行丢失(docling-project/docling#3991)。

环境排查

  • 确认 Open WebUI 版本(Issue 中为 v0.11.4;dev 分支 24c01bd 代码路径未变)。
  • 确认安装方式(Issue 中为 Docker;Kubernetes 上也出现)。
  • 确认 CONTENT_EXTRACTION_ENGINE 的取值(doclingtika)。
  • 确认内容提取引擎版本(Issue 中为 docling-serve 1.34.0)。
  • 检查客户端上传 .md 时实际发送的 multipart content type 是 application/octet-stream 还是 text/markdown
  • 确认运行环境是否缺少 /etc/mime.types,以及 Python 版本(Issue 提到 Python 3.11 的 mimetypes.md 条目)。
  • 操作系统:macOS 15(Colima),以及 Kubernetes 环境。

解决步骤

  1. 先确认触发条件:把 Content Extraction Engine 设为 Docling(docling-serve 1.34.0)。
  2. 构造一个含表格的 Markdown 文件,内容如:| Endpoint | p50 | / | --- | --- | / | `/v1/schema` | 34 | / | `/v2/invoice` | 59 |
  3. curl -F "file=@doc.md;type=application/octet-stream" .../api/v1/files/ 上传,模拟客户端以 octet-stream 发送。
  4. 调用 GET /api/v1/files/{id}/data/content,观察返回内容:若表格变成空行表头、行内代码被拆成散落文本、每个数字单独成表,说明复现成功。
  5. 作为临时规避,把同一个文件以 text/markdown 上传再对比,Issue 中该方式下内容与源文件逐字节一致。
  6. 代码层面的可优先尝试修改:在 _is_text_file 的扩展名检查中加入 mdmarkdowntxtrst,与 slim 路径保持一致,使引擎分支也按扩展名把 Markdown 交给 TextLoader
  7. 若需要客户端侧处理,可查看 open-webui/oikb#128 的修复状态。

验证方法

GET /api/v1/files/{id}/data/content 读取已上传文件的内容,与源 Markdown 文件逐字节或逐行比对:若内容与原文一致、表格行和行内代码保持完整,则问题已解决。另可对照 docling-serve 日志:如果 octet-stream 上传不再出现 POST /v1/convert/file,说明文件已走 TextLoader。Issue 中的对照数据是 7 个测试文件(5 KB 到 620 KB),octet-stream 下出现 145 个表格单元格重排、2 个单元格丢失,而 text/markdown 下 0 差异。

参考来源

open-webui/open-webui #30412

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 25185

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注