Files
epub_bilingual_translator/archive/v0.13/scripts/test_backfill.py
T

213 lines
7.0 KiB
Python

#!/usr/bin/env python3
"""
Placeholder Backfill Test Script
Tests placeholder restoration on translated entries.
Usage:
python scripts/test_backfill.py --chapter 38
python scripts/test_backfill.py --chapter 38 --limit 10
"""
import argparse
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent))
from src.manifest_manager import ManifestManager
from src.format_restorer import FormatRestorer
# Configuration - Use unified .work directory
BOOK_NAME = "Empire of AI Dreams and Nightmares in Sam Altmans OpenAI (Karen Hao)"
WORK_DIR = Path(f".work/{BOOK_NAME}")
MANIFEST_PATH = WORK_DIR / "manifest.json"
def build_toc_from_manifest(manager: ManifestManager) -> list:
"""Build TOC from manifest entries."""
files = {}
for entry in manager.entries:
fp = entry.file_path
if fp not in files:
files[fp] = {'count': 0, 'first_text': ''}
files[fp]['count'] += 1
if not files[fp]['first_text'] and entry.original_text:
files[fp]['first_text'] = entry.original_text[:40].replace('\n', ' ')
toc = []
for i, (fp, info) in enumerate(sorted(files.items()), 1):
toc.append({
'index': i,
'href': fp,
'title': info['first_text'] or f"File {i}",
'paragraphs': info['count']
})
return toc
def get_chapter_entries(manager: ManifestManager, chapter_index: int) -> tuple:
"""Get entries for a specific chapter by index."""
toc = build_toc_from_manifest(manager)
if chapter_index < 1 or chapter_index > len(toc):
print(f"错误: 章节编号 {chapter_index} 无效 (范围: 1-{len(toc)})")
return None, None
chapter = toc[chapter_index - 1]
href = chapter['href']
entries = [e for e in manager.entries if e.file_path == href]
return chapter, entries
def test_backfill(chapter: dict, entries: list, limit: int = None):
"""Test placeholder restoration for a chapter."""
print(f"\n" + "=" * 70)
print(f"占位符回填测试 - 章节 #{chapter['index']}: {chapter['title'][:40]}...")
print("=" * 70)
# Filter entries with translation and placeholders
translated = [e for e in entries if e.translated_text]
with_placeholders = [e for e in translated if e.placeholders and len(e.placeholders) > 0]
print(f"\n统计:")
print(f" 总段落: {len(entries)}")
print(f" 已翻译: {len(translated)}")
print(f" 有占位符: {len(with_placeholders)}")
if not translated:
print("\n⚠️ 该章节没有已翻译的内容!")
return
# Test restoration
restorer = FormatRestorer()
success_count = 0
fail_count = 0
results = []
test_entries = with_placeholders[:limit] if limit else with_placeholders
print(f"\n测试 {len(test_entries)} 个带占位符的段落:")
print("-" * 70)
for i, entry in enumerate(test_entries, 1):
original = entry.original_text
translated = entry.translated_text
placeholders = entry.placeholders
# Get non-internal placeholders
visible_ph = {k: v for k, v in placeholders.items() if not k.startswith('_')}
# Perform restoration
restored, success = restorer.restore(translated, placeholders)
if success:
success_count += 1
status = "✅"
else:
fail_count += 1
status = "❌"
results.append({
'index': i,
'entry_id': entry.entry_id,
'original': original,
'translated': translated,
'restored': restored,
'placeholders': visible_ph,
'success': success
})
# Print summary
print(f"\n[{i}] {status} {entry.entry_id[-40:]}")
print(f" 占位符: {list(visible_ph.keys())}")
print(f" 原文: {original[:50]}...")
print(f" 译文: {translated[:50]}...")
if not success:
print(f" 还原: {restored[:50]}...")
# Show what placeholders are missing
missing = []
for k in visible_ph.keys():
if k.isdigit():
if f{k}φ" not in translated and f"φ/{k}φ" not in translated:
missing.append(k)
if missing:
print(f" 缺失: {missing}")
# Summary
print("\n" + "=" * 70)
print(f"测试结果汇总")
print("=" * 70)
print(f" 成功: {success_count}/{len(test_entries)}")
print(f" 失败: {fail_count}/{len(test_entries)}")
if fail_count > 0:
print(f"\n失败案例详情:")
for r in results:
if not r['success']:
print(f"\n [{r['index']}] {r['entry_id'][-50:]}")
print(f" 原文: {r['original'][:60]}...")
print(f" 译文: {r['translated'][:60]}...")
print(f" 还原: {r['restored'][:60]}...")
print(f" 占位符: {r['placeholders']}")
# Also test entries without visible placeholders (only _prefix/_suffix)
prefix_suffix_only = [e for e in translated
if e.placeholders
and all(k.startswith('_') for k in e.placeholders.keys())]
if prefix_suffix_only:
print(f"\n\n额外测试: 只有 _prefix/_suffix 的段落 ({len(prefix_suffix_only)} 个)")
print("-" * 70)
ps_success = 0
ps_fail = 0
for entry in prefix_suffix_only[:5]: # Test first 5
restored, success = restorer.restore(entry.translated_text, entry.placeholders)
if success:
ps_success += 1
status = "✅"
else:
ps_fail += 1
status = "❌"
print(f" {status} {entry.entry_id[-40:]}")
if '_prefix' in entry.placeholders:
print(f" _prefix: {entry.placeholders['_prefix'][:30]}...")
if '_suffix' in entry.placeholders:
print(f" _suffix: {entry.placeholders['_suffix'][:30]}...")
print(f"\n 结果: {ps_success}/{min(5, len(prefix_suffix_only))} 成功")
def main():
parser = argparse.ArgumentParser(description="测试占位符回填")
parser.add_argument("--chapter", "-c", type=int, required=True, help="章节编号")
parser.add_argument("--limit", "-l", type=int, default=20, help="测试数量限制 (默认20)")
args = parser.parse_args()
if not MANIFEST_PATH.exists():
print(f"错误: Manifest 不存在: {MANIFEST_PATH}")
return
# Load manifest
manager = ManifestManager(MANIFEST_PATH)
manager.load()
print(f"已加载 manifest: {len(manager.entries)} 条目")
# Get chapter
chapter, entries = get_chapter_entries(manager, args.chapter)
if not chapter:
return
# Test backfill
test_backfill(chapter, entries, args.limit)
if __name__ == "__main__":
main()