kgrag/app_pkg/examples/convert_word_pdf.py
2026-07-29 18:10:19 +08:00

177 lines
6.2 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.

from fastapi import UploadFile
import os
from typing import Optional
import tempfile
import requests
import time
from tqdm import tqdm
from pathlib import Path
class ProgressFileReader:
def __init__(self, file_path, progress_bar):
self.file = open(file_path, 'rb')
self.progress_bar = progress_bar
def read(self, size=-1):
data = self.file.read(size)
if data:
self.progress_bar.update(len(data))
return data
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close()
async def convert_doc_to_pdf(api_url: str, file: UploadFile, timeout: int = 300) -> Optional[str]:
"""
将DOC文件转换为pdf
参数:
api_url: 转换服务的URL (如 "http://172.18.127.124:8000")
file: 要转换的UploadFile对象
timeout: 请求超时时间(秒)
"""
try:
with tempfile.NamedTemporaryFile(delete=False, suffix=".doc") as tmp_doc:
content = await file.read()
tmp_doc.write(content)
tmp_path = tmp_doc.name
file_name = file.filename
file_size = os.path.getsize(tmp_path)
output_name = Path(file_name).stem + ".pdf"
with tqdm(total=file_size, unit='B', unit_scale=True, desc="上传进度") as pbar:
with ProgressFileReader(tmp_path, pbar) as file_reader:
files = {'file': (file_name, file_reader)}
params = {'src': 'doc', 'to': 'pdf'}
response = requests.post(
f"{api_url}/transfer",
files=files,
params=params,
timeout=timeout
)
if response.status_code == 200:
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_docx:
tmp_docx.write(response.content)
output_path = tmp_docx.name
os.unlink(tmp_path)
return output_path
else:
raise Exception(f"转换失败: {response.text}")
except requests.exceptions.Timeout:
raise Exception(f"请求超时(超过{timeout}秒)")
except requests.exceptions.RequestException as e:
raise Exception(f"请求错误: {str(e)}")
except Exception as e:
# 确保临时文件被清理
if 'tmp_path' in locals() and os.path.exists(tmp_path):
os.unlink(tmp_path)
if 'output_path' in locals() and os.path.exists(output_path):
os.unlink(output_path)
raise Exception(f"转换过程中出错: {str(e)}")
async def convert_docx_to_pdf(api_url: str, file: UploadFile, timeout: int = 300) -> Optional[str]:
"""
将DOCX文件转换为PDF解决中文缺失问题
参数:
api_url: 转换服务的URL (如 "http://172.18.127.124:8000")
file: 要转换的UploadFile对象
timeout: 请求超时时间(秒)
"""
try:
# 创建临时文件保存上传的DOCX
with tempfile.NamedTemporaryFile(delete=False, suffix=".docx") as tmp_docx:
content = await file.read()
tmp_docx.write(content)
tmp_path = tmp_docx.name
# 获取文件信息
file_name = file.filename
file_size = os.path.getsize(tmp_path)
output_name = Path(file_name).stem + ".pdf"
print(f"正在转换: {file_name} ({file_size/1024:.1f} KB) -> PDF")
start_time = time.time()
# 使用带进度条的文件读取器
with tqdm(total=file_size, unit='B', unit_scale=True, desc="上传进度") as pbar:
with ProgressFileReader(tmp_path, pbar) as file_reader:
files = {'file': (file_name, file_reader)}
params = {
'src': 'docx',
'to': 'pdf',
'font': 'SimSun',
'encoding': 'utf-8'
}
response = requests.post(
f"{api_url}/transfer",
files=files,
params=params,
timeout=timeout
)
# 处理响应
if response.status_code == 200:
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_pdf:
tmp_pdf.write(response.content)
output_path = tmp_pdf.name
if os.path.getsize(output_path) < 1024: # 如果PDF文件过小
raise Exception("生成的PDF可能不包含有效内容")
elapsed = time.time() - start_time
print(f"\n转换成功! 保存为: {output_path}")
print(f"总耗时: {elapsed:.2f}")
os.unlink(tmp_path)
return output_path
else:
raise Exception(f"转换失败: {response.text}")
except requests.exceptions.Timeout:
raise Exception(f"请求超时(超过{timeout}秒)")
except requests.exceptions.RequestException as e:
raise Exception(f"请求错误: {str(e)}")
except Exception as e:
# 确保临时文件被清理
if 'tmp_path' in locals() and os.path.exists(tmp_path):
os.unlink(tmp_path)
if 'output_path' in locals() and os.path.exists(output_path):
os.unlink(output_path)
raise Exception(f"转换过程中出错: {str(e)}")
#调用示例:
async def split_result(file: UploadFile = File(...),
chunk_type: str = Form("01"),
chunk_size: int = Form(256),
chunk_overlap: int = Form(50),
max_level: Optional[int]=Form(3)):
"""
拆分结果
"""
filename = file.filename
file_ext = os.path.splitext(filename)[1]
if file_ext == ".docx":
# 处理DOCX文件
converted_path = await convert_docx_to_pdf(os.getenv("CONVERT_DOC_URL","http://172.18.127.124:8000"), file)
# 读取转换后的DOCX文件
with open(converted_path, 'rb') as f:
converted_file = UploadFile(filename=f"{PATH(filename).stem}.pdf", file=f,headers=headers)
#调用Mineru
md_content = await process_pdf_logic(converted_file)