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)