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,110 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Manifest 错误分析工具
|
||||
用于深入分析翻译结果中的占位符问题
|
||||
"""
|
||||
import sys
|
||||
import re
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, '.')
|
||||
from src.manifest_manager import ManifestManager
|
||||
|
||||
def analyze_item(item):
|
||||
"""详细分析单个 Item 的占位符状态"""
|
||||
issues = []
|
||||
|
||||
twp = item.text_with_placeholders or ""
|
||||
trans = item.translation_with_placeholders or ""
|
||||
pmap = item.placeholder_map or {}
|
||||
|
||||
ph_regex = r'φ(/?\d+)φ'
|
||||
src_phs = set(re.findall(ph_regex, twp))
|
||||
trans_phs = set(re.findall(ph_regex, trans))
|
||||
map_ids = {k for k in pmap.keys() if not k.startswith('_')}
|
||||
|
||||
# 模拟 FormatRestorer 的宽松逻辑
|
||||
unknowns = trans_phs - map_ids
|
||||
real_unknowns = set()
|
||||
for pid in unknowns:
|
||||
# 如果是 /N,且 N 在 map 中,则认为是安全的冗余闭合
|
||||
if pid.startswith('/') and pid[1:] in map_ids:
|
||||
continue
|
||||
real_unknowns.add(pid)
|
||||
|
||||
if real_unknowns:
|
||||
issues.append(f"未知占位符(幻觉): {real_unknowns}")
|
||||
|
||||
missing = map_ids - trans_phs
|
||||
if missing:
|
||||
issues.append(f"丢失占位符: {missing}")
|
||||
|
||||
# Check Reordering
|
||||
src_ph_list = re.findall(ph_regex, twp)
|
||||
trans_ph_list = re.findall(ph_regex, trans)
|
||||
common = [p for p in src_ph_list if p in trans_ph_list]
|
||||
trans_common = [p for p in trans_ph_list if p in src_ph_list]
|
||||
if common != trans_common:
|
||||
issues.append(f"占位符乱序: 原文{common} -> 译文{trans_common}")
|
||||
|
||||
return issues
|
||||
|
||||
def main():
|
||||
manifest_dir = Path("cache/manifests")
|
||||
files = list(manifest_dir.glob("*_manifest.json"))
|
||||
if not files:
|
||||
print("未找到 manifest 文件")
|
||||
return
|
||||
|
||||
target = next((f for f in files if "Karen Hao" in f.name), files[0])
|
||||
print(f"Loading: {target}")
|
||||
|
||||
manifest = ManifestManager(str(target))
|
||||
if not manifest.load():
|
||||
print("加载失败")
|
||||
return
|
||||
|
||||
items = manifest.get_items()
|
||||
error_count = 0
|
||||
total_analyzed = 0
|
||||
|
||||
print("\n" + "="*50)
|
||||
print(" 异常项目分析报告")
|
||||
print("="*50 + "\n")
|
||||
|
||||
for item in items:
|
||||
# 只分析非成功状态或有 warning 的
|
||||
if item.status == "completed":
|
||||
continue
|
||||
|
||||
# 即使是 format_error, failed, translated (with issues)
|
||||
issues = analyze_item(item)
|
||||
has_error = (item.status in ["failed", "format_error"]) or bool(issues)
|
||||
|
||||
if has_error:
|
||||
total_analyzed += 1
|
||||
print(f"ID: {item.global_id} (Status: {item.status})")
|
||||
if item.error_msg:
|
||||
print(f" Error Msg: {item.error_msg}")
|
||||
|
||||
# 只有当有具体 issue 时才打印详细文本,避免刷屏
|
||||
if issues or item.status == "format_error":
|
||||
print(f" 原文: {item.text_with_placeholders[:100]}...")
|
||||
print(f" 译文: {item.translation_with_placeholders[:100]}..." if item.translation_with_placeholders else " 译文: (None)")
|
||||
print(f" Map: {list(item.placeholder_map.keys())}")
|
||||
|
||||
for issue in issues:
|
||||
print(f" -> {issue}")
|
||||
|
||||
print("-" * 50)
|
||||
error_count += 1
|
||||
|
||||
if error_count > 50:
|
||||
print("... (Errors truncated) ...")
|
||||
break
|
||||
|
||||
print(f"\n分析完成。共发现 {total_analyzed} 个异常项目。")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user