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,163 @@
|
||||
# 纯中文模式格式丢失问题 - 深度分析
|
||||
|
||||
## 🔴 根本原因:Mode 参数未被正确传递
|
||||
|
||||
### 问题概述
|
||||
|
||||
当前 `translator.py` 的 `translate_epub()` 方法签名只有 3 个参数:
|
||||
```python
|
||||
async def translate_epub(self, epub_path: str, test_mode: bool = False, output_dir: str = None) -> str:
|
||||
```
|
||||
|
||||
**缺失 `mode` 参数!** 这意味着:
|
||||
1. 无论用户指定 `-m chinese` 还是 `-m bilingual`,都走相同的代码路径
|
||||
2. 永远使用 `BilingualEPUBBuilder`
|
||||
3. 格式提取功能 (`format_extractor.py`) 从未被调用
|
||||
|
||||
---
|
||||
|
||||
## 问题链路分析
|
||||
|
||||
### main.py 调用
|
||||
```python
|
||||
# main.py:55-59
|
||||
await translator.translate_epub(
|
||||
args.epub_path,
|
||||
test_mode=args.test,
|
||||
output_dir=args.output,
|
||||
mode=args.mode # ❌ 此参数被忽略!因为 translate_epub 不接受 mode
|
||||
)
|
||||
```
|
||||
|
||||
### translator.py 未处理 mode
|
||||
```python
|
||||
# translator.py:39 - 缺少 mode 参数
|
||||
async def translate_epub(self, epub_path: str, test_mode: bool = False, output_dir: str = None) -> str:
|
||||
|
||||
# translator.py:53 - 提取时未传 mode
|
||||
self.text_processor.extract_to_manifest(item['content'], item['file_name'], manifest)
|
||||
# 应该是: extract_to_manifest(..., mode=mode)
|
||||
|
||||
# translator.py:72 - 分块时未传 mode
|
||||
chunks = self.text_processor.create_chunks_from_manifest(manifest)
|
||||
# 应该是: create_chunks_from_manifest(manifest, mode=mode)
|
||||
|
||||
# translator.py:84 - 永远使用 BilingualBuilder
|
||||
builder = BilingualEPUBBuilder(self.parser.book, self.config)
|
||||
# 应根据 mode 选择 ChineseEPUBBuilder
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 完整的格式保留流程 (应有逻辑)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 1. 提取阶段 (format_extractor.py) │
|
||||
│ Input: <p>This is <strong>bold</strong> text.</p> │
|
||||
│ Output: │
|
||||
│ - clean_text: "This is bold text." │
|
||||
│ - text_with_placeholders: "This is φc00001φboldφc00002φ text." │
|
||||
│ - placeholder_map: {c00001: "<strong>", c00002: "</strong>"} │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 2. 翻译阶段 (llm_client.py) │
|
||||
│ Prompt: p_00001 [BODY] This is φc00001φboldφc00002φ text. │
|
||||
│ LLM Response: p_00001 这是φc00001φ粗体φc00002φ文本。 │
|
||||
│ ⚠️ 问题:LLM 可能丢失/错放占位符! │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 3. 还原阶段 (format_restorer.py) │
|
||||
│ Input: "这是φc00001φ粗体φc00002φ文本。" │
|
||||
│ Output: "这是<strong>粗体</strong>文本。" │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 4. 构建阶段 (chinese_builder.py) │
|
||||
│ 使用 translation_with_original_html 替换原始内容 │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**当前状态**: 步骤 1、3、4 从未执行!
|
||||
|
||||
---
|
||||
|
||||
## LLM 占位符丢失的常见原因
|
||||
|
||||
即使修复了 mode 传递问题,LLM 仍可能丢失占位符:
|
||||
|
||||
| 原因 | 示例 | 解决方案 |
|
||||
|------|------|----------|
|
||||
| 占位符被"翻译" | φc00001φ → φ中00001φ | 强调 Prompt: "φ...φ 是代码,禁止修改" |
|
||||
| 占位符位置错误 | 原: Aφc1φB → 译: φc1φAB | 修复 Agent (repair_format) |
|
||||
| 占位符完全丢失 | 原: φc1φ → 译: (无) | 后处理:从原文恢复 |
|
||||
| 幻觉占位符 | 原: (无) → 译: φc99φ | 忽略未知 ID |
|
||||
|
||||
---
|
||||
|
||||
## 修复建议
|
||||
|
||||
### 修复 1: translator.py 添加 mode 参数
|
||||
|
||||
```python
|
||||
async def translate_epub(self, epub_path: str, test_mode: bool = False,
|
||||
output_dir: str = None, mode: str = "bilingual") -> str:
|
||||
# ...
|
||||
|
||||
# 提取时传递 mode
|
||||
self.text_processor.extract_to_manifest(item['content'], item['file_name'], manifest, mode=mode)
|
||||
|
||||
# 分块时传递 mode
|
||||
chunks = self.text_processor.create_chunks_from_manifest(manifest, mode=mode)
|
||||
|
||||
# 翻译时传递 mode
|
||||
await self._translate_concurrently(chunks, manifest, profile, mode=mode)
|
||||
|
||||
# 构建时选择正确的 Builder
|
||||
if mode == "chinese":
|
||||
builder = ChineseEPUBBuilder(self.parser.book, self.config)
|
||||
result_file = builder.create_chinese_epub_with_mapping(manifest.get_items(), output_path)
|
||||
else:
|
||||
builder = BilingualEPUBBuilder(self.parser.book, self.config)
|
||||
result_file = builder.create_bilingual_epub_with_mapping(...)
|
||||
```
|
||||
|
||||
### 修复 2: llm_client.py 添加占位符指令
|
||||
|
||||
```python
|
||||
if mode == "chinese":
|
||||
base_sys_prompt += """
|
||||
|
||||
Placeholder Instructions:
|
||||
1. Text contains φcXXXXXφ placeholders representing HTML formatting.
|
||||
2. These are CODE tokens - DO NOT translate, modify, or remove them.
|
||||
3. Keep placeholders in corresponding positions in your translation.
|
||||
4. Example: "This is φc00001φboldφc00002φ text." → "这是φc00001φ粗体φc00002φ文本。"
|
||||
"""
|
||||
```
|
||||
|
||||
### 修复 3: 增强 format_restorer.py 容错
|
||||
|
||||
```python
|
||||
def restore(self, text_with_placeholders, placeholder_map):
|
||||
# 如果 LLM 完全丢失占位符,尝试智能合并
|
||||
if not self.PLACEHOLDER_REGEX.search(text_with_placeholders):
|
||||
logger.warning("所有占位符丢失,降级为纯文本")
|
||||
return text_with_placeholders, False
|
||||
|
||||
# 现有逻辑...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 优先级
|
||||
|
||||
| 优先级 | 修复项 | 工作量 |
|
||||
|--------|--------|--------|
|
||||
| P0 | translator.py 传递 mode 参数 | 小 |
|
||||
| P0 | translator.py 选择正确 Builder | 小 |
|
||||
| P1 | llm_client.py 占位符 Prompt | 小 |
|
||||
| P2 | format_restorer.py 容错增强 | 中 |
|
||||
| P2 | repair_format 机制完善 | 中 |
|
||||
Reference in New Issue
Block a user