一个功能强大且易于使用的文档转换工具,支持将多种格式的文档转换为高质量的Markdown格式。
Solming - 项目创建者
- 🚀 多引擎支持: 集成多种转换引擎,自动选择最佳方案
- 📄 格式丰富: 支持PDF、Word、PPT、图片等多种文档格式
- ⚡ 异步处理: 高性能异步架构,支持批量处理
- 🔧 配置灵活: 丰富的配置选项,满足不同需求
- ☁️ 云存储: 内置OBS云存储支持,自动上传和链接替换
- 🛠️ 开发友好: 完善的错误处理和调试模式
文档类型 | 支持格式 | 推荐工具 |
---|---|---|
.pdf |
marker, docling | |
Word | .docx , .doc |
docling |
PPT | .pptx , .ppt |
pptx2md |
图片 | .png , .jpg , .jpeg 等 |
paddleocr |
# 激活环境(如果使用conda)
conda activate file-extract
# 基础转换工具(选装)
pip install marker-pdf # PDF转换(推荐)
pip install docling # 通用转换
pip install pptx2md # PPT转换
pip install paddleocr # 图片OCR
import asyncio
from converter_engine import CleanConverter
async def main():
# 创建转换器
converter = CleanConverter()
# 转换文件
result = await converter.convert_file("document.pdf")
if result.success:
print(f"✅ 转换成功: {result.file_id}")
print(f"📄 内容长度: {len(result.markdown_content)} 字符")
# 保存结果
with open(f"{result.file_id}.md", "w", encoding="utf-8") as f:
f.write(result.markdown_content)
else:
print(f"❌ 转换失败: {result.error_message}")
# 运行
asyncio.run(main())
async def batch_convert():
converter = CleanConverter()
files = ["doc1.pdf", "doc2.docx", "slide.pptx"]
results = await converter.convert_files(files)
for result in results:
if result.success:
print(f"✅ {result.file_id}")
else:
print(f"❌ {result.file_id}: {result.error_message}")
asyncio.run(batch_convert())
from converter_engine import CleanConverter, ConversionConfig, FileManagementConfig
config = ConversionConfig(
work_temp_dir="/tmp/converter", # 工作目录
log_level="INFO", # 日志级别
file_management=FileManagementConfig(
keep_work_files=False, # 是否保留临时文件
debug_mode=False # 调试模式
)
)
converter = CleanConverter(config)
from converter_engine import ObsUploadConfig
obs_config = ObsUploadConfig(
enabled=True,
obs_config={
"access_key": "your_access_key",
"secret_key": "your_secret_key",
"endpoint": "obs.cn-north-4.myhuaweicloud.com",
"bucket": "your_bucket",
"region": "cn-north-4"
},
upload_types=["image"], # 只上传图片
replace_links=True # 替换Markdown中的链接
)
config = ConversionConfig(obs_upload=obs_config)
converter = CleanConverter(config)
创建 .env
文件:
# 基础配置
WORK_TEMP_DIR=/tmp/converter
LOG_LEVEL=INFO
DEBUG_MODE=false
# OBS配置
OBS_UPLOAD_ENABLED=true
OBS_ACCESS_KEY=your_access_key
OBS_SECRET_KEY=your_secret_key
OBS_ENDPOINT=obs.cn-north-4.myhuaweicloud.com
OBS_BUCKET=your_bucket
OBS_REGION=cn-north-4
然后加载配置:
from converter_engine import load_config_from_env
config = load_config_from_env()
converter = CleanConverter(config)
# 指定PDF转换方法
result = await converter.convert_file("document.pdf", "marker")
# 指定图片OCR方法
result = await converter.convert_file("image.png", "paddleocr")
# 批量转换时指定不同方法
methods = {
"doc1.pdf": "marker",
"doc2.pdf": "docling",
"image.png": "paddleocr"
}
results = await converter.convert_files(files, methods)
config = ConversionConfig(
file_management=FileManagementConfig(
debug_mode=True # 启用调试模式,保留所有临时文件
),
log_level="DEBUG" # 详细日志
)
converter = CleanConverter(config)
result = await converter.convert_file("document.pdf")
# 调试模式下可以查看工作目录
print(f"工作目录: {result.work_dir}")
- 安装指南 - 详细的安装说明和常见问题解决
- 详细使用指南 - 完整的功能说明和配置选项
- 使用示例 - 各种使用场景的代码示例
- 第三方工具许可证 - 集成工具的许可证说明
- 贡献指南 - 如何参与项目开发
- 更新日志 - 版本历史和更新记录
from converter_engine import CleanConverter, ConversionConfig, FileManagementConfig, ObsUploadConfig
# 所有参数都是可选的,可以完全使用默认配置
converter = CleanConverter() # 使用默认配置
# 或者自定义配置
config = ConversionConfig(
work_temp_dir=None, # [可选] 工作目录路径,默认: 系统临时目录
log_level="INFO", # [可选] 日志级别,默认: "INFO"
file_management=FileManagementConfig(
keep_work_files=False, # [可选] 是否保留工作文件,默认: False
debug_mode=False, # [可选] 调试模式,默认: False
keep_only_types=None, # [可选] 只保留特定类型文件,默认: None
custom_cleanup_func=None # [可选] 自定义清理函数,默认: None
),
obs_upload=ObsUploadConfig(
enabled=False, # [可选] 是否启用OBS上传,默认: False
obs_config=None, # [可选] OBS配置字典,默认: None
upload_types=["image"], # [可选] 上传的文件类型,默认: ["image"]
storage_prefix="md", # [可选] 存储路径前缀,默认: "md"
replace_links=True, # [可选] 是否替换Markdown链接,默认: True
remove_local_image_links=True # [可选] 不上传时是否移除图片链接,默认: True
)
)
converter = CleanConverter(config)
参数说明:
- 🟢 全部可选:所有参数都有默认值,可以零配置启动
- 🔧 智能默认:默认配置适合大多数使用场景
- ⚙️ 渐进配置:可以只配置需要修改的部分
result = await converter.convert_file(
file_path="document.pdf", # [必需] 文件路径
conversion_method=None, # [可选] 指定转换方法,默认: 自动选择最佳方法
# PDF专用参数(可选)
max_pages=None, # [可选] 最大页数限制,默认: 无限制
langs="Chinese,English", # [可选] 语言设置,默认: "Chinese,English"
# OCR专用参数(可选)
y_tolerance=10, # [可选] Y坐标容差,默认: 10
paragraph_gap=30, # [可选] 段落间距阈值,默认: 30
confidence_threshold=0.5, # [可选] 置信度阈值,默认: 0.5
# PPT专用参数(可选)
disable_notes=True, # [可选] 是否禁用备注,默认: True
)
参数说明:
- 🔴 file_path: 唯一必需参数,其他参数都有合理的默认值
- 🟡 conversion_method: 不指定时自动选择可用的最佳转换器
- 🟢 格式专用参数: 根据文件类型自动使用对应参数
@dataclass
class ConversionResult:
file_id: str # 唯一文件ID(时间戳+UUID)
markdown_content: str # 转换后的Markdown内容
local_files: List[FileInfo] # 本地生成的文件列表
uploaded_files: List[UploadedFile] # 上传到云端的文件列表
success: bool # 转换是否成功
error_message: Optional[str] # 错误信息(失败时)
work_dir: Optional[Path] # 工作目录路径(调试时有用)
@dataclass
class FileInfo:
file_path: Path # 文件完整路径
file_id: str # 文件ID
file_name: str # 文件名
file_size: int # 文件大小(字节)
file_type: str # 文件类型:"image", "document", "file"
mime_type: str # MIME类型
@dataclass
class UploadedFile:
file_name: str # 原始文件名
file_size: int # 文件大小(字节)
upload_url: str # 上传后的访问URL
upload_type: str # 上传类型:"obs", "local"
object_key: Optional[str] # 对象存储的键名
# 启用调试模式
config = ConversionConfig(
file_management=FileManagementConfig(
debug_mode=True, # 强制保留所有中间文件
keep_work_files=True # 保留工作文件
),
log_level="DEBUG" # 详细日志输出
)
converter = CleanConverter(config)
result = await converter.convert_file("document.pdf")
if result.success:
print(f"工作目录: {result.work_dir}")
print(f"生成文件数: {len(result.local_files)}")
# 查看所有生成的文件
for file_info in result.local_files:
print(f"- {file_info.file_name} ({file_info.file_type})")
调试模式特性:
- ✅ 保留所有中间文件和临时目录
- ✅ 输出详细的转换过程日志
- ✅ 提供工作目录路径便于检查
- ✅ 显示每个转换步骤的文件生成情况
# 方式1:配置中指定
config = ConversionConfig(work_temp_dir="/custom/work/dir")
# 方式2:环境变量
import os
os.environ['WORK_TEMP_DIR'] = '/custom/work/dir'
# 方式3:检查当前工作目录状态
from converter_engine import work_dir_config
status = work_dir_config.get_status()
print(f"工作目录: {status['base_dir']}")
print(f"可写: {status['writable']}")
print(f"子目录数: {status['subdirs_count']}")
print(f"总大小: {status['total_size_mb']} MB")
# 策略1: 上传到OBS并替换链接
config = ConversionConfig(
obs_upload=ObsUploadConfig(
enabled=True,
replace_links=True, # 替换为OBS链接
remove_local_image_links=False
)
)
# 策略2: 保留本地图片链接
config = ConversionConfig(
obs_upload=ObsUploadConfig(
enabled=False,
remove_local_image_links=False # 保留本地链接
)
)
# 策略3: 移除所有图片链接
config = ConversionConfig(
obs_upload=ObsUploadConfig(
enabled=False,
remove_local_image_links=True # 移除图片链接,保留文本标记
)
)
链接处理效果对比:
# 原始: 
# OBS替换: 
# 保留本地: 
# 移除链接: *[图片]*
obs_config = {
"access_key": "your_access_key", # 访问密钥
"secret_key": "your_secret_key", # 秘密密钥
"endpoint": "obs.cn-north-4.myhuaweicloud.com", # 终端点
"bucket": "your_bucket", # 存储桶名称
"region": "cn-north-4" # 区域
}
config = ConversionConfig(
obs_upload=ObsUploadConfig(
enabled=True,
obs_config=obs_config,
upload_types=["image", "document"], # 上传文件类型
storage_prefix="projects/docs", # 存储路径前缀
replace_links=True # 替换Markdown链接
)
)
converter = CleanConverter(config)
result = await converter.convert_file("document.pdf")
# 查看上传结果
for uploaded_file in result.uploaded_files:
print(f"文件: {uploaded_file.file_name}")
print(f"URL: {uploaded_file.upload_url}")
print(f"大小: {uploaded_file.file_size} bytes")
OBS存储路径结构:
bucket/
├── projects/docs/20241201_123456_abc12345/ # storage_prefix/file_id/
│ ├── image1.png
│ ├── image2.jpg
│ └── document.md
converter = CleanConverter()
# 查看引擎状态
converter.print_status()
# 获取可用转换器信息
status = converter.get_converter_status()
print(status)
- 检查依赖: 确保安装了对应格式的转换工具
- 启用调试: 设置
debug_mode=True
查看详细错误 - 尝试其他方法: 如marker失败可尝试docling
- PDF: marker(推荐), docling, mineru
- DOCX: docling, python-docx
- PPT: pptx2md(推荐), docling
- 图片: paddleocr(推荐), easyocr, tesseract
# PDF转换(选择一个)
pip install marker-pdf # 推荐,质量最高
pip install docling # 通用,速度快
# PPT转换
pip install pptx2md # 专业PPT转换
# 图片OCR(选择一个)
pip install paddleocr # 推荐,中文支持好
pip install easyocr # 多语言支持
# 方式1: 直接复制整个 converter_engine 目录到你的项目
cp -r /path/to/extractToMarkdown/converter_engine /your/project/
# 方式2: 作为 Git 子模块引入
cd /your/project
git submodule add <repository_url> converter_engine
# 方式3: 安装为 Python 包(如果已打包)
pip install converter-engine
# 激活你的项目虚拟环境
conda activate your-env # 或 source venv/bin/activate
# 安装基础依赖
pip install asyncio pathlib dataclasses typing
# 安装转换工具依赖(按需选择)
pip install marker-pdf # PDF转换
pip install docling # 通用转换
pip install pptx2md # PPT转换
pip install paddleocr # 图片OCR
# your_project/document_service.py
import asyncio
import sys
from pathlib import Path
# 添加 converter_engine 到 Python 路径
sys.path.append(str(Path(__file__).parent / "converter_engine"))
from converter_engine import CleanConverter, ConversionConfig
class DocumentService:
def __init__(self):
# 使用项目专用配置
config = ConversionConfig(
work_temp_dir=str(Path(__file__).parent / "temp"),
log_level="INFO"
)
self.converter = CleanConverter(config)
async def convert_document(self, file_path: str) -> dict:
"""转换文档为Markdown"""
try:
result = await self.converter.convert_file(file_path)
return {
"success": result.success,
"content": result.markdown_content,
"file_id": result.file_id,
"error": result.error_message
}
except Exception as e:
return {"success": False, "error": str(e)}
# 使用示例
async def main():
service = DocumentService()
result = await service.convert_document("document.pdf")
print(result)
if __name__ == "__main__":
asyncio.run(main())
# 安装华为云OBS SDK
pip install obs-sdk-python
# 如果你的项目已有其他云存储,可以扩展上传器
# config/obs_config.py
import os
from converter_engine import ConversionConfig, ObsUploadConfig
def get_obs_config():
"""从环境变量或配置文件加载OBS配置"""
obs_config = {
"access_key": os.getenv("HUAWEI_OBS_ACCESS_KEY"),
"secret_key": os.getenv("HUAWEI_OBS_SECRET_KEY"),
"endpoint": os.getenv("HUAWEI_OBS_ENDPOINT", "obs.cn-north-4.myhuaweicloud.com"),
"bucket": os.getenv("HUAWEI_OBS_BUCKET"),
"region": os.getenv("HUAWEI_OBS_REGION", "cn-north-4")
}
# 检查必需配置
if not all([obs_config["access_key"], obs_config["secret_key"], obs_config["bucket"]]):
return None
return ConversionConfig(
obs_upload=ObsUploadConfig(
enabled=True,
obs_config=obs_config,
upload_types=["image"],
storage_prefix=f"documents/{os.getenv('PROJECT_NAME', 'default')}",
replace_links=True
)
)
# 在你的服务中使用
from config.obs_config import get_obs_config
config = get_obs_config()
if config:
converter = CleanConverter(config)
print("✅ OBS上传已启用")
else:
converter = CleanConverter() # 使用默认配置
print("⚠️ OBS未配置,使用本地模式")
# .env 或环境变量
# OBS配置
HUAWEI_OBS_ACCESS_KEY=your_access_key
HUAWEI_OBS_SECRET_KEY=your_secret_key
HUAWEI_OBS_ENDPOINT=obs.cn-north-4.myhuaweicloud.com
HUAWEI_OBS_BUCKET=your_project_bucket
HUAWEI_OBS_REGION=cn-north-4
PROJECT_NAME=my_project
# 转换器配置
WORK_TEMP_DIR=/tmp/my_project_converter
LOG_LEVEL=INFO
-
敏感信息管理
# ❌ 不要硬编码敏感信息 obs_config = {"access_key": "hardcoded_key"} # ✅ 使用环境变量或密钥管理服务 obs_config = {"access_key": os.getenv("OBS_ACCESS_KEY")}
-
权限控制
# 确保工作目录权限正确 chmod 755 /tmp/converter chown app_user:app_group /tmp/converter
your_project/
├── converter_engine/ # 转换引擎(复制或子模块)
├── config/
│ ├── __init__.py
│ └── converter_config.py # 转换器配置
├── services/
│ └── document_service.py # 文档服务封装
├── temp/ # 临时工作目录
├── requirements.txt # 包含转换器依赖
└── .env # 环境变量配置
-
文件权限
# 确保应用有临时目录写权限 mkdir -p /app/temp chown -R app_user:app_group /app/temp
-
依赖管理
# Dockerfile 示例 FROM python:3.9 # 安装系统依赖(如果需要) RUN apt-get update && apt-get install -y \ tesseract-ocr \ libreoffice \ && rm -rf /var/lib/apt/lists/* # 复制转换引擎 COPY converter_engine/ /app/converter_engine/ # 安装Python依赖 COPY requirements.txt . RUN pip install -r requirements.txt
-
资源限制
# 控制转换器并发数 import asyncio semaphore = asyncio.Semaphore(3) # 最多3个并发转换 async def limited_convert(file_path): async with semaphore: return await converter.convert_file(file_path)
-
健康检查
def health_check(): """检查转换器健康状态""" try: converter = CleanConverter() status = converter.get_converter_status() return {"status": "healthy", "converters": status} except Exception as e: return {"status": "unhealthy", "error": str(e)}
如果你的项目使用AWS S3、阿里云OSS等其他云存储:
# 扩展上传器(可选)
from converter_engine.uploader import BaseUploader, UploadResult
class S3Uploader(BaseUploader):
def __init__(self, s3_config):
self.s3_client = boto3.client('s3', **s3_config)
async def upload_file(self, file_path: str, file_type: str) -> UploadResult:
# 实现S3上传逻辑
pass
欢迎提交Issue和Pull Request!在贡献之前,请确保:
- 遵循现有的代码风格
- 添加适当的测试
- 更新相关文档
本项目基于 MIT License 开源。
- 本项目的MIT许可证仅适用于项目本身的代码
- 项目集成的第三方工具(如marker、mineru、docling等)具有各自的开源协议
- 使用者需要遵守所有相关第三方工具的许可证要求
- 本项目仅提供对这些工具的封装和集成,不改变其原有许可证条款
感谢以下开源项目:
- marker-pdf - 高质量PDF转换
- docling - 通用文档处理
- PaddleOCR - 中文OCR识别
- pptx2md - PowerPoint转换
如有问题或建议,请通过GitHub联系:
- 创建 Issue - 问题报告和功能建议
- 提交 Pull Request - 代码贡献
Made with ❤️ by Solming
async def upload_file(self, file_path, object_key=None, **kwargs):
# 实现S3上传逻辑
pass
def is_available(self):
# 检查S3是否可用
pass
from converter_engine.uploader import uploader_manager uploader_manager.register_uploader("s3", S3Uploader(s3_config))
## 📄 许可证
本项目采用 MIT 许可证。