Files
openclaw-config/workspace-finances/skills/mineru-agent/scripts/mineru_parse.py
T

149 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""MinerU Agent 轻量解析 API - 文档转 Markdown
用法:
URL 模式: python3 mineru_parse.py --url "https://example.com/file.pdf"
文件模式: python3 mineru_parse.py --file /path/to/document.pdf
可选参数:
--language ch|en 解析语言,默认 ch
--page_range 1-10 页码范围,仅 PDF 有效
--output /path/to/out.md 指定输出文件路径
--timeout 300 轮询超时秒数,默认 300
"""
import argparse
import json
import os
import sys
import time
import requests
BASE_URL = "https://mineru.net/api/v1/agent"
STATE_LABELS = {
"uploading": "文件下载中",
"pending": "排队中",
"running": "解析中",
"waiting-file": "等待文件上传",
}
def poll_result(task_id, timeout=300, interval=3):
"""轮询查询解析结果,返回 Markdown 文本或 None。"""
start = time.time()
while time.time() - start < timeout:
resp = requests.get(f"{BASE_URL}/parse/{task_id}")
result = resp.json()
data = result.get("data", {})
state = data.get("state", "unknown")
elapsed = int(time.time() - start)
if state == "done":
md_url = data["markdown_url"]
print(f"[{elapsed}s] 解析完成", file=sys.stderr)
md_resp = requests.get(md_url)
md_resp.encoding = "utf-8"
return md_resp.text
if state == "failed":
err_msg = data.get("err_msg", "未知错误")
err_code = data.get("err_code", "")
print(f"[{elapsed}s] 解析失败 [{err_code}]: {err_msg}", file=sys.stderr)
return None
label = STATE_LABELS.get(state, state)
print(f"[{elapsed}s] {label}...", file=sys.stderr)
time.sleep(interval)
print(f"轮询超时 ({timeout}s)task_id: {task_id}", file=sys.stderr)
return None
def parse_by_url(url, language="ch", page_range=None, timeout=300):
"""通过 URL 提交文档解析任务并等待结果。"""
data = {"url": url, "language": language}
if page_range:
data["page_range"] = page_range
resp = requests.post(f"{BASE_URL}/parse/url", json=data)
result = resp.json()
if result.get("code") != 0:
print(f"提交失败: {result.get('msg')}", file=sys.stderr)
return None
task_id = result["data"]["task_id"]
print(f"任务已提交, task_id: {task_id}", file=sys.stderr)
return poll_result(task_id, timeout=timeout)
def parse_by_file(file_path, language="ch", page_range=None, timeout=300):
"""通过文件上传提交文档解析任务并等待结果。"""
if not os.path.exists(file_path):
print(f"文件不存在: {file_path}", file=sys.stderr)
return None
file_name = os.path.basename(file_path)
file_size = os.path.getsize(file_path)
if file_size > 10 * 1024 * 1024:
print(f"文件大小 {file_size/1024/1024:.1f}MB 超出 10MB 限制", file=sys.stderr)
return None
# 1. 获取签名上传 URL
data = {"file_name": file_name, "language": language}
if page_range:
data["page_range"] = page_range
resp = requests.post(f"{BASE_URL}/parse/file", json=data)
result = resp.json()
if result.get("code") != 0:
print(f"获取上传链接失败: {result.get('msg')}", file=sys.stderr)
return None
task_id = result["data"]["task_id"]
file_url = result["data"]["file_url"]
print(f"任务已创建, task_id: {task_id}", file=sys.stderr)
# 2. PUT 上传文件到 OSS
with open(file_path, "rb") as f:
put_resp = requests.put(file_url, data=f)
if put_resp.status_code not in (200, 201):
print(f"文件上传失败, HTTP {put_resp.status_code}", file=sys.stderr)
return None
print("文件上传成功,等待解析...", file=sys.stderr)
# 3. 轮询等待结果
return poll_result(task_id, timeout=timeout)
def main():
parser = argparse.ArgumentParser(description="MinerU 文档解析")
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--url", help="远程文件 URL")
group.add_argument("--file", help="本地文件路径")
parser.add_argument("--language", default="ch", help="解析语言 (默认 ch)")
parser.add_argument("--page_range", help="页码范围,如 1-10(仅 PDF")
parser.add_argument("--output", "-o", help="输出文件路径(默认 stdout")
parser.add_argument("--timeout", type=int, default=300, help="轮询超时秒数(默认 300")
args = parser.parse_args()
if args.url:
content = parse_by_url(args.url, language=args.language, page_range=args.page_range, timeout=args.timeout)
else:
content = parse_by_file(args.file, language=args.language, page_range=args.page_range, timeout=args.timeout)
if content is None:
sys.exit(1)
if args.output:
with open(args.output, "w", encoding="utf-8") as f:
f.write(content)
print(f"结果已保存到: {args.output}", file=sys.stderr)
else:
print(content)
if __name__ == "__main__":
main()