Upload files to "/"
upload OCR code
This commit is contained in:
339
batchOCR.py
Normal file
339
batchOCR.py
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
import os
|
||||||
|
import base64
|
||||||
|
import time
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# ⚙️ 配置变量 - 在这里设置
|
||||||
|
# ============================================================
|
||||||
|
INPUT_DIR = "D:\\新風\\國標GB\\OCR" # 存放 PDF 的目录
|
||||||
|
OUTPUT_DIR = "D:\\新風\\國標GB\\OCR\\電梯知識" # 输出 Markdown 的目录
|
||||||
|
|
||||||
|
# API 配置
|
||||||
|
API_KEY = "cea4984c93aee4c3"
|
||||||
|
BASE_URL = "https://agent.imqimacau.com"
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
# 确保输出目录存在
|
||||||
|
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
def print_full_data(full_data, max_length=500):
|
||||||
|
"""打印完整数据结构的辅助函数"""
|
||||||
|
if not full_data:
|
||||||
|
print("⚠️ 没有返回完整数据 (full_data = None)")
|
||||||
|
return
|
||||||
|
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("完整数据 (Full Data):")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
# 打印元数据
|
||||||
|
if 'metadata' in full_data:
|
||||||
|
print("\n📊 元数据:")
|
||||||
|
print(f" 总文本块数: {full_data['metadata'].get('total_blocks', 0)}")
|
||||||
|
print(f" 总字符数: {full_data['metadata'].get('total_chars', 0)}")
|
||||||
|
|
||||||
|
# 打印 OCR 文本
|
||||||
|
ocr_text = full_data.get('ocr_text', '')
|
||||||
|
if ocr_text:
|
||||||
|
print(f"\n📝 OCR 文本 (共 {len(ocr_text)} 字符):")
|
||||||
|
print("-" * 60)
|
||||||
|
print(ocr_text[:max_length])
|
||||||
|
if len(ocr_text) > max_length:
|
||||||
|
print(f"... (还有 {len(ocr_text) - max_length} 字符)")
|
||||||
|
|
||||||
|
# 打印文本块详情
|
||||||
|
blocks = full_data.get('blocks', [])
|
||||||
|
if blocks:
|
||||||
|
print(f"\n📦 文本块详情 (共 {len(blocks)} 个块):")
|
||||||
|
print("-" * 60)
|
||||||
|
for i, block in enumerate(blocks[:10]): # 只显示前10个块
|
||||||
|
print(f"\n块 {i+1}:")
|
||||||
|
print(f" 内容: {block.get('content', '')[:100]}...")
|
||||||
|
print(f" 类型: {block.get('block_type', 'unknown')}")
|
||||||
|
print(f" 置信度: {block.get('confidence', 'N/A')}")
|
||||||
|
if block.get('bbox'):
|
||||||
|
bbox = block['bbox']
|
||||||
|
if len(bbox) == 4:
|
||||||
|
print(f" 位置: [{bbox[0]:.1f}, {bbox[1]:.1f}, {bbox[2]:.1f}, {bbox[3]:.1f}]")
|
||||||
|
else:
|
||||||
|
print(f" 位置: {bbox}")
|
||||||
|
|
||||||
|
if len(blocks) > 10:
|
||||||
|
print(f"\n... (还有 {len(blocks) - 10} 个块未显示)")
|
||||||
|
|
||||||
|
# 打印原始输出摘要
|
||||||
|
if 'raw_output' in full_data:
|
||||||
|
print(f"\n🔧 原始输出: {'存在但可能包含不可序列化对象' if full_data['raw_output'] else 'None'}")
|
||||||
|
|
||||||
|
|
||||||
|
def process_pdf_file(input_file, output_dir, api_url, api_key):
|
||||||
|
"""处理单个 PDF 文件"""
|
||||||
|
|
||||||
|
print("\n" + "=" * 80)
|
||||||
|
print(f"📄 开始处理: {input_file}")
|
||||||
|
print("=" * 80)
|
||||||
|
|
||||||
|
# 生成输出文件名
|
||||||
|
file_name = os.path.basename(input_file)
|
||||||
|
base_name = os.path.splitext(file_name)[0]
|
||||||
|
|
||||||
|
# 输出文件路径
|
||||||
|
output_md = os.path.join(output_dir, f"{base_name}.md")
|
||||||
|
raw_response_file = os.path.join(output_dir, f"{base_name}_raw_response.json")
|
||||||
|
full_data_file = os.path.join(output_dir, f"{base_name}_full_data.json")
|
||||||
|
blocks_detail_file = os.path.join(output_dir, f"{base_name}_blocks_detail.json")
|
||||||
|
spatial_json_file = os.path.join(output_dir, f"{base_name}_spatial_structure.json")
|
||||||
|
pure_text_file = os.path.join(output_dir, f"{base_name}_ocr_text_only.txt")
|
||||||
|
|
||||||
|
# 读取并编码 PDF
|
||||||
|
print("读取图片...")
|
||||||
|
try:
|
||||||
|
with open(input_file, "rb") as f:
|
||||||
|
file_base64 = base64.b64encode(f.read()).decode()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 读取文件失败: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print(f"文件编码完成,大小: {len(file_base64)} 字符")
|
||||||
|
|
||||||
|
# 提交任务
|
||||||
|
print("提交任务...")
|
||||||
|
try:
|
||||||
|
response = requests.post(
|
||||||
|
f"{api_url}/task/submit",
|
||||||
|
headers={
|
||||||
|
"X-API-Key": api_key,
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
json={
|
||||||
|
"file_base64": file_base64,
|
||||||
|
"file_type": "pdf",
|
||||||
|
"enable_ai_description": False,
|
||||||
|
"output_type": "ocr_only",
|
||||||
|
},
|
||||||
|
timeout=30
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 提交任务失败: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print(f"状态码: {response.status_code}")
|
||||||
|
|
||||||
|
# 解析 JSON
|
||||||
|
try:
|
||||||
|
result = response.json()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"JSON 解析失败: {e}")
|
||||||
|
print(f"原始响应: {response.text[:200]}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if response.status_code != 200:
|
||||||
|
print(f"请求失败: {result}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
task_id = result.get('task_id')
|
||||||
|
print(f"Task ID: {task_id}")
|
||||||
|
|
||||||
|
# 轮询获取结果
|
||||||
|
print("等待处理...", end="")
|
||||||
|
ocr_text = None
|
||||||
|
ai_description = None
|
||||||
|
spatial_structure = None
|
||||||
|
full_data = None
|
||||||
|
error_msg = None
|
||||||
|
raw_result = None
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
status_response = requests.get(
|
||||||
|
f"{api_url}/task/result/{task_id}",
|
||||||
|
headers={"X-API-Key": api_key},
|
||||||
|
timeout=30
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n❌ 状态查询失败: {e}")
|
||||||
|
time.sleep(4)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if status_response.status_code != 200:
|
||||||
|
print(f"\n状态查询失败: {status_response.status_code}")
|
||||||
|
time.sleep(4)
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = status_response.json()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\nJSON 解析失败: {e}")
|
||||||
|
time.sleep(4)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if data.get('status') == 'completed':
|
||||||
|
print("\n✅ 任务完成!")
|
||||||
|
|
||||||
|
# 获取结果
|
||||||
|
if data.get('result'):
|
||||||
|
ocr_text = data['result'].get('ocr_text', '')
|
||||||
|
ai_description = data['result'].get('ai_description', '')
|
||||||
|
spatial_structure = data['result'].get('spatial_structure', None)
|
||||||
|
full_data = data['result'].get('full_data', None)
|
||||||
|
raw_result = data.get('result')
|
||||||
|
|
||||||
|
# 保存原始返回数据
|
||||||
|
# with open(raw_response_file, "w", encoding="utf-8") as f:
|
||||||
|
# json.dump(raw_result, f, ensure_ascii=False, indent=2)
|
||||||
|
# print(f"✓ 原始返回数据已保存到: {raw_response_file}")
|
||||||
|
|
||||||
|
# 打印完整数据结构(可选,注释掉以减少输出)
|
||||||
|
# print_full_data(full_data)
|
||||||
|
|
||||||
|
# 保存完整数据
|
||||||
|
if full_data:
|
||||||
|
with open(full_data_file, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(full_data, f, ensure_ascii=False, indent=2)
|
||||||
|
print(f"✓ 完整数据已保存到: {full_data_file}")
|
||||||
|
|
||||||
|
if full_data.get('blocks'):
|
||||||
|
with open(blocks_detail_file, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(full_data['blocks'], f, ensure_ascii=False, indent=2)
|
||||||
|
print(f"✓ 文本块详情已保存到: {blocks_detail_file}")
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
elif data.get('status') == 'failed':
|
||||||
|
error_msg = data.get('error', 'Unknown error')
|
||||||
|
print(f"\n❌ 任务失败: {error_msg}")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
status = data.get('status', 'unknown')
|
||||||
|
print(f". ({status})", end="", flush=True)
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
# 保存结果到 Markdown 文件
|
||||||
|
print("💾 正在保存结果到文件...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(output_md, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(f"# OCR 识别结果\n\n")
|
||||||
|
f.write(f"**生成时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
|
||||||
|
f.write(f"**Task ID**: `{task_id}`\n\n")
|
||||||
|
f.write(f"**源文件**: `{input_file}`\n\n")
|
||||||
|
f.write("---\n\n")
|
||||||
|
|
||||||
|
if error_msg:
|
||||||
|
f.write(f"## ❌ 任务失败\n\n")
|
||||||
|
f.write(f"错误信息: {error_msg}\n")
|
||||||
|
else:
|
||||||
|
# OCR 结果
|
||||||
|
f.write(f"## 📝 OCR 识别结果\n\n")
|
||||||
|
if ocr_text:
|
||||||
|
f.write(ocr_text)
|
||||||
|
else:
|
||||||
|
f.write("(无 OCR 结果)\n")
|
||||||
|
|
||||||
|
# 空间结构信息
|
||||||
|
if spatial_structure:
|
||||||
|
f.write(f"\n\n## 🗺️ 空间结构信息\n\n")
|
||||||
|
if 'block_count' in spatial_structure:
|
||||||
|
f.write(f"- **图片尺寸**: {spatial_structure.get('width', 'N/A')} x {spatial_structure.get('height', 'N/A')}\n")
|
||||||
|
f.write(f"- **识别块数量**: {spatial_structure.get('block_count', 0)}\n")
|
||||||
|
|
||||||
|
# AI 分析
|
||||||
|
if ai_description:
|
||||||
|
f.write(f"\n\n## 🤖 AI 分析结果\n\n")
|
||||||
|
f.write(ai_description)
|
||||||
|
|
||||||
|
print(f"✓ Markdown 结果已保存到: {output_md}")
|
||||||
|
|
||||||
|
# 保存空间结构 JSON
|
||||||
|
if spatial_structure:
|
||||||
|
with open(spatial_json_file, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(spatial_structure, f, ensure_ascii=False, indent=2)
|
||||||
|
print(f"✓ 空间结构已保存到: {spatial_json_file}")
|
||||||
|
|
||||||
|
# 保存纯文本
|
||||||
|
# if ocr_text and not error_msg:
|
||||||
|
# with open(pure_text_file, 'w', encoding='utf-8') as f:
|
||||||
|
# f.write(ocr_text)
|
||||||
|
# print(f"✓ OCR 纯文本已保存到: {pure_text_file}")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ 保存结果失败: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""主函数:遍历目录处理所有 PDF 文件"""
|
||||||
|
|
||||||
|
print("=" * 80)
|
||||||
|
print("🚀 PDF OCR 批量处理工具")
|
||||||
|
print("=" * 80)
|
||||||
|
print(f"输入目录: {INPUT_DIR}")
|
||||||
|
print(f"输出目录: {OUTPUT_DIR}")
|
||||||
|
print("=" * 80)
|
||||||
|
|
||||||
|
# 检查输入目录是否存在
|
||||||
|
if not os.path.exists(INPUT_DIR):
|
||||||
|
print(f"❌ 错误:输入目录不存在 - {INPUT_DIR}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 获取所有 PDF 文件
|
||||||
|
pdf_files = []
|
||||||
|
for file in os.listdir(INPUT_DIR):
|
||||||
|
if file.lower().endswith('.pdf'):
|
||||||
|
pdf_files.append(os.path.join(INPUT_DIR, file))
|
||||||
|
|
||||||
|
if not pdf_files:
|
||||||
|
print(f"⚠️ 在目录 {INPUT_DIR} 中没有找到 PDF 文件")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"\n📁 找到 {len(pdf_files)} 个 PDF 文件:")
|
||||||
|
for f in pdf_files:
|
||||||
|
print(f" - {os.path.basename(f)}")
|
||||||
|
print("-" * 80)
|
||||||
|
|
||||||
|
# 统计处理结果
|
||||||
|
success_count = 0
|
||||||
|
fail_count = 0
|
||||||
|
|
||||||
|
# 逐个处理 PDF 文件
|
||||||
|
for i, pdf_file in enumerate(pdf_files, 1):
|
||||||
|
print(f"\n[{i}/{len(pdf_files)}] 处理中...")
|
||||||
|
|
||||||
|
result = process_pdf_file(
|
||||||
|
input_file=pdf_file,
|
||||||
|
output_dir=OUTPUT_DIR,
|
||||||
|
api_url=BASE_URL,
|
||||||
|
api_key=API_KEY
|
||||||
|
)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
success_count += 1
|
||||||
|
print(f"✅ 完成: {os.path.basename(pdf_file)}")
|
||||||
|
else:
|
||||||
|
fail_count += 1
|
||||||
|
print(f"❌ 失败: {os.path.basename(pdf_file)}")
|
||||||
|
|
||||||
|
# 在文件之间添加短暂延迟,避免请求过快
|
||||||
|
if i < len(pdf_files):
|
||||||
|
print("\n⏳ 等待 2 秒后处理下一个文件...")
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
# 打印最终统计
|
||||||
|
print("\n" + "=" * 80)
|
||||||
|
print("📊 批量处理完成!")
|
||||||
|
print("=" * 80)
|
||||||
|
print(f"总计: {len(pdf_files)} 个文件")
|
||||||
|
print(f"成功: {success_count} 个")
|
||||||
|
print(f"失败: {fail_count} 个")
|
||||||
|
print(f"输出目录: {OUTPUT_DIR}")
|
||||||
|
print("=" * 80)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user