Files
epub_bilingual_translator/main.py
T
2026-01-19 09:51:07 +08:00

108 lines
3.7 KiB
Python

#!/usr/bin/env python3
import asyncio
import sys
import argparse
from pathlib import Path
from loguru import logger
from src.translator import EPUBTranslator
from src.epub_parser import EPUBParser
from src.toc_parser import TOCParser
from src.utils import load_config, setup_logging
def parse_args():
parser = argparse.ArgumentParser(description="EPUB 双语翻译工具")
parser.add_argument("epub_path", help="输入 EPUB 文件路径")
parser.add_argument("--provider", "-p", default="openrouter", help="LLM 供应商 (config.json 中 providers 的 key)")
parser.add_argument("--mode", "-m", default="bilingual", choices=["bilingual", "chinese"],
help="输出模式: bilingual (双语对照) 或 chinese (纯中文,保留格式)")
parser.add_argument("--test", action="store_true", help="测试模式(仅翻译前几段)")
parser.add_argument("--output", "-o", help="输出目录")
parser.add_argument("--no-cache", action="store_true", help="禁用缓存(强制重新翻译)")
parser.add_argument("--clear-cache", action="store_true", help="清理所有缓存文件")
# TOC 章节选择
parser.add_argument("--show-toc", action="store_true", help="显示书籍目录结构")
parser.add_argument("--from", dest="from_chapter", help="起始章节标题")
parser.add_argument("--to", dest="to_chapter", help="结束章节标题")
return parser.parse_args()
def flatten_provider_config(config: dict, provider_name: str) -> dict:
"""
将选定的 provider 配置扁平化到 config['llm'] 中,
以便下游模块统一调用。
"""
providers = config.get('providers', {})
if provider_name not in providers:
available = list(providers.keys())
logger.error(f"未找到供应商 '{provider_name}'。可用供应商: {available}")
sys.exit(1)
selected_config = providers[provider_name]
logger.info(f"使用 LLM 供应商: {provider_name} ({selected_config.get('base_url')})")
# 注入到 config['llm']
config['llm'] = selected_config
return config
async def run_translation(args):
try:
# 1. 加载配置
config = load_config()
# 2. 处理 Provider 选择
config = flatten_provider_config(config, args.provider)
# 3. 设置日志
setup_logging(config)
logger.info("程序启动")
# 4. 初始化翻译器
translator = EPUBTranslator(config, use_cache=not args.no_cache)
# 5. 执行翻译 (传递章节范围参数)
await translator.translate_epub(
args.epub_path,
test_mode=args.test,
output_dir=args.output,
mode=args.mode,
from_chapter=args.from_chapter,
to_chapter=args.to_chapter
)
except Exception as e:
import traceback
traceback.print_exc()
logger.error(f"翻译失败: {e}")
sys.exit(1)
def show_toc(epub_path: str):
"""显示 EPUB 的目录结构"""
parser = EPUBParser(epub_path)
toc_parser = TOCParser(parser.book)
print(f"\n📖 {parser.metadata.get('title', 'Unknown')} - {parser.metadata.get('author', 'Unknown')}")
print(toc_parser.format_toc_table())
print("提示: 使用 --from \"章节名\" --to \"章节名\" 指定翻译范围")
print()
def main():
args = parse_args()
if args.clear_cache:
import shutil
cache_dir = Path("cache")
if cache_dir.exists():
shutil.rmtree(cache_dir)
print("缓存已清理")
sys.exit(0)
if args.show_toc:
show_toc(args.epub_path)
sys.exit(0)
asyncio.run(run_translation(args))
if __name__ == "__main__":
main()