技术博客
在知识库系统里集成PDF文档转换:从上传到Markdown入库的完整流程

在知识库系统里集成PDF文档转换:从上传到Markdown入库的完整流程

作者: 万维易源
2026-09-07
pdf-doc-convert-knowledge-base-3275
# 在知识库系统里集成PDF文档转换:从上传到Markdown入库的完整流程 > 接口:PDF文档转换 · 接入点 `3275-1` / `3275-2` / `3275-3` · 付费 · POST/GET · JSON > 适用人群:产品经理、全栈工程师、RAG 系统开发者 > 阅读时间:约 7 分钟 > 最后实测核对:2026-09-07 --- ## 核心要点 - 接口返回的是转换结果的**下载链接**,不是 Markdown 内容本身;入库前需要先下载文件再读内容。 - 建议数据库表设计包含 `task_id`、`state`、`download_url`、`local_path`、`ct` 五个核心字段。 - 7 天时效的下载链接意味着**入库前必须下载**,不能把链接当永久引用。 --- ## 场景切入 你做 RAG 知识库,有一份 PDF 年报,需要把内容转成 Markdown 塞进向量数据库。不用接口时,你要自己写 PDF 解析脚本,处理表格丢失、公式乱码、图片缺失各种问题;用这个接口,HTTP 调用一次,拿到 Markdown 文件,后续流程照常走。 关键在于:**接口只负责转换,不负责存储和入库**,你需要自己串联"上传→轮询→下载→入库"这整条链路。 --- ## 数据表设计 转换任务需要在你的系统里持久化,推荐最小字段集: ```sql CREATE TABLE pdf_convert_tasks ( id BIGINT PRIMARY KEY AUTO_INCREMENT, task_id VARCHAR(64) NOT NULL UNIQUE, -- ShowAPI 返回的 task_id original_filename VARCHAR(255), -- 原文件名 output_format ENUM('md', 'docx') NOT NULL, -- 输出格式 state VARCHAR(20) NOT NULL, -- preparing/processing/success/failed download_url TEXT, -- 下载链接(实效7天) local_path VARCHAR(512), -- 本地存储路径(转换完成后写入) error_msg TEXT, -- state=failed 时的错误描述 ct DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME ON UPDATE CURRENT_TIMESTAMP, INDEX idx_task_id (task_id), INDEX idx_state (state) ); ``` --- ## 完整流程伪代码 ``` 1. 用户上传 PDF → 你的服务器接收文件 2. 写入 pdf_convert_tasks 表,state=preparing,上传原始文件到本地/OSS 3. 调用 3275-1,传入 file_url(你服务器的临时地址)或 file_byte(本地文件字节) 4. 收到 task_id,更新数据库记录 5. 启动异步任务(Celery / 消息队列 / 定时任务),每 2 秒调用 3275-2 轮询 6. state=success 时: a. 下载 download_url 指向的文件到本地 b. 更新 local_path 和 state c. 读取 Markdown 内容,送入向量库(如 LangChain + ChromaDB) 7. state=failed 时:记录 error_msg,通知用户上传方 ``` --- ## Python 生产级示例(含异步入库) ```python import time import requests from pathlib import Path import hashlib APP_KEY = "YOUR_APPKEY" BASE = "https://route.showapi.com" def convert_pdf_and_store(pdf_local_path: str, output_format: str = "md", doc_title: str = ""): """ 转换 PDF 并入库,返回入库后的文档 ID(此处为示例,实际接入向量库) """ # 1. 上传到 ShowAPI with open(pdf_local_path, "rb") as f: file_bytes = f.read() resp = requests.post( f"{BASE}/3275-1", params={"appKey": APP_KEY}, data={"type": output_format}, files={"file_byte": ("temp.pdf", file_bytes, "application/pdf")}, timeout=10, ) body = resp.json()["showapi_res_body"] if body["ret_code"] != "0": raise RuntimeError(f"上传失败: {body['remark']}") task_id = body["task_id"] # 2. 轮询结果 for _ in range(60): time.sleep(2) r = requests.post( f"{BASE}/3275-2", params={"appKey": APP_KEY}, data={"task_id": task_id}, timeout=10, ) body = r.json()["showapi_res_body"] if body["state"] == "success": break if body["state"] == "failed": raise RuntimeError(f"转换失败: {body['remark']}") else: raise TimeoutError("转换超时") # 3. 下载转换结果 ext = ".md" if output_format == "md" else ".docx" save_dir = Path("/tmp/pdf_outputs") save_dir.mkdir(exist_ok=True) file_hash = hashlib.md5(file_bytes).hexdigest()[:8] save_path = save_dir / f"{file_hash}{ext}" dl_resp = requests.get(body["download_url"], timeout=30) dl_resp.raise_for_status() save_path.write_bytes(dl_resp.content) # 4. 入库(以 LangChain 为例) if output_format == "md": from langchain.document_loaders import TextLoader loader = TextLoader(str(save_path), encoding="utf-8") docs = loader.load() # docs[0].page_content 即 Markdown 文本,可送入 VectorStore return {"task_id": task_id, "local_path": str(save_path), "content": docs[0].page_content if docs else ""} return {"task_id": task_id, "local_path": str(save_path)} ``` --- ## 大文件处理策略 接口限制单文件 100MB,超过这个限制需要自行分割。 思路:用 `pypdf` 或 `pdfplumber` 按页拆分,每 N 页一组,分别上传转换,最后合并 Markdown。 ```python from pypdf import PdfReader, PdfWriter import os def split_pdf_by_pages(pdf_path: str, pages_per_chunk: int = 10): reader = PdfReader(pdf_path) total = len(reader.pages) chunks = [] for start in range(0, total, pages_per_chunk): writer = PdfWriter() end = min(start + pages_per_chunk, total) for i in range(start, end): writer.add_page(reader.pages[i]) chunk_path = f"/tmp/chunk_{start}.pdf" with open(chunk_path, "wb") as f: writer.write(f) chunks.append(chunk_path) return chunks ``` 每块转换完成后合并 Markdown 文件即可。 --- ## 注意事项 1. **不要缓存 download_url 当永久链接**:7 天时效,过期后链接失效。入库时必须立即下载并存储到自有存储。 2. **并发控制**:多文件批量转换时,控制并发数(建议 ≤5),避免触发接口限流。 3. **失败重试**:state=failed 时先查原因再重新上传,不要无限重试同一文件。 4. **历史记录查询**:调用 `3275-3` 可以分页查询近期转换任务,适合做任务管理面板。 --- ## FAQ **Q1:转换后的 Markdown 能保留原文的表格格式吗?** 可以,showapi PDF文档转换接口(apiCode=3275)支持识别表格并以 Markdown 表格语法输出,但复杂排版(多栏、嵌套表格)仍有损失,建议抽样验证后决定是否适用于你的场景。 **Q2:支持扫描版 PDF(纯图片,无文字层)吗?** 不支持有效转换。纯图片 PDF 没有文字层,解析结果为空或乱码。这类文件需要先做 OCR,目前该接口不提供内置 OCR 能力。 **Q3:转换完成后如何知道文件具体内容质量如何?** 接口本身不返回内容预览,只能下载后人工或脚本检查。建议在接入流程里加一个"转换质量校验"步骤,抽样读取前 100 行检查格式是否正常。 **Q4:可以用通用资源包调用这个接口吗?** 可以,通用资源包充值后可直接调用全站付费接口,无需单独购买专用资源包。 --- ## 下一步阅读 - [PDF文档转换:5分钟完成异步上传与结果下载](https://www.showapi.com/guides/pdf-doc-convert-quickstart-3275) - [PDF文档转换返回字段全解:state 状态机与 task_id 生命周期](https://www.showapi.com/guides/pdf-doc-convert-state-machine-3275) - [PDF文档转换失败怎么处理:超时、重试与7天时效下载链接管理](https://www.showapi.com/guides/pdf-doc-convert-fail-retry-3275) --- *本系列共 5 篇:查看[PDF文档转换指南总目录](https://www.showapi.com/guides/pdf-doc-convert-guides-3275)*