# 智能抽取 Source: https://docs.textin.com/api-reference/endpoint/extract-v3 api-reference/extract-1.0.3.openapi.yaml POST /ai/service/v3/entity_extraction 智能抽取API已更新至v3, 如需查看旧版API请[点击](https://www.textin.com/document/legacy/open_kie_vlm_engine) 快速调试:请参考[Postman调试教程](/xparse/extract-debug-postman)或[Apifox调试教程](/xparse/extract-debug-apifox) # 文档解析 Source: https://docs.textin.com/api-reference/endpoint/parse api-reference/parse-1.0.1.openapi.yml POST /ai/service/v1/pdf_to_markdown 上传图片/pdf/word/html/excel/ppt/txt,进行版面检测,文字识别,表格识别,版面分析等操作,并生成markdown文档及结构化数据 快速调试:请参考[Postman调试教程](/xparse/parse-debug-postman)或[Apifox调试教程](/xparse/parse-debug-apifox) # 异步解析 Source: https://docs.textin.com/api-reference/endpoint/xparse/v1/parse-async api-reference/parse-async-1.4.0.openapi.yaml POST /api/v1/xparse/parse/async 创建异步文档解析任务,立即返回job_id,通过job_id查询处理状态和结果。 适用于处理大文件或批量文件,避免HTTP超时限制。 # 获取异步解析结果 Source: https://docs.textin.com/api-reference/endpoint/xparse/v1/parse-async-status api-reference/parse-async-1.4.0.openapi.yaml GET /api/v1/xparse/parse/async/{job_id} 通过job_id查询异步解析任务的处理状态和结果。 任务状态包括: - pending: 排队中 - in_progress: 处理中 - completed: 已完成 - failed: 处理失败 # 同步解析 Source: https://docs.textin.com/api-reference/endpoint/xparse/v1/parse-sync api-reference/parse-sync-1.4.0.openapi.yaml POST /api/v1/xparse/parse/sync 将非结构化文档(image/pdf/word/html/excel/ppt/txt等)解析为 AI 友好的结构化数据(JSON、Markdown),包含丰富的元数据(可追溯、可解释、可验证) # API Key Source: https://docs.textin.com/xparse/api-key 快速获取您的 x-ti-app-id 和 x-ti-secret-code 点击链接获取API Key:[TextIn工作台 - 账号与开发者信息](https://www.textin.com/console/dashboard/setting) 1. 在功能体验页面点按左下角的个人资料图标 2. 点击「账号与开发者信息」进入工作台相应页面 AP Ikey 1 Pn 3. 单击“复制”图标获取您的 x-ti-app-id 和 x-ti-secret-code AP Ikey Jp # 大版本更新迁移说明 Source: https://docs.textin.com/xparse/api-migration 从旧版 pdf_to_markdown 接口平滑迁移到新版 xParse API 的完整指南 本文档帮助你从旧版 `pdf_to_markdown` 接口平滑迁移到新版 xParse API,并介绍新增的异步处理能力。 文中所有参数映射、字段名与默认值均以 TextIn 官方接口文档为准。 *** ## 为什么迁移 新版 xParse API 对旧版 `pdf_to_markdown` 做了全面升级,核心优势: 标准化的 Element 模型,语义类型清晰(Title / NarrativeText / Table / Image / Formula),JSON 体积更小 统一的请求配置(config)与响应结构(schema),便于集成与迁移 支持 TextIn / GUI 多引擎,可按场景选最优或对比效果 新增异步接口,适合大文件(建议 >10 页)和批量场景,避免 HTTP 超时;支持 Webhook 回调 归一化坐标(0\~1),不再依赖 dpi 参数 行内公式、手写体、复选框(checkbox)、内嵌图片 *** ## 接口变更总览 | 维度 | 旧版 | 新版 | | ------------ | ------------------------------------- | ----------------------------------------- | | **URL(同步)** | `/ai/service/v1/pdf_to_markdown` | `/api/v1/xparse/parse/sync` | | **URL(异步)** | ❌ 不支持 | `/api/v1/xparse/parse/async` | | **任务状态查询** | ❌ 不支持 | `GET /api/v1/xparse/parse/async/{job_id}` | | **文件上传** | Body 二进制流(`application/octet-stream`) | `multipart/form-data`,字段名 `file` | | **URL 文件方式** | Body 文本(`text/plain`) | `multipart/form-data`,字段名 `file_url` | | **参数传入位置** | Query String | `config` JSON 字段(form-data 内) | | **参数开关类型** | 整数 `0` / `1` | Boolean `false` / `true` | | **响应根节点** | `result` | `data` | | **坐标系** | 绝对像素(受 dpi 影响) | 归一化值(0\~1) | | **页码起始** | `page_id`(起始值 1-based) | `page_number`(1-based,第一页为 1) | *** ## 入参迁移指南 ### 请求方式变更 ```http theme={null} POST https://api.textin.com/ai/service/v1/pdf_to_markdown?parse_mode=auto&table_flavor=html&page_details=1 Content-Type: application/octet-stream x-ti-app-id: x-ti-secret-code: [二进制文件内容] ``` ```http theme={null} POST https://api.textin.com/api/v1/xparse/parse/sync Content-Type: multipart/form-data x-ti-app-id: x-ti-secret-code: --boundary Content-Disposition: form-data; name="file"; filename="doc.pdf" [二进制文件内容] --boundary Content-Disposition: form-data; name="config" {"capabilities":{"table_view":"html","pages":true,"title_tree":true}} ``` ### 新版 config 结构总览 新版参数不再是扁平的 Query String,而是放在 form-data 的 `config` 字段里。该字段的值是一个 JSON,内部又分四个区块(注意:其中一个区块也叫 config,下文以「config 字段值 → config 区块」指代,切勿写成 `{"config":{"config":{...}}}` 之外的多层嵌套): ```json theme={null} { "document": { "password": "..." }, "capabilities": { "table_view": "html", "pages": true, "...": "..." }, "scope": { "page_range": "1-10" }, "config": { "force_engine": "textin", "engine_params": { "parse_mode": "auto", "formula_level": 0, "image_output_type": "url" } } } ``` | 区块 | 作用 | | ---------------- | ----------------------------------------------- | | **document** | 文档本身处理参数(如加密 PDF 密码) | | **capabilities** | 解析策略与返回格式开关(决定返回哪些字段、表格格式等) | | **scope** | 处理范围(如页码区间) | | **config(区块)** | 引擎选择(`force_engine`)+ 引擎级自定义参数(`engine_params`) | **关键认知**:旧版的 `parse_mode`、`formula_level` 等"引擎行为参数"在新版并未消失,而是下沉到了 `config` 区块的 `engine_params` 里。它们与 `capabilities` 里的"返回内容开关"是两个不同维度,迁移时不要混淆。(注:`dpi` 是例外,新版已彻底移除。) ### 参数字段映射表(核心) 下表已按官方文档逐项核对。「新版参数」列给出在 `config` 字段值内的相对路径(`engine_params` 即 `config` 区块下的 `engine_params`)。 | 旧版参数
(Query) | 旧默认 | 新版参数 | 新默认 | 变更说明 | | -------------------------------------------- | -------- | ---------------------------------------------------------- | ------- | ---------------------------------------------------- | | `pdf_pwd` | — | `document.password` | — | 仅改位置 | | `page_start` +
`page_count` | 0 / 1000 | `scope.page_range`
(如 `"1-10"`) | — | 合并为区间字符串 | | `apply_document_tree`
(0/1) | 1 | `capabilities.include_hierarchy` | `true` | int→bool | | `table_flavor`
(md/html/none) | html | `capabilities.table_view`
(markdown/html) | `html` | "md" → "markdown"
"none" 已移除 | | `get_image`
(none/page/objects/both) | none | `capabilities.include_image_data`
(是否返回) | `false` | 详见下方说明 | | `image_output_type`
(base64str/default) | default | `engine_params.image_output_type`
(url/base64) | `url` | 取值体系不同:
旧 base64str/default
→ 新 url/base64 | | `formula_level`
(0/1/2) | 0 | `engine_params.formula_level`
(0/1) | 0 | ⚠️ 保留在引擎参数,
取值改为 0/1 | | `page_details`
(0/1) | 1 | `capabilities.pages` | `false` | ⚠️ 默认反转,需显式 `true` | | `char_details`
(0/1) | 0 | `capabilities.include_char_details` | `false` | int→bool | | `catalog_details`
(0/1) | 0 | `capabilities.title_tree` | `false` | 改名 | | `crop_dewarp`
(0/1) | 0 | `capabilities.crop_dewarp` | `false` | int→bool | | `remove_watermark`
(0/1) | 0 | `capabilities.remove_watermark` | `false` | int→bool | | `parse_mode`
(auto/scan/lite/parse) | scan | `engine_params.parse_mode`
(auto/scan/parse/lite/vlm) | 见下方说明 | ✅ 保留;新增 vlm 模式 | | `raw_ocr`
(0/1) | 0 | 近似改用
`capabilities.include_char_details` | `false` | ⚠️ 语义非完全等价 | | `dpi`
(72/144/216) | 144 | ❌ 已移除 | — | 新版用归一化坐标,
无对应参数 | | `get_excel` | 0 | ❌ 已移除 | — | 新版不支持 Excel 输出 | | `markdown_details` | 1 | ❌ 已移除 | — | elements 始终返回 | **get\_image 迁移注意**:旧版 `get_image` 有 none/page/objects/both 四档语义(整页图 / 子图 / 两者)。新版通过组合 `capabilities.pages` 和 `capabilities.include_image_data` 实现: * 当 `pages=true` 时,`include_image_data=true/false` 对应 `get_image=both/page` * 当 `pages=false` 时,`include_image_data=true/false` 对应 `get_image=objects/none` 图片格式由 `engine_params.image_output_type`(url/base64)控制。 * **parse\_mode 在新版的默认值**:旧版默认 `scan`;新版 parse/sync 接口默认值以官方文档为准 * **force\_engine 是新增的"引擎选择"维度**(textin/textin\_gui),不是 `parse_mode` 的替代品;在textin引擎下,`parse_mode`可同时配置 ### 新增能力(仅新版支持) | 参数 | 默认 | 说明 | | -------------------------------------- | -------- | ------------------------------------------------- | | `capabilities.include_inline_objects` | `false` | 返回文本内的细粒度行内对象:公式、手写、复选框、内嵌图片 | | `capabilities.include_table_structure` | `false` | 返回表格结构化数据(行列数、单元格坐标、跨行跨列、单元格内容类型) | | `config.force_engine` | `textin` | 指定引擎:`textin`(默认)/ `textin_gui`。各引擎适用场景与限制以官方文档为准 | | `config.engine_params` | — | 引擎自定义参数(专家模式),不同引擎支持的参数不同 | *** ## 出参迁移指南 ### 顶层结构变化 ```json theme={null} { "code": 200, "message": "success", "result": { "...": "主体数据" }, "version": "v1.0", "duration": 1234 } ``` ```json theme={null} { "code": 200, "message": "success", "data": { "schema_version": "1.3.0", "file_id": "doc_7f3a2b", "job_id": "job_x9k2m", "success_count": 10, "metadata": { "...": "文件名/类型/页数" }, "markdown": "...", "elements": [], "pages": [], "title_tree": [], "summary": { "duration_ms": 972 } } } ``` ### 主体数据字段映射 | 旧版 `result.*` | 新版 `data.*` | 变更说明 | | ------------------- | ---------------------------------------------------- | ------------ | | `markdown` | `markdown` | 不变 | | `detail` | `elements` | 改名,结构重组(见下节) | | `pages` | `pages` | 字段名相同,内部结构重组 | | `catalog`(含 `toc`) | `title_tree` | 改名,结构变为节点数组 | | `total_page_number` | `metadata.page_count` | 下沉至 metadata | | `valid_page_number` | `success_count` | 改名 | | `excel_base64` | ❌ 已移除 | 新版不支持 Excel | | (无) | `schema_version` / `file_id` / `job_id` / `metadata` | 新增字段 | ### 元素结构变化(detail → elements) 旧版 `detail[]` 与新版 `elements[]` 的字段对照: | 旧版 `detail[]` | 新版 `elements[]` | 变更说明 | | --------------------------------- | ------------------------------------- | -------------------------------------------------------- | | `paragraph_id`(整数) | `element_id`(字符串,如 `el_001`) | ID 类型由整数改为字符串 | | `type`("paragraph" / "table" 等) | `type`(语义字符串) | 改为 Title / NarrativeText / Table / Image / Formula 等语义类型 | | `text` | `text` | 不变 | | `position`(绝对像素) | `coordinates`(归一化 0\~1) | ⚠️ 坐标系变化,需换算 | | `page_id` | `page_number` | 页码起始位置相同(具体说明见下节) | | `outline_level` | `metadata.category_depth` | 层级信息下沉至 metadata | | `cells`(表格单元格) | `table_structure.cells` | 下沉至 `table_structure` 子对象 | | `caption_id` | `metadata.ref_element_id` | 关联关系下沉至 metadata | | `tags`
(formula/handwritten) | `objects[]`(内嵌对象) | 改为结构化的行内对象数组 | | (无) | `metadata.parent_id` / `children_ids` | 新增:父子层级关系 | | (无) | `image_data` | 新增:图片 URL / MIME / base64 | | (无) | `char_details` | 新增:字符级详情 | ### 新版元素示例 ```json theme={null} { "element_id": "el_001", "type": "Title", "text": "检验结果", "page_number": 1, "coordinates": [0.1, 0.12, 0.32, 0.12, 0.32, 0.16, 0.1, 0.16], "metadata": { "category_depth": 0, "children_ids": ["el_002", "el_003"], "is_continuation": false } } ``` ### 坐标系与页码换算 #### 坐标换算 ```python theme={null} # 旧版:绝对像素坐标(受 dpi 影响),字段名 position # position = [x1, y1, x2, y2, x3, y3, x4, y4] 单位:像素 # 新版:归一化坐标(范围 0~1),字段名 coordinates # 如需换算为像素,从 data.pages[] 取该页宽高: page_width = page["page_width"] page_height = page["page_height"] pixel_coords = [ (coords[i] * page_width, coords[i + 1] * page_height) for i in range(0, 8, 2) ] ``` #### 页码说明 * **旧版**:`page_id`,1-based(第一页为 1) * **新版**:`page_number`,1-based(第一页为 1) 两者起始值相同,均为 1-based,遍历/定位页面的逻辑可直接迁移。 归一化 `coordinates` 8 个值的点序为:左上 → 右上 → 右下 → 左下。 *** ## 异步接口使用指南 旧版不支持异步。新版异步接口适合大文件(建议 >10 页)或批量处理,避免 HTTP 连接超时。 ### 接口概览 | 接口 | HTTP | URL | 说明 | | ----------- | ---- | ------------------------------------- | ---------------------- | | **提交异步任务** | POST | `/api/v1/xparse/parse/async` | 上传文件,返回 `job_id` | | **查询状态/结果** | GET | `/api/v1/xparse/parse/async/{job_id}` | 轮询状态,完成后含 `result_url` | #### 任务状态枚举 | 状态 | 含义 | | ------------- | ------------------------------------ | | `pending` | 排队等待中 | | `in_progress` | 处理中 | | `completed` | 已完成(响应含 `result_url`,下载该 URL 获取完整结果) | | `failed` | 处理失败(响应含 `message` 错误说明) | 异步提交成功仅返回 `{"data": {"job_id": "..."}}`,完整解析结果需通过 `result_url` 二次下载。`result_url` 返回的数据结构与同步接口 `data` 一致。 ### 异步调用完整流程(Python) ```python theme={null} import requests, time, json APP_ID = "your_app_id" SECRET = "your_secret_code" HEADERS = {"x-ti-app-id": APP_ID, "x-ti-secret-code": SECRET} def submit_async_job(file_path: str, config: dict = None) -> str: """提交异步解析任务,返回 job_id""" url = "https://api.textin.com/api/v1/xparse/parse/async" with open(file_path, "rb") as f: files = {"file": (file_path, f, "application/pdf")} data = {"config": json.dumps(config)} if config else {} resp = requests.post(url, headers=HEADERS, files=files, data=data) resp.raise_for_status() # 先校验 HTTP 状态 result = resp.json() if result.get("code") != 200: # 再校验业务 code,避免 KeyError raise RuntimeError(f"提交失败: {result.get('message')}") return result["data"]["job_id"] def poll_result(job_id: str, interval: int = 3, max_wait: int = 300) -> dict: """轮询任务状态,完成后返回完整解析结果""" url = f"https://api.textin.com/api/v1/xparse/parse/async/{job_id}" elapsed = 0 while elapsed < max_wait: resp = requests.get(url, headers=HEADERS) resp.raise_for_status() job_data = resp.json()["data"] status = job_data["status"] if status == "completed": # result_url 鉴权要求待确认,此处带 headers 以求稳妥 return requests.get(job_data["result_url"], headers=HEADERS).json() elif status == "failed": raise RuntimeError(f"任务失败: {job_data.get('message')}") print(f" {status},已等待 {elapsed}s ...") time.sleep(interval) elapsed += interval raise TimeoutError(f"超时({max_wait}s),job_id={job_id}") config = { "capabilities": { "include_hierarchy": True, "table_view": "html", "include_image_data": True, # ⚠️ 默认 false,需显式开启 "pages": True, # ⚠️ 默认 false,需显式开启 "title_tree": True, } } job_id = submit_async_job("large_document.pdf", config) result = poll_result(job_id) print(result["data"]["markdown"]) ``` ### Webhook 回调(推荐生产环境) 提交任务时附带 `webhook` 参数,任务完成/失败后系统主动 POST 推送,无需轮询: ```python theme={null} # 注意:file_url 同样走 multipart/form-data 提交。 # requests 用 files= 触发 multipart;下方用 data= 会变成 urlencoded; # 服务端通常也能解析表单字段,但若严格遵循 multipart 协议,建议统一用 files=。 fields = { "file_url": (None, "https://your-storage.com/document.pdf"), "webhook": (None, "https://your-server.com/callback/textin"), "config": (None, json.dumps({"capabilities": {"table_view": "html"}})), } resp = requests.post( "https://api.textin.com/api/v1/xparse/parse/async", headers=HEADERS, files=fields ) resp.raise_for_status() job_id = resp.json()["data"]["job_id"] # 你的服务器收到的 Webhook Body(Method: POST, Content-Type: application/json): # { # "job_id": "xxx", # "status": "completed", # "result_url": "https://..." # } ``` *** ## 完整代码迁移示例 ```python theme={null} import requests def parse_pdf_old(file_path, app_id, secret): url = "https://api.textin.com/ai/service/v1/pdf_to_markdown" params = { "parse_mode": "auto", "table_flavor": "html", "get_image": "objects", "page_details": 1, "catalog_details": 1, "apply_document_tree": 1, } headers = { "x-ti-app-id": app_id, "x-ti-secret-code": secret, "Content-Type": "application/octet-stream", } with open(file_path, "rb") as f: resp = requests.post(url, headers=headers, params=params, data=f) resp.raise_for_status() data = resp.json() if data.get("code") != 200: raise RuntimeError(data.get("message")) return { "markdown": data["result"]["markdown"], "total_pages": data["result"]["total_page_number"], "elements": data["result"]["detail"], "catalog": data["result"]["catalog"], "pages": data["result"]["pages"], } ``` ```python theme={null} import requests, json def parse_pdf_new(file_path, app_id, secret): url = "https://api.textin.com/api/v1/xparse/parse/sync" config = { "capabilities": { "include_hierarchy": True, # 原 apply_document_tree=1 "table_view": "html", # 原 table_flavor=html "include_image_data": True, # 原 get_image ⚠️需显式 "pages": True, # 原 page_details=1 ⚠️需显式 "title_tree": True, # 原 catalog_details=1 }, "config": { "force_engine": "textin", "engine_params": {"parse_mode": "auto"}, # 原 parse_mode }, } headers = {"x-ti-app-id": app_id, "x-ti-secret-code": secret} with open(file_path, "rb") as f: resp = requests.post( url, headers=headers, files={"file": (file_path, f, "application/pdf")}, data={"config": json.dumps(config)}) resp.raise_for_status() data = resp.json() if data.get("code") != 200: raise RuntimeError(data.get("message")) d = data["data"] return { "markdown": d["markdown"], "total_pages": d["metadata"]["page_count"], "elements": d["elements"], # type 现为字符串 "title_tree": d.get("title_tree"), "pages": d.get("pages"), } ``` *** ## 迁移检查清单 `/ai/service/v1/pdf_to_markdown` → `/api/v1/xparse/parse/sync` Query String + 二进制 Body → `multipart/form-data` + `config` JSON 整数开关(0/1)全部改为 boolean(false/true) ⚠️ 显式声明 `capabilities.include_image_data: true`(默认已反转)\ ⚠️ 显式声明 `capabilities.pages: true`(默认已反转) `parse_mode` / `formula_level` / `image_output_type` 迁移到 `config` 区块的 `engine_params`(非 capabilities) 评估是否需要 `force_engine` 选择特定引擎(新增能力,textin引擎下可同时配置 `parse_mode` ) * 响应根节点:`result` → `data` * `total_page_number` → `data.metadata.page_count` * `valid_page_number` → `data.success_count` * `detail` → `data.elements`(`paragraph_id` → `element_id`;`type` 由 "paragraph" 等改为语义字符串) * `catalog` → `data.title_tree` 坐标:`position`(绝对像素)→ `coordinates`(归一化,× page\_width/height 换算) `table_flavor='md'` → `table_view='markdown'`;'none' 已移除,需调整逻辑 `image_output_type`:取值由 base64str/default 改为 url/base64 * 如用 `get_excel`:新版不支持 Excel 输出,需另寻替代 * 如用 `raw_ocr`:近似改用 `capabilities.include_char_details`(语义非完全等价,需验证) * `dpi`:新版无对应参数,坐标改为归一化输出 所有响应在读取 `["data"]` 前先校验 HTTP 状态与业务 `code`,避免鉴权/参数错误变成 KeyError 大文件(建议 >10 页)评估迁移至异步接口 生产环境异步场景配置 Webhook 回调替代轮询 # 计费说明 Source: https://docs.textin.com/xparse/charge 您可以[在此处](https://www.textin.com/market/chager/pdf_to_markdown?cache=7919)查看定价选项及购买套餐。 ## 具体使用计费规则说明 TextIn xParse智能文档解析采用「按量计费」制,计费单位为“T币/页”。在实际使用时,您可以选择[购买页数套餐](https://www.textin.com/market/chager/pdf_to_markdown?cache=7921)包,也可以直接[充值T币](https://www.textin.com/console/dashboard/userCenter/charge)使用。套餐和T币的计费规则为: * 扣费顺序:优先消耗即将到期的套餐包,未购买套餐包则按实际使用量扣减T币余额。 * 购买套餐后,会自动开启按量计费模式;当套餐额度使用完毕后,如果未购买新套餐包,则会按实际使用量扣减T币余额,扣减T币余额时按[套餐](https://www.textin.com/market/chager/pdf_to_markdown?cache=7921)中的最高单价进行扣减。 * 可以在【[工作台-我的套餐](https://www.textin.com/console/dashboard/userCenter/package_management)】中查看套餐使用情况,可以在【[工作台-充值与消费明细](https://www.textin.com/console/dashboard/userCenter/finance)】中查看T币订单和消费情况。 TextIn xParse智能文档解析的使用方式包括:在线Web平台使用、API使用、第三方Agent平台使用。需要注意的是:[**文档解析**](https://docs.textin.com/api-reference/endpoint/parse)和[**文档抽取**](https://docs.textin.com/api-reference/endpoint/extract)是2个独立的API,其使用计费和消耗额度也是独立区分开的。 下面会为您详细介绍不同使用方式的计费说明。 ### 在线Web平台使用 在Web平台使用时,可以直接在页面左下角账号信息处看到当前拥有的总额度和已消耗额度。 Charge Web Pn 在平台上使用示例文件进行解析和抽取是**完全免费**的!您可以先通过示例文件快速感受效果。 同时我们为每位新注册的用户朋友**免费赠送100页**使用额度,添加TextIn福利官还可获得**免费加赠1000页**使用额度和其他超多福利!您可以自行上传文档进行解析和抽取,验证TextIn xParse智能文档解析在您实际业务场景中的表现。 当您的免费额度使用完毕后,需要[购买页数套餐](https://www.textin.com/market/chager/pdf_to_markdown?cache=7921)包或[充值T币](https://www.textin.com/console/dashboard/userCenter/charge)使用。 * 文档解析会根据您实际解析成功的文件页数进行计费扣减,解析失败的页数不计费。 * 您可以通过`page_start`和`page_count`这两个参数控制要解析的页数范围。 * 文档解析成功后,在返回的JSON结果中有`success_count`字段,即为解析成功的页数。 * 文档解析成功后,解析结果会在Web平台缓存;无论您何时重新查看解析结果,还是修改参数配置后重新解析识别,都是**限时免费**的! 在文档解析Web页面使用智能抽取功能**限时免费**!您可以充分体验,感受文档抽取能力的应用价值。 ### 通过API使用 通过API使用时,仍然是根据实际解析和抽取的文件页数进行计费扣减。API请求失败不会计费。 与Web平台使用不同的是:无论何种文件,每次成功调用API进行解析或抽取后均会产生计费扣减。 您可以通过以下字段进行核验 * 文档解析:[**返回JSON结构说明**](https://docs.textin.com/xparse/parse-getjson);`success_count`字段,解析成功的页数 * 文档抽取:[**返回JSON结构说明**](https://docs.textin.com/xparse/extract-getjson); * prompt模式抽取:`success_count`字段,智能抽取处理的页数 * 自定义字段抽取:`page_count`字段,智能抽取处理的页数 另外还需要特殊注意的是:由于文档抽取API整合了文档解析处理能力和大模型语义理解能力,会先对文档进行解析预处理再进行语义理解抽取,因此在计费上:**文档抽取API的消耗是文档解析API的2倍**。这样做是为了更好的保障文档抽取的结果准确性,以及可以提供精确的原文坐标,便于对结果做快速复核校验。 **例如一份10页的文档,对10页全部解析和抽取且均成功,那么:** * 单独调用文档解析API时消耗页数额度为10页,单独调用文档抽取API时消耗页数额度为20页。 * 如果是T币扣减,单独使用文档解析扣减0.5T币(单价0.05T币/页),单独使用文档抽取扣减1T币。 ### 第三方Agent平台使用 TextIn xParse智能文档解析在Coze、Dify等主流Agent平台上架了文档解析官方插件。 详情可见:[TextIn官方插件使用教程](https://vrk3wty1lu.feishu.cn/docx/Mhh2dJJFLoFjl2x7i2Ic7VrBnyc) 在Agent平台使用文档解析插件时,需要先前往【[**工作台 - 账号与开发者信息**](https://www.textin.com/console/dashboard/setting)】获取 `x-ti-app-id` 和 `x-ti-secret-code`;当插件运行后,会根据账号信息进行套餐页数额度和T币余额扣减。 # 最佳实践 Source: https://docs.textin.com/xparse/extract-best-practices-v3 关于如何创建高质量 JSON schema 的建议 ## 概述 构造良好的 schema 可以确保抽取结果更符合预期,且便于下游使用,本文分享的最佳实践包括: * 如何定义清晰的字段 * 使用枚举与描述 * 避免不必要的嵌套 * 聚焦于原文档中的关键信息,引导抽取引擎准确理解抽取意图和解读文档 通过应用这些实践,您可以减少抽取错误、提高输出信息完整度,并利于下游更容易接入。 ## JSON schema 建议 您的抽取 schema 对输出质量起着至关重要的作用。您可以在 schema 结构、描述(description)以及类型约束上多做尝试,以取得最佳抽取效果。 **1. 使用与原文档内容高度匹配的字段名,并为每个字段提供清晰的描述。** 采用与原文档中信息呈现方式一致的字段名和描述,有助于抽取引擎更容易识别并提取正确的值。例如从表格中抽取数据,可以直接使用表头作为字段名。 **2. 如果要抽取的数据是少量有限值的集合,可以使用枚举类型约束。** 如果某个字段有可预测的一组取值(例如“是/否”或预定义的类别),使用枚举(enum)类型来约束输出并提升一致性。 ```json theme={null} "properties": { "币种": { "type": ["enum", "null"], "enum": [ "USD", "EUR", "JPY", "CAD", "AUD", "Other" ], "description": "国际货币种类代码" } } ``` **3. 避免在 schema 中创造新数据,将数据处理放到下游完成。** ```python theme={null} # 通过 schema 抽取原文档中的月消费值 "properties": { "monthly_cost": { "type": ["number", "null"], "description": "服务月度消费总计" }, } . . . # 下游计算年消费值 total_annual_price = extract_result.json()["result"][0]["monthly_cost"] * 12 ``` **4. 对于长列表使用数组类型。** 如果你需要抽取一个较长的项目列表(例如发票表格中的订单列表),请在 schema 中使用数组类型(array)。这有助于引擎完整获取列表中的每一项,避免遗漏末尾的数据。 # Apifox调试教程 Source: https://docs.textin.com/xparse/extract-debug-apifox 通过Apifox快速调试文档抽取API ## 概述 本文档将指导您如何使用Apifox导入和调试文档抽取API。文档抽取API使用JSON格式的请求体,通过定义schema来指定要抽取的字段。 ## 先决条件 * 已安装Apifox([下载地址](https://apifox.com/)) * 已获取API Key(x-ti-app-id 和 x-ti-secret-code),请前往 [TextIn工作台 - 账号与开发者信息](https://www.textin.com/console/dashboard/setting) 获取 ## curl命令示例 ```bash theme={null} curl -X POST 'https://api.textin.com/ai/service/v3/entity_extraction' \ --header 'x-ti-app-id: YOUR_APP_ID' \ --header 'x-ti-secret-code: YOUR_SECRET_CODE' \ --header 'Content-Type: application/json' \ --data '{ "file": { "file_url": "https://web-api.textin.com/open/image/download?filename=54efc36a05cf475aa6b39137b0717726" }, "schema": { "type": "object", "properties": { "商品": { "type": ["string","null"], "description": "商品名称" } }, "required": ["商品"] } }' ``` ## 导入curl命令到Apifox ### 步骤1:复制curl命令 复制上面的curl命令。 ### 步骤2:打开Apifox导入功能 1. 打开Apifox应用 2. 点击左侧菜单栏的 **+** 按钮,或使用快捷键 `Ctrl+I` (Windows) / `Cmd+I` (Mac) 点击导入按钮 ### 步骤3:选择导入方式 1. 在弹出的导入窗口中,将复制的curl命令粘贴到文本框中 选择cURL导入 ### 步骤4:确认导入 1. 在预览页面确认请求信息 2. 点击 **确定** 按钮完成导入 确认导入 ## 配置请求 ### 修改API Key 1. 点击 **Headers** 标签页 2. 找到 `x-ti-app-id` 和 `x-ti-secret-code` 两个header 3. 将 `YOUR_APP_ID` 替换为您的实际x-ti-app-id 4. 将 `YOUR_SECRET_CODE` 替换为您的实际x-ti-secret-code 修改API Key ### 修改JSON Body 文档抽取API的核心是JSON schema配置。您可以根据需要修改Body中的内容: 1. 点击 **Body** 标签页 2. 确保Body类型为 **raw** 和 **JSON** 3. 修改JSON内容,主要包括: **修改文件信息:** ```json theme={null} { "file": { "file_url": "https://web-api.textin.com/open/image/download?filename=54efc36a05cf475aa6b39137b0717726" }, ... } ``` 或者使用base64编码的文件: ```json theme={null} { "file": { "file_base64": "base64编码的文件内容" }, ... } ``` **修改抽取schema:** 根据您的需求修改schema,例如抽取更多字段: ```json theme={null} { ... "schema": { "type": "object", "properties": { "商品": { "type": ["string","null"], "description": "商品名称" }, "价格": { "type": ["number","null"], "description": "商品价格" }, "商品列表": { "type": "array", "description": "商品列表", "items": { "type": "object", "properties": { "名称": { "type": ["string","null"], "description": "商品名称" }, "类型": { "type": ["string","null"], "description": "商品类型" } }, "required": ["名称", "类型"] } } }, "required": ["商品", "价格", "商品列表"] } } ``` **添加解析选项(可选):** ```json theme={null} { ... "parse_options": { "page_start": 1, "page_count": 10, "parse_mode": "scan", "get_image": "objects", "crop_dewarp": 0, "remove_watermark": 0 } } ``` **添加抽取选项(可选):** ```json theme={null} { ... "extract_options": { "generate_citations": true, "stamp": true } } ``` 修改JSON Body ## 发送请求 1. 确认所有配置无误后,点击右上角的 **发送** 按钮 2. 等待响应返回 3. 在下方查看响应结果 发送请求 ## 查看响应结果 响应结果会显示在Apifox下方的响应区域: * **Body**:查看JSON格式的响应内容,包括: * `extracted_schema`: 抽取的结构化数据 * `citations`: 带坐标信息的抽取结果 * `pages`: 文档页面信息 * **Headers**:查看响应头信息 * **状态码**:查看HTTP状态码(200表示成功) 响应结果如上图。 ## 常见问题 ### Q: 如何修改要抽取的字段? A: 在Body标签页中修改`schema`字段,根据您的需求定义字段名称、类型和描述。详细说明请参考[文档抽取快速启动](/xparse/extract-quickstart-v3)。 ### Q: 响应返回400错误? A: 请检查JSON格式是否正确,确保schema格式符合JSON Schema规范。 ### Q: 响应返回401错误? A: 请检查API Key是否正确设置,确保x-ti-app-id和x-ti-secret-code都已正确替换。 ### Q: 如何保存请求? A: 可以将请求保存到项目中,方便后续重复使用。请求会自动保存到当前项目。 ## 相关链接 * [文档抽取快速启动](/xparse/extract-quickstart-v3) * [Postman调试教程](/xparse/extract-debug-postman) * [API参考文档](/api-reference/endpoint/extract-v3) # Postman调试教程 Source: https://docs.textin.com/xparse/extract-debug-postman 通过Postman快速调试文档抽取API ## 概述 本文档将指导您如何使用Postman导入和调试文档抽取API。文档抽取API使用JSON格式的请求体,通过定义schema来指定要抽取的字段。 ## 先决条件 * 已安装Postman([下载地址](https://www.postman.com/downloads/)) * 已获取API Key(x-ti-app-id 和 x-ti-secret-code),请前往 [TextIn工作台 - 账号与开发者信息](https://www.textin.com/console/dashboard/setting) 获取 ## curl命令示例 ```bash theme={null} curl -X POST 'https://api.textin.com/ai/service/v3/entity_extraction' \ --header 'x-ti-app-id: YOUR_APP_ID' \ --header 'x-ti-secret-code: YOUR_SECRET_CODE' \ --header 'Content-Type: application/json' \ --data '{ "file": { "file_url": "https://web-api.textin.com/open/image/download?filename=54efc36a05cf475aa6b39137b0717726" }, "schema": { "type": "object", "properties": { "商品": { "type": ["string","null"], "description": "商品名称" } }, "required": ["商品"] } }' ``` ## 导入curl命令到Postman ### 步骤1:复制curl命令 复制上面的curl命令。 ### 步骤2:打开Postman导入功能 1. 打开Postman应用 2. 点击左上角的 **Import** 按钮 点击Import按钮 ### 步骤3:粘贴curl命令 1. 在弹出的导入窗口中,将复制的curl命令粘贴到文本框中 粘贴curl命令 ### 步骤4:确认导入 1. 在预览页面确认请求信息 2. 点击 **Import Into Collection**或者**Import Without Saving** 按钮完成导入 确认导入 ## 配置请求 ### 修改API Key 1. 点击 **Headers** 标签页 2. 找到 `x-ti-app-id` 和 `x-ti-secret-code` 两个header 3. 将 `YOUR_APP_ID` 替换为您的实际x-ti-app-id 4. 将 `YOUR_SECRET_CODE` 替换为您的实际x-ti-secret-code 修改API Key ### 修改JSON Body 文档抽取API的核心是JSON schema配置。您可以根据需要修改Body中的内容: 1. 点击 **Body** 标签页 2. 确保Body类型为 **raw** 和 **JSON** 3. 修改JSON内容,主要包括: **修改文件信息:** ```json theme={null} { "file": { "file_url": "https://web-api.textin.com/open/image/download?filename=54efc36a05cf475aa6b39137b0717726" }, ... } ``` 或者使用base64编码的文件: ```json theme={null} { "file": { "file_base64": "base64编码的文件内容" }, ... } ``` **修改抽取schema:** 根据您的需求修改schema,例如抽取更多字段: ```json theme={null} { ... "schema": { "type": "object", "properties": { "商品": { "type": ["string","null"], "description": "商品名称" }, "价格": { "type": ["number","null"], "description": "商品价格" }, "商品列表": { "type": "array", "description": "商品列表", "items": { "type": "object", "properties": { "名称": { "type": ["string","null"], "description": "商品名称" }, "类型": { "type": ["string","null"], "description": "商品类型" } }, "required": ["名称", "类型"] } } }, "required": ["商品", "价格", "商品列表"] } } ``` **添加解析选项(可选):** ```json theme={null} { ... "parse_options": { "page_start": 1, "page_count": 10, "parse_mode": "scan", "get_image": "objects", "crop_dewarp": 0, "remove_watermark": 0 } } ``` **添加抽取选项(可选):** ```json theme={null} { ... "extract_options": { "generate_citations": true, "stamp": true } } ``` 修改JSON Body ## 发送请求 1. 确认所有配置无误后,点击右上角的 **Send** 按钮 2. 等待响应返回 3. 在下方查看响应结果 发送请求 ## 查看响应结果 响应结果会显示在Postman下方的响应区域: * **Body**:查看JSON格式的响应内容,包括: * `extracted_schema`: 抽取的结构化数据 * `citations`: 带坐标信息的抽取结果 * `pages`: 文档页面信息 * **Headers**:查看响应头信息 * **Status**:查看HTTP状态码(200表示成功) 响应结果如上图。 ## 常见问题 ### Q: 如何修改要抽取的字段? A: 在Body标签页中修改`schema`字段,根据您的需求定义字段名称、类型和描述。详细说明请参考[文档抽取快速启动](/xparse/extract-quickstart-v3)。 ### Q: 响应返回400错误? A: 请检查JSON格式是否正确,确保schema格式符合JSON Schema规范。 ### Q: 响应返回401错误? A: 请检查API Key是否正确设置,确保x-ti-app-id和x-ti-secret-code都已正确替换。 ### Q: 如何保存请求? A: 可以将请求保存到Collection中,方便后续重复使用。点击请求右侧的"Save"按钮即可。 ## 相关链接 * [文档抽取快速启动](/xparse/extract-quickstart-v3) * [Apifox调试教程](/xparse/extract-debug-apifox) * [API参考文档](/api-reference/endpoint/extract-v3) # 快速启动 Source: https://docs.textin.com/xparse/extract-quickstart-v3 本文档基于最新抽取API版本v3 ,如需查看旧版API(包含**Prompt模式**)或在线调试,请移步[Textin文档中心](https://www.textin.com/document/legacy/open_kie_vlm_engine)。 ## 概述 TextIn xParse现已推出的全新版本的文档抽取API(v3)。在文档抽取中,您可以自定义抽取配置(JSON schema),指定您要抽取的字段名称、类型和字段描述,系统会根据您定义的配置进行抽取。 通过定义JSON schema,文档抽取兼顾了定义字段的**灵活性**和输出结果的**稳定性**。 您可以从多种样式的表单或文档中提取统一的结构化信息,并根据字段设定的标准类型完成自动格式转换。您可以根据下游系统的字段和结构要求来定义抽取JSON schema,以实现API"即插即用"的效果。例如,当您想要完成文档数据自动化录入系统时,文档抽取可以帮助您快速完成从复杂文档到系统结构化数据的无缝衔接。 新增功能 1. 支持更灵活的上传文件传参方式,兼容`file_url`和`file_base64` 2. 支持设定字段类型,包括常见的文本、数字、枚举等格式 3. 支持抽取多个表格,且限定抽取范围 4. 支持通过参数开关按需返回坐标信息,提升响应速度 ## 文档抽取配置 ### JSON schema 结构示例 在文档抽取中最核心的配置是JSON schema,其结构示例如下: ```json theme={null} { "type": "object", "properties": { "field_name": { "type": ["string","null"], "description": "Field description" }, "table_name": { "type": "array", "description": "Table description", "items": { "type": "object", "properties": { "name": { "type": ["string","null"], "description": "" }, "category": { "type": ["string","null"], "description": "" } }, "required": [ "name", "category" ] } } }, "required": [ "field_name", "table_name" ] } ``` ### JSON schema 结构说明和抽取指南 我们使用[JSON Schema](https://json-schema.org/)来定义要抽取的数据结构,在遵循 schema 规范的基础上,剔除了一些不必要的字段,文档抽取使用的 schema 字段如下: * **type**:schema的类型,最外层固定为`object` * **properties**:抽取字段的集合 * **\**:要抽取的字段名称,由用户自定义,每个字段包含以下信息: * **type**:要抽取的字段类型,参考[支持的字段类型](#json-schema-支持的字段类型)列表 * **description**:要抽取的字段描述 * **enum**:当type为`enum`时,该字段表示抽取字段的枚举值列表 * **items**:当type为`array`时,该字段表示要抽取的列表中的字段集合,与`properties`类似 * **required**:指定抽取必要字段,其顺序表达了抽取输出的字段顺序,仅在type为`object`时需要。 在定义要抽取的数据时,您需要为每个字段提供一个名称,以及确定该字段的类型。您还可以添加可选的字段描述为大模型提供更多的上下文,帮助文档抽取准确了解需要从文档中查找和提取哪些信息。字段名称和描述越具体、表义越明确,文档抽取就越能准确地识别和抽取文档中的正确数据。 ### JSON schema 支持的字段类型 * string:字符串 * number:数字 * integer:整数 * enum:枚举 * object:对象,对象内可以包含以下类型:string、number、integer、enum。 * array:数组,数组内可以包含以下类型:string、number、integer、enum、object。 请注意,在JSON schema中array、object类型均支持层级嵌套结构,以便于抽取如表格或者具有多个属性的实体对象。目前文档抽取仅支持最多**不超过3级**的嵌套。 type可以设置为字符串(如`"type": "string"`)或者包含null的数组(如`"type": ["string", "null"]`),即使type不带null,接口底层也会默认带上null,当抽取不到数据时,接口统一返回null值。 ### JSON schema 支持的字段数量 为了获得最佳性能,保障抽取的精度和速度,在JSON schema中包含的最低层级(叶子节点)字段数量限制总计应**不超过100个**。 ### 更多请求体参数说明 **file**: `object` 必填,传入需要处理的文件内容 * file\_url: `string` 待处理文件的url链接,与file\_base64二选一 * file\_base64: `string` 待处理文件的base64编码,与file\_url二选一 * file\_name: `string` 文件名,可选 如果file\_base64和file\_url同时存在,优先取file\_base64的值。 **parse\_options**: `object` 用于控制文档解析输出的相关参数 * **page\_start**:当上传的是pdf时,page\_start 表示从第几页开始抽取,取值范围从1开始,不传该参数时默认从首页开始。 * **page\_count**:当上传的是pdf时,page\_count 表示要进行抽取的pdf页数。 * **parse\_mode**:文档的解析模式,默认为scan模式。 * auto 由引擎自动选择,适用范围最广 * scan 文档统一当成图片解析(如pdf每一页都当成图片解析) * lite 轻量版,只输出表格和文字结果 * parse 仅电子档文字解析,速度最快 * vlm 视觉语言模型解析模式 * **get\_image**:获取图片,默认为objects。 * none 不返回任何图像 * page 返回每一页的整页图像:即pdf页的完整页图片 * objects 返回页面内的子图像:即pdf页内的各个子图片 * both 返回整页图像和图像对象 * **crop\_dewarp**:是否进行切边矫正预处理,默认为0,不进行切边矫正。 * 0 不进行切边矫正 * 1 进行切边矫正 * **remove\_watermark**:是否进行去水印预处理,默认为0,不去水印。 * 0 不去水印 * 1 去水印 * **formula\_level**:公式识别等级,默认为0,全识别。 * 0 行间公式和行内公式都识别 * 1 仅识别行间公式,行内公式不识别 * 2 不识别公式 * **table\_flavor**:markdown里的表格格式,默认为html,按html语法输出表格。 * md 按md语法输出表格 * html 按html语法输出表格 * none 不进行表格识别,把表格图像当成普通文字段落来识别 * **pdf\_pwd**:当pdf为加密文档时,需要提供密码。 **extract\_options**: `object` 用于控制更多抽取的高级功能 * generate\_citations `boolean` 是否生成坐标,默认为`true` * stamp `boolean` 是否开启印章识别,默认为`true` ## 使用文档抽取 API:快速启动 推荐使用我们的[在线Web平台](https://www.textin.com/console/recognition/robot_markdown?service=pdf_to_markdown)快速创建和验证 schema 抽取效果,页面使用方式请参考[使用指南](/extract-tutorial-v3),之后您可以在[**API**](/api-reference/endpoint/extract-v3)调用中直接使用。 您也可以参考以下示例文件和示例代码,快速验证并将文档抽取接入到您的系统和应用流程中。 ### 示例文件 这里为您提供了一份Textin官方示例图片,您可以点击下载使用:[文档抽取png示例.png](https://web-api.textin.com/open/image/download?filename=54efc36a05cf475aa6b39137b0717726) Extract Sample Image ### 先决条件:获取API Key 使用文档抽取API处理文档时,您需要先获取[API Key](/xparse/api-key.mdx)。请先登录后前往 [TextIn工作台 - 账号与开发者信息](https://www.textin.com/console/dashboard/setting) 获取您的x-ti-app-id 和 x-ti-secret-code。 想要快速调试API?请参考[Postman调试教程](/xparse/extract-debug-postman)或[Apifox调试教程](/xparse/extract-debug-apifox)。 ### 请求示例 ```python theme={null} import requests url = "https://api.textin.com/ai/service/v3/entity_extraction" payload = { # 您要抽取的文件 "file": { "file_url": "https://web-api.textin.com/open/image/download?filename=54efc36a05cf475aa6b39137b0717726" }, # 定义抽取的schema "schema": { "type": "object", "properties": { "商品": { "type": ["string","null"], "description": "" }, "商品列表": { "type": "array", "description": "", "items": { "type": "object", "properties": { "名称": { "type": ["string","null"], "description": "" }, "类型": { "type": ["string","null"], "description": "" } }, "required": ["名称","类型"] } } }, "required": [ "商品", "商品列表" ] }, # 解析相关参数 "parse_options":{ "crop_dewarp":1, "get_image":"both" }, # 抽取高级配置 "extract_options":{ "generate_citations": True, "stamp": True } } # 设置API key headers = { "x-ti-app-id": "", #需替换为你的x-ti-app-id "x-ti-secret-code": "", #需替换为你的x-ti-secret-code "Content-Type": "application/json" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ### 返回示例 ```json theme={null} { "code": 200, "message": "Success", "version": "v3.0.60", "duration": 8267, "x_request_id": "7596b8c9d2ddbc9924b66651e9efc174", "status": "finished", "result": { "success_count": 1, "extracted_schema": { "商品": "童装 Looney Tunes UT(短袖T恤)女装SUPIMA COTTON圆领T恤(短袖)", "商品列表": [ { "名称": "童装 Looney Tunes UT(短袖T恤)", "类型": "童装" }, { "名称": "女装SUPIMA COTTON圆领T恤(短袖)", "类型": "女装" } ] }, "citations": { "商品": { "value": "童装 Looney Tunes UT(短袖T恤)女装SUPIMA COTTON圆领T恤(短袖)", "bounding_regions": [ { "page_number": 1, "position": [137, 599, 1129, 599, 1129, 625, 182, 625], "text": "童装 Looney Tunes UT(短袖T恤)" } ], } // 商品列表... }, "pages": [ { "page_number": 1, "image_id": "62bfe3c3a8e9c9cf.jpg", "height": 1824, "width": 600, "angle": 0, "status": "Success", "durations": 930.178466796875 } ] } } ``` ## 返回结果说明 ### 常规字段说明 * x\_request\_id:该请求的唯一标识 * code:错误码,200表示成功。详情见[错误码说明](/xparse/extract-quickstart-v3#错误码说明) * message:错误信息,成功时为”Success” * version:版本号,例如”v3.0.29\_20250819” * duration:总耗时(毫秒),例如”8267” * status:处理状态,例如"finished" ### 主要结果说明:result对象 文档抽取会在返回结果的result对象中包含以下关键信息。 **success\_count**:成功处理的文档页数。 **extracted\_schema**:结构化的抽取结果,以json格式返回,与抽取时传入的schema定义的结构一致。 **citations**:抽取结果的详细信息,包含坐标位置,结构与schema定义一致。 每个抽取字段的详细信息如下: * **\**:在schema中定义的抽取字段名 * **value**:该字段的抽取结果 * **bounding\_regions**:抽取结果value对应的坐标位置 * **page\_number**:所在页码,从1开始 * **text**:边界框所在区域内的文本内容 * **position**:坐标位置,长度为8的数组,表示四个顶点的像素坐标 \[左上x, 左上y, 右上x, 右上y, 右下x, 右下y, 左下x, 左下y] **stamps**:印章相关信息 * **color**:当前印章颜色,可选值有:红色、蓝色、黑色、其他 * **position**:印章的坐标信息 * **stamp\_shape**:当前印章形状,可选值有:圆章、椭圆章、方章、三角章、菱形章、其他 * **type**:当前印章类型,可选值有:公章、个人章、专用章、其他、合同专用章、财务专用章、发票专用章、业务专用章 * **value**:印章的文本内容 **pages**:文档页面相关信息 * **page\_number**:当前页码 * **image\_id**:当前页面图片id * **height**:文档页面高度 * **width**:文档页面宽度 * **angle**:页面角度(可选值0, 90, 180, 270) * **status**:当前页处理状态 * **durations**:当前页处理耗时(毫秒) ### 错误码说明 | **错误码** | **描述** | | :------ | :------------------------------------------------- | | 40101 | x-ti-app-id 或 x-ti-secret-code 为空 | | 40102 | x-ti-app-id 或 x-ti-secret-code 无效,验证失败 | | 40103 | 客户端IP不在白名单 | | 40003 | 余额不足,请充值后再使用 | | 40004 | Parameter error (参数错误,请检查入参) | | 40007 | 机器人不存在或未发布 | | 40008 | 机器人未开通,请至市场开通后重试 | | 40301 | 图片类型不支持 | | 40302 | 上传文件大小不符,文件大小不超过 50M | | 40303 | 文件类型不支持,接口会返回实际检测到的文件类型,如“当前文件类型为.gif” | | 40304 | 图片尺寸不符,图像宽高须介于 20 和 10000(像素)之间 | | 40305 | File not uploaded (识别文件未上传) | | 40306 | qps超过限制 | | 40400 | 无效的请求链接,请检查链接是否正确 | | 40422 | The file is corrupted (文件损坏) | | 40423 | Password required or incorrect password (PDF密码错误) | | 40424 | Page number out of range (页面设置超出文件范围) | | 40425 | The input file format is not supported (输入文件格式不支持) | | 40428 | Process office file failed (word和ppt转pdf失败或者超时) | | 500 | Engine failed (服务器内部错误) | | 50011 | LLM Connection Failed (访问大模型超时) | | 50012 | LLM Engine Failed (大模型引擎错误) | | 50207 | Partial failed (部分页面解析失败) | ## Prompt 模式 目前v3版本仅支持字段模式(JSON Schema )抽取,Prompt 模式抽取请参考[v2](https://www.textin.com/document/legacy/open_kie_vlm_engine)版本文档。 # 使用指南 Source: https://docs.textin.com/xparse/extract-tutorial-v3 为了创建一个正确可用的schema,我们提供了一个[Web配置](https://www.textin.com/console/recognition/robot_markdown?service=pdf_to_markdown\&tab=llmExtract)界面,您可以按以下步骤操作: 使用Web界面上传文件,或点击示例文件,系统会自动开始解析文件内容,为抽取做准备 使用Web界面从0开始创建一个schema。 使用配置好的schema进行抽取,验证结果是否符合您的预期。 当schema调试好后,您可以导出为json文件,以便在api调用时使用。 ## 创建Schema 您可以通过我们的[Web配置](https://www.textin.com/console/recognition/robot_markdown?service=pdf_to_markdown\&tab=llmExtract)界面来创建抽取schema。 1. 登录并进入到TextIn xParse智能文档解析 [工作台](https://www.textin.com/console/recognition/robot_markdown?service=pdf_to_markdown); 2. 上传一个文件,或打开一个已存在的文件; 3. 切换到**智能抽取**tab,并切换到**字段模式**; Extract V3 Schema Empty Jp 4. 在**抽取配置**中,可以添加您想抽取的字段,如 ”商品名称“; 5. 选择**字段类型**下拉框,可以设定您所期望返回的字段类型,详情请参考[支持的字段类型](/xparse/extract-quickstart-v3#json-schema-%E6%94%AF%E6%8C%81%E7%9A%84%E5%AD%97%E6%AE%B5%E7%B1%BB%E5%9E%8B); 6. 为字段增加一个**字段描述**(可选); 7. 点击**添加字段**按钮,可以新加一个字段; 8. 鼠标 hover 时字段左侧出现小图标,可以**删除字段**和**拖拽排序**; 9. 重复以上步骤,直到添加完您想抽取的全部字段; Extract V3 Schema Edit Jp 10. 点击右上角**抽取**按钮,配置面板会收起,并自动切换到抽取结果面板,您可以在结果面板查看所有的内容。 ## 验证抽取效果 1. 抽取完成后,会展示抽取结果面板,您可以点击字段抽取结果,会在左侧原文件区域找到对应的坐标边界(高亮显示); Extract V3 Schema Result Panel Jp 2. 抽取结果默认显示**预览**面板,您也可以切换到**JSON**面板查看对应的结构化数据; Extract V3 Json Preview Jp 3. 您可以展开下方抽取配置面板,进一步调整schema后再抽取,直到抽取结果符合预期。 ## 导出Schema 1. 在**抽取配置**面板,点击**导出配置**,可将当前schema对应的JSON文件下载到本地; 2. 在后续API调用时,通过该Schema,就能保证每次抽取的结果符合格式要求。 使用schema文件,可以参考以下代码示例: ```python theme={null} import requests import json url = "https://api.textin.com/ai/service/v3/entity_extraction" schema_file = '/Downloads/商铺小票.json' #您所保存的实际schema文件路径 payload = { "file": { "file_url": "https://web-api.textin.com/open/image/download?filename=54efc36a05cf475aa6b39137b0717726" }, "schema":json.loads(open(schema_file).read()), #读入schema文件 "parse_options":{ "crop_dewarp":1, "get_image":"both" }, "extract_options":{ "generate_citations": True, "stamp": True } } headers = { "x-ti-app-id": "", #需替换为你的x-ti-app-id "x-ti-secret-code": "", #需替换为你的x-ti-secret-code "Content-Type": "application/json" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ## 常见抽取场景的配置方式 ### 抽取单值 当待抽取的字段在文件中仅会有一个值时,推荐单值抽取,使用`string`, `number`, `integer`, `enum`类型。 Extract V3 Mono Key Jp ### 抽取多值 当待抽取的字段存在多个并列的值时,推荐多值抽取,使用`array/string`,`array/number`等类型。 Extract V3 Multi Value Jp Extract V3 Multi Value Demo Jp ### 抽取表格 当待抽取的内容有多组重复属性的数据组成,一般在原文档中呈现为类表格形式时,推荐表格抽取,使用`array/object`加单值字段嵌套表示。 Extract V3 Schema Table Sample Jp 如果文件中存在多个表格,可以添加多个`array/object`类型的字段。 Extract V3 Schema Multi Table Jp ### 抽取嵌套对象 当待抽取的内容由多个相关联的属性字段组成,推荐使用嵌套对象抽取,使用`object`类型。 Extract V3 Object Jp # 产品简介 Source: https://docs.textin.com/xparse/overview TextIn xParse for ETL TextIn xParse智能文档解析,致力于将复杂文档转变为结构化数据,让任意文档的信息都能高效准确流入您的数据库,将非结构化内容转化为可查询、可分析的宝贵数据资产,同时兼容关系型数据库与向量数据库。 TextIn xParse智能文档解析可以从 pdf、word、excel、ppt、图片等十余种格式的非结构化文档中提取结构化数据。[文档解析](/xparse/v1/quickstart)可以识别文本、图像、表格、公式、手写体、表单字段、页眉页脚等各种元素,并支持印章、二维码、条形码等子类型,转换成 markdown 和 JSON 格式返回,同时包含精确的页面元素和坐标信息。[文档抽取](/xparse/extract-quickstart-v3)可以根据定义的规则提取特定的数据信息,支持根据prompt(自然语言)和自定义字段模式(JSON Schema)抽取。 解析或抽取后的数据是LLM友好的格式,非常适用于下游应用程序,如知识库、RAG、Agent或其他自定义工作流程。 ### TextIn xParse 助力从文档到可操作的数据资产 提供全链路的文档结构化工具,最大化挖掘数据资产价值,您只需关心业务,剩下的交给TextIn Index 1 Pn ### 立即试用 免费试用,一站式极速体验解析抽取效果 灵活使用不同编程语言,支持接口高度自定义 提供可直接复制运行的命令行工具与 SDK,快速将 xParse 文档解析能力集成到开发环境中 适配 Langchain, Dify, RAGFlow 等框架 ### 核心优势 * **支持任意复杂布局**:将任意版式的文档拆解为语义完整的段落,并按阅读顺序还原,更加适配大模型。 * **多元素高精度解析**:准确提取标题、公式、图表、手写体、印章、跨页段落、页眉页脚、表单字段等各种元素,同时具备行业领先的表格识别能力,轻松解决合并单元格、跨页表格、无线表格等识别难题。 * **强大的语义理解和上下文感知**:捕捉更多版面元素间的语义关系,让大模型更加读懂一份文档。 * **强大的预处理工具**:无缝集成TextIn平台中的图像处理能力,文档带水印、图片有弯曲、模糊,都能搞定。 * **高精度坐标还原**:JSON结果包含高精度的页面、元素、字符级坐标数据,方便人工复核。 * **极简、智能、灵活的语义抽取**:xParse提供prompt模式和Schema模式两种抽取规则定制,帮助您根据业务需要实现更灵活的文档信息精准提取。 * **开发者友好**:提供清晰的API文档和灵活的集成方式,支持FastGPT、Coze、CherryStudio等主流平台。 更多详情见: [TextIn xParse for ETL 产品介绍](https://www.textin.com/market/detail/xparse) # Apifox调试教程 Source: https://docs.textin.com/xparse/parse-debug-apifox 通过Apifox快速调试文档解析API ## 概述 本文档将指导您如何使用Apifox导入和调试文档解析API。Apifox是一款功能强大的API协作工具,支持导入curl命令并快速调试API。 ## 先决条件 * 已安装Apifox([下载地址](https://apifox.com/)) * 已获取API Key(x-ti-app-id 和 x-ti-secret-code),请前往 [TextIn工作台 - 账号与开发者信息](https://www.textin.com/console/dashboard/setting) 获取 ## curl命令示例 ### 方式一:上传本地文件 ```bash theme={null} curl -X POST 'https://api.textin.com/ai/service/v1/pdf_to_markdown?dpi=144&get_image=objects&parse_mode=auto' \ --header 'x-ti-app-id: YOUR_APP_ID' \ --header 'x-ti-secret-code: YOUR_SECRET_CODE' \ --header 'Content-Type: application/octet-stream' \ --data-binary '@your_file.pdf' ``` ### 方式二:使用文件URL ```bash theme={null} curl -X POST 'https://api.textin.com/ai/service/v1/pdf_to_markdown?dpi=144&get_image=objects&parse_mode=auto' \ --header 'x-ti-app-id: YOUR_APP_ID' \ --header 'x-ti-secret-code: YOUR_SECRET_CODE' \ --header 'Content-Type: text/plain' \ --data 'https://web-api.textin.com/open/image/download?filename=54efc36a05cf475aa6b39137b0717726' ``` ## 导入curl命令到Apifox ### 步骤1:复制curl命令 复制上面的curl命令(方式一或方式二),根据您的需求选择。 ### 步骤2:打开Apifox导入功能 1. 打开Apifox应用 2. 点击左侧菜单栏的 **+** 按钮,或使用快捷键 `Ctrl+I` (Windows) / `Cmd+I` (Mac) 点击导入按钮 ### 步骤3:选择导入方式 1. 在弹出的导入窗口中,选择 **cURL** 选项 2. 将复制的curl命令粘贴到文本框中 3. 点击 **确认** 按钮 选择cURL导入 ### 步骤4:确认导入 1. 在预览页面确认请求信息 2. 点击 **确定** 按钮完成导入 确认导入 ## 配置请求 ### 重要:设置Body类型(仅方式一需要) 当导入包含`--data-binary '@file'`的curl命令时,Apifox可能会将Body类型识别为raw而不是binary。您需要手动设置Body类型为binary。 **对于方式一(本地文件上传):** 1. 在导入的请求中,点击 **Body** 标签页 2. 选择 **Binary** 类型(而不是raw) 3. 点击 **Upload** 按钮选择要上传的文件 设置Body类型为binary **对于方式二(文件URL):** Body类型会自动设置为raw,无需修改。确保Body内容为文件URL字符串。 ### 修改API Key 1. 点击 **Headers** 标签页 2. 找到 `x-ti-app-id` 和 `x-ti-secret-code` 两个header 3. 将 `YOUR_APP_ID` 替换为您的实际x-ti-app-id 4. 将 `YOUR_SECRET_CODE` 替换为您的实际x-ti-secret-code 修改API Key ### 修改请求参数(可选) 如果需要修改URL参数,可以: 1. 点击 **Params** 标签页查看所有参数 2. 修改参数值,例如: * `dpi`: 144(默认值) * `get_image`: objects(默认值) * `parse_mode`: auto(默认值) 修改请求参数 ## 发送请求 1. 确认所有配置无误后,点击右上角的 **发送** 按钮 2. 等待响应返回 3. 在下方查看响应结果 发送请求 ## 查看响应结果 响应结果会显示在Apifox下方的响应区域: * **Body**:查看JSON格式的响应内容 * **Headers**:查看响应头信息 * **状态码**:查看HTTP状态码(200表示成功) 响应结果如上图。 ## 常见问题 ### Q: 导入后Body类型不是binary怎么办? A: 请按照上述"设置Body类型"步骤,手动将Body类型改为binary,然后选择文件。 ### Q: 如何修改文件? A: 在Body标签页选择binary类型后,点击"选择文件"按钮重新选择文件。 ### Q: 响应返回401错误? A: 请检查API Key是否正确设置,确保x-ti-app-id和x-ti-secret-code都已正确替换。 ### Q: 如何保存请求? A: 可以将请求保存到项目中,方便后续重复使用。请求会自动保存到当前项目。 ## 相关链接 * [文档解析快速启动](/xparse/parse-quickstart) * [Postman调试教程](/xparse/parse-debug-postman) * [API参考文档](/api-reference/endpoint/parse) # Postman调试教程 Source: https://docs.textin.com/xparse/parse-debug-postman 通过Postman快速调试文档解析API ## 概述 本文档将指导您如何使用Postman导入和调试文档解析API。Postman是一款流行的API测试工具,可以帮助您快速验证API调用。 ## 先决条件 * 已安装Postman([下载地址](https://www.postman.com/downloads/)) * 已获取API Key(x-ti-app-id 和 x-ti-secret-code),请前往 [TextIn工作台 - 账号与开发者信息](https://www.textin.com/console/dashboard/setting) 获取 ## curl命令示例 ### 方式一:上传本地文件 ```bash theme={null} curl -X POST 'https://api.textin.com/ai/service/v1/pdf_to_markdown?dpi=144&get_image=objects&parse_mode=auto' \ --header 'x-ti-app-id: YOUR_APP_ID' \ --header 'x-ti-secret-code: YOUR_SECRET_CODE' \ --header 'Content-Type: application/octet-stream' \ --data-binary '@your_file.pdf' ``` ### 方式二:使用文件URL ```bash theme={null} curl -X POST 'https://api.textin.com/ai/service/v1/pdf_to_markdown?dpi=144&get_image=objects&parse_mode=auto' \ --header 'x-ti-app-id: YOUR_APP_ID' \ --header 'x-ti-secret-code: YOUR_SECRET_CODE' \ --header 'Content-Type: text/plain' \ --data 'https://web-api.textin.com/open/image/download?filename=54efc36a05cf475aa6b39137b0717726' ``` ## 导入curl命令到Postman ### 步骤1:复制curl命令 复制上面的curl命令(方式一或方式二),根据您的需求选择。 ### 步骤2:打开Postman导入功能 1. 打开Postman应用 2. 点击左上角的 **Import** 按钮 点击Import按钮 ### 步骤3:粘贴curl命令 1. 在弹出的导入窗口中,将复制的curl命令粘贴到文本框中 粘贴curl命令 ### 步骤4:确认导入 1. 在预览页面确认请求信息 2. 点击 **Import Into Collection**或者**Import Without Saving** 按钮完成导入 确认导入 ## 配置请求 ### 重要:设置Body类型(仅方式一需要) 当导入包含`--data-binary '@file'`的curl命令时,Postman可能会将Body类型识别为raw而不是binary。您需要手动设置Body类型为binary。 **对于方式一(本地文件上传):** 1. 在导入的请求中,点击 **Body** 标签页 2. 选择 **binary** 类型(而不是raw) 3. 点击 **Select File** 按钮选择要上传的文件 设置Body类型为binary **对于方式二(文件URL):** Body类型会自动设置为raw,无需修改。确保Body内容为文件URL字符串。 ### 修改API Key 1. 点击 **Headers** 标签页 2. 找到 `x-ti-app-id` 和 `x-ti-secret-code` 两个header 3. 将 `YOUR_APP_ID` 替换为您的实际x-ti-app-id 4. 将 `YOUR_SECRET_CODE` 替换为您的实际x-ti-secret-code 修改API Key ### 修改请求参数(可选) 如果需要修改URL参数,可以: 1. 点击 **Params** 标签页查看所有参数 2. 修改参数值,例如: * `dpi`: 144(默认值) * `get_image`: objects(默认值) * `parse_mode`: auto(默认值) 修改请求参数 ## 发送请求 1. 确认所有配置无误后,点击右上角的 **Send** 按钮 2. 等待响应返回 3. 在下方查看响应结果 发送请求 ## 查看响应结果 响应结果会显示在Postman下方的响应区域: * **Body**:查看JSON格式的响应内容 * **Headers**:查看响应头信息 * **Status**:查看HTTP状态码(200表示成功) 响应结果如上图。 ## 常见问题 ### Q: 导入后Body类型不是binary怎么办? A: 请按照上述"设置Body类型"步骤,手动将Body类型改为binary,然后选择文件。 ### Q: 如何修改文件? A: 在Body标签页选择binary类型后,点击"Select File"按钮重新选择文件。 ### Q: 响应返回401错误? A: 请检查API Key是否正确设置,确保x-ti-app-id和x-ti-secret-code都已正确替换。 ### Q: 如何保存请求? A: 可以将请求保存到Collection中,方便后续重复使用。点击请求右侧的"Save"按钮即可。 ## 相关链接 * [文档解析快速启动](/xparse/parse-quickstart) * [Apifox调试教程](/xparse/parse-debug-apifox) * [API参考文档](/api-reference/endpoint/parse) # 获取目录树 Source: https://docs.textin.com/xparse/parse-getcatalog 在处理长篇技术文档、学术论文或企业规范文档时,RAG系统面临的最大挑战之一是如何理解内容的逻辑层次和上下文关系。简单的文本分块往往会破坏文档的原有结构,导致检索到的信息缺乏必要的背景context。例如:当用户询问"数据安全相关的实施要求"时,如果系统无法区分这些要求是来自"总体概述"、"技术规范"还是"合规检查"章节,就可能提供不准确或不完整的信息。 实践中通常有一种技巧,即利用文档的标题层级分chunk,然后在检索和重排序的时候也利用标题层级过滤无关的chunk,从而提升Top5召回的相关度,以便让大模型在最终回答时效果更好。 在TextIn xParse文档解析API中,我们提供了获取文档标题层级的功能,最多可支持6级标题的输出,您可以基于API的返回结果来构建完整的文档目录树。 ## 如何获取目录树 当您想要获取文档目录树(即大纲结构)时,您可以参考以下教程和示例代码。 这里为您提供了一份Textin官方pdf示例文件,您可点击下载或使用该链接:[文档解析pdf示例.pdf](https://web-api.textin.com/open/image/download?filename=c9cf7431eb314c7ba3f43ee716c799a3) * 参考[快速启动](/xparse/parse-quickstart),在 options 中设置URL参数 catalog\_details=1,API会在返回结果中包含目录相关信息。 * 在main函数中添加以下示例代码,获取API输出的目录信息,并保存为 json 文件。 ```python theme={null} # 解析JSON响应 json_response = json.loads(response) if "result" in json_response and "catalog" in json_response["result"]: catalog = json_response["result"]["catalog"] # 保存为json文件 with open("catalog.json", "w", encoding="utf-8") as f: json.dump(catalog, f, ensure_ascii=False, indent=2) print("目录已保存为 catalog.json") else: print("未检测到目录字段,可能文档没有目录或参数设置有误。") return ``` * 请注意:为了更加灵活的支持下游业务场景,文档解析API的目录返回结果中通过**hierarchy**字段表示目录的标题层级,但并没有目录之间直接的父子层级关系,您可以参考以下示例代码获取标题目录间的父子层级关系,以构建目录树状结构。 ```python theme={null} toc_list = catalog['toc'] result = [] parent_stack = [] # 用于跟踪当前路径上的父节点 for item in toc_list: # 复制当前项目,避免修改原始数据 current_item = item.copy() current_item['children'] = [] current_level = item.get('hierarchy', 1) # 根据层级调整父节点栈 # 移除层级大于等于当前层级的节点 while parent_stack and parent_stack[-1]['hierarchy'] >= current_level: parent_stack.pop() # 如果有父节点,将当前项目添加到父节点的children中 if parent_stack: parent_stack[-1]['children'].append(current_item) else: # 如果没有父节点,说明是根节点 result.append(current_item) # 将当前项目添加到父节点栈中 parent_stack.append(current_item) print(result) # 保存处理后的目录结构为json文件 with open("processed_catalog.json", "w", encoding="utf-8") as f: json.dump(result, f, ensure_ascii=False, indent=2) print("处理后的目录结构已保存为 processed_catalog.json") return result ``` * 处理后的目录结构如下,标题目录间有了父子层级关系,您可以据此构建标题目录的树状结构。 ```json expandable theme={null} [ { "title": "Textin", "hierarchy": 1, "page_id": 1, "paragraph_id": 0, "pos": [ 276, 228, 467, 228, 467, 272, 276, 272 ], "pos_list": [ [ 276, 228, 467, 228, 467, 272, 276, 272 ] ], "sub_type": "text_title", "children": [] }, { "pos": [ 371, 382, 906, 382, 906, 450, 371, 450 ], "pos_list": [ [ 371, 382, 906, 382, 906, 450, 371, 450 ] ], "sub_type": "text_title", "title": "标准参考样例", "hierarchy": 1, "page_id": 1, "paragraph_id": 2, "children": [] }, { "paragraph_id": 3, "pos": [ 214, 564, 974, 564, 974, 657, 214, 657 ], "pos_list": [ [ 214, 564, 974, 564, 974, 657, 214, 657 ] ], "sub_type": "text_title", "title": "本科毕业论文模板", "hierarchy": 1, "page_id": 1, "children": [] }, { "sub_type": "text_title", "title": "目录", "hierarchy": 1, "page_id": 2, "paragraph_id": 0, "pos": [ 571, 198, 685, 198, 685, 228, 571, 228 ], "pos_list": [ [ 571, 198, 685, 198, 685, 228, 571, 228 ] ], "children": [] }, { "title": "第一章 背景介绍", "hierarchy": 1, "page_id": 3, "paragraph_id": 0, "pos": [ 456, 212, 733, 212, 733, 241, 456, 241 ], "pos_list": [ [ 456, 212, 733, 212, 733, 241, 456, 241 ] ], "sub_type": "text_title", "children": [ { "page_id": 3, "paragraph_id": 2, "pos": [ 342, 413, 657, 413, 657, 440, 342, 440 ], "pos_list": [ [ 342, 413, 657, 413, 657, 440, 342, 440 ] ], "sub_type": "text_title", "title": "第1节 模板使用说明", "hierarchy": 2, "children": [ { "title": "1.1.如何使用样式?", "hierarchy": 3, "page_id": 3, "paragraph_id": 5, "pos": [ 179, 798, 411, 798, 411, 820, 179, 820 ], "pos_list": [ [ 179, 798, 411, 798, 411, 820, 179, 820 ] ], "sub_type": "text_title", "children": [] } ] }, { "title": "第2节 如何刷新目录", "hierarchy": 2, "page_id": 3, "paragraph_id": 7, "pos": [ 342, 1019, 657, 1019, 657, 1046, 342, 1046 ], "pos_list": [ [ 342, 1019, 657, 1019, 657, 1046, 342, 1046 ] ], "sub_type": "text_title", "children": [ { "hierarchy": 3, "page_id": 3, "paragraph_id": 9, "pos": [ 177, 1286, 747, 1286, 747, 1308, 177, 1308 ], "pos_list": [ [ 177, 1286, 747, 1286, 747, 1308, 177, 1308 ] ], "sub_type": "text_title", "title": "2.1.为什么我写了新的章节后没有新的目录项出现?", "children": [] }, { "title": "2.2. 如何排版文章章节", "hierarchy": 3, "page_id": 4, "paragraph_id": 1, "pos": [ 176, 221, 445, 221, 445, 243, 176, 243 ], "pos_list": [ [ 176, 221, 445, 221, 445, 243, 176, 243 ] ], "sub_type": "text_title", "children": [] }, { "paragraph_id": 4, "pos": [ 176, 522, 423, 522, 423, 543, 176, 543 ], "pos_list": [ [ 176, 522, 423, 522, 423, 543, 176, 543 ] ], "sub_type": "text_title", "title": "2.3. 其他的一些样式", "hierarchy": 3, "page_id": 4, "children": [] }, { "sub_type": "text_title", "title": "2.4.如何使用其他的高级功能?", "hierarchy": 3, "page_id": 4, "paragraph_id": 6, "pos": [ 176, 684, 531, 684, 531, 704, 176, 704 ], "pos_list": [ [ 176, 684, 531, 684, 531, 704, 176, 704 ] ], "children": [] } ] } ] }, { "title": "第二章 正文要求说明", "hierarchy": 1, "page_id": 5, "paragraph_id": 0, "pos": [ 422, 210, 766, 210, 766, 241, 422, 241 ], "pos_list": [ [ 422, 210, 766, 210, 766, 241, 422, 241 ] ], "sub_type": "text_title", "children": [ { "hierarchy": 2, "page_id": 5, "paragraph_id": 2, "pos": [ 384, 412, 642, 412, 642, 439, 384, 439 ], "pos_list": [ [ 384, 412, 642, 412, 642, 439, 384, 439 ] ], "sub_type": "text_title", "title": "第1节 字体和大小", "children": [ { "hierarchy": 3, "page_id": 5, "paragraph_id": 3, "pos": [ 176, 496, 349, 496, 349, 518, 176, 518 ], "pos_list": [ [ 176, 496, 349, 496, 349, 518, 176, 518 ] ], "sub_type": "text_title", "title": "1.1.文章标题", "children": [] }, { "pos": [ 176, 636, 324, 636, 324, 657, 176, 657 ], "pos_list": [ [ 176, 636, 324, 636, 324, 657, 176, 657 ] ], "sub_type": "text_title", "title": "1.2. 章标题", "hierarchy": 3, "page_id": 5, "paragraph_id": 5, "children": [] }, { "hierarchy": 3, "page_id": 5, "paragraph_id": 7, "pos": [ 176, 775, 324, 775, 324, 795, 176, 795 ], "pos_list": [ [ 176, 775, 324, 775, 324, 795, 176, 795 ] ], "sub_type": "text_title", "title": "1.3. 节标题", "children": [] }, { "title": "1.4.子节标题", "hierarchy": 3, "page_id": 5, "paragraph_id": 9, "pos": [ 176, 913, 349, 913, 349, 934, 176, 934 ], "pos_list": [ [ 176, 913, 349, 913, 349, 934, 176, 934 ] ], "sub_type": "text_title", "children": [] }, { "title": "1.5.正文", "hierarchy": 3, "page_id": 5, "paragraph_id": 11, "pos": [ 176, 1054, 300, 1054, 300, 1076, 176, 1076 ], "pos_list": [ [ 176, 1054, 300, 1054, 300, 1076, 176, 1076 ] ], "sub_type": "text_title", "children": [] } ] } ] }, { "title": "第三章 公式排版", "hierarchy": 1, "page_id": 6, "paragraph_id": 0, "pos": [ 457, 211, 733, 211, 733, 241, 457, 241 ], "pos_list": [ [ 457, 211, 733, 211, 733, 241, 457, 241 ] ], "sub_type": "text_title", "children": [ { "hierarchy": 2, "page_id": 6, "paragraph_id": 2, "pos": [ 297, 412, 731, 412, 731, 441, 297, 441 ], "pos_list": [ [ 297, 412, 731, 412, 731, 441, 297, 441 ] ], "sub_type": "text_title", "title": "第1节 Microsoft Equation Editor", "children": [] }, { "page_id": 6, "paragraph_id": 4, "pos": [ 366, 641, 637, 641, 637, 669, 366, 669 ], "pos_list": [ [ 366, 641, 637, 641, 637, 669, 366, 669 ] ], "sub_type": "text_title", "title": "第2节 MathType", "hierarchy": 2, "children": [] } ] }, { "pos_list": [ [ 359, 163, 644, 163, 644, 189, 359, 189 ] ], "sub_type": "text_title", "title": "第3节 TeX/LaTeX", "hierarchy": 1, "page_id": 7, "paragraph_id": 0, "pos": [ 359, 163, 644, 163, 644, 189, 359, 189 ], "children": [] }, { "pos": [ 442, 210, 750, 210, 750, 241, 442, 241 ], "pos_list": [ [ 442, 210, 750, 210, 750, 241, 442, 241 ] ], "sub_type": "text_title", "title": "第四章 图形和表格", "hierarchy": 1, "page_id": 8, "paragraph_id": 0, "children": [ { "pos": [ 428, 350, 602, 350, 602, 376, 428, 376 ], "pos_list": [ [ 428, 350, 602, 350, 602, 376, 428, 376 ] ], "sub_type": "text_title", "title": "第1节 图形", "hierarchy": 2, "page_id": 8, "paragraph_id": 1, "children": [ { "sub_type": "image_title", "title": "图表1.1这是一幅牛的图片", "hierarchy": 3, "page_id": 8, "paragraph_id": 4, "pos": [ 471, 847, 719, 847, 719, 865, 471, 865 ], "pos_list": [ [ 471, 847, 719, 847, 719, 865, 471, 865 ] ], "children": [] } ] }, { "pos": [ 401, 1087, 602, 1087, 602, 1114, 401, 1114 ], "pos_list": [ [ 401, 1087, 602, 1087, 602, 1114, 401, 1114 ] ], "sub_type": "text_title", "title": "第2节 表格", "hierarchy": 2, "page_id": 8, "paragraph_id": 6, "children": [ { "sub_type": "table_title", "title": "插入表格与图片类似。当然,可以使用Excel预先作一个表格,然后导入进来,但是word本身也可以胜任一部分简单表格的绘制,如:", "hierarchy": 3, "page_id": 8, "paragraph_id": 8, "pos": [ 179, 1167, 1011, 1167, 1011, 1231, 179, 1231 ], "pos_list": [ [ 179, 1167, 1011, 1167, 1011, 1231, 179, 1231 ] ], "children": [] }, { "hierarchy": 3, "page_id": 8, "paragraph_id": 10, "pos": [ 479, 1372, 713, 1372, 713, 1391, 479, 1391 ], "pos_list": [ [ 479, 1372, 713, 1372, 713, 1391, 479, 1391 ] ], "sub_type": "table_title", "title": "表格2.1一个简单的表格", "children": [] } ] } ] }, { "sub_type": "text_title", "title": "第五章 定理环境", "hierarchy": 1, "page_id": 9, "paragraph_id": 0, "pos": [ 456, 208, 734, 208, 734, 242, 456, 242 ], "pos_list": [ [ 456, 208, 734, 208, 734, 242, 456, 242 ] ], "children": [ { "pos_list": [ [ 357, 452, 673, 452, 673, 478, 357, 478 ] ], "sub_type": "text_title", "title": "第1节 自定义定理环境", "hierarchy": 2, "page_id": 9, "paragraph_id": 2, "pos": [ 357, 452, 673, 452, 673, 478, 357, 478 ], "children": [ { "page_id": 9, "paragraph_id": 4, "pos": [ 176, 581, 411, 581, 411, 603, 176, 603 ], "pos_list": [ [ 176, 581, 411, 581, 411, 603, 176, 603 ] ], "sub_type": "text_title", "title": "定理1.1.对顶角相等。", "hierarchy": 3, "children": [] }, { "hierarchy": 3, "page_id": 9, "paragraph_id": 6, "pos": [ 176, 683, 581, 683, 581, 706, 176, 706 ], "pos_list": [ [ 176, 683, 581, 683, 581, 706, 176, 706 ] ], "sub_type": "text_title", "title": "定理1.2.三边对应相等的三角形全等。", "children": [] } ] }, { "page_id": 9, "paragraph_id": 9, "pos": [ 371, 925, 631, 925, 631, 951, 371, 951 ], "pos_list": [ [ 371, 925, 631, 925, 631, 951, 371, 951 ] ], "sub_type": "text_title", "title": "第2节 已有环境", "hierarchy": 2, "children": [] }, { "pos_list": [ [ 357, 1255, 645, 1255, 645, 1282, 357, 1282 ] ], "sub_type": "text_title", "title": "第3节 自定义环境", "hierarchy": 2, "page_id": 9, "paragraph_id": 14, "pos": [ 357, 1255, 645, 1255, 645, 1282, 357, 1282 ], "children": [] } ] } ] ``` # 获取图片并持久化 Source: https://docs.textin.com/xparse/parse-getimage TextIn xParse为了保护您的数据隐私安全,从文档解析API返回的图片链接有效期为30天,30天后平台会自动删除图片资源。如果您想要获取图片保存到本地并使markdown中的图片链接持久化,以便您在下游诸如知识库问答等AI应用中长期稳定地为用户展示图片,有以下两种方法供您选择: 1. 设置URL参数[image-output-type](https://docs.textin.com/api-reference/endpoint/parse#parameter-image-output-type)为base64str,此时图片直接以base64格式在API结果中返回。(这种方式返回结果体积会很大,长文档不推荐) 2. 设置URL参数[image-output-type](https://docs.textin.com/api-reference/endpoint/parse#parameter-image-output-type)为default(不传时默认为该值),此时图片直接以TextIn平台的链接方式返回,您可以通过链接下载图片到本地,或上传到您的云存储。 ## 如何将markdown中的图片链接替换为本地图片链接 **您可以参考如下教程:使用上述方法2让API返回图片链接,并完成markdown中的图片链接替换。** 这里为您提供了一份Textin官方pdf示例文件,您可点击下载或使用该链接:[文档解析pdf示例.pdf](https://web-api.textin.com/open/image/download?filename=c9cf7431eb314c7ba3f43ee716c799a3) * 参考[快速启动](/xparse/parse-quickstart),在 options 中设置参数 get\_image 为 objects 或 both,让API返回页面内的图片对象;设置参数 image\_output\_type 为 default,API会返回图片URL。如下图: Parse Image Ori Pn * 参考如下示例代码:提取返回结果markdown中的图片URL将图片下载保存至本地,并将markdown中的图片链接替换为本地图片链接。 ```python theme={null} import os import re import requests import hashlib from urllib.parse import urlparse from pathlib import Path import time from typing import List, Tuple, Optional class ImageDownloader: def __init__(self, md_file: str, images_dir: str = "images"): """ 初始化图片下载器 Args: md_file: markdown文件路径 images_dir: 图片存储目录 """ self.md_file = md_file self.images_dir = images_dir self.session = requests.Session() self.session.headers.update({ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' }) # 创建图片目录 Path(self.images_dir).mkdir(exist_ok=True) def extract_image_urls(self, content: str) -> List[Tuple[str, str]]: """ 提取markdown内容中的图片链接 Args: content: markdown文件内容 Returns: (完整的markdown语法, 图片URL) 的元组列表 """ # 匹配 ![...](https://...) 格式的markdown图片语法 pattern = r'!\[([^\]]*)\]\((https://[^\s\)]+\.(?:jpg|jpeg|png|gif|bmp|webp|svg))\)' matches = re.findall(pattern, content, re.IGNORECASE) # 返回完整的markdown语法和URL result = [] for alt_text, url in matches: full_markdown = f"![{alt_text}]({url})" result.append((full_markdown, url)) return result def generate_filename(self, url: str) -> str: """ 根据URL生成本地文件名 Args: url: 图片URL Returns: 本地文件名 """ # 解析URL获取文件名 parsed_url = urlparse(url) original_filename = os.path.basename(parsed_url.path) # 如果没有扩展名,从URL中提取 if not original_filename or '.' not in original_filename: # 使用URL的MD5哈希作为文件名 url_hash = hashlib.md5(url.encode()).hexdigest()[:12] original_filename = f"{url_hash}.jpg" # 默认为jpg return original_filename def download_image(self, url: str, max_retries: int = 3) -> Optional[str]: """ 下载单个图片 Args: url: 图片URL max_retries: 最大重试次数 Returns: 成功时返回本地文件路径,失败时返回None """ filename = self.generate_filename(url) local_path = os.path.join(self.images_dir, filename) # 如果文件已存在,跳过下载 if os.path.exists(local_path): print(f"📁 文件已存在: {local_path}") return local_path for attempt in range(max_retries): try: print(f"⬇️ 正在下载 ({attempt + 1}/{max_retries}): {url}") response = self.session.get(url, timeout=30) response.raise_for_status() # 检查是否是图片文件 content_type = response.headers.get('content-type', '') if not content_type.startswith('image/'): print(f"⚠️ 警告: {url} 不是图片文件 (Content-Type: {content_type})") # 保存文件 with open(local_path, 'wb') as f: f.write(response.content) file_size = len(response.content) print(f"✅ 下载成功: {filename} ({file_size} bytes)") return local_path except requests.exceptions.RequestException as e: print(f"❌ 下载失败 (尝试 {attempt + 1}/{max_retries}): {e}") if attempt < max_retries - 1: time.sleep(2) # 重试前等待2秒 else: print(f"💀 下载彻底失败: {url}") return None return None def process_markdown(self) -> bool: """ 处理markdown文件,下载图片并替换链接 Returns: 处理是否成功 """ try: # 读取markdown文件 with open(self.md_file, 'r', encoding='utf-8') as f: content = f.read() # 备份原文件 backup_file = f"{self.md_file}.backup" with open(backup_file, 'w', encoding='utf-8') as f: f.write(content) print(f"🗂️ 已创建备份文件: {backup_file}") # 提取图片链接 image_data = self.extract_image_urls(content) if not image_data: print("🔍 未找到图片链接") return True print(f"🔍 找到 {len(image_data)} 个图片链接") # 下载图片并替换链接 replacements = [] for i, (markdown_syntax, url) in enumerate(image_data, 1): print(f"\n📋 处理第 {i}/{len(image_data)} 个链接:") print(f"🔍 原始语法: {markdown_syntax}") local_path = self.download_image(url) if local_path: # 使用相对路径 relative_path = os.path.relpath(local_path, os.path.dirname(self.md_file)) # 保留原始的alt text,只替换URL alt_text = re.search(r'!\[([^\]]*)\]', markdown_syntax).group(1) new_markdown = f"![{alt_text}]({relative_path})" replacements.append((markdown_syntax, new_markdown)) print(f"🔗 将替换为: {new_markdown}") else: print(f"⚠️ 保留原始链接: {markdown_syntax}") # 应用替换 modified_content = content for old_link, new_link in replacements: modified_content = modified_content.replace(old_link, new_link) # 保存修改后的文件 with open(self.md_file, 'w', encoding='utf-8') as f: f.write(modified_content) print(f"\n✅ 处理完成!") print(f"📊 成功替换 {len(replacements)} 个链接") print(f"📁 图片保存在: {self.images_dir}/") print(f"📄 原文件备份: {backup_file}") return True except Exception as e: print(f"❌ 处理失败: {e}") return False def cleanup(self): """清理资源""" self.session.close() def main(): """主函数""" print("🚀 图片下载器启动") print("=" * 50) # 配置 md_file = "test.md" # 这里替换为你的markdown文件路径 images_dir = "images" # 这里替换为你的图片存储目录 # 检查文件是否存在 if not os.path.exists(md_file): print(f"❌ 文件不存在: {md_file}") return # 创建下载器并处理 downloader = ImageDownloader(md_file, images_dir) try: success = downloader.process_markdown() if success: print("\n🎉 所有操作完成!") else: print("\n💥 操作失败!") finally: downloader.cleanup() if __name__ == "__main__": main() ``` * 如下图:可以看到图片已经保存到本地指定目录下,打开markdown文件可以看到图片链接已经替换为本地图片链接。 Parse Image Re Pn # 返回JSON结构说明 Source: https://docs.textin.com/xparse/parse-getjson 当您使用文档解析API解析文档时,解析后的数据将按照以下结构的JSON格式返回。 **重要说明:根据 `parse_mode` 参数的不同,返回结构会有所不同**: * 当 `parse_mode` 为 `auto`、`scan`、`parse` 时,返回 `markdown`、`detail`、`pages` 等字段 * 当 `parse_mode` 为 `lite` 时,返回新的 `elements` 结构(包含 `success_count`、`elements` 数组等字段) 如需将 `elements` 格式转换为统一的`detail`/`pages`格式,请参考[转换脚本](/xparse/parse-quickstart#elements格式转换脚本)。 ```json expandable theme={null} { "code": 200, "message": "success", "result": { "markdown": "# hello markdown", "detail": [ { "page_id": 1, "paragraph_id": 123, "outline_level": -1, "text": "hello markdown", "position": [217,390,1336,390,1336,460,217,460], "origin_position": [217,390,1336,390,1336,460,217,460], "content": 0, "type": "paragraph", "sub_type": "catalog", "image_url": "", "tags": [ "formula", "handwritten" ], "caption_id": { "page_id": 123, "paragraph_id": 123 }, "cells": [ { "row": 123, "col": 123, "row_span": 123, "col_span": 123, "position": [10,10,100,10,100,50,10,50], "origin_position": [ 123 ], "text": "", "type": "" } ], "split_section_page_ids": [1,2,3], "split_section_positions": [ [0,0,100,100,100,200,0,200], [0,0,100,100,100,200,0,200], [0,0,100,100,100,200,0,200] ], "stamp": { "value": "", "stamp_shape": "", "type": "", "color": "" } } ], "pages": [ { "status": "success", "page_id": 0, "durations": 612.5, "image_id": "90u12adcad08r2", "origin_image_id": "90u12adcad08r2", "base64": "", "origin_base64": "", "width": 123, "height": 123, "angle": 123, "content": [ { "id": 123, "type": "line", "text": "", "angle": 0, "pos": [ 123 ], "origin_position": [ 123 ], "sub_type": "handwriting", "direction": 123, "score": 0.5, "char_pos": [ [ 123 ] ] } ], "raw_ocr": [ { "text": "这是一个例子。", "score": 0.99, "type": "text", "position": [10,10,100,10,100,50,10,50], "angle": 123, "direction": 1, "handwritten": 1, "char_scores": [0.99,0.98,0.95,0.95,0.99,0.93,0.87], "char_centers": [ [20,10], [30,10], [40,10], [50,10], [60,10], [70,10], [80,10] ], "char_positions": [ [ [18,8,22,8,22,12,18,12] ], [ [28,88,32,8,32,12,28,12] ], [ [38,88,42,8,42,12,38,12] ], [ [48,88,52,8,52,12,48,12] ], [ [58,88,62,8,62,12,58,12] ], [ [68,88,72,8,72,12,68,12] ], [ [78,88,82,8,82,12,78,12] ] ], "char_candidates": [ ["这"], ["是"], ["一","-"], ["个"], ["例"], ["子"], ["。","O"] ], "char_candidates_score": [ [0.99], [0.99], [0.95,0.05], [0.99], [0.99], [0.99], [0.89,0.11] ] } ], "structured": [ { "type": "textblock", "pos": [ 123 ], "origin_position": [ 123 ], "content": [0,1,2], "sub_type": "text", "continue": true, "next_page_id": 2, "next_para_id": 1, "text": "", "outline_level": 123 } ] } ], "catalog": { "toc": [ [ { "hierarchy": 2, "title": "1.公司简介和主要财务指标", "page_id": 3, "pos": [10,10,100,10,100,50,10,50] }, { "hierarchy": 3, "title": "1.1 公司简介", "page_id": 4, "pos": [10,10,100,10,100,50,10,50] } ] ] }, "total_page_number": 10, "valid_page_number": 3, "excel_base64": "", "success_count": 1, "elements": [ { "element_id": "", "type": "NarrativeText", "text": "xParse 是一个端到端文档处理 AI 基础设施", "metadata": { "page_image_url": "https://web-api.textin.com/ocr_image/external/01a91572ca81092c.jpg", "original_image_url": "", "angle": 0, "page_number": 1, "page_width": 600, "page_height": 800, "coordinates": [0.182212, 0.231622, 0.671733, 0.231634, 0.671754, 0.273244, 0.182266, 0.273255], "is_continue": false, "category_depth": -1, "parent_id": "", "sub_type": "stamp", "image_url": "https://web-api.textin.com/ocr_image/external/e47f8aed69ccabce.jpg", "image_base64": "" } } ] }, "version": "2.1.0", "duration": 999, "metrics": [ { "page_image_width": 1024, "page_image_height": 768, "dpi": 72, "durations": 123, "status": "", "page_id": 123, "angle": 90, "image_id": "" } ] } ``` ## 常规字段说明 * x\_request\_id:该请求的唯一标识。 * code:错误码,200表示成功。详情见[快速启动-错误码说明](/xparse/parse-quickstart)。 * message:错误信息,成功时为"success"。 * version:引擎版本号,例如"3.18.9"。 * duration:引擎耗时(毫秒),例如"999"。 ## 主要结果说明:result对象 文档解析API会在返回结果的result对象中包含以下关键信息。 ### markdown:正文字符串 * **markdown**:解析结果 markdown 的正文字符串。 ### detail:markdown 各类型元素详细信息 detail包含markdown中不同类型元素的详细信息。受URL参数**markdown\_details**影响,默认返回detail字段,详情见[快速启动-URL参数说明](/xparse/parse-quickstart)。 * **detail**:markdown各类型元素详细信息 * **page\_id**:当前元素所在页码,例如"1"。 * **paragraph\_id**:当前元素id。 * **outline\_level**:标题级别(最多支持5级标题) -1表示正文,0表示一级标题,1表示二级标题 ... * **text**:文本,例如"hello markdown"。 * **position**:以长度为8的整型数组表示四边形,8个数两两一组为一个点的横纵坐标,分别是左上,右上,右下,左下。 当输入是PDF时, 此坐标是基于72dpi的;当输入是图片时,此坐标是原图里的坐标。 单位:像素。例如\[217, 390, 1336, 390, 1336, 460, 217, 460] * **origin\_position**:受URL参数**切边矫正**和**去水印**影响,详情见[快速启动-URL参数说明](/xparse/parse-quickstart)。仅当打开切边或去水印时返回,表示该段落在原图中的坐标。格式同**position**。 * **content**:表示元素是否为正文。0 正文(段落、图片、表格);1 非正文(页眉、页脚、侧边栏) * **type**:元素的类型。 * paragraph(段落类型,包括正文、标题、公式等文字信息) * image(图片类型) * table(表格类型) * **sub\_type**:元素子类型,受**type**影响。 * 当**type**为**paragraph**时,取值范围为catalog(目录),header(页眉),footer(页脚),sidebar(侧边栏),text(正文普通文本),text\_title(文本标题),image\_title(图片标题),table\_title(表格标题); * 当**type**是**image**时,取值范围为stamp(印章),chart(图表),qrcode(二维码),barcode(条形码); * 当**type**为**table**时,取值范围为bordered(有线表), borderless(无线表) * **image\_url**:图片链接,仅在**type**为**image**时返回。受URL参数**get\_image**和**image\_output\_type**影响,详情见[快速启动-URL参数说明](/xparse/parse-quickstart)。 * 当get\_image = objects, image\_output\_type = default时,返回图片的url,图片默认保存30天;如需长久保存,请在有效期内下载图片并自行保存,可参考[获取图片并持久化](/xparse/parse-getimage); * 或者使用image\_output\_type = base64str,图片以base64的方式返回。 * **tags**:表示段落内是否存在特殊文本,类型包括公式formula和手写体handwritten,仅在**type**为**paragraph**时返回。 * **caption\_id**:表格或图片的标题id,仅在**type**为**image**或**table**时返回。 * **page\_id**:标题所在页码。 * **paragraph\_id**:标题所在段落id。 * **cells**:单元格数组,仅在**type**为**table**时返回。 * **row**:单元格行号。 * **col**:单元格列号。 * **row\_span**:单元格行跨度,默认为1。 * **col\_span**:单元格列跨度,默认为1。 * **position**:单元格的四个角点坐标,依次为左上,右上,右下,左下。例如\[10, 10, 100, 10, 100, 50, 10, 50] * **origin\_position**:受URL参数**切边矫正**或**去水印**影响,详情见[快速启动-URL参数说明](/xparse/parse-quickstart)。仅当打开切边或去水印时返回,表示该单元格在原图中的坐标。格式同position。 * **text**:单元格文本内容。 * **type**:类型,固定为cell,表示单元格。 * **split\_section\_page\_ids**:当表格/段落有合并时,记录合并前各个子表格/段落所在的页的id * **split\_section\_positions**:当表格/段落有合并时,记录合并前各个子表格/段落所在页的位置,位置所属的页码与split\_section\_page\_ids按索引一一对应,如split\_section\_positions\[2]所属的页码为split\_section\_page\_ids\[2] * **stamp**:当sub\_type为stamp时,返回印章识别结果 * **value**:印章文本内容 * **stamp\_shape**:印章形状 * **type**:印章类型 * **color**:印章颜色 ### pages:每一页的详细信息 文档按页为单位展开时, 存储每一页的详情和状态(适用于PDF),部分信息与**metrics**字段重复。受URL参数**page\_details**影响,默认返回pages,详情见[快速启动-URL参数说明](/xparse/parse-quickstart)。 * **pages**:每一页的详细信息 * **page\_id**:当前页码 (若为流式文件, 页码置为0),例如"0"。 * **status**:表示当前页的引擎输出状态,或者error\_message,例如"success"。 * **durations**:当前页总耗时(毫秒),例如"612.5"。 * **width**:文档页宽度 * **height**:文档页高度 * **angle**:图像的角度(可选值0, 90, 180, 270) * **image\_id**:当前页图片id 。受URL参数**get\_image**和**image\_output\_type**影响,当URL参数image\_output\_type=default且get\_image=page/both时返回,详情见[快速启动-URL参数说明](/xparse/parse-quickstart)。 * 下载方式:[https://api.textin.com/ocr\_image/download?image\_id=xxx](https://api.textin.com/ocr_image/download?image_id=xxx) ,需要在headers里添加appid和key * **origin\_image\_id**:切边或去水印前的原始页图片。受URL参数**切边矫正**或**去水印**影响,详情见[快速启动-URL参数说明](/xparse/parse-quickstart)。仅当开启切边或去水印,image\_output\_type=default且get\_image=page/both时返回。 * 下载方式同image\_id * **base64**:当前页图片的base64字符串,受URL参数**image\_output\_type**影响,详情见[快速启动-URL参数说明](/xparse/parse-quickstart)。当输入参数image\_output\_type=base64str且get\_image=page/both时返回。 * **origin\_base64**:切边或去水印前的原始页图片base64字符串。受URL参数**切边矫正**或**去水印**影响,详情见[快速启动-URL参数说明](/xparse/parse-quickstart)。仅当开启切边或去水印,image\_output\_type=base64str且get\_image=page/both时返回。 * **raw\_ocr**:全部文字识别结果,只包含文字结果。受URL参数**raw\_ocr**影响,默认不返回,详情见[快速启动-URL参数说明](/xparse/parse-quickstart)。 * **text**:识别内容字符串,例如"这是一个例子。" * **score**:识别置信度(0 \<= x \<= 1),例如"0.99"。 * **type**:文本类型,用于表示文字的形态。 当前版本下,文本类型包括: * text(文本) * formula(公式) * **position**:文本行的四个角点坐标,依次为左上,右上,右下,左下。例如\[10, 10, 100, 10, 100, 50, 10, 50] * **angle**:文本行的角度(可选值0, 90, 180, 270) * **direction**:文字阅读方向。 * -1: 其他 * 0: 单字 * 1: 横向阅读 * 2: 纵向阅读 * **handwritten**:文字是否手写所得。 * -1: 未知 * 0: 非手写文字, 一般为印刷文字 * 1: 文字手写, 一般具备明显的书写特征 * **char\_scores**:字符置信度,值域范围0-1。 受URL参数**char\_details**影响,详情见[快速启动-URL参数说明](/xparse/parse-quickstart)。设置char\_details=1时输出。 * **char\_centers**:字符中心点坐标。受URL参数**char\_details**影响,详情见[快速启动-URL参数说明](/xparse/parse-quickstart)。设置char\_details=1时输出。 * **char\_positions**:字符四边形点坐标,以顺时针构成闭合区域。 受URL参数**char\_details**影响,详情见[快速启动-URL参数说明](/xparse/parse-quickstart)。设置char\_details=1时输出。 * **char\_candidates**:候选字数组,表示每一个字符的候选,与候选置信度配套使用。受URL参数**char\_details**影响,详情见[快速启动-URL参数说明](/xparse/parse-quickstart)。 设置char\_details=1时输出。 * **char\_candidates\_score**:候选字置信度数组,表示每一个候选字符的置信度,与候选字符配套使用。 受URL参数**char\_details**影响,详情见[快速启动-URL参数说明](/xparse/parse-quickstart)。 设置char\_details=1时输出。 * **content**:基础数据,为文字行、图像中的其中一种。 * **textline:文字行** * **id**:数据id(页内唯一) * **type**:数据类型,line * **text**:文本行文字内容 * **angle**:文本行文字方向, 默认为0(angle为0时, json中可能不包含angle属性)。 * **pos**:文本行四个角点坐标。 * **origin\_position**:表示文本行在原图中的坐标。受URL参数**切边矫正**或**去水印**影响,详情见[**快速启动-URL参数说明**](https://docs.textin.com/xparse/parse-quickstart)。仅当打开切边或去水印时返回,格式同pos。 * **sub\_type**:子类型。有handwriting, formula。 * **direction**:文字方向, 默认为0。 * 0:横向文本; * 1:竖向文本; * 2:横向右往左文本(如阿拉伯语) * **score**:文本行内每个字符的置信度(仅当输入图像做ocr时) * **char\_pos**:文本行内每个字符的坐标,每个item是一个由八个整数组成的数组,分别表示,左上,右上,右下,左下四个点的(x,y)坐标。受URL参数**char\_details**影响,详情见[**快速启动-URL参数说明**](https://docs.textin.com/xparse/parse-quickstart)。设置char\_details=1时输出。 * **image:图像** * **id**:数据id * **type**:数据类型, image * **pos**:图像四个角点坐标 * **sub\_type**:子类型, 包括stamp, chart, qrcode, barcode * **size**:图像大小\[width, height] * **data**:图像内容 * **base64**:图像文件(jpg, png)的base64字符串 * **region**:图像在页图像中的区域(四边形4个点坐标) * **path**:图像文件路径(如在zip包中的路径) * **stamp**:当sub\_type为stamp时,返回印章识别结果 * **value**:印章文本内容 * **stamp\_shape**:印章形状 * **type**:印章类型 * **color**:印章颜色 * **structured**:结构化数据,为段落块、图像块、表格块、页脚块、页眉块中的一种。 * **textblock:段落块** * **type**:段落块类型, 固定为 textblock * **pos**:文本行四个角点坐标 * **origin\_position**:表示该段落在原图中的坐标。受URL参数**切边矫正**或**去水印**影响,详情见[**快速启动-URL参数说明**](https://docs.textin.com/xparse/parse-quickstart)。仅当打开切边或去水印时返回,格式同pos。 * **content**:段落块内文本行id数据组 * **sub\_type**:段落块子类型,包括catalog(目录),text(正文普通文本),text\_title(文本标题),image\_title(图片标题),table\_title(表格标题) * **continue**:段落块连续属性,用于判断完整的段落块是否被页面或栏分割,为true表示该段落块和下一个段落块连续(即两个段落块可合成一个逻辑段落块)。 * **next\_page\_id**:当且仅当continue为true时有值。表示下一个段落块的page\_id。 * **next\_para\_id**:当且仅当continue为true时有值。表示下一个段落块的paragraph\_id。 * **text**:段落块文本内容 * **outline\_level**:标题级别: (最多支持5级标题) * -1:正文 * 0:一级标题 * 1:二级标题 * … * **imageblock:图像块** * **type**:图像块类型, 值为 image * **pos**:文本行四个角点坐标 * **origin\_position**:表示该子图在原图中的坐标。受URL参数**切边矫正**或**去水印**影响,详情见[**快速启动-URL参数说明**](https://docs.textin.com/xparse/parse-quickstart)。仅当打开切边或去水印时返回,格式同pos。 * **lines**:图像包含的文本行id * **content**:图像资源数据id数组 * **caption\_id**:图片的标题id * **page\_id**:标题所在页码 * **paragraph\_id**:标题所在段落id * **text**:子图片识别得到的文本内容。受URL参数**apply\_image\_analysis**影响,详情见[**快速启动-URL参数说明**](https://docs.textin.com/xparse/parse-quickstart)。开启图像分析后,该字段内容会替换为大模型对子图片的分析结果。 * **table:表格块** * **type**:表格块类型, 固定为table * **sub\_type**:表格子属性,取值为bordered(有线表)或borderless(无线表),默认为bordered(即json中无该字段时,默认值为bordered) * **pos**:文本行四个角点坐标 * **origin\_position**:表示该表格在原图中的坐标。受URL参数**切边矫正**或**去水印**影响,详情见[**快速启动-URL参数说明**](https://docs.textin.com/xparse/parse-quickstart)。仅当打开切边或去水印时返回,格式同pos。 * **rows**:表格行数 * **cols**:表格列数 * **columns\_width**:表格列宽度列表 * **rows\_height**:表格行高度列表 * **text**:表格文本内容,以html或md格式展示 * **continue**:当前表格与后一表格连续,用来判断一个表格是否被页面分割(如果 continue为true 且该表格位于本页结尾,该表格可与下一页开头表格组合为一个表格) * **caption\_id**:表格的标题id * **page\_id**:标题所在页码 * **paragraph\_id**:标题所在段落id * **cells**:单元格数组 * **row**:单元格行号 * **col**:单元格列号 * **row\_span**:单元格行跨度,默认为1 * **col\_span**:单元格列跨度,默认为1 * **pos**:单元格的四个角点坐标,依次为左上,右上,右下,左下。 * **content**:单元格内容 * **footer:页脚块** * **type**:页脚块类型,固定为 footer * **pos**:文本行四个角点坐标 * **blocks**:footer段落内容,为textblock, imageblock, table中其中的一种 * **header:页眉块** * **type**:页眉块类型,固定为 header * **pos**:文本行四个角点坐标 * **blocks**:header段落内容,为textblock, imageblock, table中的其中一种 ### catalog:描述目录树的结构 * **catalog**:目录树结构。受URL参数**catalog\_details**和**apply\_document\_tree**影响,详情见[快速启动-URL参数说明](/xparse/parse-quickstart)。 * **toc**:返回的table of contents * **sub\_type**:标题类型 text\_title、 image\_title、 table\_title * **hierarchy**:标题层级, 1 是 一级标题, 2 是 二级标题,依次类推 * **title**:标题内容 * **page\_id**:标题所在页码(最小页码为 1) * **paragraph\_id**:标题所在段落id * **pos**:该目录区域的四个角点坐标,依次为左上,右上,右下,左下。 * **pos\_list**:发生标题合并时,为合并前多个标题的坐标;未发生标题合并时,即为该标题的坐标。 ### elements:元素数组(parse\_mode 为 lite 时返回) 当 `parse_mode` 为 `lite` 时,返回 `elements` 数组结构,替代原有的 `detail` 和 `pages` 结构。如需将 `elements` 格式转换为原有格式,请参考[转换脚本](/xparse/parse-quickstart#elements格式转换脚本)。 * **success\_count**:解析成功页数 * **elements**:element 数组,包含文档中的所有元素 * **element\_id**:唯一标识 * **type**:类型,具体见下文 Element type 类型说明 * **text**:文本内容 * **metadata**:元数据对象 * **page\_image\_url**:页图url * **original\_image\_url**:原始页图url,仅当开启去水印或切边时返回 * **angle**:页面角度 * **page\_number**:页码 * **page\_width**:页宽 * **page\_height**:页高 * **coordinates**:element的归一化坐标(float数组,8个值,六位小数) * **is\_continue**:是否和下一个element合并 * **category\_depth**:目录层级,0表示一级标题,1表示2级标题,依次增加。-1表示正文段落 * **parent\_id**:父节点的element\_id。表格和图片等父节点为对应的表格标题和图片标题。文本段落的父节点为对应的文本标题 * **sub\_type**:仅当type为Image时返回,包括stamp, card, qrcode\_barcode, chart * **image\_url**:仅当type为Image 且请求参数 image\_output\_type=default 时返回,值为子图的url * **image\_base64**:仅当type为Image 且请求参数 image\_output\_type=base64str时返回,值为子图的base64字符串 #### Element type 类型说明 当 `parse_mode` 为 `lite` 时,返回的 `elements` 数组中每个 element 的 `type` 字段可能的值如下: | Element type | 说明 | | ----------------- | -------------------------- | | NarrativeText | 除了标题、页眉页脚、图片说明文字列表外的普通段落文字 | | Title | 章节标题 | | Table | 表格 | | TableCaption | 表格标题 | | Image | 图片 | | FigureCaption | 图片标题 | | Formula | 公式 | | Header | 页眉 | | Footer | 页脚 | | CodeSnippet | 代码片段 | | PageNumber | 页码 | | UncategorizedText | 其他文本 | ### 其他result字段 * **total\_count**:解析总页数 * **success\_count**:解析成功的页数(parse\_mode 为 lite 时返回) * **total\_page\_number**:输入PDF时, 返回文档的总页数。 * **valid\_page\_number**:记录本次解析成功的总页数。 * **excel\_base64**:excel的base64结果,受URL参数**get\_excel**影响,仅当get\_excel=1时返回。详情见[快速启动-URL参数说明](/xparse/parse-quickstart)。 ## metrics:每一页的信息 部分信息跟**pages**字段重复,当URL参数**page\_details**设置为不返回pages字段时,可以在**metrics**字段获取每一页的信息。 * **metrics**:每一页信息 * **page\_image\_width**:当前段落所在页的图片宽或者pdf转成的图片宽,例如"1024"。 * **page\_image\_height**:当前段落所在页的图片高或者pdf转成的图片高,例如"768"。 * **dpi**:当前pdf页转成图片所用的dpi,例如"72"。 * **durations**:当前页总耗时(毫秒) * **status**:当前页状态 * **page\_id**:当前页码 * **angle**:图像角度, 定义0度为人类阅读文字的图像方向,称为正置图像, 本字段表示输入图像是正置图像进行顺时针若干角度的旋转所得。 * 0: ▲ * 90: ▶ * 180: ▼ * 270: ◀ * **image\_id**:当前页图片id。 * 下载方式:[https://api.textin.com/ocr\_image/download?image\_id=xxx](https://api.textin.com/ocr_image/download?image_id=xxx), 需要在headers里添加appid和key, 有效期30天 **另外您也可以在**[**API**](/api-reference/endpoint/parse)**中查看Response说明以及调试查看结果。** ## 将结果保存为JSON或markdown文件 参考[快速启动](/xparse/parse-quickstart)中的使用示例,您可以将API返回的结果保存为JSON文件,也可以解析JSON响应以提取并保存markdown文件。以下示例代码在快速启动中已提供,您可以直接使用。 ```python theme={null} # 保存完整的JSON响应到result.json文件 with open("result.json", "w", encoding="utf-8") as f: f.write(response) # 解析JSON响应以提取markdown内容 json_response = json.loads(response) if "result" in json_response and "markdown" in json_response["result"]: markdown_content = json_response["result"]["markdown"] with open("result.md", "w", encoding="utf-8") as f: f.write(markdown_content) ``` # 前端可视化:获取精确坐标 Source: https://docs.textin.com/xparse/parse-getpos 一个功能丰富的RAG应用,通常会支持用户查看大模型找到的片段在原文档中的具体位置,从而让用户检查大模型是否在胡编乱造。而这就需要能把文本段落等各元素在原文档中高亮标记出来的能力。 TextIn xParse文档解析API支持返回块级坐标`position`以及字符级坐标`char_pos`(请求时设置URL参数`char_details=true`),代表解析结果片段在原文档中的精确位置。 将解析结果和坐标可视化,有助于: * 与原文档对照,细粒度验证解析的效果 * 审核校正解析结果 例如,下面是一个原文档(带坐标回显,左)和解析结果(Markdown,右)的对比图: 接下来详细介绍如何利用python实现坐标可视化。 本教程基于Textin官方pdf示例文件,您可点击下载或使用该链接:[文档解析pdf示例.pdf](https://web-api.textin.com/open/image/download?filename=a2bd40607faa4be7ba975d41c96b9a47) ## 上传pdf文件,获取解析结果 参考[快速启动](/xparse/parse-quickstart),上传pdf文件,获取解析结果。为获得详细的页面信息和坐标数据,解析时需要设置URL参数page\_details=1和markdown\_details=1。 本次示例文件解析结果如下(为方便展示,此处只解析一页,仅列出坐标相关数据): ```python theme={null} { "code": 200, "message": "success", "duration": 1751, "result": { "pages": [ { "status": "Success", "angle": 0, "page_id": 1, "width": 1191, "height": 1684, "structured": [ { "blocks": [ { "id": 0, "pos": [71,146,549,144,548,185,70,187], "text": "某服装企业(600398.SH)", "type": "textblock" # ... } ], "type": "header" }, { "type": "header", "blocks": [ { "id": 2, "pos": [69,203,781,203,781,238,69,238], "text": "第三季度收入下滑11%,费用率提升盈利承压", "type": "textblock", } ], } ] # ... } ], "detail": [ { "page_id": 1, "text": "**某服装企业(600398.SH)**" "position": [71,146,549,144,548,185,70,187] # ... }, { "page_id": 1, "text": "**第三季度收入下滑11%,费用率提升盈利承压**" "position": [69,203,781,203,781,238,69,238] # ... } # ... ] } } ``` `pages`字段包含每一页的信息,其中`page_id`表示页码(从1开始),`width, height`表示识别时文档转成图像的宽高,`angle`表示将图像转正的角度(如需要),`structured`表示解析后对应页的结构化数据,包含元素块内容以及对应的坐标`pos`。 `detail`中包含所有markdown块级元素(文字、段落、表格等)的详细信息,每一块通过`page_id`与页码关联,`position`字段表示该块的坐标信息。与`pages`不同的是,detail中是将markdown内容规整后元素块,比如跨页段落、跨页表格在detail中已经合并,采用了更好的语义上的分割,可以直接用于下游需要分块的应用,而`pages`中最大限度地保留了每一页的原始信息。 **坐标系统说明** 接口返回的坐标格式为:`[x1, y1, x2, y2, x3, y3, x4, y4]` 这表示一个四边形的四个顶点坐标,按顺时针排列: ``` 坐标数组: [x1, y1, x2, y2, x3, y3, x4, y4] ↑左上 ↑右上 ↑右下 ↑左下 ``` 该坐标表示在识别时以页面左上角为原点,宽高为`page.width`、`page.height`画布下的绝对坐标,单位为像素(px)。 比如上述接口返回: ```json theme={null} "pages": [{ "width": 1191, "height": 1684}] "position": [69,203,781,203,781,238,69,238] ``` 在图像上示意如下: ``` 图像坐标系 (原点在左上角) ┌───────────────1191────────────────── x │(0,0) │ │ │ (69,203) ───────────── (781,203) │ │ │ 1684 文本区域 │ │ │ │ (69,238) ───────────── (781,238) │ │ │ │ y ``` 下面演示如何从pages中和detail中获取页面和元素块坐标信息,并在原文档上绘制标注。 原文档页面图片可以通过设置参数`get_image="page"或"both"`返回, 您将获得每一页的image\_id或者base64(详见[JSON结构说明](/xparse/parse-getjson))用于预览,也可以手动将您的原文档转成图片, 只要保证每一页的图片跟上述`page.width`、`page.height`同比例渲染,`position`中的坐标值也需要跟随页面同比例缩放,,即可准确绘制。 ## 从API返回结果中获取坐标数据 从json结果提取出每一页的元素坐标信息,输出到二维数组: ```python theme={null} def extract_coordinates_from_parse_result(parse_result): """ 从API返回的解析结果中提取每页的宽高、角度和所有detail块的坐标信息 返回: [{width, height, angle, details: [detail, ...]}, ...] """ result = parse_result.get("result", {}) pages = result.get("pages", []) details = result.get("detail", []) # 按页组织details page_map = {} for page in pages: page_id = page.get("page_id", 1) page_map[page_id] = { "width": page.get("width", 0), "height": page.get("height", 0), "angle": page.get("angle", 0), "details": [] } for d in details: page_id = d.get("page_id", 1) if page_id in page_map: page_map[page_id]["details"].append(d) # 保证顺序 return [page_map[pid] for pid in sorted(page_map.keys())] ``` ## 绘制坐标框到原图 ```python theme={null} import fitz # PyMuPDF from PIL import Image, ImageDraw import os # pdf转图片,获取页面图片 def pdf_to_images(pdf_path, output_dir="./temp_images"): os.makedirs(output_dir, exist_ok=True) doc = fitz.open(pdf_path) zoom = 144 / 72 # dpi=144,图片更清晰 mat = fitz.Matrix(zoom, zoom) image_paths = [] for i, page in enumerate(doc): pix = page.get_pixmap(matrix=mat) img_path = os.path.join(output_dir, f"page_{i+1}.png") pix.save(img_path) image_paths.append(img_path) doc.close() return image_paths # 绘制一页坐标 def draw_boxes_on_image(image_path, details, page_width, page_height, color=(26,102,255), line_width=2): image = Image.open(image_path).convert("RGB") draw = ImageDraw.Draw(image) img_w, img_h = image.size # 根据解析时的页面宽高缩放适配,确保绘制坐标准确 scale_x = img_w / page_width if page_width else 1 scale_y = img_h / page_height if page_height else 1 for d in details: pos = d.get("position") if pos and len(pos) == 8: points = [ (pos[0]*scale_x, pos[1]*scale_y), (pos[2]*scale_x, pos[3]*scale_y), (pos[4]*scale_x, pos[5]*scale_y), (pos[6]*scale_x, pos[7]*scale_y), (pos[0]*scale_x, pos[1]*scale_y) ] draw.line(points, fill=color, width=line_width) out_path = image_path.replace('.png', '_boxed.png') image.save(out_path) return out_path # 绘制所有页面全部坐标 def annotate_pdf_with_boxes(pdf_path, page_details, output_dir="./annotated_images"): os.makedirs(output_dir, exist_ok=True) image_paths = pdf_to_images(pdf_path, output_dir=output_dir) result_paths = [] for i, page in enumerate(page_details): img_path = image_paths[i] out_path = draw_boxes_on_image( img_path, page["details"], page["width"], page["height"] ) result_paths.append(out_path) return result_paths # 使用示例 if __name__ == "__main__": import json PDF_PATH = "your_document.pdf" JSON_PATH = "parse_result.json" with open(JSON_PATH, "r", encoding="utf-8") as f: parse_result = json.load(f) page_details = extract_coordinates_from_parse_result(parse_result) result_imgs = annotate_pdf_with_boxes(PDF_PATH, page_details) print("标注图片:", result_imgs) ``` ### 代码使用说明 **1. 准备环境** ```bash theme={null} pip install PyMuPDF pillow ``` **2. 绘制图片和坐标** 将上述代码保存为`pdf_coordinate_drawer.py`文件,替换main函数中的`your_document.pdf`和`parse_result.json`为真实文件路径,运行: ```bash theme={null} python3 pdf_coordinate_drawer.py ``` **3. 输出结果** * 每页生成一个标注后的PNG图片 * 坐标框用指定颜色绘制,您也可以自定义颜色,不同类型元素用不同颜色绘制 * 生成坐标类型图例 该示例生成的标注最终效果如下: 可以看到,Textin xParse针对复杂布局的文档,能够精准识别并细粒度还原坐标,方便您将解析结果与原文件进行对比,查看解析效果以及审核校正。 ## 前端开源项目 此外,我们开源了web前端项目[xparse-frontend](https://github.com/intsig-textin/xparse-frontend/),该项目包含跟我们[在线web平台](https://www.textin.com/console/recognition/robot_markdown?service=pdf_to_markdown)效果一致的全套前端代码,具备文件预览、坐标回显、动态交互对照、编辑校正、导出多种格式结果文件等丰富功能。上手方便,开箱即用,欢迎体验! ## 常见问题 ### **坐标偏移不准确,有错位** **可能原因:** * 文档转图片使用了跟解析时不同的DPI,且坐标没有根据解析返回的页面宽高缩放适配 * 页面旋转角度未正确处理 **解决方案** * 文档转图片的时候使用跟解析相同的DPI,或者渲染时将页面和坐标值根据解析返回的页面宽高缩放适配(推荐,参考上述代码示例) * 确认页面是否经过旋转(angle),绘制时设置angle修正角度 ### **如何处理跨页段落和表格** 跨页信息可以在两个位置获取: * 在pages的structure中:跨页信息通过continue和next\_page\_id、next\_para\_id表示 * 在detail中:跨页信息通过通过split\_section\_page\_ids和split\_section\_positions表示 更多信息请参考[JSON结构说明](/xparse/parse-getjson)。 # 获取表格 Source: https://docs.textin.com/xparse/parse-gettable 在RAG应用中,为了更高的信息精度或稳定性,通常需要对表格做单独处理,如将表格区域保存为图片供前端展示,或者单独为表格设置分chunk策略等。在TextIn xParse文档解析API的输出中,对每个表格都有单独的定义,您可以获取每个表格并单独保存下来。 此外,我们也提供了一步到位的从PDF中提取表格并保存为Excel文件的教程,方便整合到您现有的基于Excel的业务任务流程中。 ## 如何获取表格 您可以参考以下步骤和示例代码将解析获取到的表格保存为 md 和 json 以及 excel 格式的文件。 ### 将表格保存为 md 和 json 文件 * * 参考[快速启动](/xparse/parse-quickstart),在 options 中设置URL参数 table\_flavor 为 md 或 html,这样API会以Markdown或HTML格式输出表格。您可根据实际需要进行设置。 * 在main函数中添加以下示例代码,解析API输出markdown中的表格,并保存为 md 和 json 文件。 ```python theme={null} import re if "result" in json_response and "markdown" in json_response["result"]: markdown_content = json_response["result"]["markdown"] # 提取所有表格 tables = re.findall(r'(?:\|.*\n)+', markdown_content) tables_md = '\n'.join(tables) # 保存为md文件 with open("tables.md", "w", encoding="utf-8") as f: f.write(tables_md) tables_json = [] for page in json_response["result"]["pages"]: for block in page.get("structured", []): if block.get("type") == "table": tables_json.append(block) # 保存为 json 文件 with open("tables.json", "w", encoding="utf-8") as f: json.dump(tables_json, f, ensure_ascii=False, indent=2) ``` ### 将表格保存为 excel 文件 * 参考[快速启动](/xparse/parse-quickstart),在 options 中设置URL参数 get\_excel=1,让API返回 excel\_base64 字段(Excel文件的base64编码)。 * 在main函数中添加以下示例代码,将表格保存为excel文件。 ```python theme={null} import base64 if "result" in json_response and "excel_base64" in json_response["result"]: excel_base64 = json_response["result"]["excel_base64"] excel_bytes = base64.b64decode(excel_base64) with open("result.xlsx", "wb") as f: f.write(excel_bytes) print("Excel 文件已保存为 result.xlsx") else: print("未检测到 excel_base64 字段,可能 PDF 中没有表格或参数设置有误。") ``` * 参考[快速启动](/xparse/parse-quickstart)中的示例文件,保存后的表格如下图(仅截取部分作为示例) Parse Gettable Pn # 多并发请求 Source: https://docs.textin.com/xparse/parse-max-workers 在实际使用过程中,您可能会需要在一定时间内集中性的批量解析文档;在这种情况下,即使TextIn xParse 文档解析API本身的速度足够快,但依次逐个解析大批量文档所需要的总耗时也可能会较长。 针对这种情况,TextIn xParse 文档解析API支持多并发请求,默认2 QPS,如果您有更大并发的需求,可以联系我们进行[商务咨询](https://www.textin.com/contact?type=28)。帮助您快速高效的完成大批量文档解析工作。 ### 多并发测试 您可以先参考以下示例代码进行文档解析API的多并发请求测试。 ```python theme={null} import concurrent.futures import subprocess import time # 要测试的命令 CMD = [ "python3", "用于跑示例的请求脚本.py" # 替换为你用于测试的请求脚本,也可以使用下文提供的脚本进行测试 ] # 并发数 CONCURRENCY = 5 # 总测试次数 TOTAL_RUNS = 5 def run_cmd(i): try: result = subprocess.run(CMD, capture_output=True, text=True, check=True) print(f"任务 {i} 成功,输出:{result.stdout.strip()}") except subprocess.CalledProcessError as e: print(f"任务 {i} 失败,错误:{e.stderr.strip()}") if __name__ == "__main__": print(f'并发测试,当前并发数为: {CONCURRENCY}') start_time = time.time() with concurrent.futures.ThreadPoolExecutor(max_workers=CONCURRENCY) as executor: futures = [executor.submit(run_cmd, i) for i in range(TOTAL_RUNS)] concurrent.futures.wait(futures) end_time = time.time() print(f"程序总耗时:{end_time - start_time:.2f} 秒") ``` 这里使用[快速启动](/xparse/parse-quickstart)中的示例文件进行多并发测试:[文档解析pdf示例.pdf](https://dllf.intsig.net/download/2025/Solution/textin/sample/pdf_to_markdown/sample_02.pdf) * 测试脚本如下:参考[快速启动](/xparse/parse-quickstart),解析位于URL的文件并保存结果;需替换您自己的 x-ti-app-id 和 x-ti-secret-code 注意:进行多并发测试等同对当前账号发起线上资源操作,请留意费用情况,请小心操作。 ```python theme={null} import json import requests class OCRClient: def __init__(self, app_id: str, secret_code: str): self.app_id = app_id self.secret_code = secret_code def recognize(self, file_content: bytes, options: dict) -> str: # 构建请求参数 params = {} for key, value in options.items(): params[key] = str(value) # 设置请求头 headers = { "x-ti-app-id": self.app_id, "x-ti-secret-code": self.secret_code, # 方式一:读取本地文件 # "Content-Type": "application/octet-stream" # 方式二:使用URL方式 "Content-Type": "text/plain" } # 发送请求 response = requests.post( f"https://api.textin.com/ai/service/v1/pdf_to_markdown", params=params, headers=headers, data=file_content ) # 检查响应状态 response.raise_for_status() return response.text def main(): # 创建客户端实例,需替换为你的API Key client = OCRClient("你的x-ti-app-id", "你的x-ti-secret-code") # 文件URL,这里为你提供了一份真实可用的示例URL file_content = "https://dllf.intsig.net/download/2025/Solution/textin/sample/pdf_to_markdown/sample_02.pdf" # 设置URL参数,可按需设置,这里已为你默认设置了一些参数 options = dict( dpi=144, get_image="objects", markdown_details=1, page_count=10, parse_mode="auto", table_flavor="html" ) import time # 在发送请求前记录开始时间 start_time = time.time() try: response = client.recognize(file_content, options) # 保存完整的JSON响应到result.json文件 with open("result.json", "w", encoding="utf-8") as f: f.write(response) # 解析JSON响应以提取markdown内容 json_response = json.loads(response) if "result" in json_response and "markdown" in json_response["result"]: markdown_content = json_response["result"]["markdown"] with open("result.md", "w", encoding="utf-8") as f: f.write(markdown_content) # 记录请求结束时间 end_time = time.time() print(f"请求耗时:{end_time - start_time:.2f} 秒") except Exception as e: print(f"Error: {e}") if __name__ == "__main__": main() ``` * 多并发测试结果如下图:可以看到文档解析API支持多并发请求,并且可以极大程度上节省时间。我们始终贯彻“您只需关心业务,剩下的文档解析处理工作交给TextIn”的理念,希望尽一切可能为您的业务发展提供帮助。 Concurrent1 Pn Concurrent5 Pn ### 多并发请求 当您想要进行文档解析API的多并发请求时,以下是一份完整的示例代码供您参考,您也可以根据实际使用需要进行修改调整。 ```python theme={null} import os import json import requests from concurrent.futures import ThreadPoolExecutor, as_completed class OCRClient: def __init__(self, app_id: str, secret_code: str): self.app_id = app_id self.secret_code = secret_code def recognize(self, file_content: bytes, options: dict) -> str: params = {key: str(value) for key, value in options.items()} headers = { "x-ti-app-id": self.app_id, "x-ti-secret-code": self.secret_code, "Content-Type": "application/octet-stream" } response = requests.post( "https://api.textin.com/ai/service/v1/pdf_to_markdown", params=params, headers=headers, data=file_content ) response.raise_for_status() return response.text def process_file(client: OCRClient, file_path: str, output_dir: str, options: dict): filename = os.path.basename(file_path) try: with open(file_path, "rb") as f: file_content = f.read() response = client.recognize(file_content, options) base_name = os.path.splitext(filename)[0] # 保存JSON with open(os.path.join(output_dir, f"{base_name}.json"), "w", encoding="utf-8") as fw: fw.write(response) # 保存Markdown json_response = json.loads(response) if "result" in json_response and "markdown" in json_response["result"]: markdown_content = json_response["result"]["markdown"] with open(os.path.join(output_dir, f"{base_name}.md"), "w", encoding="utf-8") as fw: fw.write(markdown_content) print(f"{filename} 处理完成") except Exception as e: print(f"{filename} 处理出错: {e}") def main(): client = OCRClient("你的x-ti-app-id", "你的x-ti-secret-code") input_dir = "./tmp" # 你的待解析文件夹 output_dir = "./output" # 输出结果的文件夹 os.makedirs(output_dir, exist_ok=True) exts = (".pdf",".png",".jpg",".jpeg",".bmp",".tiff",".webp",".doc",".docx",".html",".mhtml",".xls",".xlsx",".csv",".ppt",".pptx",".txt",".ofd",".rtf") files = [f for f in os.listdir(input_dir) if f.lower().endswith(exts)] file_paths = [os.path.join(input_dir, f) for f in files] # 设置URL参数,可按需设置,这里已为你默认设置了一些参数 options = dict( dpi=144, get_image="objects", markdown_details=1, page_count=10, parse_mode="auto", table_flavor="html" ) # 设置并发数 max_workers = 5 # 你可以根据需要调整并发数 with ThreadPoolExecutor(max_workers=max_workers) as executor: futures = [ executor.submit(process_file, client, file_path, output_dir, options) for file_path in file_paths ] for future in as_completed(futures): # 这里可以捕获每个任务的异常 try: future.result() except Exception as exc: print(f"任务出错: {exc}") if __name__ == "__main__": main() ``` # 快速启动 Source: https://docs.textin.com/xparse/parse-quickstart 参考示例,快速将文档解析API接入到您的系统和应用流程中。 本教程基于python示例分步讲解如何使用文档解析API。我们另外提供了完整的多语言示例代码包,可在本地一键运行,助您10s跑通接口示例,请[点击下载](https://static.textin.com/docs/%E9%80%9A%E7%94%A8%E6%96%87%E6%A1%A3%E8%A7%A3%E6%9E%90-%E7%A4%BA%E4%BE%8B%E4%BB%A3%E7%A0%81.zip)。如需在线快捷调试API,请参考[Textin文档中心](https://www.textin.com/document/legacy/pdf_to_markdown)。 ## 为什么使用文档解析API ? 大模型时代,文档(尤其是复杂文档)中蕴含着海量高价值的数据内容,借助文档解析API将其结构化为大模型更容易理解的格式(如markdown),可以更大程度上增强大模型的能力、发挥更大价值,快速实现业务AI升级。 TextIn xParse 文档解析API 是专为大模型重新设计的文档理解引擎,可以满足AI开发者的核心需求:✅ 文档结构完整保持 ✅ 语义关系准确理解 ✅ 大模型原生友好 使用文档解析API解析一个或多个文档,您可以选择将输出结果作为markdown或JSON文件保存在指定的目录中,也可以对输出结果做进一步的处理以满足您的业务需求。如果您正在进行知识库、RAG、大模型原生应用、Agent等业务方向的产品建设,文档解析API会为您提供帮助。 ## 如何使用文档解析API ? 您可以参考以下示例文件和步骤,快速验证并将文档解析API接入到您的系统和应用流程中。 这里为您提供了一份Textin官方pdf示例文件,您可以点击下载或使用该链接:[文档解析pdf示例.pdf](https://dllf.intsig.net/download/2025/Solution/textin/sample/pdf_to_markdown/sample_02.pdf)