feat: Release v0.10 - Modular Architecture & External Config
- Refactor codebase into src/ (preprocessing, translation, assembly) - Add pipeline/ scripts for individual stages - Externalize configuration to config/config.yaml - Fix Cover Image preservation - Update documentation and manuals
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
# 预处理与回填层技术文档
|
||||
|
||||
本文档详细描述 EPUB 双语翻译器的预处理(Preprocessing)和回填(Backfill)层的技术方案、数据结构、问题解决方案,用于指导代码开发、调试和维护。
|
||||
|
||||
---
|
||||
|
||||
## 1. 架构概览
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌────────────────┐ ┌───────────────────┐
|
||||
│ EPUB 文件 │ ──► │ EpubCleaner │ ──► │ book_structure.json│
|
||||
└─────────────┘ └────────────────┘ └───────────────────┘
|
||||
│
|
||||
▼
|
||||
┌────────────────┐ ┌───────────────────┐
|
||||
│FineGrainedExt. │ ──► │ manifest.json │
|
||||
└────────────────┘ └───────────────────┘
|
||||
│
|
||||
┌────────────────┐ │
|
||||
│ BackfillEngine │ ◄───────────┘
|
||||
└────────────────┘
|
||||
│
|
||||
▼
|
||||
┌────────────────┐ ┌───────────────────┐
|
||||
│BilingualBuilder│ ──► │ 输出 EPUB │
|
||||
└────────────────┘ └───────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 目录结构
|
||||
|
||||
```
|
||||
work/
|
||||
├── {book_name}/ # 每本书独立的工作目录
|
||||
│ ├── book_structure.json # 书籍结构(会被复用)
|
||||
│ ├── manifest.json # 翻译清单(持久化,Source of Truth)
|
||||
│ └── assets/ # 解压出的 EPUB 资源文件
|
||||
│ └── OEBPS/images/... # 保留原始路径结构
|
||||
└── translations/ # (可选) 翻译记忆或其他中间文件
|
||||
```
|
||||
|
||||
**关键设计**:`book_structure.json` **默认复用**。为避免 UUID 不一致导致回填失败,除非显式指定强制清理,否则程序优先读取现有的结构文件。
|
||||
|
||||
---
|
||||
|
||||
## 3. 数据结构定义
|
||||
|
||||
### 3.1 BookStructure (book_structure.json)
|
||||
|
||||
记录书籍的“骨架”,确保翻译后的章节能按正确顺序和层级重组。
|
||||
|
||||
```json
|
||||
{
|
||||
"metadata": {
|
||||
"title": "书名",
|
||||
"author": "作者",
|
||||
"language": "en",
|
||||
"identifier": "ISBN或UUID"
|
||||
},
|
||||
"spine": ["item_id_1", "item_id_2", ...], // 阅读顺序
|
||||
"resources": {
|
||||
"item_id_1": {
|
||||
"href": "OEBPS/chapter1.xhtml",
|
||||
"media_type": "application/xhtml+xml",
|
||||
"content": "<html>...</html>", // 清理并注入ID后的HTML内容
|
||||
"properties": "nav"
|
||||
},
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 ManifestEntry (manifest.json)
|
||||
|
||||
翻译清单是全生命周期的核心,记录了所有待翻译段落的状态。
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"entry_id": "OEBPS/c3Z.xhtml#uuid-603ff3fb",
|
||||
"file_path": "OEBPS/c3Z.xhtml",
|
||||
"element_id": "uuid-603ff3fb",
|
||||
"original_text": "φ1φHelloφ/1φ world.",
|
||||
"placeholders": {
|
||||
"1": "<b>",
|
||||
"/1": "</b>",
|
||||
"_prefix": "<p>",
|
||||
"_suffix": "</p>"
|
||||
},
|
||||
"translated_text": "φ1φ你好φ/1φ 世界。",
|
||||
"context": "body"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `entry_id` | str | **全局唯一ID** (`file_path#element_id`),用于精准追踪。 |
|
||||
| `file_path` | str | 标识该段落属于哪一章,用于按章分组批处理。 |
|
||||
| `element_id` | str | HTML DOM 元素的 ID,回填时的锚点。 |
|
||||
| `original_text` | str | 经过智能抽提和占位符化后的文本,发送给 LLM。 |
|
||||
| `placeholders` | Dict | 格式映射表,用于还原 HTML 结构。 |
|
||||
| `translated_text`| str | 翻译结果(含占位符),初始为 null。 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 预处理与抽提流程 (Extraction)
|
||||
|
||||
流程由 `FormatExtractor` 驱动,分为三个阶段:
|
||||
|
||||
### Step 1: 结构索引 (Structure Indexing)
|
||||
* **动作**: 解析 OPF 文件,提取 Spine 和 Metadata。
|
||||
* **目的**: 建立骨架,确定处理顺序。
|
||||
|
||||
### Step 2: 语义识别 (Semantic Detection)
|
||||
* **动作**: 使用 `HeadingDetector` 分析 DOM 节点。
|
||||
* **逻辑**:
|
||||
* 匹配 `h1`-`h6` 正则,区分 `Chapter`(章)与 `Section`(节)。
|
||||
* 识别 `blockquote` 或特定 class 判定 `Epigraph`(引言)。
|
||||
* **目的**: 为 LLM 提供差异化的 Prompt(例如翻译标题时不要加句号)。
|
||||
|
||||
### Step 3: 智能抽提 (Smart Extraction - `_smart_extract_v3`)
|
||||
这是核心算法,将 HTML 转换为“纯文本+占位符”。
|
||||
|
||||
1. **首尾分离 (Prefix/Suffix Separation)**:
|
||||
* 将包裹文本的外层标签(如 `<p>`, `div`)剥离到 `_prefix` 和 `_suffix`。
|
||||
* **目的**: 极大减少 LLM 输入 Token,且防止 LLM 随意修改外层布局。
|
||||
|
||||
2. **首字下沉处理 (Drop Cap Handling)**:
|
||||
* 检测并合并被 `<span>` 单独包裹的首字母(如 `<span class="drop">O</span>` + `nce` → `Once`)。
|
||||
* **目的**: 修复语意割裂,让 LLM 看到完整的单词。
|
||||
|
||||
3. **占位符化 (Placeholder Mapping)**:
|
||||
* 将内联标签(`<a>`, `<em>`)或公式替换为短码 `φIDφ`。
|
||||
* **目的**: 保护 HTML 属性不被“翻译”,降低噪声干扰。
|
||||
|
||||
4. **完整性校验 (Integrity Check)**:
|
||||
* **逻辑**: 抽提后的文本(去占位符)与原始纯文本进行归一化比对,要求覆盖率 **100%**。
|
||||
* **兜底**: 若校验失败(如误删内容),回退到简单模式(只剥离首尾标签)。
|
||||
|
||||
---
|
||||
|
||||
## 5. 构建与回填流程 (Backfill & Build)
|
||||
|
||||
### 5.1 翻译回填
|
||||
* 根据 `entry_id` 找到对应的 DOM 节点。
|
||||
* 使用 `FormatRestorer` 将 `translated_text` 中的占位符(`φ1φ`)还原为原始 HTML 标签(`<b>`)。
|
||||
* 根据模式(双语/单语)决定将新节点插入到原文后还是替换原文。
|
||||
|
||||
### 5.2 链接修复 (Link Repair)
|
||||
在 `BilingualBuilder` 中执行:
|
||||
1. **ID 补全**: 为缺失 ID 的 TOC 节点自动生成 UUID。
|
||||
2. **死链检测**: 检查 TOC/Nav 指向的文件是否存在。
|
||||
3. **模糊修复**: 尝试通过文件名后缀匹配(解决路径前缀变更问题)或特定重定向(如 `c0.xhtml` -> `cover.xhtml`)。
|
||||
4. **坏死剔除**: 无法修复的死链将从目录中移除。
|
||||
|
||||
### 5.3 CSS 样式恢复
|
||||
`EbookLib` 默认可能会重写 `<head>` 导致样式丢失。
|
||||
* **逻辑**:
|
||||
* 收集所有 CSS 资源。
|
||||
* 在构建每个 HTML Item 时,显式计算 HTML 到 CSS 的**相对路径**。
|
||||
* 强制调用 `item.add_link(..., rel='stylesheet', type='text/css')` 注入引用。
|
||||
|
||||
---
|
||||
|
||||
## 6. 常见问题排查
|
||||
|
||||
### 6.1 UUID 不匹配
|
||||
**现象**: `WARNING - Element uuid-xxx not found`.
|
||||
**原因**: 手动删除了 `book_structure.json` 但保留了 `manifest.json`,导致重新生成的 HTML ID 与清单记录不一致。
|
||||
**解决**: 清空 `work/BookName` 目录重新运行,或确保两个 JSON 文件版本一致。
|
||||
|
||||
### 6.2 样式丢失
|
||||
**现象**: 打开书面目全非,只有黑白文字。
|
||||
**检查**: 解压 EPUB,查看 HTML `<head>` 是否有 `<link rel="stylesheet">`。如果没有,检查 `BilingualBuilder` 的 Step 4 逻辑。
|
||||
|
||||
### 6.3 翻译错位
|
||||
**现象**: 译文出现在了错误的位置。
|
||||
**检查**: 确认 `entry_id` 生成逻辑是否包含文件名,且文件名在处理过程中未被意外修改。
|
||||
Reference in New Issue
Block a user