面向开发者和AI助手,提供系统架构、模块关系和代码定位信息
软件名称: 公文转换器 (Docwen)
软件全称: 公文图表格式转换软件
项目定位: 本地运行的公文格式转换工具,支持 Word ↔ Markdown ↔ Excel 多向转换
本地运行的公文格式转换工具,支持 Word ↔ Markdown ↔ Excel 多向转换,内置文本校对系统。
✅ 完全离线运行 - 数据不出本地,网络深度隔离
✅ 智能识别公文元素 - 三轮评分算法,准确率高
✅ 基于模板的格式生成 - 灵活可定制,符合规范
✅ 自定义规则的文本校对 - 规则驱动,精准标注
| 类别 | 技术 | 版本要求 | 用途 |
|---|---|---|---|
| 核心语言 | Python | 3.12+ | 主要开发语言 |
| GUI框架 | ttkbootstrap | - | 现代化主题界面 |
| GUI框架 | tkinter | 内置 | 图形用户界面基础 |
| 文档处理 | python-docx | - | Word文档操作 |
| 表格处理 | openpyxl | - | Excel文档操作 |
| 版式处理 | PyMuPDF | - | PDF文件处理 |
| 版式处理 | easyofd | - | OFD文件处理 |
| 数据处理 | pandas | - | 表格数据解析 |
| 数据格式 | PyYAML | - | YAML解析与生成 |
| 配置管理 | tomlkit | - | TOML配置文件 |
| 公式转换 | latex2mathml | - | LaTeX转MathML |
| 文档解析 | lxml | - | XML解析(docx底层处理) |
| 文件识别 | olefile | - | OLE文件识别(DOC/XLS实际格式检测) |
| OCR识别 | rapidocr_onnxruntime | ≥1.4.0 | 离线文字识别(包含ONNX Runtime) |
| 图片处理 | Pillow | - | 图片读写与基础转换 |
| 图片扩展 | pillow-heif | - | HEIC/HEIF图片支持 |
| PDF生成 | img2pdf | - | 图片转PDF |
| PDF提取 | pymupdf4llm | - | PDF→Markdown(版面友好) |
| PDF转换 | pdf2docx | - | PDF→DOCX(兜底方案) |
| Windows自动化 | pywin32 | - | Word/Excel COM接口(质量更佳的转换路径) |
| GUI增强 | tkinterdnd2 | - | 拖拽文件支持 |
| 数值计算 | numpy | - | 图片/表格处理辅助 |
| 构建工具 | PyInstaller | - | 应用打包(dev可选依赖) |
| 进程通信 | watchdog | - | 文件系统监控 |
docwen/
├── assets/ # 图标与截图等资源
├── configs/ # 配置文件(当前 18 个)
├── doc/ # 文档
├── samples/ # 示例文件
├── src/
│ └── docwen/ # 核心代码(Python包)
│ ├── bootstrap.py # 统一启动器
│ ├── cli_run.py # CLI入口(main 在此,脚本: docwen)
│ ├── gui_run.py # GUI入口(main 在此,脚本: docwen-gui)
│ ├── cli/ # CLI实现(含 i18n.py)
│ ├── config/ # 配置管理(ConfigManager + schemas/)
│ ├── converter/ # 转换引擎(docx2md/md2docx/md2xlsx/xlsx2md/pdf2md/formats/)
│ ├── docx_spell/ # 校对引擎
│ ├── gui/ # GUI界面(components/core/settings)
│ │ └── settings/ # 设置对话框(含 editors/ 子目录)
│ ├── i18n/ # 国际化模块
│ │ └── locales/ # 语言包(当前约 11 个,以仓库为准)
│ ├── ipc/ # 进程间通信
│ ├── security/ # 安全模块
│ ├── services/ # 服务层
│ │ └── strategies/ # 策略层(按类别子包组织)
│ │ ├── document/
│ │ ├── spreadsheet/
│ │ ├── image/
│ │ ├── layout/
│ │ ├── markdown/
│ │ └── operations/
│ ├── table_merger/ # 表格汇总工具
│ ├── template/ # 模板系统
│ └── utils/ # 工具函数库
├── templates/ # 模板文件(多语言)
├── tests/ # 单元测试
├── scripts/ # 辅助脚本(可能在部分发布/打包场景被忽略提交)
├── models/ # (可选)OCR模型目录(默认不纳入仓库)
│ └── rapidocr/ # RapidOCR ONNX模型文件(需要时下载放置)
└── pyproject.toml # 依赖与打包配置
src/docwen/services/:用例层入口与批量编排(负责“做什么/怎么选策略/怎么组织批量”)src/docwen/services/strategies/:策略注册与动作实现适配(负责“选择哪条转换路径并调用 converter”)src/docwen/converter/:具体格式转换实现与算法细节(负责“怎么转换”)src/docwen/gui//src/docwen/cli/:交互层与输出展示(尽量薄,只组装请求与展示结果)configs/:运行期可编辑的 TOML 配置文件(用户/打包后可直接修改)src/docwen/config/:配置 schema、读取与访问器(代码侧的配置系统实现)tests/:单元/契约测试;tests/fixtures/golden/用于锁定对外 JSON 输出契约
本文档中的代码块分为两类:
- API 示例:用于说明真实可调用接口,函数名/参数与当前实现对齐
- 流程伪代码:用于描述数据流与步骤,变量名/函数名可能是示意
| 模块路径 | 主要功能 | 关键入口 | 依赖模块 |
|---|---|---|---|
| bootstrap.py | 应用初始化 | initialize_app() |
security, config |
| config/ | 配置管理 | ConfigManager(单例 + 10个Mixin) |
schemas, toml_operations |
| converter/docx2md/ | DOCX→MD | convert_docx_to_md() |
gongwen/scorer, shared/* |
| converter/md2docx/ | MD→Word | convert() |
docx_processor, template |
| converter/md2xlsx/ | MD→Excel | convert() |
placeholder_processor |
| converter/xlsx2md/ | Excel→MD | convert_spreadsheet_to_md() |
pandas, openpyxl |
| converter/pdf2md/ | PDF→MD | extract_pdf_with_pymupdf4llm() |
pymupdf4llm |
| converter/formats/layout/ | PDF→DOCX/OFD→PDF 等 | pdf_to_docx(), ofd_to_pdf(), xps_to_pdf() |
pywin32/pdf2docx/easyofd |
| converter/smart_converter.py | 智能转换路径规划 | SmartConverter.convert() |
各格式转换器 |
| table_merger/core.py | 表格汇总 | merge_tables() |
openpyxl |
| converter/formats/spreadsheet/csv_convert.py | CSV↔XLSX | csv_to_xlsx(), xlsx_to_csv() |
pandas |
| converter/formats/ | 格式支持 | convert_image(), office_to_docx(), office_to_xlsx() |
PIL, pywin32 |
| docx_spell/core.py | 校对核心 | process_docx() |
spell_checker |
| docx_spell/spell_checker.py | 文本校对 | TextValidator |
config |
| docx_spell/utils.py | 校对工具 | plan_run_splits(), rebuild_paragraph_with_splits() |
docx_utils |
| gui/core/ | GUI核心 | MainWindow, MainWindowLogic |
components, services |
| gui/components/ | UI组件 | 约 12 个组件类(以仓库为准) | dpi_utils |
| gui/settings/ | 设置对话框 | 多个设置页 + editors 子模块 | config |
| services/strategies/ | 策略层 | register_*(), get_strategy() |
converter, docx_spell |
| template/loader.py | 模板加载 | TemplateLoader.get_template_path(), load_docx_template() |
- |
| security/network_isolation.py | 网络隔离 | initialize_network_isolation() |
- |
| ipc/ | 进程间通信 | SingleInstance, FileIPC |
watchdog |
| i18n/ | 国际化支持 | I18nManager, StyleResolver |
config |
| utils/ | 工具函数库 | 当前 21 个工具模块(以仓库为准) | - |
关键入口定位(常用代码跳转点):
- 启动:
src/docwen/bootstrap.py→initialize_app() - 策略查找:
src/docwen/services/strategies/__init__.py→get_strategy() - 配置合并:
src/docwen/config/config_manager.py→_reload_config_block() - 输出落盘:
src/docwen/utils/workspace_manager.py→finalize_output()/save_output_with_fallback() - 错误模型:
src/docwen/errors.py→DocWenError/ExitCode
| 配置文件 | ConfigManager方法 | 主要配置项 | 用途 |
|---|---|---|---|
| gui_config.toml | get_gui_config_block() |
window, theme, transparency, template | GUI界面设置 |
| logger_config.toml | get_logger_config_block() |
logging | 日志级别和行为 |
| conversion_config.toml | get_conversion_config_block() |
docx_to_md, md_to_docx, syntax, code_detection, horizontal_rule | 格式保留配置(DOCX↔MD)、分隔符转换配置 |
| heading_numbering_add.toml | get_heading_numbering_config_block() |
schemes, number_styles | 标题序号方案(MD→DOCX添加序号) |
| heading_numbering_clean.toml | get_numbering_patterns_block(), get_cleaning_rules() |
settings, rules | 序号清理规则(DOCX→MD清除序号) |
| link_config.toml | get_link_config_block() |
format, embed_links, embedding | 链接嵌入和格式 |
| conversion_defaults.toml | get_conversion_defaults_block() |
document, spreadsheet, image, layout, text | 文件处理默认设置 |
| optimization_config.toml | get_optimization_config_block() |
settings, types | 优化配置 |
| output_config.toml | get_output_config_block() |
directory, behavior, intermediate_files | 输出目录和行为 |
| proofread_config.toml | get_proofread_config_block() |
engine, skip | 校对主配置 |
| proofread_symbols.toml | get_proofread_symbols_block() |
symbol_pairing, symbol_map | 符号校对规则 |
| proofread_typos.toml | get_proofread_typos_block() |
typos | 错别字映射 |
| proofread_sensitive.toml | get_proofread_sensitive_block() |
sensitive_words | 敏感词规则 |
| software_priority.toml | get_software_priority_block() |
default_priority, special_conversions | Office软件优先级 |
| style_code.toml | get_style_code_block() |
docx_to_md, md_to_docx | 代码样式配置(Code Block/Inline Code) |
| style_formula.toml | get_style_formula_block() |
md_to_docx | 公式样式配置(Formula Block/Inline Formula) |
| style_quote.toml | get_style_quote_block() |
docx_to_md, md_to_docx | 引用样式配置(Quote 1-9) |
| style_table.toml | get_style_table_block() |
md_to_docx | 表格样式配置(Three Line Table/Table Content) |
组织方式: services/strategies/ 采用“装饰器注册表 + 显式清单(registry.py)+ 按需导入”的机制:按文件类别拆分子包;必要时可全量加载;部分格式互转策略通过工厂批量动态注册。
| 类别 | 策略子包 | 典型策略类 | 注册方式 |
|---|---|---|---|
| 文档(document) | services/strategies/document/ |
DocxToMdStrategy, DocumentToPdfStrategy, DocxValidationStrategy,以及 services/strategies/document/format_conversion.py 批量互转 |
@register_conversion / @register_action |
| 表格(spreadsheet) | services/strategies/spreadsheet/ |
SpreadsheetToMarkdownStrategy、表格→PDF、CSV↔XLSX |
@register_conversion |
| Markdown(markdown) | services/strategies/markdown/ |
MdToDocxStrategy、MdToXlsxStrategy 等 |
@register_conversion |
| 图片(image) | services/strategies/image/ |
ImageFormatConversionStrategy(通用互转)、图片→PDF、图片→MD(含OCR) |
@register_conversion |
| 版式(layout) | services/strategies/layout/ |
LayoutToMarkdownStrategy、版式→PDF、版式→图片、PDF工具箱 |
@register_conversion / @register_action |
| 操作(operations) | services/strategies/operations/ |
MergeTablesStrategy、MD序号处理等 |
@register_action |
图片格式互转:
- 使用 1个通用策略类
ImageFormatConversionStrategy - 支持常见格式:JPEG/PNG/GIF/BMP/TIFF/WebP(并对 HEIC/HEIF 等做预处理)
- 注册方式:
@register_conversion(CATEGORY_IMAGE, CATEGORY_IMAGE)
| 工具模块 | 关键函数 | 功能说明 | 返回类型 |
|---|---|---|---|
| ocr_utils.py | get_ocr() |
OCR实例(单例) | RapidOCR |
| ocr_utils.py | extract_text_simple() |
纯文本提取 | str |
| ocr_utils.py | extract_text_with_sizes() |
带字号提取 | List[Dict] |
| path_utils.py | generate_output_path() |
生成输出文件路径 | str |
| file_type_utils.py | detect_actual_file_format() |
文件格式检测 | str |
| file_type_utils.py | validate_file_format() |
格式验证(含等价扩展名) | dict |
| link_processing.py | process_markdown_links() |
展开/处理嵌入链接与普通链接 | str |
| markdown_utils.py | format_image_link() |
图片链接格式化 | str |
| markdown_utils.py | format_md_file_link() |
MD文件链接格式化 | str |
| workspace_manager.py | prepare_input_file() |
创建安全输入副本 | str |
| workspace_manager.py | get_output_directory() |
获取输出目录 | str |
| yaml_utils.py | parse_yaml() |
解析YAML字符串 | Dict |
| yaml_utils.py | process_list_field() |
字段值归一化(列表/字符串/数字) | str |
| docx_utils.py | extract_format_from_rpr() |
从rPr元素提取格式信息 | dict |
| docx_utils.py | apply_body_formatting() |
应用格式到run | None |
| docx_utils.py | is_inside_fallback() |
检测元素是否在Fallback中 | bool |
| converter/docx2md/shared/break_processor.py | extract_paragraph_border_info() |
提取段落边框信息 | dict |
| converter/docx2md/shared/break_processor.py | detect_horizontal_rule_in_paragraph() |
检测分隔线段落 | bool |
| converter/docx2md/shared/break_processor.py | detect_page_or_section_break() |
检测分页符/分节符 | Tuple |
| converter/docx2md/shared/style_detector.py | detect_paragraph_style_type() |
段落样式检测 | Tuple |
| converter/docx2md/shared/style_detector.py | detect_run_style_type() |
Run样式检测 | str |
| converter/docx2md/shared/markdown_converter.py | convert_paragraph_to_markdown_with_styles() |
带样式转换 | Tuple |
| validation_utils.py | is_chinese() |
判断单字符是否为中文 | bool |
| date_utils.py | format_date() |
格式化日期 | str |
| font_utils.py | get_default_font() |
获取默认字体与字号 | Tuple[str, int] |
| heading_utils.py | NUMBERING_PLACEHOLDERS |
序号清理占位符定义(常量) | Dict |
| heading_utils.py | detect_heading_level() |
检测小标题级别并清理序号 | Tuple[str, int] |
| heading_utils.py | remove_heading_numbering() |
清除标题序号(从配置加载规则) | str |
| heading_numbering.py | add_numbering_to_md() |
为Markdown标题添加序号 | str |
| heading_numbering.py | get_formatter_from_config() |
从配置创建序号格式化器 | Optional[HeadingFormatter] |
| 设计模式 | 应用位置 | 具体实现 | 优势 |
|---|---|---|---|
| 单例模式 | ConfigManager | 全局唯一配置实例 | 避免重复加载配置 |
| 单例模式 | OCR实例 | 全局唯一OCR实例 | 避免重复初始化模型 |
| 策略模式 | services/strategies/ | 按类别组织的可插拔策略(含动态注册) | 易于扩展新格式 |
| 工厂模式 | template/loader.py | 模板对象创建 | 统一模板管理 |
| 工厂模式 | 动态策略生成 | _create_xxx_strategy() | 批量生成策略 |
| MVP模式 | gui/core/ | View-Presenter分离 | 界面与逻辑解耦 |
| 观察者模式 | GUI进度回调 | progress_callback机制 | 实时进度通知 |
| 装饰器模式 | 策略注册 | @register_conversion | 自动注册策略 |
CLI模式:
# 查看帮助
docwen --help
# 常用:导出为 Markdown
docwen convert document.docx --to md
# 不安装包时的等价方式
python -m docwen.cli_run convert document.docx --to mdGUI模式:
# 启动GUI
docwen-gui质量检查(推荐本地统一入口):
# 默认:ruff + pyright(core/gui/optional) + pytest fast
python tools/qa.py
# 跑完整测试(包含 integration/slow)
python tools/qa.py --suite full
# 只跑类型检查(跳过 ruff/pytest 可按需组合)
python tools/qa.py --skip-ruff --skip-pytest调试模式:
# 启用DEBUG日志
# 编辑 configs/logger_config.toml,设置 level = "DEBUG"| 类别 | 支持格式 | 输入 | 输出 | 备注 |
|---|---|---|---|---|
| 文本 | MD, TXT | ✅ | ✅(仅MD) | TXT 仅作为输入(按 Markdown 流程处理) |
| 文档 | DOCX, DOC, WPS, RTF, ODT | ✅ | ✅ | 旧格式自动转DOCX |
| 表格 | XLSX, XLS, ET, ODS, CSV | ✅ | ✅ | 旧格式自动转XLSX |
| 版式 | PDF, XPS, OFD | ✅ | ✅ | XPS/OFD自动转PDF |
| 图片 | JPEG, PNG, GIF, BMP, TIFF, WebP, HEIC | ✅ | ✅ | HEIC/BMP自动转PNG |
转换API:
# MD→DOCX
from docwen.converter.md2docx.core import convert
result = convert(md_path, output_path, template_name="模板名称")
# DOCX→MD
from docwen.converter.docx2md.core import convert_docx_to_md
result = convert_docx_to_md(docx_path, extract_image=True, extract_ocr=False)
# 校对
from docwen.docx_spell.core import process_docx
result = process_docx(docx_path, proofread_options={
"symbol_pairing": True,
"symbol_correction": True,
"typos_rule": True,
"sensitive_word": True,
})
# 策略调用
from docwen.services.strategies import get_strategy
strategy = get_strategy(source_format="docx", target_format="pdf")
result = strategy.execute(file_path, options={})配置API:
from docwen.config.config_manager import config_manager
# 获取配置
keep_images = config_manager.get_docx_to_md_keep_images()
link_settings = config_manager.get_markdown_link_style_settings()
window_width = config_manager.get_center_panel_width()
# 修改配置
config_manager.update_config_value("gui_config", "window", "default_height", 800)工具API:
# 路径生成
from docwen.utils.path_utils import generate_output_path
output = generate_output_path(
"test.md",
description="fromMd",
file_type="docx"
)
# 结果: test_20251129_161234_fromMd.docx
# 文件类型检测
from docwen.utils.file_type_utils import detect_actual_file_format
actual_format = detect_actual_file_format("file.doc") # 可能返回 'doc' 或 'docx'
# 链接处理
from docwen.utils.link_processing import process_markdown_links
expanded = process_markdown_links(md_text, source_file_path)
# OCR识别
from docwen.utils.ocr_utils import extract_text_simple
text = extract_text_simple("image.jpg")┌─────────────────────────────────────────────────────────────┐
│ 应用入口层 │
│ (gui_run.py, cli_run.py) │
└────────────────────┬────────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────┐
│ 统一启动器 │
│ (bootstrap.py) │
│ • 安全检查 • 网络隔离 • 路径初始化 │
└────────────────────┬────────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────┐
│ 核心功能层 │
├─────────────────────────────────────────────────────────────┤
│ config/ │ 配置管理(单例,100+方法) │
│ converter/ │ 转换引擎(多个子模块) │
│ docx_spell/ │ 校对引擎(规则驱动) │
│ gui/ │ 图形界面(MVP模式,约 25 个组件) │
│ cli/ │ 命令行界面 │
│ security/ │ 安全模块(网络隔离) │
│ services/ │ 服务策略层(按类别子包组织,显式清单+按需导入) │
│ template/ │ 模板系统(工厂模式 + 缓存) │
│ ipc/ │ 进程间通信(文件监控) │
│ utils/ │ 工具函数库(21个模块) │
└─────────────────────────────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────┐
│ 资源与配置层 │
│ configs/ templates/ assets/ (models可选)/ logs(运行时) │
└─────────────────────────────────────────────────────────────┘
bootstrap (启动器)
├─→ security (安全检查)
└─→ config (配置初始化)
gui/cli (界面层)
├─→ services.strategies (调用策略)
├─→ config (读取配置)
├─→ template (加载模板)
└─→ ipc (进程间通信,GUI专属)
services.strategies (策略层:装饰器注册表 + 显式清单 + 按需导入)
├─→ converter (转换核心)
├─→ docx_spell (校对核心)
└─→ utils (工具函数)
converter (转换引擎)
├─→ template (模板加载)
├─→ config (读取配置)
└─→ utils (工具函数)
用户操作 → GUI/CLI事件 → 策略选择 → 转换/校对 → 结果返回 → UI更新
关键设计:
- 策略模式: 所有转换通过策略层统一调度
- 临时目录保护: 使用
tempfile.TemporaryDirectory()保护原文件 - 统一输入副本:
prepare_input_file()为所有转换创建安全副本 - 路径规范化:
generate_output_path()统一生成带时间戳的输出文件名
📍 位置: src/docwen/config/
配置文件数量: 当前 19 个(以 configs/ 目录为准)
configs/
├── gui_config.toml # GUI设置
├── logger_config.toml # 日志配置
├── conversion_config.toml # 格式转换配置(DOCX↔MD格式保留、分隔符转换)
├── conversion_defaults.toml # 文件处理默认设置(提取、OCR、校对、汇总、压缩、DPI等)
├── heading_numbering_add.toml # 标题序号方案(添加序号)
├── heading_numbering_clean.toml # 序号清理规则(清除序号)
├── link_config.toml # 链接嵌入配置
├── output_config.toml # 输出配置
├── proofread_config.toml # 校对主配置
├── proofread_symbols.toml # 符号校对规则
├── proofread_typos.toml # 错别字映射表
├── proofread_sensitive.toml # 敏感词规则
├── software_priority.toml # Office软件优先级
├── style_code.toml # 代码样式配置(Code Block/Inline Code)
├── style_formula.toml # 公式样式配置(Formula Block/Inline Formula)
├── style_quote.toml # 引用样式配置(Quote 1-9)
├── style_table.toml # 表格样式配置(Three Line Table/Table Content)
├── field_processors.toml # 字段处理器(MD→DOCX 字段优化开关/locale)
└── optimization_config.toml # 优化配置
配置文件:configs/field_processors.toml
读取入口:src/docwen/converter/md2docx/field_registry.py(独立于 ConfigManager,直接读取并带缓存)
GUI 开关位置:设置 → 文本 → 字段优化(按当前界面语言过滤显示)
配置语义(简化):
[settings].order:处理器顺序(影响执行/合并顺序)[processors.<id>]:module:处理器模块路径(import 时完成注册)locales:适用语言(如["zh_CN"]/["*"])enabled:启用开关(GUI 勾选后立即写回)name/description:GUI 展示用元信息(name_key预留给多语言处理器)
核心类: ConfigManager
设计模式: 单例模式 + Mixin架构
架构: 核心类约15个方法 + 10个功能Mixin(共100+方法)
位置: config/schemas/__init__.py
CONFIG_FILES = {
"logger_config": "logger_config.toml",
"gui_config": "gui_config.toml",
"proofread_config": "proofread_config.toml",
"proofread_symbols": "proofread_symbols.toml",
"proofread_typos": "proofread_typos.toml",
"proofread_sensitive": "proofread_sensitive.toml",
"output_config": "output_config.toml",
"software_priority": "software_priority.toml",
"link_config": "link_config.toml",
"heading_numbering_add": "heading_numbering_add.toml",
"heading_numbering_clean": "heading_numbering_clean.toml",
"style_code": "style_code.toml",
"style_quote": "style_quote.toml",
"style_formula": "style_formula.toml",
"style_table": "style_table.toml",
"conversion_defaults": "conversion_defaults.toml",
"conversion_config": "conversion_config.toml",
"optimization_config": "optimization_config.toml",
}10个功能Mixin:
LoggerConfigMixin- 日志配置GUIConfigMixin- GUI配置ProofreadConfigMixin- 校对配置(4个文件)OutputConfigMixin- 输出配置SoftwareConfigMixin- 软件优先级LinkConfigMixin- 链接配置NumberingConfigMixin- 序号配置(2个文件)StyleConfigMixin- 样式配置(4个文件)ConversionConfigMixin- 转换配置(2个文件)OptimizationConfigMixin- 优化配置
Level 1: get_xxx_config_block() # 整个配置块(示意)
Level 2: get_xxx_config()/get_xxx_settings() # 子表(示意)
Level 3: get_xxx() # 具体值 getter(示意)
| 方法名 | 功能 | 返回类型 |
|---|---|---|
get_logger_config_block() |
获取日志配置块 | Dict |
get_gui_config_block() |
获取GUI配置块 | Dict |
get_link_config_block() |
获取链接配置块 | Dict |
get_conversion_defaults_block() |
获取文件处理默认配置块 | Dict |
get_conversion_config_block() |
获取转换行为配置块 | Dict |
get_output_config_block() |
获取输出配置块 | Dict |
get_proofread_config_block() |
获取校对主配置块 | Dict |
get_proofread_symbols_block() |
获取符号校对配置块 | Dict |
get_proofread_typos_block() |
获取错别字配置块 | Dict |
get_proofread_sensitive_block() |
获取敏感词配置块 | Dict |
get_software_priority_block() |
获取软件优先级配置块 | Dict |
get_heading_numbering_config_block() |
获取标题序号方案配置块 | Dict |
get_numbering_patterns_block() |
获取序号清理规则配置块 | Dict |
get_style_code_block() |
获取代码样式配置块 | Dict |
get_style_quote_block() |
获取引用样式配置块 | Dict |
get_style_formula_block() |
获取公式样式配置块 | Dict |
get_style_table_block() |
获取表格样式配置块 | Dict |
get_optimization_config_block() |
获取优化配置块 | Dict |
GUI配置子表:
| 方法名 | 功能 | 返回类型 |
|---|---|---|
get_window_config() |
获取窗口设置子表 | Dict |
get_component_config() |
获取组件设置子表 | Dict |
get_theme_config() |
获取主题设置子表 | Dict |
get_transparency_config() |
获取透明度设置子表 | Dict |
get_template_config() |
获取模板设置子表 | Dict |
链接配置子表:
| 方法名 | 功能 | 返回类型 |
|---|---|---|
get_link_format_config() |
获取链接格式配置 | Dict |
get_non_embed_links_config() |
获取非嵌入链接配置 | Dict |
get_embed_links_config() |
获取嵌入链接配置 | Dict |
get_embedding_config() |
获取嵌入详细配置 | Dict |
get_path_resolution_config() |
获取路径解析配置 | Dict |
get_link_error_handling_config() |
获取错误处理配置 | Dict |
其他子表方法: extraction_defaults_config, logging_config, output_directory_settings, output_behavior_settings 等
窗口布局配置:
get_center_panel_width()→ intget_batch_panel_width()→ intget_template_panel_width()→ intget_window_height()→ intget_default_mode()→ str ('single' or 'batch')
图片提取配置:
get_docx_to_md_keep_images()→ boolget_docx_to_md_enable_ocr()→ boolget_xlsx_to_md_keep_images()→ boolget_layout_to_md_keep_images()→ boolget_image_to_md_enable_ocr()→ bool
链接格式配置:
get_markdown_link_style_settings()→ Dict(包含4个链接格式设置)get_embed_links_config()→ Dict(包含enabled等配置项)get_max_embed_depth()→ intget_search_dirs()→ List[str]
软件优先级配置:
get_word_processors_priority()→ List[str]get_spreadsheet_processors_priority()→ List[str]get_document_to_pdf_priority()→ List[str]get_spreadsheet_to_pdf_priority()→ List[str]
配置修改方法:
update_config_value()→ boolupdate_config_section()→ boolreload_configs()→ None
📍 位置: configs/link_config.toml
🎯 功能: 控制Markdown链接处理行为,支持Obsidian等知识管理工具的链接格式
配置节结构(6个):
[format]
# 生成MD时的链接格式
image_link_format = "wiki" # "markdown" 或 "wiki"
image_embed = true # 是否嵌入显示
md_file_link_format = "wiki" # "markdown" 或 "wiki"
md_file_embed = true # 是否嵌入显示
[non_embed_links]
# MD转文档/表格时处理普通链接
wiki_mode = "extract_text" # "keep", "extract_text", "remove"
markdown_mode = "extract_text" # "keep", "extract_text", "remove"
[embed_links]
# MD转文档/表格时处理嵌入链接
enabled = true # 总开关
image_mode = "embed" # "keep", "extract_text", "remove", "embed"
md_file_mode = "embed" # "keep", "extract_text", "remove", "embed"
[embedding]
# 嵌入详细配置
max_depth = 3 # 最大递归深度
[path_resolution]
# 路径解析配置
search_dirs = [".", "assets", "images", "attachments"]
[error_handling]
# 错误处理配置
file_not_found = "placeholder"
file_not_found_text = "⚠️ 文件未找到: {filename}"
detect_circular = true
circular_reference = "placeholder"
circular_text = "⚠️ 检测到循环引用: {filename}"
max_depth_reached = "placeholder"
max_depth_text = "⚠️ 达到最大嵌入深度"程序启动
↓
bootstrap.initialize_app()
↓
ConfigManager实例化(单例模式)
↓
加载 CONFIG_FILES 中定义的全部配置块(当前 18 个)
├─ 读取用户配置
├─ 与默认配置深度合并
└─ 存储在内存中
↓
各模块通过 config_manager 访问配置
[window]
center_panel_width = 400
left_panel_width = 400 # 批量面板
right_panel_width = 300 # 模板面板
center_panel_screen_x = 0
window_y = 0
default_mode = "single"
default_height = 740
min_height = 720
auto_center = true
remember_gui_state = true
[component]
file_drop_height = 200
[theme]
default_theme = "morph"
[transparency]
enabled = true
default_value = 0.95
[template]
md_default_template = "docx" # 或 "xlsx"[default_priority]
word_processors = ["wps_writer", "msoffice_word", "libreoffice"]
spreadsheet_processors = ["wps_spreadsheets", "msoffice_excel", "libreoffice"]
[special_conversions]
odt = ["msoffice_word", "libreoffice"]
ods = ["msoffice_excel", "libreoffice"]
pdf_to_office = ["msoffice_word", "libreoffice"]
document_to_pdf = ["wps_writer", "msoffice_word", "libreoffice"]
spreadsheet_to_pdf = ["wps_spreadsheets", "msoffice_excel", "libreoffice"][directory]
mode = "source" # 或 "custom"
custom_path = ""
create_date_subfolder = false
date_folder_format = "%Y-%m-%d"
[behavior]
auto_open_folder = false
[intermediate_files]
save_to_output = true # 是否保存中间文件📍 位置: src/docwen/bootstrap.py
🎯 功能: 所有应用入口的统一初始化点
核心函数:
def initialize_app() -> None职责:
- 确保包路径正确
- 执行安全防护检查
- 初始化网络隔离
- 设置日志系统
被调用位置:
src/docwen/gui_run.py- GUI入口(实际main()在此,启动前调用)src/docwen/cli_run.py- CLI入口(实际main()在此,启动前调用)
已在第4章详细说明,参见 4. 配置系统
📍 位置: src/docwen/converter/
实际结构(当前 7 个子模块):
converter/
├── __init__.py
├── smart_converter.py # 智能转换路径规划
├── docx2md/ # Word → Markdown(3个子目录)
├── md2docx/ # Markdown → Word(3个子目录)
├── md2xlsx/ # Markdown → Excel(3个文件)
├── xlsx2md/ # Excel → Markdown(3个文件)
├── pdf2md/ # PDF → Markdown(3个文件)
└── formats/ # 格式转换层(6个子模块)
├── common/ # 公共模块
├── document/ # 文档转换
├── spreadsheet/ # 表格转换(含 csv_convert.py)
├── layout/ # 版式转换
├── image/ # 图片转换
└── pdf_export/ # PDF导出
注意:
table_merger是独立模块,位于src/docwen/table_merger/- CSV↔XLSX 转换功能在
formats/spreadsheet/csv_convert.py
职责分离架构:
- 策略层: 控制文件命名,生成完整的
output_path - 底层转换函数: 接收完整路径,专注格式转换
- 统一输入副本: 所有转换前先调用
prepare_input_file()创建input.{ext}副本 - 中间文件: 统一使用 "from原始格式" 描述风格
统一接口设计:
所有底层转换函数遵循相同的接口模式:
- 接收完整的
output_path参数(非output_dir) original_source_path/original_file_path参数用于:- 链接嵌入功能的路径解析
- 图片文件的规范化命名
- 策略层通过
generate_output_path()生成标准化路径
中间文件命名规范:
所有中间文件使用 "from原始格式" 的描述方式:
| 转换类型 | 中间文件命名示例 |
|---|---|
| DOC→DOCX | 文件_20251129_161234_fromDoc.docx |
| XLS→XLSX | 文件_20251129_161234_fromXls.xlsx |
| ODT→DOCX | 文件_20251129_161234_fromOdt.docx |
| BMP→PNG | 图片_20251129_161234_fromBmp.png |
设计优势:
- 命名逻辑集中在策略层,易于维护
- 底层函数接口简洁明确
- 所有文件命名风格一致
- 中间文件具有可读性,便于追踪转换历史
📍 位置: src/docwen/utils/formula_utils.py
核心功能: 实现 DOCX (OMML) 和 Markdown (LaTeX) 之间数学公式的双向转换。
技术原理:
- MD → DOCX: LaTeX → (latex2mathml) → MathML → (自定义转换) → OMML
- DOCX → MD: OMML → (自定义转换) → MathML → (自定义转换) → LaTeX
支持特性:
- 基础运算: 四则运算、分数、根式
- 高级结构: 求和 (
\sum)、积分 (\int)、极限 (\lim)、矩阵(基础支持) - 特殊符号: 完整的希腊字母表、常用数学符号映射
- 复杂下标: 同时上下标 (
msubsup)、n次根 (mroot)
关键模块:
utils/formula_utils.py: 核心转换逻辑,OMML/MathML 节点递归处理converter/docx2md/shared/formula_processor.py: DOCX 段落中的公式提取与转换converter/md2docx/handlers/formula_handler.py: Markdown 文本中的公式解析与插入
字符样式的技术限制:
字符样式(Inline Formula)对 OMML 公式只能部分控制格式:
| 属性 | 字符样式能否控制 | 说明 |
|---|---|---|
| 下划线 | ✅ 可以 | <w:u> 生效 |
| 颜色 | ✅ 可以 | <w:color> 生效 |
| 字号 | ✅ 可以 | <w:sz> 生效 |
| 字体 | ❌ 无效 | Word 公式使用专用数学字体系统 |
| 粗体 | ❌ 无效 | 由 <m:sty> 控制,不受字符样式影响 |
| 斜体 | ❌ 无效 | 由 <m:sty> 控制,不受字符样式影响 |
原因:Word 公式文本使用 <m:t> 元素而非普通的 <w:t>,公式的粗体/斜体由 <m:rPr><m:sty m:val="..."/> 数学属性控制,Word 默认使用 Cambria Math 字体渲染公式,忽略字符样式的字体设置。
📍 位置: src/docwen/converter/docx2md/
目录结构(3个子目录,约 19 个文件):
docx2md/
├── __init__.py # 模块入口
├── core.py # 路由入口(纯分发逻辑)
├── shared/ # 共享处理器
│ ├── __init__.py
│ ├── conversion_context.py # 转换上下文状态管理
│ ├── list_processor.py # 列表处理(预扫描、编号计数)
│ ├── break_processor.py # 边框组处理
│ ├── table_processor.py # 表格处理
│ ├── image_processor.py # 图片处理
│ ├── formula_processor.py # 公式处理
│ ├── note_processor.py # 脚注/尾注处理
│ ├── textbox_processor.py # 文本框处理
│ └── content_injector.py # 内容注入
├── simple/ # 通用简化模式
│ ├── __init__.py
│ ├── converter.py # 简化模式转换器
│ ├── paragraph_handler.py # 段落处理器
│ └── yaml_builder.py # YAML头部生成
└── gongwen/ # 公文文种
├── __init__.py
├── converter.py # 公文模式转换器
├── scorer.py # 公文元素评分器
├── content_generator.py # 内容生成器
└── extractor.py # 元素提取器
架构设计:
多文种支持架构,根据文档类型分发到对应转换器:
# core.py - 路由函数
def convert_docx_to_md(
docx_path: str,
extract_image: bool = True,
extract_ocr: bool = False,
optimize_for_type: str = None, # 文种类型参数
progress_callback: Optional[Callable[[str], None]] = None,
cancel_event: Optional[threading.Event] = None,
output_folder: Optional[str] = None,
original_file_path: Optional[str] = None
) -> dict参数说明:
optimize_for_type: 文种类型None- 简化模式(默认)"gongwen"- 公文优化模式- (可扩展其他类型)
original_file_path: 原始文件路径(可选)- 用于图片文件的规范化命名
- 当docx_path是临时副本时,使用此参数获取原始文件名
返回值结构:
{
'success': bool, # 转换是否成功
'main_content': str, # 主要markdown内容(含YAML头部)
'attachment_content': str, # 附件markdown内容(可选,仅公文模式)
'metadata': dict, # 提取的YAML元数据
'error': str # 错误信息(如果失败)
}两种转换模式:
1. 简化模式 (simple/converter.py)
适用于普通Word文档的基础转换:
- YAML元数据:只提取标题和副标题(2个字段)
- 段落处理:基于Word样式(Title、Subtitle、Heading 1-6)
- 无公文识别:不执行三轮评分算法
- 图片支持:完全支持图片提取和OCR
- 适用场景:报告、笔记、普通文档等
2. 公文优化模式 (gongwen/converter.py)
专为标准公文设计:
- YAML元数据:提取14个公文专用字段
- 三轮评分识别:智能识别公文元素
- 附件处理:附件内容单独输出为独立MD文件
- 图片支持:完全支持图片提取和OCR
- 适用场景:标准公文文档
共享功能 (converter/docx2md/shared/image_processor.py)
所有转换模式共享的图片处理功能:
process_image_with_ocr()- 根据选项生成图片或图片MD链接create_image_md_file()- 创建图片的MD文件(含OCR文本)extract_images_from_docx()- 从DOCX提取图片
公文模式的三轮评分识别流程:
第1轮:识别唯一性元素(得分≥80)
├─ 标题、发文字号、份号
├─ 密级、紧急程度
└─ 组合格式(份号+发文字号等)
第2轮:识别上下文相关元素(基于第1轮结果)
├─ 发文机关标志
├─ 印发机关
└─ 相对位置判断
第3轮:识别非唯一性元素
├─ 正文、附件内容
├─ 空图片段落识别
└─ 排除法 + 启发式规则
图片和OCR支持:
- OCR 依赖图片提取:不能只启用 OCR(extract_ocr=True 需要 extract_image=True)
- 两种处理场景:
- 提取图片(可选)→ 段落中插入图片链接
- 提取图片 + OCR(可选)→ 生成图片 OCR 结果文件,并在正文中插入链接
输出结构:
文件名_时间戳_fromDocx/
├── 文件名_时间戳_fromDocx.md # 主文件
├── 文件名_附件部分_时间戳_fromDocx.md # 附件文件(如有)
├── image_1.png # 图片(如勾选)
├── image_1.md # 图片 OCR 结果(需要勾选 OCR 且提取图片)
└── image_2.png / image_2.md
📍 位置: src/docwen/converter/md2docx/
目录结构(3个子目录,约 17 个文件):
md2docx/
├── __init__.py # 模块入口
├── core.py # 转换入口函数
├── processors/ # 【核心处理器】
│ ├── __init__.py
│ ├── docx_processor.py # DOCX文档处理(主处理流程)
│ ├── md_processor.py # Markdown解析
│ ├── placeholder_handler.py # 占位符处理
│ └── xml_processor.py # XML级别操作
├── handlers/ # 【元素处理器】
│ ├── __init__.py
│ ├── break_handler.py # 分页/分节/分隔线处理
│ ├── formula_handler.py # 公式处理
│ ├── list_handler.py # 列表处理
│ ├── note_handler.py # 脚注/尾注处理
│ ├── notes_part_handler.py # Word notes.xml处理
│ ├── numbering_handler.py # 编号处理
│ ├── table_handler.py # 表格创建与样式处理
│ └── text_handler.py # 文本格式化处理(MD格式→Word格式)
└── style/ # 【样式系统】
├── __init__.py
├── injector.py # 样式注入逻辑
├── templates.py # 样式XML模板定义
└── helper.py # 样式查找辅助函数
核心函数:
def convert(
md_path: str,
output_path: str, # 完整输出路径(由策略层生成)
*,
template_name: str, # 必需参数,无默认值
progress_callback: Optional[Callable[[str], None]] = None,
cancel_event: Optional[threading.Event] = None,
original_source_path: Optional[str] = None,
options: Optional[dict] = None
) -> Optional[str]参数说明:
original_source_path: 原始源文件路径(可选)- 用于链接嵌入功能的路径解析
- 用于标题提取:当md_path是临时副本时,使用此参数提取文件名作为标题
- 传递到_convert_internal()和_get_title_from_yaml()用于正确的标题提取
工作流程(统一流程):
1. 创建临时目录(tempfile.TemporaryDirectory)
2. 创建input.md副本(prepare_input_file)
3. 读取并解析MD文件
├─ 提取YAML头部
├─ 提取MD正文
└─ 展开嵌入链接(如果启用)
├─ 处理YAML字段中的链接(递归)
├─ 处理正文中的链接
├─ ![[image.png]] → {{IMAGE:绝对路径}}
├─ ![[image.png|300]] / ![[image.png\\|300]] → {{IMAGE:绝对路径\\|300\\|}}
├─  → {{IMAGE:绝对路径\\|300\\|200}}
└─ ![[file.md]] → 读取并递归展开内容
4. 预处理YAML数据
├─ 提取标题(_get_title_from_yaml)
│ 优先级:YAML'标题'键 → YAML'aliases'键 → 原始文件名 → 默认值"标题"
├─ 附件说明格式化(悬挂缩进)
├─ 抄送机关处理
└─ 特殊字段处理(附注、日期等)
5. 处理MD正文 → 段落列表(md_processor)
6. 加载Word模板(template.loader)
7. 替换占位符(docx_processor)
├─ 标记特殊占位符
├─ 处理普通占位符(支持组规则)
├─ 插入正文
├─ 处理附件说明(悬挂缩进)
└─ 处理图片占位符 {{IMAGE:path}} / {{IMAGE:path|width|height}}(支持 \\| 转义)
8. 错别字检查(可选,spell_check_option)
9. 移动到输出目录
10. 保留中间文件(可选)
11. 临时目录自动清理
标题提取机制:
原始文件路径的传递链:
策略层 → convert() → _convert_internal() → _get_title_from_yaml()
关键设计:
- 转换使用临时副本 input.md 保护原文件
- original_source_path 参数传递原始文件路径
- _get_title_from_yaml() 从原始路径提取文件名作为标题
标题提取优先级:
1. YAML中的'标题'键
2. YAML中的'aliases'键(字符串或列表第一项)
3. 从md_path提取文件名(去除扩展名)
4. 默认值"标题"
注意:md_path参数接收的是原始文件路径(通过original_source_path传递),而非临时副本路径
占位符组规则:
PLACEHOLDER_RULES = {
"delete_paragraph_if_empty": [
["密级和保密期限"], # 单字段组
["份号", "发文字号"], # 多字段组
],
"delete_row_if_empty": [
["印发机关", "印发日期"], # 表格行
],
}关键机制:
- 只有组内所有字段都为空且在同一位置时才执行删除
- 优先级: delete_row > delete_cell > 正常替换
📍 位置: src/docwen/converter/md2xlsx/
目录结构(约 3 个文件):
md2xlsx/
├── __init__.py
├── core.py # 入口函数
└── placeholder_processor.py # Excel占位符处理
核心函数:
def convert(
md_path: str,
output_path: str, # 完整输出路径(由策略层生成)
*,
template_name: str,
progress_callback: Optional[Callable[[str], None]] = None,
cancel_event: Optional[threading.Event] = None,
original_source_path: Optional[str] = None
) -> Optional[str]工作流程(统一流程):
1. 创建临时目录
2. 创建input.md副本
3. 读取并解析MD文件
└─ 展开嵌入链接(与md2docx一致)
4. 提取模板占位符(分类为YAML字段和表格填充)
5. 创建YAML字段替换配置
6. 提取MD表格数据
7. 加载Excel模板(保存合并单元格信息)
8. 替换YAML字段占位符
9. 填充表格数据
├─ 列填充 {{↓字段}}
├─ 行填充 {{→字段}}
├─ 智能跳过合并单元格
└─ 检测只读单元格并添加批注
10. 恢复合并单元格
11. 处理图片占位符 {{IMAGE:path}} / {{IMAGE:path|width|height}}
12. 清理剩余占位符 → 保存文件
智能跳过机制:
- 合并单元格的非左上角:跳过单元格,不消耗数据项
- 只读单元格:添加批注,消耗数据项(不填充)
- 正常单元格:填充数据,消耗数据项
单元格格式处理:
- 分数(如1/3):转为公式
=1/3 - 超长数字(>15位):设置为文本格式防止科学计数法
- 短数字:保持数字格式
- 文本:清理HTML和零宽字符
📍 位置: src/docwen/converter/xlsx2md/
目录结构(约 3 个文件):
xlsx2md/
├── __init__.py
├── core.py # 核心转换逻辑
└── image_processor.py # 图片处理
核心函数:
def convert_spreadsheet_to_md(
file_path: str,
extract_image: bool = True,
extract_ocr: bool = False,
output_folder: Optional[str] = None,
original_file_path: Optional[str] = None
) -> str支持格式:
- XLSX - Excel工作簿(标准格式,支持图片提取)
- CSV - 逗号分隔值文件(标准格式,不支持图片)
注意: 旧格式(XLS, ET, ODS)应在策略层预处理为XLSX
核心算法: BFS数据块查找算法
def _find_blocks(df: pd.DataFrame) -> List[pd.DataFrame]算法特点:
- 使用**广度优先搜索(BFS)**查找数据块
- 数据块定义: 周围被空行/空列或边界包围的连通区域
- 8方向邻居检测(包括对角线)
- 自动清理空行和空列
输出格式:
# 文件名
## 工作表名称1
表格1...
表格2...
## 工作表名称2
表格3...图片和OCR支持:
- 图片位置追踪: 提取图片时记录其在Excel中的行列位置
- 单元格插入: 图片链接直接插入到对应的表格单元格中
- 三种处理场景: 与文档转MD完全一致
📍 位置: src/docwen/converter/pdf2md/
目录结构(约 3 个文件):
pdf2md/
├── __init__.py
├── core.py # PDF转Markdown核心(pymupdf4llm)
└── docx_extractor.py # 从PDF转换的DOCX中提取内容
核心特性:
- PDF转Markdown:使用pymupdf4llm库,支持图片提取和OCR识别
- PDF转DOCX:三级容错机制(Word > LibreOffice > pdf2docx)
- 完全统一的输出结构(所有内容在一个文件夹内)
pdf2md/core.py - PDF转MD核心
核心函数:
def extract_pdf_with_pymupdf4llm(
pdf_path: str,
extract_images: bool,
extract_ocr: bool,
output_dir: str,
basename_for_output: str = None,
cancel_event: Optional[threading.Event] = None,
progress_callback: Optional[Callable] = None
) -> Dict三种提取组合(OCR 依赖图片提取):
- ❌图片 ❌OCR:纯文本 → 仅生成
*.md - ✅图片 ❌OCR:文本+图片 →
*.md+ 图片文件 - ✅图片 ✅OCR:文本+图片+OCR →
*.md+ 图片文件(并包含 OCR 文本)
converter/formats/layout/external.py - PDF转DOCX(三级容错)
核心函数:
def pdf_to_docx(
pdf_path: str,
output_path: str,
cancel_event: Optional[threading.Event] = None,
software_callback: Optional[Callable[[str], None]] = None
) -> Optional[str]三级容错转换:
- Microsoft Word COM接口 - 质量最佳
- LibreOffice命令行 - 免费开源
- pdf2docx纯Python库 - 备选方案
临时目录保护机制:
with tempfile.TemporaryDirectory() as temp_dir:
# 1. 创建PDF副本(保护原文件)
temp_pdf = os.path.join(temp_dir, "input.pdf")
shutil.copy2(pdf_path, temp_pdf)
# 2. 在临时目录生成DOCX
temp_docx = os.path.join(temp_dir, "temp_output.docx")
# 3. 三级容错转换(操作副本)
result = _try_conversions(temp_pdf, temp_docx, ...)
# 4. 移动到最终位置
if result:
shutil.move(result, output_path)
return output_path📍 位置: src/docwen/converter/smart_converter.py
🎯 功能: 智能规划多步骤转换路径,支持复杂的格式转换链
核心类: SmartConverter
核心方法:
def convert(
source_file: str,
source_format: str,
target_format: str,
options: dict = None
) -> str设计理念:
- 自动规划最优转换路径
- 支持多步骤转换链(如 XLS → XLSX → CSV)
- 智能选择转换策略
- 提供WPS格式排除机制
- CSV转换特殊处理:创建子文件夹并正确移动到输出目录
CSV转换特殊机制:
CSV转换会创建子文件夹(包含多个CSV文件),需要特殊的文件移动处理:
# 在_convert_multi_step()方法中
if final_format == 'csv':
# CSV转换:移动整个子文件夹到output_dir
csv_subfolder = os.path.dirname(final_file)
# 移动整个子文件夹
final_subfolder = shutil.move(csv_subfolder, output_dir)
# 返回output_dir中的文件路径
final_output_path = os.path.join(final_subfolder, os.path.basename(final_file))
else:
# 非CSV转换:移动单个文件
final_output_path = os.path.join(output_dir, os.path.basename(final_file))
shutil.move(final_file, final_output_path)嵌套临时目录机制:
多步转换使用嵌套的临时目录:
- SmartConverter的临时目录 (temp_dir_B): 执行转换步骤
- Strategy的临时目录 (temp_dir_A): 接收SmartConverter的输出
关键设计:
- CSV子文件夹必须在temp_dir_B退出前移动,否则会被自动删除
- 采用两次移动策略:temp_dir_B → temp_dir_A → 最终输出目录
📍 位置: src/docwen/table_merger/core.py
🎯 功能: 将多个表格文件合并到一个基准表格中,支持三种汇总模式
三种汇总模式:
- 按行汇总: 合并重复或相似的行,保留更完整的行
- 按列汇总: 合并重复或相似的列,保留更完整的列
- 按单元格汇总: 将对应位置的单元格值进行合并(数值相加、文本拼接)
核心算法: 滑块对齐算法
工作原理:
遍历所有可能的偏移组合(行偏移[-10,+10],列偏移[-10,+10])
↓
计算每个偏移量下的重合度(相同非空单元格数量)
↓
选择重合度最高的偏移量作为对齐方案
↓
根据选定模式执行相应的汇总操作主要方法:
| 方法名 | 功能 | 返回类型 |
|---|---|---|
merge_tables() |
主汇总入口 | str |
_find_best_offset() |
滑块对齐算法 | Tuple[int, int] |
_calculate_overlap() |
计算重合度 | int |
_merge_by_row() |
按行汇总 | None |
_merge_by_column() |
按列汇总 | None |
_merge_by_cell() |
按单元格汇总 | None |
_check_row_coverage() |
检查行涵盖关系 | str |
_merge_cell_values() |
合并单元格值 | Any |
单元格合并规则(按优先级):
- 空值处理: 都为空→保持空,一个为空→保留非空值
- 数值类型: 数值相加(含公式计算结果和文本型数字)
- 相同文本: 保持不变(避免重复)
- 不同文本: 逗号拼接
序列化合并流程:
基准表格(表格3)
↓
+ 表格1 → 新基准(3+1)
↓
+ 表格2 → 新基准(3+1+2)
↓
+ 表格4 → 新基准(3+1+2+4)
↓
+ 表格5 → 最终结果
格式处理策略: 只比较单元格文本内容,不考虑格式差异
📍 位置: src/docwen/converter/formats/spreadsheet/csv_convert.py
🎯 功能: 提供 CSV 和 XLSX 之间的双向转换(底层工具函数),并被策略层复用(见 services/strategies/spreadsheet/csv_xlsx.py)。
核心函数:
def csv_to_xlsx(csv_path: str, output_path: str = None) -> str
def xlsx_to_csv(xlsx_path: str, output_dir: str) -> list[str]功能特点:
- CSV → XLSX: 将CSV文件转换为单工作表XLSX
- XLSX → CSV: 将每个工作表导出为独立CSV文件(通常输出到同一目录/子目录)
- 适配批量场景(一个XLSX可能导出多个CSV)
📍 位置: src/docwen/converter/formats/
目录结构(约 6 个子模块):
formats/
├── __init__.py # 统一导出
├── common/ # 公共模块
│ ├── __init__.py
│ ├── detection.py # 软件可用性检测
│ └── fallback.py # 三级容错框架
├── document/ # 文档类转换
│ ├── __init__.py
│ └── external.py # DOC/ODT/RTF/DOCX 互转
├── spreadsheet/ # 表格类转换
│ ├── __init__.py
│ ├── external.py # XLS/ODS/XLSX 互转
│ └── csv_convert.py # CSV 转换
├── layout/ # 版式类转换
│ ├── __init__.py
│ ├── preprocess.py # OFD/XPS/CAJ → PDF
│ └── external.py # PDF → DOCX(三级容错)
├── image/ # 图片类转换
│ ├── __init__.py
│ ├── core.py # 图片格式转换
│ ├── compression.py # 图片压缩
│ └── preprocess.py # HEIC/BMP 预处理
└── pdf_export/ # PDF 导出
├── __init__.py
├── document.py # DOCX → PDF
└── spreadsheet.py # XLSX → PDF
common/ - 公共模块
converter/formats/common/detection.py- 办公软件可用性检测(WPS/Office/LibreOffice)converter/formats/common/fallback.py- 三级容错转换框架(WPS → Office → LibreOffice)
document/ - 文档格式转换
核心函数:
office_to_docx()- DOC/WPS → DOCXrtf_to_docx()- RTF → DOCXodt_to_docx()- ODT → DOCXdocx_to_doc()- DOCX → DOCdocx_to_odt()- DOCX → ODTdocx_to_rtf()- DOCX → RTF
spreadsheet/ - 表格格式转换
核心函数:
office_to_xlsx()- XLS/ET → XLSXods_to_xlsx()- ODS → XLSXxlsx_to_xls()- XLSX → XLSxlsx_to_ods()- XLSX → ODScsv_to_xlsx()/xlsx_to_csv()- CSV 双向转换
layout/ - 版式文件转换
核心函数:
ofd_to_pdf()- OFD转PDF(使用easyofd库)xps_to_pdf()- XPS转PDF(使用pymupdf)caj_to_pdf()- CAJ转PDFpdf_to_docx()- PDF转DOCX(三级容错:Word → LibreOffice → pdf2docx)
pdf_export/ - PDF 导出
核心函数:
docx_to_pdf()- 文档转PDFxlsx_to_pdf()- 表格转PDF
image/ - 图片格式转换与压缩
📍 位置: src/docwen/converter/formats/image/
🎯 功能: 提供图片格式转换和智能压缩功能
核心函数:
convert_image() - 主转换函数
def convert_image(
source_path: str,
target_format: str,
output_path: str,
options: dict = None
) -> str参数说明:
source_path: 源文件路径target_format: 目标格式(小写,如'jpeg', 'png', 'webp'等)output_path: 输出文件完整路径(由调用方/策略层生成)options: 转换选项compress_mode: 'lossless'(最高质量)或 'limit_size'(限制大小)size_limit: 文件大小上限(仅压缩模式)size_unit: 单位 'KB' 或 'MB'(仅压缩模式)
两种压缩模式:
-
最高质量模式 (compress_mode='lossless'):
- JPEG/WebP:
quality=95(高质量有损) - 其他格式: 无损保存,使用最优压缩参数
- JPEG/WebP:
-
压缩模式 (compress_mode='limit_size'):
- 智能判断:源文件≤目标大小则无损转换
- JPEG/WebP: 二分查找最优quality
- 其他格式: 不支持有效压缩,使用无损保存
compress_to_size() - 二分查找压缩算法
def compress_to_size(
img: Image.Image,
output_path: str,
target_format: str,
target_size: int,
unit: str
) -> bool算法原理:
1. 转换目标大小为字节(KB×1024 或 MB×1024×1024)
2. 二分查找最优quality(范围15-95)
├─ 保存到内存缓冲区测试大小
├─ 如果≤目标:提高quality(寻求更高质量)
└─ 如果>目标:降低quality(减小文件)
3. 使用最优quality保存到磁盘
搜索效率: 通常4-6次迭代即可找到最优质量参数
格式特定参数:
| 格式 | 参数 | 说明 |
|---|---|---|
| JPEG | quality, optimize=True |
有损压缩,质量15-95 |
| WebP | quality, method=6 |
有损压缩,method=6最优 |
| PNG | compress_level=9, optimize=True |
无损压缩,效果有限 |
| BMP | 无 | 不支持压缩 |
| GIF | optimize=True |
有限压缩 |
| TIFF | compression='tiff_lzw' |
LZW无损压缩 |
辅助函数:
converter/formats/image/preprocess.py:heic_to_png()/bmp_to_png()(特殊格式预处理)converter/formats/image/compression.py:compress_to_size()(JPEG/WebP 二分压缩到目标大小)
📍 位置: src/docwen/services/strategies/
基类: services/strategies/base_strategy.py
class BaseStrategy(ABC):
@abstractmethod
def execute(
self,
file_path: str,
options: Optional[Dict[str, Any]] = None,
progress_callback: Optional[Callable[[str], None]] = None,
) -> ConversionResult装饰器:
@register_conversion(source_format, target_format) # 格式转换策略
@register_action(action_name) # 命名动作策略策略查找逻辑(优先级):
- 命名动作匹配(如 'validate', 'merge_tables')
- 精确格式匹配(如 docx → pdf)
- 源类别→目标格式(如 document → pdf)
- 纯类别匹配(如 image → image)
核心函数:
def get_strategy(
action_type: Optional[str] = None,
source_format: Optional[str] = None,
target_format: Optional[str] = None
) -> Type入口文件: services/strategies/__init__.py
- 定义两类注册表:
_conversion_registry(source→target)与_action_registry(action_name) services/strategies/registry.py维护“可按需加载”的显式模块清单(按类别子包/按 action 模块)get_strategy()在首次查找失败时按需导入对应模块,必要时再全量加载(避免 import 阶段副作用)
策略子包划分(与文件类型/操作类型对应):
| 子包 | 典型模块 | 说明 |
|---|---|---|
document/ |
services/strategies/document/to_markdown.py, services/strategies/document/to_pdf.py, services/strategies/document/validation.py, services/strategies/document/format_conversion.py |
DOC/DOCX/ODT/RTF/WPS:导出MD、转PDF、校对、互转(含动态批量注册) |
spreadsheet/ |
services/strategies/spreadsheet/to_markdown.py, services/strategies/spreadsheet/to_pdf.py, services/strategies/spreadsheet/csv_xlsx.py, services/strategies/spreadsheet/format_conversion.py |
XLS/XLSX/ODS/ET/CSV:导出MD、转PDF、CSV↔XLSX、互转(含动态批量注册) |
markdown/ |
services/strategies/markdown/to_document.py, services/strategies/markdown/to_spreadsheet.py |
MD/TXT(TXT按MD处理):转文档、转表格 |
image/ |
services/strategies/image/to_pdf.py, services/strategies/image/to_markdown.py, services/strategies/image/format_conversion.py, services/strategies/image/merge.py |
图片:转PDF、导出MD(含OCR)、通用格式互转、合并为多页TIFF |
layout/ |
services/strategies/layout/to_markdown.py, services/strategies/layout/to_pdf.py, services/strategies/layout/to_document.py, services/strategies/layout/to_image.py, services/strategies/layout/operations.py |
PDF/OFD:导出MD、转PDF/文档/图片,以及PDF合并/拆分等操作 |
operations/ |
services/strategies/operations/merge_tables.py, services/strategies/operations/md_numbering.py |
非格式转换类操作(如表格汇总、MD序号处理) |
关键发现:
- 图片格式互转走 1 个通用策略类
ImageFormatConversionStrategy(非“每个格式一类”) LayoutToMarkdownStrategy为版式文件导出 Markdown 的主策略类
📍 位置: 所有策略类的 execute() 方法
核心机制: 使用标准库 tempfile.TemporaryDirectory() 管理转换过程中的临时文件
关键特性:
- 全部转换过程在临时目录中进行
- 每步返回实际生成文件的路径
- 路径逐步传递,明确可靠
- 转换完成后根据配置决定文件去向
🎯 架构改进: 确保所有文件类型使用统一、安全的输入文件处理机制
📍 实现位置: src/docwen/utils/workspace_manager.py
核心函数:
def prepare_input_file(
original_file: str,
temp_dir: str,
actual_format: str
) -> str设计原则:
- 永不直接操作原文件 - 所有处理都从副本开始
- 统一命名规范 - 副本文件统一命名为
input.{正确扩展名} - 扩展名修正 - 即使原文件扩展名不正确,副本也使用正确的扩展名
- 调试友好 - 临时目录中始终有明确的
input.*文件可供检查
处理流程:
原始文件 (任意扩展名)
↓
[步骤0] prepare_input_file()
├─ 在temp_dir创建 input.{actual_format}
├─ 复制原文件内容到副本
└─ 返回副本的完整路径
↓
[后续步骤] 从副本进行所有操作
├─ 格式转换从副本读取
├─ 内容提取从副本读取
└─ 原文件保持不变 ✓
应用范围 - 覆盖所有策略子包:
services/strategies/document/services/strategies/spreadsheet/services/strategies/layout/services/strategies/image/services/strategies/markdown/services/strategies/operations/
优势总结:
- ✅ 绝对安全: 永不修改原文件
- ✅ 完全统一: 所有格式处理流程一致
- ✅ 扩展名正确: 副本使用正确的扩展名
- ✅ 调试友好: 临时目录始终有
input.*
配置位置: configs/output_config.toml
[intermediate_files]
save_to_output = true # 是否保存中间文件到输出目录工作流程:
with tempfile.TemporaryDirectory() as temp_dir:
# 步骤1-N: 在临时目录转换
final_file = multi_step_conversion(...)
# 根据配置决定是否保留中间文件
if should_save_intermediate_files():
for name in os.listdir(temp_dir):
if name.startswith("input."):
continue
save_intermediate_item(os.path.join(temp_dir, name), output_dir)
# 最终落盘统一入口(含冲突处理与降级保存)
finalize_output(final_file, target_path, original_input_file=original_file)
# 退出with块时,临时目录自动清理📍 位置: src/docwen/utils/workspace_manager.py
目的: 避免“目标目录不可写/被占用”导致输出丢失;保证目录/文件同名冲突时不覆盖已有结果。
核心入口:
finalize_output(temp_item, target_path, original_input_file=...)- 内部调用
save_output_with_fallback(...),实现多级降级保存
降级顺序(从高到低):
- 目标位置(用户指定或配置决定)
- 原文件所在目录
- 用户桌面
- 临时救援目录(
%TEMP%/docwen_rescue)
覆盖策略:
- 默认不覆盖:若目标文件已存在,会自动生成唯一文件名(追加
_001/_002/...) - 需要“原地覆盖”时,必须使用
replace_file_atomic(temp_file, target_path)做原子替换
📍 位置: src/docwen/utils/path_utils.py
核心规则: 原文件名(去除旧时间戳后缀) + section + 时间戳 + description,冲突时追加 _001/_002/...
常用函数:
strip_timestamp_suffix(name):去除_YYYYMMDD_HHMMSS...后缀make_output_stem(input_path, section=..., description=...):生成不带扩展名的输出 stemgenerate_named_output_path(output_dir=..., base_name=..., file_type=...):以 base_name 为输入生成输出文件路径(带唯一化)generate_output_path(input_path, output_dir=..., file_type=...):以输入文件路径为输入生成输出文件路径(带唯一化)
📍 位置: src/docwen/docx_spell/
目录结构(约 4 个文件):
docx_spell/
├── __init__.py
├── core.py # 校对核心入口
├── spell_checker.py # 文本校对器
└── utils.py # 校对工具函数
文件: docx_spell/core.py
主函数:
def process_docx(
docx_path: str,
output_path: str = None,
proofread_options: Dict[str, bool] = None,
progress_callback = None,
cancel_event = None
) -> str校对选项(字典格式):
proofread_options = {
"symbol_pairing": True, # 标点配对检查
"symbol_correction": True, # 符号校对
"typos_rule": True, # 错别字检查
"sensitive_word": True, # 敏感词匹配
}
# any(proofread_options.values()) == True 时执行校对
# 全部为 False 时不执行校对文件: docx_spell/spell_checker.py
核心类: TextValidator
校对规则:
| 规则名 | 配置文件 | 检查内容 |
|---|---|---|
| symbol_pairing | proofread_symbols.toml | 括号、引号配对 |
| symbol_correction | proofread_symbols.toml | 中英文标点混用 |
| typos_rule | proofread_typos.toml | 自定义错别字 |
| sensitive_word | proofread_sensitive.toml | 敏感词匹配 |
敏感词匹配算法特点:
- 有效例外词过滤: 自动过滤不包含敏感词的例外词
- 统一扩展范围: 计算所有例外词的最大长度,一次性确定检查范围
- 精确位置验证: 验证敏感词是否完全在例外词范围内
- 性能优化: 减少重复计算,只提取一次上下文子串
工作流程:
文本输入 → 规则检查 → 错误定位 → Run拆分规划 → 段落重建 → 添加批注
文件: docx_spell/utils.py
核心函数:
def plan_run_splits(paragraph, errors) -> list
def rebuild_paragraph_with_splits(old_paragraph, split_plan, doc) -> tuple
def copy_run_formatting(source_run, target_run) -> None
def copy_paragraph_format(source_para, target_para) -> Noneplan_run_splits - Run拆分规划器
🎯 功能: 分析段落和错误,一次性规划整个段落的run拆分方案
特点:
- 支持多个错误同时处理
- 为每个错误部分标记
error_index - 避免多次重建导致批注丢失
rebuild_paragraph_with_splits - 段落重建器
🎯 功能: 根据拆分计划重建段落,返回所有错误对应的run
关键机制:
- 一次性重建段落
- 记录所有错误run(按错误索引)
- 确保格式完整保留
📍 位置: src/docwen/template/
核心类: TemplateLoader
设计模式: 工厂模式 + 缓存机制
核心方法:
def get_template_path(self, template_type: str, template_name: str) -> str
def load_docx_template(self, template_name: str) -> Document
def load_xlsx_template(self, template_name: str) -> Workbook模板类型:
docx- Word文档模板xlsx- Excel表格模板
缓存机制:
_template_cache = {
"docx:xxx.docx": Document对象,
"xlsx:xxx.xlsx": Workbook对象
}模板验证器:
文件: template/validator.py
核心类: TemplateValidator
核心方法:
def validate_template(template_path, required_placeholders) -> Tuple[bool, List[str], Dict]验证流程:
加载模板文件
↓
遍历所有段落和表格单元格
↓
搜索占位符({{xxx}}格式)
↓
对比必需占位符列表
↓
生成验证报告
📍 位置: src/docwen/security/
目录结构(约 3 个文件):
security/
├── __init__.py
├── network_isolation.py # 网络隔离
└── protection_utils.py # 安全工具
文件: security/network_isolation.py
实现方式: 猴子补丁(Monkey Patching)
阻断的模块:
阻断列表 = [
socket, # TCP/UDP连接
urllib, # HTTP/HTTPS请求
http.client, # HTTP客户端
ftplib, # FTP连接
smtplib, # 邮件发送
ssl # SSL/TLS连接
]📍 位置: src/docwen/ipc/
设计理念: 基于文件系统的IPC,完全不依赖网络,与网络隔离机制兼容
核心组件:
ipc/single_instance.py- 单实例锁管理ipc/file_ipc.py- 文件监控通信
文件: ipc/single_instance.py
核心类: SingleInstance
实现原理:
# Windows: 使用 msvcrt.locking
msvcrt.locking(file.fileno(), msvcrt.LK_NBLCK, 1)
# Linux/Mac: 使用 fcntl.flock
fcntl.flock(file.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)IPC目录结构:
%TEMP%/docwen/
├── instance.lock # 单实例锁文件
├── commands/ # 命令队列目录
│ └── cmd_*.json # 命令文件(瞬时)
└── status.json # 程序状态文件
崩溃恢复机制: 文件锁是进程级别,进程崩溃时操作系统自动释放锁
文件: ipc/file_ipc.py
核心类: FileIPC
技术栈: watchdog 库(文件系统事件监控)
支持的命令:
| 命令 | 参数 | 功能 |
|---|---|---|
add_file |
file_path, mode | 添加文件到转换器 |
clear |
无 | 清空文件列表 |
activate |
无 | 激活并置顶窗口 |
命令格式:
{
"action": "add_file",
"file_path": "D:/test.md",
"mode": "single"
}集成: 与Obsidian插件配合实现单实例管理和文件传递
📍 位置: src/docwen/cli/
🎯 架构特点:
- 子命令模型: 每个动作一个子命令(避免参数组合歧义)
- AI友好设计: JSON输出、自描述功能
- 与GUI共享策略: 完全复用Strategy层,避免代码重复
- 智能批量处理: 支持单文件/批量/混合类型场景
实际结构(6个文件):
cli/
├── __init__.py
├── main.py # 命令行入口 + argparse
├── executor.py # Strategy统一调用器
├── doctor.py # 自检(doctor)
├── i18n.py # CLI 的翻译/多语言辅助
└── utils.py # 辅助函数
文件职责:
- main.py: 参数解析、子命令路由、通用文件处理(展开/校验/批量)
- executor.py: Strategy调用、JSON输出、批量执行
- utils.py: 路径解析、文件分类、用户交互
核心函数:
| 函数名 | 功能 | 返回类型 |
|---|---|---|
main() |
CLI主程序入口 | int(退出码) |
create_argument_parser() |
创建argparse解析器 | ArgumentParser |
build_options() |
从子命令参数构建选项字典 | dict |
命令模型(以 create_argument_parser() 为准):
- 转换类子命令:
convert、validate、merge-pdfs、split-pdf、merge-tables、merge-images-to-tiff、md-numbering - 查询类子命令:
inspect、actions list、templates list、optimizations list、numbering-schemes list、doctor - 通用选项:
--json/--quiet/--verbose/--timing与批处理相关的--batch/--jobs/--continue-on-error/--yes
批量并发说明:
--jobs N仅影响批量路径(execute_batch→BatchRequest.max_workers)。- N 会做安全裁剪:至少 1,且不超过
min(4, cpu_count);同时 Office/版式预处理/OCR 仍会被锁/信号量进一步限流。 --continue-on-error影响“遇错是否继续处理后续文件”的语义;并发上限仍由--jobs与安全裁剪共同决定。
批量耗时与 processed_count 语义:
--timing:仅影响 JSON 输出里的duration字段;未开启时保持兼容,批量结果中的 duration 统一为0.0。processed_count:表示“实际完成执行(产出 FileResult)的数量”。在“遇错停止”的批量中通常等于停止时已执行的数量;在“取消”场景下,剩余文件会被标记为 cancelled 并出现在 results 中,但processed_count仍可能小于 total。- CLI JSON 输出格式可参考:
tests/fixtures/golden/*.json。
使用示例:
# 导出为 Markdown
docwen convert report.docx --to md --extract-img --json
# 批量处理
docwen convert *.xlsx --to pdf --batch --yes
# AI自描述
docwen inspect document.docx --json核心函数:
| 函数名 | 功能 | 返回类型 |
|---|---|---|
execute_action() |
执行单个文件操作 | int(退出码) |
execute_batch() |
批量执行操作 | int |
get_strategy_for_action() |
根据action获取Strategy | BaseStrategy |
inspect_file() |
查询文件支持的操作(AI) | int |
list_all_actions() |
列出所有可用操作 | int |
Strategy获取逻辑:
# convert:
# - 目标为 md 时:类别 → md
# - 其它目标:具体格式 → 目标格式
if action == 'convert' and target_fmt == 'md':
return get_strategy(source_format=category, target_format='md')
elif action == 'convert':
return get_strategy(source_format=actual_fmt, target_format=target_fmt)
# 命名动作: validate, merge_tables等
else:
return get_strategy(action_type=action)JSON输出模式:
{
"schema_version": 2,
"success": true,
"command": "convert",
"data": {
"action": "convert",
"input_file": "report.docx",
"output_file": "report.md",
"message": "操作成功",
"error_code": null,
"details": null,
"duration": 2.35,
"metadata": {
"images_extracted": 5,
"ocr_performed": false
}
},
"error": null,
"warnings": [],
"timing": null
}metadata为策略可选扩展字段;CLI 在缺失时会输出空对象{}以便脚本解析。
AI自描述功能:
inspect_file()- 输出文件支持的操作列表(JSON格式)list_all_actions()- 输出所有可用操作get_supported_actions()- 根据文件类别返回操作列表
批量执行特性:
- 进度显示([1/10] file.docx... ✓)
- 错误处理(--continue-on-error)
- 汇总报告(成功/失败统计)
核心函数分类:
文件路径处理:
| 函数名 | 功能 | 返回类型 |
|---|---|---|
parse_file_path() |
解析拖放格式路径 | str |
expand_paths() |
展开通配符和目录 | List[str] |
is_supported_file() |
检查文件是否支持 | bool |
文件分类:
| 函数名 | 功能 | 返回类型 |
|---|---|---|
detect_category() |
检测文件类别 | str |
categorize_files() |
批量文件分组 | Dict[str, List[str]] |
detect_format() |
检测文件格式 | str |
用户交互:
| 函数名 | 功能 | 返回类型 |
|---|---|---|
prompt_yes_no() |
询问是/否 | bool |
prompt_choice() |
选项列表选择 | int |
prompt_input() |
文本输入 | str |
prompt_files() |
文件路径输入 | List[str] |
文件验证:
| 函数名 | 功能 | 返回类型 |
|---|---|---|
validate_file() |
验证单个文件 | Tuple[bool, str] |
validate_files() |
批量验证文件 | Tuple[List, List, List] |
路径解析器特性:
# 支持多种拖放格式
1. PowerShell格式: & 'd:\测试.md'
2. 标准拖放格式: "d:\测试.md"
3. 带空格的未加引号路径: d:\测试.md
4. 自动处理路径前后空格与GUI一致的格式检测:
- 使用
detect_actual_file_format()检测实际格式 - 支持
ACTUAL_FORMAT_TO_CATEGORY映射 - 处理格式不匹配警告(但仍接受文件)
进度显示:
def create_progress_callback(quiet=False, verbose=False):
"""创建进度回调函数"""
def callback(message):
if not quiet:
if verbose:
print(f"[进度] {message}")
else:
print(f"... {message}")
return callback完全复用Strategy层:
CLI → executor.py → get_strategy() → Strategy.execute()
GUI → logic.py → get_strategy() → Strategy.execute()
↑________共享同一套Strategy层_________↑
职责分离:
- main.py: 参数解析、子命令路由、批量/单文件调度
- executor.py: Strategy调用、结果处理
- utils.py: 底层工具(不包含业务逻辑)
AI友好特性:
- JSON输出模式:
--json标志,适合脚本解析 - 自描述功能:
inspect <file>查询文件支持的操作 - 操作列表:
actions list列出所有可用操作 - 标准退出码: 见下文(基于
docwen.errors.ExitCode)
📍 领域异常: src/docwen/errors.py
DocWenError:领域错误基类,包含code/user_message/details,用于在服务层/CLI/GU I 之间传递一致错误信息StrategyNotFoundError:找不到处理策略时抛出(例如action或source->target不存在)ExitCode:CLI 的标准退出码枚举
CLI 退出码映射(见 src/docwen/cli_run.py):
0:成功2:输入无效(DocWenError.code == "invalid_input")3:策略不存在(DocWenError.code == "strategy_not_found")4:依赖缺失(DocWenError.code == "dependency_missing")130:用户中断(KeyboardInterrupt)- 其他异常:
1(未知错误)
与 JSON 输出的关系:
- 策略执行返回
ConversionResult,失败时可携带error_code/details - CLI 在
--json模式下会把error_code/details写入输出,便于脚本稳定解析失败原因
批量处理策略:
- 智能检测: 自动识别单文件/批量/混合场景
- 操作记忆: 第一个文件配置后应用到所有文件
- 错误处理:
--continue-on-error选项 - 进度显示: 实时显示处理进度
场景1: 单文件导出Markdown
$ docwen convert document.docx --to md场景2: 批量导出Markdown
$ docwen convert *.docx --to md --extract-img --batch场景3: AI调用(JSON输出)
$ docwen inspect report.docx --json
{
"schema_version": 2,
"success": true,
"command": "inspect",
"data": {
"file": "report.docx",
"category": "document",
"format": "docx",
"supported_actions": [...]
},
"error": null,
"warnings": [],
"timing": null
}场景4: 文档校对
$ docwen validate doc.docx --check typo --check symbol场景5: PDF操作
# 合并PDF
$ docwen merge-pdfs file1.pdf file2.pdf file3.pdf
# 拆分PDF
$ docwen split-pdf report.pdf --pages "1-3,5,7-10"📍 位置: src/docwen/gui/
架构设计: MVP模式变体
目录结构:
gui/
├── __init__.py
├── core/ # 核心逻辑(6个文件)
│ ├── __init__.py
│ ├── window.py
│ ├── layout.py
│ ├── logic.py
│ ├── event_handler.py
│ └── theme_manager.py
├── components/ # UI组件(4个子目录+8个文件)
│ ├── __init__.py
│ ├── base_dialog.py
│ ├── file_drop.py
│ ├── template_selector.py
│ ├── template_selector_tabbed.py
│ ├── status_bar.py
│ ├── about_dialog.py
│ ├── selector_manager.py
│ ├── action_panel/ # 操作面板(5个文件)
│ ├── common/ # 公共组件(3个文件)
│ ├── conversion_panel/ # 转换面板(7个文件)
│ └── file_selector/ # 文件选择器(6个文件)
└── settings/ # 设置对话框
├── __init__.py
├── base_tab.py
├── config.py
├── dialog.py
├── document_tab.py
├── formatting_tab.py
├── general_tab.py
├── image_tab.py
├── layout_tab.py
├── link_tab.py
├── logging_tab.py
├── mapping_editor.py
├── output_tab.py
├── spreadsheet_tab.py
├── text_tab.py
└── editors/
├── __init__.py
├── base.py
├── numbering_add.py
└── numbering_clean.py
核心特性:
- MVP模式: 界面与逻辑分离
- 组件化: 25个可复用组件
- 事件驱动: 通过回调机制解耦
- DPI支持: 高DPI缩放
- 主题系统: 支持20+种主题
📍 位置: src/docwen/i18n/
🎯 功能: 提供多语言(国际化/i18n)支持,使 GUI 界面和转换逻辑能够根据用户选择的语言显示/生成不同的文本。
i18n/
├── __init__.py # 模块入口,导出 t() 翻译函数
├── i18n_manager.py # 语言管理器单例类
├── style_resolver.py # 多语言样式名解析器
└── locales/ # 语言包目录
├── zh_CN.toml # 简体中文(canonical)
├── zh_TW.toml # 繁体中文
├── en_US.toml # 英文
├── ja_JP.toml # 日文
├── ko_KR.toml # 韩文
├── es_ES.toml # 西班牙语
├── vi_VN.toml # 越南语
├── fr_FR.toml # 法语
├── de_DE.toml # 德语
├── pt_BR.toml # 葡萄牙语(巴西)
└── ru_RU.toml # 俄语
| 配置项 | 说明 |
|---|---|
| 语言切换方式 | 切换后需要重启应用生效 |
| 翻译范围 | GUI 界面文本、样式名、占位符、YAML 键名(不包括日志消息) |
| 语言文件格式 | TOML(与项目现有配置系统一致) |
| 支持的语言 | src/docwen/i18n/locales/(当前约 11 个,以仓库为准) |
核心类: I18nManager(单例模式)
主要 API:
| 方法 | 功能 | 返回类型 |
|---|---|---|
t(key, **kwargs) |
获取当前语言的翻译 | str |
t_locale(key, locale) |
获取指定语言的翻译 | str |
t_all_locales(key) |
获取所有语言版本的翻译 | Dict[str, str] |
get_current_locale() |
获取当前语言代码 | str |
set_locale(locale) |
设置语言(需重启生效) | bool |
get_available_locales() |
获取可用语言列表 | List[Dict] |
get_detection_priority() |
获取样式检测优先级 | List[str] |
使用示例:
from docwen.i18n import t
# 简单翻译
label = tb.Label(parent, text=t("common.close"))
# 带参数的翻译
message = t("messages.file_added", filename="test.docx")
# 获取所有语言版本
all_names = t_all_locales("styles.code_block")
# {"zh_CN": "代码块", "en_US": "Code Block"}🎯 功能: 处理样式名的国际化,支持 MD ↔ DOCX 双向转换
数据源分离原则:
| 存储位置 | 内容 | 用途 |
|---|---|---|
i18n/locales/ 的 [styles] 节 |
我们定义的样式名 | 注入 + 检测 |
configs/style_code.toml 等的 *_aliases |
第三方软件内置样式名 | 仅检测 |
三层缓存机制:
| 缓存字典 | 存储内容 | 用途 |
|---|---|---|
_detection_names_cache |
合并后的检测名称列表 | 顶层缓存,命中率最高 |
_locale_names_cache |
各语言版本样式名 | 语言文件翻译缓存 |
_alias_cache |
第三方软件别名 | 配置文件别名缓存 |
核心 API:
| 方法 | 方向 | 功能 |
|---|---|---|
get_injection_name(style_key) |
MD→DOCX | 获取当前语言的样式名(用于注入) |
get_all_detection_names(style_key) |
DOCX→MD | 获取所有可能的样式名(带缓存) |
is_style_match(style_name, style_key) |
DOCX→MD | 判断样式名是否匹配 |
get_quote_level(style_name) |
DOCX→MD | 获取引用样式级别(1-9) |
clear_cache() |
管理 | 清除所有三层缓存 |
使用示例:
from docwen.i18n import style_resolver
# MD → DOCX: 获取注入时使用的样式名
style_name = style_resolver.get_injection_name("code_block") # "代码块" 或 "Code Block"
# DOCX → MD: 检测段落样式是否是代码块
if style_resolver.is_style_match(paragraph.style.name, "code_block"):
output_as_code_block(paragraph)📍 位置: gui/components/config_combobox.py
🎯 功能: 解决语言切换时下拉框映射问题,实现配置值与显示文本的分离
设计优势:
- 内部存储配置值(如
"markdown_embed") - 显示翻译后的文本(如 "Markdown 嵌入显示")
- 通过
get_config_value()直接获取配置值,无需映射转换 - 天然支持多语言切换
common.* - 通用文本(关闭、确定、取消等)
settings.* - 设置对话框相关
components.* - GUI 组件
messages.* - 消息和提示
styles.* - 样式名(用于文档转换)
placeholders.* - 占位符(用于文档模板)
yaml_keys.* - YAML 键名(用于元数据)
canonical:以 zh_CN.toml 作为结构顺序基准(canonical)。
一致性要求:
- 顶级 section 顺序必须一致(以
zh_CN.toml为准) - leaf key 集合必须一致(不缺、不多)
[styles]内部键顺序必须一致(以zh_CN.toml为准)- 除
[styles]外,其它 section 内部的 key 顺序不作为硬性约束(仅保证 key 集合一致)
维护工具入口:python -m docwen.i18n.locale_validator ...(见 src/docwen/i18n/locale_validator.py)
# 校验:各语言包是否缺/多 key(相对 zh_CN)
python -m docwen.i18n.locale_validator check-completeness
# 同步:把其他语言的顶级 section 顺序与 [styles] 键序同步到 zh_CN
python -m docwen.i18n.locale_validator sync-order
# 检测:未使用 key(以代码扫描为准)
python -m docwen.i18n.locale_validator check-unused
# 清理:删除未使用 key(会写回所有语言包)
python -m docwen.i18n.locale_validator remove-unused --yes
# 单测:基础一致性约束
pytest tests/test_i18n/验收记录(摘要):
check-unused曾清理并从所有语言包删除 4 个未使用 key:conversion.progress.executing_final_proofread、editors.mapping.merge_tooltip、editors.mapping.overwrite_tooltip、placeholders.body- 近期复检:
check-unused无输出;pytest tests/test_i18n/通过 - 注释维护:已对
vi_VN/es_ES/ko_KR做“纯注释本地化/结构化补齐”,不改 key/value,不改 section/键顺序
📍 位置: src/docwen/utils/
模块数量: 当前 21 个工具模块(以仓库为准)
| 文件 | 主要功能 |
|---|---|
| ocr_utils.py | OCR文字识别(RapidOCR,纯本地推理) |
| path_utils.py | 路径处理与生成 |
| file_type_utils.py | 文件类型检测(3组等价扩展名) |
| link_processing.py | 链接处理(嵌入+普通链接) |
| markdown_utils.py | Markdown处理(Wiki/标准格式) |
| workspace_manager.py | 工作空间管理(统一输入副本) |
| docx_utils.py | Word文档操作工具 |
| yaml_utils.py | YAML解析与生成 |
| text_utils.py | 文本处理与验证 |
| date_utils.py | 日期格式处理 |
| font_utils.py | 字体大小转换 |
| heading_utils.py | 标题级别识别 |
| heading_numbering.py | 标题序号添加 |
| formula_utils.py | 公式转换(LaTeX↔OMML) |
| validation_utils.py | 数据验证 |
| dpi_utils.py | DPI缩放计算 |
| gui_utils.py | GUI辅助工具 |
| icon_utils.py | 图标资源加载 |
| logging_utils.py | 日志辅助工具 |
| number_utils.py | 数字处理工具 |
ocr_utils.py - OCR文字识别工具
技术栈: rapidocr_onnxruntime(RapidOCR + ONNX Runtime)
核心函数:
get_ocr()→ RapidOCR(单例模式)extract_text_simple()→ str(纯文本提取)extract_text_with_sizes()→ List[Dict](带字号提取)estimate_font_size()→ float(字号估算)
纯本地运行:
- RapidOCR 基于 ONNX Runtime,完全离线运行
- 无需设置环境变量或网络隔离配置
- OCR 模型需放置到
models/rapidocr/(该目录通常不随仓库提交;缺失时get_ocr()会报缺失清单)
模型文件:
models/rapidocr/
├── ch_PP-OCRv4_det_infer.onnx # 检测模型(多语言共用)
├── ch_ppocr_mobile_v2.0_cls_infer.onnx # 方向分类模型(多语言共用)
├── ch_PP-OCRv4_rec_infer.onnx # 中文识别模型
├── chinese_cht_PP-OCRv3_rec_infer.onnx # 繁体中文识别模型
├── en_PP-OCRv4_rec_infer.onnx # 英文识别模型
├── japan_PP-OCRv4_rec_infer.onnx # 日文识别模型
├── korean_PP-OCRv4_rec_infer.onnx # 韩文识别模型
├── latin_PP-OCRv3_rec_infer.onnx # 拉丁语系识别模型
└── cyrillic_PP-OCRv3_rec_infer.onnx # 西里尔语系识别模型
path_utils.py - 路径处理
核心函数: generate_output_path()
参数定义:
def generate_output_path(
input_path: str,
output_dir: Optional[str] = None,
section: str = "", # 章节标识
add_timestamp: bool = True, # 是否添加时间戳
description: Optional[str] = None, # 附加描述
file_type: str = "" # 文件类型
) -> str文件名格式: 原文件名_section_timestamp_description.file_type
特点:
- 参数顺序与文件名生成顺序完全一致
- 自动清理输入文件名中的旧时间戳
- 所有参数(除input_path外)都是可选的
file_type_utils.py - 文件类型检测
核心函数:
detect_actual_file_format()- 主检测函数_detect_text_format()- 纯文本格式智能检测validate_file_format()- 格式验证(含等价扩展名)
类别口径边界:
- UI/选项卡类别:
text/document/spreadsheet/layout/image(用于界面分组与展示) - 策略/编排类别:
markdown/document/spreadsheet/layout/image(用于策略查找与路由) - 进入策略层前必须将
text归一为markdown(可通过docwen.formats或file_type_utils.get_strategy_file_category())
等价扩展名机制(3组):
- JPEG等价组:
.jpg↔.jpeg - TIFF等价组:
.tif↔.tiff - HEIC等价组:
.heic↔.heif
link_processing.py - Markdown链接处理
核心函数:
def process_markdown_links(
text: str,
source_file_path: str,
visited_files: Optional[Set[str]] = None,
depth: int = 0
) -> str功能: 处理Markdown中的所有链接
嵌入链接(带!前缀):
- Wiki嵌入图片:
![[image.png]]→ 生成{{IMAGE:path}}占位符 - Wiki嵌入MD文件:
![[file.md]]→ 读取并递归展开内容 - Markdown嵌入图片:
→ 同上
普通链接(不带!前缀):
- Wiki链接:
[[link]]或[[link|text]] - Markdown链接:
[text](url)
处理模式(可配置):
embed:嵌入文件内容/生成占位符keep:保留原链接extract_text:提取显示文本remove:完全移除
特性:
- 路径解析:支持绝对路径、相对路径、仅文件名
- 循环检测:防止嵌入链接无限递归
- 深度限制:限制嵌入嵌套层数(默认3层)
markdown_utils.py - Markdown工具
核心函数:
format_image_link()- 图片链接格式化(支持Markdown/Wiki格式)format_md_file_link()- MD文件链接格式化
支持格式:
| 格式 | 图片链接 | MD文件链接 |
|---|---|---|
| markdown |  |
[file.md](file.md) |
| wiki | ![[img]] |
![[file.md]] |
[用户操作]
用户拖入MD文件
↓
[GUI层]
handle_file_dropped()
├─ 验证文件存在
├─ 确定文件类别(UI:text,策略路由归一为 markdown)
├─ 添加到文件列表
└─ 触发UI更新
↓
[用户交互]
GUI显示模板选择器
用户选择模板 + 点击"转换"按钮
↓
[GUI层]
handle_action(action_type, file_path, options)
├─ 重置取消事件
├─ 显示取消按钮
└─ 启动后台线程
↓
[后台线程]
_run_in_background()
└─ 调用策略层
↓
[策略层]
MdToDocxStrategy.execute()
├─ 创建临时目录
├─ 步骤0: prepare_input_file() 创建input.md副本
├─ 步骤1: 调用 md2docx.core.convert()
├─ 步骤2: 校对(可选)
├─ 步骤3: 格式转换(可选)
└─ 移动文件到输出目录
↓
[转换核心]
md2docx.core.convert()
├─ 解析YAML头部
├─ 展开嵌入链接(如启用)
├─ 解析MD正文
├─ 加载模板
└─ 填充占位符
↓
[结果返回]
生成DOCX文件 → 返回策略层 → 通过队列传递给GUI → UI更新
[用户操作]
用户拖入DOCX文件
↓
[GUI层]
handle_file_dropped()
├─ 验证文件存在
├─ 确定文件类别(document)
└─ 显示操作面板
↓
[用户交互]
用户选择"转换为MD"
↓
[GUI层]
handle_action()
└─ 启动后台线程
↓
[策略层]
DocxToMdStrategy.execute()
├─ 创建临时目录
├─ 步骤0: prepare_input_file() 创建副本
├─ 预处理旧格式(DOC→DOCX,如需要)
└─ 调用 docx2md.core.convert()
↓
[转换核心]
docx2md.core.convert()
├─ 加载DOCX
├─ 三轮评分识别元素
├─ 提取内容
└─ 生成YAML+Markdown
↓
[结果返回]
生成MD文件 → 策略层 → GUI → UI更新
关键设计特点:
- 后台线程处理: 所有转换操作在独立线程执行,避免UI冻结
- 临时目录保护: 使用
tempfile.TemporaryDirectory()确保原文件安全 - 统一输入副本:
prepare_input_file()创建 input.* 副本 - 线程安全队列: 通过
Queue在后台线程和UI线程间安全传递结果 - 进度回调: 通过
root.after()确保UI更新在主线程执行
用户拖入DOCX + 选择规则
↓
GUI.logic.handle_action("validate")
↓
DocxValidationStrategy.execute()
↓
docx_spell.core.process_docx()
├─ 创建TextValidator
├─ 逐段落检查文本
│ ├─ 应用4种规则检测错误
│ ├─ plan_run_splits(规划拆分)
│ ├─ rebuild_paragraph_with_splits(重建段落)
│ └─ 为每个错误run添加批注
└─ 完成所有段落处理
↓
生成带批注的DOCX文件
核心特点:
- 每个段落只重建一次,避免批注丢失
- 所有错误位置被精确标注
- 批注简洁明确(错误内容 → 建议修改)
目的: 智能识别公文元素
位置: converter/docx2md/gongwen/scorer.py(由 docx2md/core.py 创建并注入转换器)
三轮评分机制:
第一轮: 高置信度元素(得分≥80)
├─ 格式特征评分 (字体、加粗、居中)
├─ 文本模式评分 (正则匹配)
└─ 位置特征评分 (段落索引)
→ 识别: 标题、发文字号、发文机关标志
第二轮: 上下文相关元素
├─ 基于第一轮建立的文档结构
├─ 相对位置判断
└─ 前后文关系分析
→ 识别: 主送机关、抄送机关、成文日期
第三轮: 非唯一性元素
├─ 排除法
├─ 启发式规则
└─ 默认分类
→ 识别: 正文、附件、其他
评分公式示例:
total_score = (
format_score * 0.4 + # 格式权重40%
pattern_score * 0.4 + # 模式权重40%
position_score * 0.2 # 位置权重20%
)位置: converter/md2docx/processors/placeholder_handler.py
完整流程:
1. 标记特殊占位符
├─ 查找包含特殊占位符的段落
├─ 添加隐藏标记Run(白色字体,1pt大小)
└─ 标记格式: %%SPECIAL_PH:类型%%
2. 处理段落占位符(支持组规则)
├─ 提取段落中的所有占位符键
├─ 查找占位符所属的规则组
├─ 检查组内所有字段是否都为空
└─ 支持跨run的占位符识别和替换
3. 处理表格单元格占位符(支持组规则)
├─ delete_row_if_empty规则
└─ delete_cell_if_empty规则
4. 处理附件说明占位符(悬挂缩进)
├─ 单附件:悬挂3字符
└─ 多附件:悬挂4.5字符
5. 处理图片占位符 {{IMAGE:path}}
├─ 遍历所有文档段落和表格单元格
├─ 验证图片文件存在性
├─ 使用python-docx.add_picture()插入图片
└─ 设置段落为单倍行距
位置: converter/md2xlsx/placeholder_processor.py
完整流程:
1. 提取模板占位符
├─ {{字段名}} - YAML字段占位符
├─ {{↓字段}} - 列填充占位符
└─ {{→字段}} - 行填充占位符
2. 替换YAML字段占位符
3. 填充表格数据
├─ 列填充:从占位符位置向下填充
├─ 行填充:从占位符位置向右填充
└─ 智能跳过合并单元格
4. 处理图片占位符
└─ 使用openpyxl.drawing.image.Image插入
5. 清理剩余占位符
位置: docx_spell/spell_checker.py
核心方法: sensitive_word_check()
算法特点:
- 有效例外词过滤: 只检查包含敏感词的例外词
- 统一扩展范围: 一次性计算所有例外词的最大长度
- 精确位置验证: 确认敏感词完全在例外词范围内
- 性能优化: 减少重复计算,只提取一次上下文
匹配流程:
对于每个敏感词:
查找所有出现位置
对于每个出现:
过滤有效的例外词(必须包含敏感词)
if 存在有效例外词:
计算最大例外词长度
提取扩展上下文(向前向后各最大长度)
在上下文中查找所有例外词
if 敏感词完全在某个例外词内部:
跳过(不报告)
else:
报告为敏感词
else:
报告为敏感词位置: converter/xlsx2md/core.py
核心函数: _find_blocks(df: pd.DataFrame) -> List[pd.DataFrame]
算法原理:
使用广度优先搜索(BFS)查找所有数据块:
for 每个非空单元格:
if 未访问:
初始化边界 (min_r, max_r, min_c, max_c)
创建队列 q = [(r, c)]
while 队列非空:
取出当前单元格
for 8个方向的邻居:
if 邻居在范围内 and 未访问 and 非空:
加入队列
更新边界
提取块 df.iloc[min_r:max_r+1, min_c:max_c+1]
清理空行和空列
添加到结果列表
特点:
- 8方向邻居检测(包括对角线)
- 自动识别连通区域
- 智能清理空行列
步骤:
- 在
converter/docx2md/gongwen/scorer.py中定义/扩展新元素 - 实现评分函数
- 添加到评分流程
- 更新YAML输出格式
步骤:
- 在配置文件中添加规则开关
- 实现校对逻辑
- 注册到TextValidator
步骤:
- 创建策略类并使用
@register_conversion或@register_action装饰器 - 将新模块加入
services/strategies/registry.py的清单(按 action 或按类别) - 运行
tests/test_services/test_strategies_registry_specs.py,确保清单不会遗漏;运行时通过get_strategy()按需加载
- 模板缓存: 避免重复加载模板文件
- 配置缓存: 单例模式的配置管理器
- OCR单例: 全局唯一的OCR实例
- 延迟加载: 按需导入模块
- 增量处理: 逐段落处理大文档
- BFS算法: 高效查找Excel数据块
- 二分查找: 图片压缩质量优化
| 操作 | 平均耗时 | 说明 |
|---|---|---|
| MD→DOCX (10KB) | < 1秒 | 含模板加载 |
| DOCX→MD (50KB) | < 2秒 | 元素识别 |
| 校对 (100段落) | < 3秒 | 4种规则 |
转换失败:
- 检查日志:
logs/目录 - 验证文件格式
- 确认模板完整性
- 检查占位符格式
校对不工作:
- 检查配置文件中规则是否启用
- 验证文件为 .docx 格式
- 查看日志了解详细错误
模板不显示:
- 确认文件在
templates/目录 - 检查文件扩展名
- 重启程序重新扫描
- 启用DEBUG日志:
# logger_config.toml
[logging]
level = "DEBUG"- 查看详细日志:
# 日志位置: logs/docwen_YYYYMMDD.log- 断点调试: 在关键函数设置断点
现象:启动时直接退出(或日志提示“核心安全检查失败”)。
原因:启动器会执行核心安全检查;默认严格模式下,一旦检查失败会终止进程。
处理:在确认运行环境可信的前提下,可设置环境变量允许降级继续运行:
DOCWEN_STRICT_SECURITY=0:关闭严格模式(安全检查失败时不硬退出,会给出提示)
当代码有较大改动(配置块、输出路径、OCR、错误码)时,建议对本文件做一次关键词自检,确保不存在与实现冲突的描述:
- 输出与落盘:
finalize_output、save_output_with_fallback、replace_file_atomic - 输出命名:
make_output_stem、generate_output_path、generate_named_output_path、strip_timestamp_suffix - OCR 约束:
OCR 依赖、extract_image、extract_images、extract_ocr - 配置块数量:
CONFIG_FILES、DEFAULT_CONFIG、_reload_config_block - 错误码与退出码:
DocWenError、ExitCode、StrategyNotFoundError、error_code
- 要求: Python 3.12+
- 原因: 使用了新的类型注解语法和标准库特性
参见 pyproject.toml 中的 dependencies 部分。
- Windows 10/11: 完全支持
- Linux: 实验性支持(网络隔离功能受限)
- macOS: 实验性支持(网络隔离功能受限)
创新性地采用三级评分机制识别公文元素,相比传统的正则匹配更加准确。
bootstrap.py 确保所有应用入口点的初始化一致性,提升代码复用性。
通过猴子补丁技术阻断6个网络模块(socket、urllib、http.client、ftplib、smtplib、ssl),实现全面的网络隔离,确保数据安全。
创新的配置访问机制(配置块→子表→具体值),提供灵活且类型安全的配置管理。
采用装饰器注册模式(@register_conversion/@register_action)+ 动态批量注册,并通过显式清单(registry.py)实现策略模块的按需加载。
prepare_input_file() 为所有转换创建安全副本,永不修改原文件。
使用 tempfile.TemporaryDirectory() 确保转换过程的原子性和安全性。
- 遵循 PEP 8 规范
- 使用类型注解
- 函数/类添加 docstring
- 复杂逻辑添加注释
feat: 新功能
fix: 修复bug
docs: 文档更新
refactor: 代码重构
test: 测试相关
chore: 构建/工具相关
- 单元测试覆盖核心函数
- 集成测试覆盖主要流程
- 使用测试文件验证功能
CLI 的 --json 输出被视为对外契约(供脚本/自动化/AI 调用),通过“黄金样例”测试锁定结构与语义:
- 黄金样例目录:
tests/fixtures/golden/ - 对比测试入口:
tests/test_cli/test_json_golden.py
维护原则:
- 允许变化但必须归一化:输入路径(如
input_file)、耗时(如duration)。 - 不应随意变化:字段名、层级结构、默认值语义(例如未开启
--timing时 duration 为 0.0)、退出码含义、错误字段(error_code/details)语义。 - 变更流程:若确需修改输出结构,应同步更新黄金样例与测试,并在文档/变更说明中写清楚不兼容点与迁移建议。
项目名称: 公文转换器 (DocWen)
软件全称: 公文图表格式转换软件
版本管理: 从 src/docwen/__init__.py 读取
版本格式: 主版本.次版本.修订号.构建日期.当日修订号
Python要求: >=3.12
许可证: GNU Affero General Public License v3.0 (AGPL-3.0)
作者: ZhengYX
项目主页: https://github.com/ZHYX91/docwen
- python-docx - Word文档操作
- openpyxl - Excel操作
- PyYAML - YAML解析
- ttkbootstrap - GUI主题
- RapidOCR - OCR识别(ONNX Runtime)
- PyMuPDF - PDF处理