OCR 文字识别 ocr-scan:图片、扫描版 PDF 一键转可复制文字,支持中文简体/英文/数字混排。有文本层自动跳过,扫描页强制 OCR。调 AIMS 平台视觉模型,本机无需装 Tesseract。适合发票识别、截图转文字、扫描件转 Word。
---
name: ocr-scan
description: OCR 文字识别 ocr-scan:图片、扫描版 PDF 一键转可复制文字,支持中文简体/英文/数字/标点混排。有文本层自动跳过(不浪费扣费),扫描页强制 OCR。调 AIMS 平台视觉模型,本机无需装 Tesseract。适合发票识别、截图转文字、扫描件转 Word、扫描合同提取文字、教材扫描转 Word、扫描 PDF 变可复制文字(Ctrl+F 可搜)。
---
本 skill 的真实能力依赖平台后端工具。在网页 / chat 端点下,这些工具可能不可用:
此时**请勿轻信**,请改用 **agent / CLI 路径**运行本 skill 以获取真实结果。任何路径下都**严禁谎称「已调用 / 已搜索完成」而实际未执行**。
把图片和扫描版 PDF 里的文字识别成可复制的文本。识别调用 AIMS 平台的视觉模型(qwen-vl-ocr-latest)完成,本地**无需安装任何 OCR 引擎**(不再需要 Tesseract)。
**场景 1:财务整理发票** —— 把一堆发票拍照/扫描图批量转文字,按抬头 + 金额 + 日期整理成报销单,免去手敲。
**场景 2:学生扫描教材** —— 把教材扫描版 PDF 转成可复制的 Word 文字,Ctrl+F 直接搜重点段落,笔记效率翻倍。
**场景 3:客服提取截图** —— 用户发的截图含错误信息/地址/订单号,OCR 一键转文字直接复制到工单系统。
| 角色 | 典型用途 |
|------|----------|
| 财务 / 会计 | 发票识别、报销单整理 |
| 学生 / 教师 | 教材扫描转 Word、课件截图转文字 |
| 客服 / 运营 | 截图提取文字、订单号识别 |
| 行政 / 文员 | 扫描合同提取文字、扫描通知归档 |
| 律师 / 法务 | 扫描证据材料转文字 |
| 研究员 / 学者 | 扫描文献提取引用信息 |
# 1. 图片 OCR
python scripts/ocr.py image --input 发票.png --output 发票文字.txt
# 2. 扫描版 PDF(自动检测有/无文本层)
python scripts/ocr.py pdf --input 扫描件.pdf --output 文字.txt
# 3. 强制全页 OCR(忽略文本层)
python scripts/ocr.py pdf --input 扫描件.pdf --output 文字.txt --force
输出示例:
{"ok": true, "chars": 1234, "preview": "浙江增值税普通发票\n开票日期:2026-09-17\n金额:¥1234.56..."}
| 对比项 | 装 Tesseract | ocr-scan |
|--------|--------------|----------|
| 安装 | 装 Tesseract + 中文包 + 折腾路径 | pip install Pillow pymupdf |
| 中文准确率 | 一般(自己训练语料可达标)| 平台视觉模型,中文友好 |
| 扫描 PDF 混合页 | 需要自己判断哪些页要 OCR | 自动检测,有文本层直接用 |
| 加密 / 复杂排版 | 自己写代码 | 平台模型擅长 |
| 成本 | 免费但费时间 | 按次付费,¥0.10/次起 |
pip install Pillow pymupdf
pip install Pillow pymupdf
本 skill 的识别在 AIMS 平台完成,需要您自己的 AIMS API Key(在 aimsgateway.cn 控制台获取):
export AIMS_API_KEY=aims_sk_你的key
# 或每次命令加 --api-key aims_sk_你的key
用户要求"图片转文字 / 扫描件识别 / OCR / 提取图片里的文字 / 扫描 PDF 变文字 / 发票识别 / 截图转文字"时触发。
python scripts/ocr.py image --input 截图.png --output 文字.txt
python scripts/ocr.py pdf --input 扫描件.pdf --output 文字.txt [--force]
1. 支持中文简体、英文、数字、标点混排
2. 输出 UTF-8 文本;`--output` 缺省仅打印预览
3. 输出 JSON:`{"ok": true, "chars": N, "preview": "..."}`
先设置环境变量 `AIMS_API_KEY=aims_sk_你的key`,或在命令后加 `--api-key`。这是您本人在 AIMS 平台的密钥,识别请求会带上它调用视觉模型。
扫描 PDF 可加 `--force` 强制全页 OCR;图片模糊、倾斜、低分辨率会降低准确率,建议提供清晰原图。复杂表格、手写体、艺术字准确率有限,属正常情况。
| 情况 | 处理 |
|---|---|
| 未配置 AIMS_API_KEY | 报错并提示设置方式 |
| 图片损坏/格式不支持 | 明确报错 |
| PDF 无文本层且无图片 | 报错提示该文件无内容可识别 |
| 平台调用失败 | 报错并回显原因 |
<!-- ===== 以下为内嵌脚本代码(agent 安装时按需落盘为 scripts/<name> 并 chmod +x) ===== -->
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""OCR 识别脚本(平台视觉模型版):图片 / 扫描版 PDF 文字识别。
原理:把图片用 base64 传给 AIMS 平台的视觉模型(qwen-vl-ocr-latest)做 OCR,
识别完全在平台完成,本地不安装任何 OCR 引擎(无需 Tesseract)。
用法:
python ocr.py image --input scan.png --output out.txt
python ocr.py pdf --input scan.pdf --output out.txt
鉴权:需 AIMS API Key,二选一:
1) 环境变量 AIMS_API_KEY=aims_sk_xxx
2) 命令行 --api-key aims_sk_xxx
"""
import argparse
import base64
import io
import json
import os
import sys
import time
import urllib.request
from pathlib import Path
AIMS_URL = "https://aimsgateway.cn/mcp/"
OCR_MODEL = "qwen-vl-ocr-latest"
OCR_PROMPT = (
"请逐行转录这张图片里的全部文字(含中文、英文、数字、标点),"
"保持原顺序,只输出识别到的文字,不要解释、不要加编号。"
)
def _get_key(args):
key = getattr(args, "api_key", None) or os.environ.get("AIMS_API_KEY")
if not key:
raise RuntimeError(
"缺少 AIMS API Key:请先设置环境变量 AIMS_API_KEY,或在命令后加 --api-key aims_sk_xxx"
)
return key
def _rpc(url, key, method, params, mid, tries=3):
body = json.dumps(
{"jsonrpc": "2.0", "id": mid, "method": method, "params": params}
).encode()
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {key}",
}
last = None
for _ in range(tries):
try:
req = urllib.request.Request(url, data=body, method="POST", headers=headers)
with urllib.request.urlopen(req, timeout=180) as r:
return json.loads(r.read().decode())
except Exception as e: # noqa: BLE001
last = e
time.sleep(2)
raise RuntimeError(f"MCP 调用失败: {last}")
def _handshake(key):
_rpc(
AIMS_URL,
key,
"initialize",
{
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": {"name": "ocr-scan", "version": "1.0"},
},
1,
)
try:
_rpc(AIMS_URL, key, "notifications/initialized", {}, 2)
except Exception: # noqa: BLE001
pass
def _chat(key, data_url):
resp = _rpc(
AIMS_URL,
key,
"tools/call",
{
"name": "aims.chat",
"arguments": {
"model": OCR_MODEL,
"messages": [
{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": data_url}},
{"type": "text", "text": OCR_PROMPT},
],
}
],
"max_tokens": 4000,
"temperature": 0,
"no_rag": True, # 2026-09-16 补丁:防止 RAG 知识库干扰视觉模型
},
},
7,
)
try:
txt = resp["result"]["content"][0]["text"]
except Exception: # noqa: BLE001
raise RuntimeError("平台返回格式异常: " + json.dumps(resp, ensure_ascii=False)[:300])
# 兼容 OpenAI 格式 JSON 字符串
try:
obj = json.loads(txt)
txt = obj["choices"][0]["message"]["content"]
except Exception: # noqa: BLE001
pass
return txt.strip()
def _image_to_data_url(path):
p = Path(path)
if not p.exists():
raise FileNotFoundError(path)
b64 = base64.b64encode(p.read_bytes()).decode()
ext = p.suffix.lower()
mime = {
"png": "image/png",
"jpg": "image/jpeg",
"jpeg": "image/jpeg",
"gif": "image/gif",
"webp": "image/webp",
"bmp": "image/bmp",
}.get(ext, "image/png")
return f"data:{mime};base64,{b64}"
def cmd_image(args):
key = _get_key(args)
_handshake(key)
data_url = _image_to_data_url(args.input)
text = _chat(key, data_url)
_save(text, args.output)
return {"ok": True, "output": args.output, "chars": len(text), "preview": text[:300]}
def cmd_pdf(args):
key = _get_key(args)
try:
import fitz # PyMuPDF
except ImportError:
raise RuntimeError("PDF 识别需安装 PyMuPDF:pip install pymupdf")
_handshake(key)
doc = fitz.open(args.input)
parts = []
chars = 0
zoom = 2.0 # 提高分辨率提升 OCR 准确率
for i, page in enumerate(doc, 1):
if not args.force:
txt0 = page.get_text().strip()
if txt0:
parts.append(f"---- 第 {i} 页(文本层)----\n{txt0}")
chars += len(txt0)
continue
pix = page.get_pixmap(matrix=fitz.Matrix(zoom, zoom))
raw = pix.tobytes("png")
b64 = base64.b64encode(raw).decode()
data_url = f"data:image/png;base64,{b64}"
text = _chat(key, data_url)
parts.append(f"---- 第 {i} 页 ----\n{text}")
chars += len(text)
body = "\n\n".join(parts)
_save(body, args.output)
return {
"ok": True,
"output": args.output,
"pages": doc.page_count,
"chars": chars,
"preview": body[:300],
}
def _save(text, output):
if output:
Path(output).parent.mkdir(parents=True, exist_ok=True)
Path(output).write_text(text, encoding="utf-8")
def build_parser():
ap = argparse.ArgumentParser(description="OCR 识别(平台视觉模型)")
ap.add_argument(
"--api-key",
default=None,
help="AIMS API Key(也可用环境变量 AIMS_API_KEY)",
)
sub = ap.add_subparsers(dest="command", required=True)
p = sub.add_parser("image", help="图片 OCR")
p.add_argument("--input", required=True)
p.add_argument("--output", default=None)
p.set_defaults(func=cmd_image)
p = sub.add_parser("pdf", help="扫描版 PDF OCR(无文本层页面)")
p.add_argument("--input", required=True)
p.add_argument("--output", default=None)
p.add_argument("--force", action="store_true", help="忽略文本层,强制 OCR 全部页面")
p.set_defaults(func=cmd_pdf)
return ap
def main():
args = build_parser().parse_args()
try:
result = args.func(args)
except Exception as e: # noqa: BLE001
print(json.dumps({"ok": False, "error": str(e)}, ensure_ascii=False))
sys.exit(1)
print(json.dumps(result, ensure_ascii=False, indent=2))
if __name__ == "__main__":
main()
先设置环境变量 `AIMS_API_KEY=aims_sk_你的key`,或在命令后加 `--api-key`。这是您本人在 AIMS 平台的密钥,识别请求会带上它调用视觉模型。
扫描 PDF 可加 `--force` 强制全页 OCR;图片模糊、倾斜、低分辨率会降低准确率,建议提供清晰原图。复杂表格、手写体、艺术字准确率有限,属正常情况。