Skip to content

Latest commit

 

History

History
3226 lines (2574 loc) · 113 KB

File metadata and controls

3226 lines (2574 loc) · 113 KB

技术文档

面向开发者和AI助手,提供系统架构、模块关系和代码定位信息

软件名称: 公文转换器 (Docwen)
软件全称: 公文图表格式转换软件
项目定位: 本地运行的公文格式转换工具,支持 Word ↔ Markdown ↔ Excel 多向转换


📑 文档导航

第一部分:概览与快速参考

第二部分:核心系统

第三部分:开发指南

第四部分:项目信息


第一部分:概览与快速参考

1. 项目概览

1.1 一句话总结

本地运行的公文格式转换工具,支持 Word ↔ Markdown ↔ Excel 多向转换,内置文本校对系统。

1.2 核心价值

完全离线运行 - 数据不出本地,网络深度隔离
智能识别公文元素 - 三轮评分算法,准确率高
基于模板的格式生成 - 灵活可定制,符合规范
自定义规则的文本校对 - 规则驱动,精准标注

1.3 技术栈

类别 技术 版本要求 用途
核心语言 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 - 文件系统监控

1.4 项目结构

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             # 依赖与打包配置

1.5 目录职责边界(推荐约定)

  • 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 输出契约

2. 快速参考

2.0 示例代码说明

本文档中的代码块分为两类:

  • API 示例:用于说明真实可调用接口,函数名/参数与当前实现对齐
  • 流程伪代码:用于描述数据流与步骤,变量名/函数名可能是示意

2.1 核心模块速查表

模块路径 主要功能 关键入口 依赖模块
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.pyinitialize_app()
  • 策略查找:src/docwen/services/strategies/__init__.pyget_strategy()
  • 配置合并:src/docwen/config/config_manager.py_reload_config_block()
  • 输出落盘:src/docwen/utils/workspace_manager.pyfinalize_output() / save_output_with_fallback()
  • 错误模型:src/docwen/errors.pyDocWenError / ExitCode

2.2 配置文件速查表

配置文件 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)

2.3 转换策略速查表

组织方式: 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/ MdToDocxStrategyMdToXlsxStrategy @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)

2.4 工具函数速查表

工具模块 关键函数 功能说明 返回类型
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]

2.5 设计模式应用速查

设计模式 应用位置 具体实现 优势
单例模式 ConfigManager 全局唯一配置实例 避免重复加载配置
单例模式 OCR实例 全局唯一OCR实例 避免重复初始化模型
策略模式 services/strategies/ 按类别组织的可插拔策略(含动态注册) 易于扩展新格式
工厂模式 template/loader.py 模板对象创建 统一模板管理
工厂模式 动态策略生成 _create_xxx_strategy() 批量生成策略
MVP模式 gui/core/ View-Presenter分离 界面与逻辑解耦
观察者模式 GUI进度回调 progress_callback机制 实时进度通知
装饰器模式 策略注册 @register_conversion 自动注册策略

2.6 常用命令速查

CLI模式:

# 查看帮助
docwen --help

# 常用:导出为 Markdown
docwen convert document.docx --to md

# 不安装包时的等价方式
python -m docwen.cli_run convert document.docx --to md

GUI模式:

# 启动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"

2.7 文件格式支持速查

类别 支持格式 输入 输出 备注
文本 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

2.8 核心API速查

转换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")

3. 系统架构

3.1 分层架构图

┌─────────────────────────────────────────────────────────────┐
│                     应用入口层                               │
│              (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(运行时) │
└─────────────────────────────────────────────────────────────┘

3.2 模块依赖关系

bootstrap (启动器)
    ├─→ security (安全检查)
    └─→ config (配置初始化)

gui/cli (界面层)
    ├─→ services.strategies (调用策略)
    ├─→ config (读取配置)
    ├─→ template (加载模板)
    └─→ ipc (进程间通信,GUI专属)

services.strategies (策略层:装饰器注册表 + 显式清单 + 按需导入)
    ├─→ converter (转换核心)
    ├─→ docx_spell (校对核心)
    └─→ utils (工具函数)

converter (转换引擎)
    ├─→ template (模板加载)
    ├─→ config (读取配置)
    └─→ utils (工具函数)

3.3 数据流向

用户操作 → GUI/CLI事件 → 策略选择 → 转换/校对 → 结果返回 → UI更新

关键设计:

  • 策略模式: 所有转换通过策略层统一调度
  • 临时目录保护: 使用 tempfile.TemporaryDirectory() 保护原文件
  • 统一输入副本: prepare_input_file() 为所有转换创建安全副本
  • 路径规范化: generate_output_path() 统一生成带时间戳的输出文件名

第二部分:核心系统

4. 配置系统

📍 位置: src/docwen/config/

4.1 配置文件结构

配置文件数量: 当前 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     # 优化配置

4.1.1 字段处理器配置(MD→DOCX)

配置文件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 预留给多语言处理器)

4.2 ConfigManager 详解

核心类: ConfigManager
设计模式: 单例模式 + Mixin架构
架构: 核心类约15个方法 + 10个功能Mixin(共100+方法)

4.2.1 配置文件映射

位置: 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 - 优化配置

4.2.2 三级配置访问机制

Level 1: get_xxx_config_block()     # 整个配置块(示意)
Level 2: get_xxx_config()/get_xxx_settings()  # 子表(示意)
Level 3: get_xxx()                  # 具体值 getter(示意)

4.2.3 配置块级别方法(Level 1,部分)

方法名 功能 返回类型
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

4.2.4 子表级别方法(Level 2)- 部分示例

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 等

4.2.5 具体配置方法(Level 3)- 部分示例

窗口布局配置:

  • get_center_panel_width() → int
  • get_batch_panel_width() → int
  • get_template_panel_width() → int
  • get_window_height() → int
  • get_default_mode() → str ('single' or 'batch')

图片提取配置:

  • get_docx_to_md_keep_images() → bool
  • get_docx_to_md_enable_ocr() → bool
  • get_xlsx_to_md_keep_images() → bool
  • get_layout_to_md_keep_images() → bool
  • get_image_to_md_enable_ocr() → bool

链接格式配置:

  • get_markdown_link_style_settings() → Dict(包含4个链接格式设置)
  • get_embed_links_config() → Dict(包含 enabled 等配置项)
  • get_max_embed_depth() → int
  • get_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() → bool
  • update_config_section() → bool
  • reload_configs() → None

4.3 link_config.toml 详解

📍 位置: 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 = "⚠️ 达到最大嵌入深度"

4.4 配置读取流程

程序启动
    ↓
bootstrap.initialize_app()
    ↓
ConfigManager实例化(单例模式)
    ↓
加载 CONFIG_FILES 中定义的全部配置块(当前 18 个)
    ├─ 读取用户配置
    ├─ 与默认配置深度合并
    └─ 存储在内存中
    ↓
各模块通过 config_manager 访问配置

4.5 配置示例

gui_config.toml

[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"

software_priority.toml

[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"]

output_config.toml

[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        # 是否保存中间文件

5. 核心模块详解

5.1 bootstrap(统一启动器)

📍 位置: src/docwen/bootstrap.py

🎯 功能: 所有应用入口的统一初始化点

核心函数:

def initialize_app() -> None

职责:

  1. 确保包路径正确
  2. 执行安全防护检查
  3. 初始化网络隔离
  4. 设置日志系统

被调用位置:

  • src/docwen/gui_run.py - GUI入口(实际 main() 在此,启动前调用)
  • src/docwen/cli_run.py - CLI入口(实际 main() 在此,启动前调用)

5.2 config(配置管理)

已在第4章详细说明,参见 4. 配置系统


5.3 converter(转换引擎)

📍 位置: src/docwen/converter/

5.3.1 目录结构

实际结构(当前 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

5.3.2 核心设计原则

职责分离架构:

  • 策略层: 控制文件命名,生成完整的 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

设计优势:

  • 命名逻辑集中在策略层,易于维护
  • 底层函数接口简洁明确
  • 所有文件命名风格一致
  • 中间文件具有可读性,便于追踪转换历史

5.3.3 公式处理模块

📍 位置: 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 字体渲染公式,忽略字符样式的字体设置。


5.3.4 docx2md - Word转Markdown

📍 位置: 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)
  • 两种处理场景:
    1. 提取图片(可选)→ 段落中插入图片链接
    2. 提取图片 + OCR(可选)→ 生成图片 OCR 结果文件,并在正文中插入链接

输出结构:

文件名_时间戳_fromDocx/
├── 文件名_时间戳_fromDocx.md        # 主文件
├── 文件名_附件部分_时间戳_fromDocx.md # 附件文件(如有)
├── image_1.png                        # 图片(如勾选)
├── image_1.md                         # 图片 OCR 结果(需要勾选 OCR 且提取图片)
└── image_2.png / image_2.md

5.3.5 md2docx - Markdown转Word

📍 位置: 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\\|}}
       ├─ ![alt](image.png =300x200) → {{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 > 正常替换

5.3.5 md2xlsx - Markdown转Excel

📍 位置: 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和零宽字符

5.3.6 xlsx2md - Excel转Markdown

📍 位置: 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完全一致

5.3.7 pdf2md - PDF转Markdown模块

📍 位置: 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 依赖图片提取):

  1. ❌图片 ❌OCR:纯文本 → 仅生成 *.md
  2. ✅图片 ❌OCR:文本+图片 → *.md + 图片文件
  3. ✅图片 ✅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]

三级容错转换:

  1. Microsoft Word COM接口 - 质量最佳
  2. LibreOffice命令行 - 免费开源
  3. 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

5.3.8 smart_converter - 智能转换器

📍 位置: 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 → 最终输出目录

5.3.9 table_merger - 表格汇总工具

📍 位置: src/docwen/table_merger/core.py

🎯 功能: 将多个表格文件合并到一个基准表格中,支持三种汇总模式

三种汇总模式:

  1. 按行汇总: 合并重复或相似的行,保留更完整的行
  2. 按列汇总: 合并重复或相似的列,保留更完整的列
  3. 按单元格汇总: 将对应位置的单元格值进行合并(数值相加、文本拼接)

核心算法: 滑块对齐算法

工作原理:

遍历所有可能的偏移组合行偏移[-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

单元格合并规则(按优先级):

  1. 空值处理: 都为空→保持空,一个为空→保留非空值
  2. 数值类型: 数值相加(含公式计算结果和文本型数字)
  3. 相同文本: 保持不变(避免重复)
  4. 不同文本: 逗号拼接

序列化合并流程:

基准表格(表格3)
    ↓
+ 表格1 → 新基准(3+1)
    ↓
+ 表格2 → 新基准(3+1+2)
    ↓
+ 表格4 → 新基准(3+1+2+4)
    ↓
+ 表格5 → 最终结果

格式处理策略: 只比较单元格文本内容,不考虑格式差异


5.3.10 csv_convert - CSV↔XLSX 转换

📍 位置: 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)

5.3.11 formats - 格式转换层

📍 位置: 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 → DOCX
  • rtf_to_docx() - RTF → DOCX
  • odt_to_docx() - ODT → DOCX
  • docx_to_doc() - DOCX → DOC
  • docx_to_odt() - DOCX → ODT
  • docx_to_rtf() - DOCX → RTF

spreadsheet/ - 表格格式转换

核心函数:

  • office_to_xlsx() - XLS/ET → XLSX
  • ods_to_xlsx() - ODS → XLSX
  • xlsx_to_xls() - XLSX → XLS
  • xlsx_to_ods() - XLSX → ODS
  • csv_to_xlsx() / xlsx_to_csv() - CSV 双向转换

layout/ - 版式文件转换

核心函数:

  • ofd_to_pdf() - OFD转PDF(使用easyofd库)
  • xps_to_pdf() - XPS转PDF(使用pymupdf)
  • caj_to_pdf() - CAJ转PDF
  • pdf_to_docx() - PDF转DOCX(三级容错:Word → LibreOffice → pdf2docx)

pdf_export/ - PDF 导出

核心函数:

  • docx_to_pdf() - 文档转PDF
  • xlsx_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'(仅压缩模式)

两种压缩模式:

  1. 最高质量模式 (compress_mode='lossless'):

    • JPEG/WebP: quality=95(高质量有损)
    • 其他格式: 无损保存,使用最优压缩参数
  2. 压缩模式 (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 二分压缩到目标大小)

5.4 services(服务策略层)

📍 位置: src/docwen/services/strategies/

5.4.1 策略模式实现

基类: 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

5.4.2 策略注册机制

装饰器:

@register_conversion(source_format, target_format)  # 格式转换策略
@register_action(action_name)                       # 命名动作策略

策略查找逻辑(优先级):

  1. 命名动作匹配(如 'validate', 'merge_tables')
  2. 精确格式匹配(如 docx → pdf)
  3. 源类别→目标格式(如 document → pdf)
  4. 纯类别匹配(如 image → image)

核心函数:

def get_strategy(
    action_type: Optional[str] = None, 
    source_format: Optional[str] = None, 
    target_format: Optional[str] = None
) -> Type

5.4.3 结构概览

入口文件: 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 的主策略类

5.5 临时文件管理机制

📍 位置: 所有策略类的 execute() 方法

5.5.1 设计原则

核心机制: 使用标准库 tempfile.TemporaryDirectory() 管理转换过程中的临时文件

关键特性:

  • 全部转换过程在临时目录中进行
  • 每步返回实际生成文件的路径
  • 路径逐步传递,明确可靠
  • 转换完成后根据配置决定文件去向

5.5.2 统一输入文件处理方案

🎯 架构改进: 确保所有文件类型使用统一、安全的输入文件处理机制

📍 实现位置: src/docwen/utils/workspace_manager.py

核心函数:

def prepare_input_file(
    original_file: str, 
    temp_dir: str, 
    actual_format: str
) -> str

设计原则:

  1. 永不直接操作原文件 - 所有处理都从副本开始
  2. 统一命名规范 - 副本文件统一命名为 input.{正确扩展名}
  3. 扩展名修正 - 即使原文件扩展名不正确,副本也使用正确的扩展名
  4. 调试友好 - 临时目录中始终有明确的 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.*

5.5.3 中间文件保留策略

配置位置: 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块时,临时目录自动清理

5.5.4 最终输出落盘与降级保存

📍 位置: src/docwen/utils/workspace_manager.py

目的: 避免“目标目录不可写/被占用”导致输出丢失;保证目录/文件同名冲突时不覆盖已有结果。

核心入口:

  • finalize_output(temp_item, target_path, original_input_file=...)
  • 内部调用 save_output_with_fallback(...),实现多级降级保存

降级顺序(从高到低):

  1. 目标位置(用户指定或配置决定)
  2. 原文件所在目录
  3. 用户桌面
  4. 临时救援目录(%TEMP%/docwen_rescue

覆盖策略:

  • 默认不覆盖:若目标文件已存在,会自动生成唯一文件名(追加 _001/_002/...
  • 需要“原地覆盖”时,必须使用 replace_file_atomic(temp_file, target_path) 做原子替换

5.5.5 输出命名规则(统一入口)

📍 位置: src/docwen/utils/path_utils.py

核心规则: 原文件名(去除旧时间戳后缀) + section + 时间戳 + description,冲突时追加 _001/_002/...

常用函数:

  • strip_timestamp_suffix(name):去除 _YYYYMMDD_HHMMSS... 后缀
  • make_output_stem(input_path, section=..., description=...):生成不带扩展名的输出 stem
  • generate_named_output_path(output_dir=..., base_name=..., file_type=...):以 base_name 为输入生成输出文件路径(带唯一化)
  • generate_output_path(input_path, output_dir=..., file_type=...):以输入文件路径为输入生成输出文件路径(带唯一化)

5.6 docx_spell(校对引擎)

📍 位置: src/docwen/docx_spell/

目录结构(约 4 个文件):

docx_spell/
├── __init__.py
├── core.py           # 校对核心入口
├── spell_checker.py  # 文本校对器
└── utils.py          # 校对工具函数

5.6.1 核心模块

文件: 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 时不执行校对

5.6.2 校对器

文件: 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 敏感词匹配

敏感词匹配算法特点:

  1. 有效例外词过滤: 自动过滤不包含敏感词的例外词
  2. 统一扩展范围: 计算所有例外词的最大长度,一次性确定检查范围
  3. 精确位置验证: 验证敏感词是否完全在例外词范围内
  4. 性能优化: 减少重复计算,只提取一次上下文子串

工作流程:

文本输入 → 规则检查 → 错误定位 → Run拆分规划 → 段落重建 → 添加批注

5.6.3 工具模块

文件: 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) -> None

plan_run_splits - Run拆分规划器

🎯 功能: 分析段落和错误,一次性规划整个段落的run拆分方案

特点:

  • 支持多个错误同时处理
  • 为每个错误部分标记 error_index
  • 避免多次重建导致批注丢失

rebuild_paragraph_with_splits - 段落重建器

🎯 功能: 根据拆分计划重建段落,返回所有错误对应的run

关键机制:

  • 一次性重建段落
  • 记录所有错误run(按错误索引)
  • 确保格式完整保留

5.7 template(模板系统)

📍 位置: 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}}格式)
    ↓
对比必需占位符列表
    ↓
生成验证报告

5.8 security(安全模块)

📍 位置: src/docwen/security/

目录结构(约 3 个文件):

security/
├── __init__.py
├── network_isolation.py    # 网络隔离
└── protection_utils.py     # 安全工具

5.8.1 网络隔离

文件: security/network_isolation.py

实现方式: 猴子补丁(Monkey Patching)

阻断的模块:

阻断列表 = [
    socket,      # TCP/UDP连接
    urllib,      # HTTP/HTTPS请求
    http.client, # HTTP客户端
    ftplib,      # FTP连接
    smtplib,     # 邮件发送
    ssl          # SSL/TLS连接
]

5.9 ipc(进程间通信)

📍 位置: src/docwen/ipc/

设计理念: 基于文件系统的IPC,完全不依赖网络,与网络隔离机制兼容

核心组件:

  • ipc/single_instance.py - 单实例锁管理
  • ipc/file_ipc.py - 文件监控通信

5.9.1 单实例锁管理

文件: 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           # 程序状态文件

崩溃恢复机制: 文件锁是进程级别,进程崩溃时操作系统自动释放锁

5.9.2 文件系统IPC

文件: ipc/file_ipc.py

核心类: FileIPC

技术栈: watchdog 库(文件系统事件监控)

支持的命令:

命令 参数 功能
add_file file_path, mode 添加文件到转换器
clear 清空文件列表
activate 激活并置顶窗口

命令格式:

{
  "action": "add_file",
  "file_path": "D:/test.md",
  "mode": "single"
}

集成: 与Obsidian插件配合实现单实例管理和文件传递

5.10 cli(命令行界面)

📍 位置: src/docwen/cli/

🎯 架构特点:

  • 子命令模型: 每个动作一个子命令(避免参数组合歧义)
  • AI友好设计: JSON输出、自描述功能
  • 与GUI共享策略: 完全复用Strategy层,避免代码重复
  • 智能批量处理: 支持单文件/批量/混合类型场景

5.10.1 目录结构

实际结构(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: 路径解析、文件分类、用户交互

5.10.2 main.py - 命令行入口

核心函数:

函数名 功能 返回类型
main() CLI主程序入口 int(退出码)
create_argument_parser() 创建argparse解析器 ArgumentParser
build_options() 从子命令参数构建选项字典 dict

命令模型(以 create_argument_parser() 为准):

  • 转换类子命令convertvalidatemerge-pdfssplit-pdfmerge-tablesmerge-images-to-tiffmd-numbering
  • 查询类子命令inspectactions listtemplates listoptimizations listnumbering-schemes listdoctor
  • 通用选项--json/--quiet/--verbose/--timing 与批处理相关的 --batch/--jobs/--continue-on-error/--yes

批量并发说明:

  • --jobs N 仅影响批量路径(execute_batchBatchRequest.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

5.10.3 executor.py - Strategy调用器

核心函数:

函数名 功能 返回类型
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)
  • 汇总报告(成功/失败统计)

5.10.5 utils.py - 辅助函数

核心函数分类:

文件路径处理:

函数名 功能 返回类型
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

5.10.6 CLI架构设计原则

完全复用Strategy层:

CLI → executor.py → get_strategy() → Strategy.execute()
GUI → logic.py    → get_strategy() → Strategy.execute()
     ↑________共享同一套Strategy层_________↑

职责分离:

  • main.py: 参数解析、子命令路由、批量/单文件调度
  • executor.py: Strategy调用、结果处理
  • utils.py: 底层工具(不包含业务逻辑)

AI友好特性:

  1. JSON输出模式: --json 标志,适合脚本解析
  2. 自描述功能: inspect <file> 查询文件支持的操作
  3. 操作列表: actions list 列出所有可用操作
  4. 标准退出码: 见下文(基于 docwen.errors.ExitCode
错误与退出码

📍 领域异常: src/docwen/errors.py

  • DocWenError:领域错误基类,包含 code/user_message/details,用于在服务层/CLI/GU I 之间传递一致错误信息
  • StrategyNotFoundError:找不到处理策略时抛出(例如 actionsource->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 写入输出,便于脚本稳定解析失败原因

批量处理策略:

  1. 智能检测: 自动识别单文件/批量/混合场景
  2. 操作记忆: 第一个文件配置后应用到所有文件
  3. 错误处理: --continue-on-error 选项
  4. 进度显示: 实时显示处理进度

5.10.7 使用场景示例

场景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"

5.11 gui(图形界面)

📍 位置: 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+种主题

5.12 i18n(国际化模块)

📍 位置: src/docwen/i18n/

🎯 功能: 提供多语言(国际化/i18n)支持,使 GUI 界面和转换逻辑能够根据用户选择的语言显示/生成不同的文本。

5.12.1 目录结构

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       # 俄语

5.12.2 技术方案

配置项 说明
语言切换方式 切换后需要重启应用生效
翻译范围 GUI 界面文本、样式名、占位符、YAML 键名(不包括日志消息)
语言文件格式 TOML(与项目现有配置系统一致)
支持的语言 src/docwen/i18n/locales/(当前约 11 个,以仓库为准)

5.12.3 I18nManager - 语言管理器

核心类: 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"}

5.12.4 StyleNameResolver - 样式名解析器

🎯 功能: 处理样式名的国际化,支持 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)

5.12.5 ConfigCombobox - 配置下拉框组件

📍 位置: gui/components/config_combobox.py

🎯 功能: 解决语言切换时下拉框映射问题,实现配置值与显示文本的分离

设计优势:

  • 内部存储配置值(如 "markdown_embed"
  • 显示翻译后的文本(如 "Markdown 嵌入显示")
  • 通过 get_config_value() 直接获取配置值,无需映射转换
  • 天然支持多语言切换

5.12.6 翻译键命名规范

common.*           - 通用文本(关闭、确定、取消等)
settings.*         - 设置对话框相关
components.*       - GUI 组件
messages.*         - 消息和提示
styles.*           - 样式名(用于文档转换)
placeholders.*     - 占位符(用于文档模板)
yaml_keys.*        - YAML 键名(用于元数据)

5.12.7 语言文件规范与维护

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_proofreadeditors.mapping.merge_tooltipeditors.mapping.overwrite_tooltipplaceholders.body
  • 近期复检:check-unused 无输出;pytest tests/test_i18n/ 通过
  • 注释维护:已对 vi_VN/es_ES/ko_KR 做“纯注释本地化/结构化补齐”,不改 key/value,不改 section/键顺序

5.13 utils(工具函数库)

📍 位置: 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 数字处理工具

5.12.1 重点工具模块

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.formatsfile_type_utils.get_strategy_file_category()

等价扩展名机制(3组):

  1. JPEG等价组: .jpg.jpeg
  2. TIFF等价组: .tif.tiff
  3. 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嵌入图片:![alt](image.png) → 同上

普通链接(不带!前缀):

  • 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 ![img](img) [file.md](file.md)
wiki ![[img]] ![[file.md]]

6. 数据流与协作

6.1 文件转换流程

6.1.1 Markdown → Word(完整流程)

[用户操作]
用户拖入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更新

6.1.2 Word → Markdown(完整流程)

[用户操作]
用户拖入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更新

关键设计特点:

  1. 后台线程处理: 所有转换操作在独立线程执行,避免UI冻结
  2. 临时目录保护: 使用 tempfile.TemporaryDirectory() 确保原文件安全
  3. 统一输入副本: prepare_input_file() 创建 input.* 副本
  4. 线程安全队列: 通过 Queue 在后台线程和UI线程间安全传递结果
  5. 进度回调: 通过 root.after() 确保UI更新在主线程执行

6.2 校对流程

用户拖入DOCX + 选择规则
    ↓
GUI.logic.handle_action("validate")
    ↓
DocxValidationStrategy.execute()
    ↓
docx_spell.core.process_docx()
    ├─ 创建TextValidator
    ├─ 逐段落检查文本
    │   ├─ 应用4种规则检测错误
    │   ├─ plan_run_splits(规划拆分)
    │   ├─ rebuild_paragraph_with_splits(重建段落)
    │   └─ 为每个错误run添加批注
    └─ 完成所有段落处理
    ↓
生成带批注的DOCX文件

核心特点:

  • 每个段落只重建一次,避免批注丢失
  • 所有错误位置被精确标注
  • 批注简洁明确(错误内容 → 建议修改)

7. 核心算法

7.1 多轮评分算法(DOCX→MD)

目的: 智能识别公文元素

位置: 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%
)

7.2 模板填充算法(MD→DOCX/XLSX)

7.2.1 DOCX模板填充流程

位置: 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()插入图片
   └─ 设置段落为单倍行距

7.2.2 XLSX模板填充流程

位置: converter/md2xlsx/placeholder_processor.py

完整流程:

1. 提取模板占位符
   ├─ {{字段名}} - YAML字段占位符
   ├─ {{↓字段}} - 列填充占位符
   └─ {{→字段}} - 行填充占位符

2. 替换YAML字段占位符

3. 填充表格数据
   ├─ 列填充:从占位符位置向下填充
   ├─ 行填充:从占位符位置向右填充
   └─ 智能跳过合并单元格

4. 处理图片占位符
   └─ 使用openpyxl.drawing.image.Image插入

5. 清理剩余占位符

7.3 敏感词匹配算法

位置: docx_spell/spell_checker.py

核心方法: sensitive_word_check()

算法特点:

  1. 有效例外词过滤: 只检查包含敏感词的例外词
  2. 统一扩展范围: 一次性计算所有例外词的最大长度
  3. 精确位置验证: 确认敏感词完全在例外词范围内
  4. 性能优化: 减少重复计算,只提取一次上下文

匹配流程:

对于每个敏感词:
    查找所有出现位置
    对于每个出现:
        过滤有效的例外词必须包含敏感词if 存在有效例外词:
            计算最大例外词长度
            提取扩展上下文向前向后各最大长度在上下文中查找所有例外词
            if 敏感词完全在某个例外词内部:
                跳过不报告else:
                报告为敏感词
        else:
            报告为敏感词

7.4 BFS数据块查找算法(XLSX→MD)

位置: 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方向邻居检测(包括对角线)
  • 自动识别连通区域
  • 智能清理空行列

第三部分:开发指南

8. 扩展开发

8.1 添加新的公文元素识别

步骤:

  1. converter/docx2md/gongwen/scorer.py 中定义/扩展新元素
  2. 实现评分函数
  3. 添加到评分流程
  4. 更新YAML输出格式

8.2 添加自定义校对规则

步骤:

  1. 在配置文件中添加规则开关
  2. 实现校对逻辑
  3. 注册到TextValidator

8.3 添加新的转换策略

步骤:

  1. 创建策略类并使用 @register_conversion@register_action 装饰器
  2. 将新模块加入 services/strategies/registry.py 的清单(按 action 或按类别)
  3. 运行 tests/test_services/test_strategies_registry_specs.py,确保清单不会遗漏;运行时通过 get_strategy() 按需加载

9. 性能优化

9.1 已实现的优化

  1. 模板缓存: 避免重复加载模板文件
  2. 配置缓存: 单例模式的配置管理器
  3. OCR单例: 全局唯一的OCR实例
  4. 延迟加载: 按需导入模块
  5. 增量处理: 逐段落处理大文档
  6. BFS算法: 高效查找Excel数据块
  7. 二分查找: 图片压缩质量优化

9.2 性能指标

操作 平均耗时 说明
MD→DOCX (10KB) < 1秒 含模板加载
DOCX→MD (50KB) < 2秒 元素识别
校对 (100段落) < 3秒 4种规则

10. 故障排查

10.1 常见问题定位

转换失败:

  1. 检查日志: logs/ 目录
  2. 验证文件格式
  3. 确认模板完整性
  4. 检查占位符格式

校对不工作:

  1. 检查配置文件中规则是否启用
  2. 验证文件为 .docx 格式
  3. 查看日志了解详细错误

模板不显示:

  1. 确认文件在 templates/ 目录
  2. 检查文件扩展名
  3. 重启程序重新扫描

10.2 调试方法

  1. 启用DEBUG日志:
# logger_config.toml
[logging]
level = "DEBUG"
  1. 查看详细日志:
# 日志位置: logs/docwen_YYYYMMDD.log
  1. 断点调试: 在关键函数设置断点

10.3 安全检查与严格模式

现象:启动时直接退出(或日志提示“核心安全检查失败”)。
原因:启动器会执行核心安全检查;默认严格模式下,一旦检查失败会终止进程。
处理:在确认运行环境可信的前提下,可设置环境变量允许降级继续运行:

  • DOCWEN_STRICT_SECURITY=0:关闭严格模式(安全检查失败时不硬退出,会给出提示)

10.4 文档一致性自检(维护用)

当代码有较大改动(配置块、输出路径、OCR、错误码)时,建议对本文件做一次关键词自检,确保不存在与实现冲突的描述:

  • 输出与落盘:finalize_outputsave_output_with_fallbackreplace_file_atomic
  • 输出命名:make_output_stemgenerate_output_pathgenerate_named_output_pathstrip_timestamp_suffix
  • OCR 约束:OCR 依赖extract_imageextract_imagesextract_ocr
  • 配置块数量:CONFIG_FILESDEFAULT_CONFIG_reload_config_block
  • 错误码与退出码:DocWenErrorExitCodeStrategyNotFoundErrorerror_code

第四部分:项目信息

11. 版本与兼容性

11.1 Python版本

  • 要求: Python 3.12+
  • 原因: 使用了新的类型注解语法和标准库特性

11.2 依赖版本

参见 pyproject.toml 中的 dependencies 部分。

11.3 操作系统

  • Windows 10/11: 完全支持
  • Linux: 实验性支持(网络隔离功能受限)
  • macOS: 实验性支持(网络隔离功能受限)

12. 技术创新点

12.1 三轮评分算法

创新性地采用三级评分机制识别公文元素,相比传统的正则匹配更加准确。

12.2 统一启动器架构

bootstrap.py 确保所有应用入口点的初始化一致性,提升代码复用性。

12.3 深度网络隔离

通过猴子补丁技术阻断6个网络模块(socket、urllib、http.client、ftplib、smtplib、ssl),实现全面的网络隔离,确保数据安全。

12.4 三级配置访问

创新的配置访问机制(配置块→子表→具体值),提供灵活且类型安全的配置管理。

12.5 策略注册系统

采用装饰器注册模式(@register_conversion/@register_action)+ 动态批量注册,并通过显式清单(registry.py)实现策略模块的按需加载。

12.6 统一输入副本机制

prepare_input_file() 为所有转换创建安全副本,永不修改原文件。

12.7 临时目录保护

使用 tempfile.TemporaryDirectory() 确保转换过程的原子性和安全性。


13. 开发规范

13.1 代码风格

  • 遵循 PEP 8 规范
  • 使用类型注解
  • 函数/类添加 docstring
  • 复杂逻辑添加注释

13.2 提交规范

feat: 新功能
fix: 修复bug
docs: 文档更新
refactor: 代码重构
test: 测试相关
chore: 构建/工具相关

13.3 测试规范

  • 单元测试覆盖核心函数
  • 集成测试覆盖主要流程
  • 使用测试文件验证功能

13.4 输出契约(golden JSON)

CLI 的 --json 输出被视为对外契约(供脚本/自动化/AI 调用),通过“黄金样例”测试锁定结构与语义:

  • 黄金样例目录:tests/fixtures/golden/
  • 对比测试入口:tests/test_cli/test_json_golden.py

维护原则:

  • 允许变化但必须归一化:输入路径(如 input_file)、耗时(如 duration)。
  • 不应随意变化:字段名、层级结构、默认值语义(例如未开启 --timing 时 duration 为 0.0)、退出码含义、错误字段(error_code/details)语义。
  • 变更流程:若确需修改输出结构,应同步更新黄金样例与测试,并在文档/变更说明中写清楚不兼容点与迁移建议。

14. 项目信息与参考

14.1 项目信息

项目名称: 公文转换器 (DocWen)
软件全称: 公文图表格式转换软件
版本管理: 从 src/docwen/__init__.py 读取
版本格式: 主版本.次版本.修订号.构建日期.当日修订号
Python要求: >=3.12
许可证: GNU Affero General Public License v3.0 (AGPL-3.0)
作者: ZhengYX
项目主页: https://github.com/ZHYX91/docwen

14.2 依赖库文档