Files

112 lines
4.0 KiB
Python

import argparse
import sys
import os
import asyncio
from pathlib import Path
# Add project root to sys.path
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from src.translation.translator_engine import Translator
from src.translation.llm_client import LLMClient
from src.translation.manifest_manager import ManifestManager
from src.preprocessing.profiler import BookProfiler
from src.common.utils import setup_logger
from src.common.exceptions import EpubTranslatorError
from src.common.config import load_global_config
from src.common.paths import get_work_dirs
logger = setup_logger("pipeline_translate")
async def run_translate(args):
# Resolve paths
input_path = None
if args.input_epub:
input_path = Path(args.input_epub)
elif args.book_name:
# Try to infer from work dir if book_name provided (legacy support)
# But paths.py needs input_path to determine work dir.
# So we really need input_epub for get_work_dirs.
# But if the user only provides book_name, we might be in trouble with get_work_dirs logic
# which relies on input_path.stem.
# Let's check get_work_dirs again.
pass
# Actually get_work_dirs relies on input_path.stem.
# If the user gives only --book-name, we can't easily construct input_path
# unless we fake it or change get_work_dirs.
# However, pipeline instructions say input_epub is required for 02_translate.
# checking args... 02_translate has --input-epub AND --book-name.
if args.input_epub:
input_path = Path(args.input_epub)
else:
logger.error("Must provide --input-epub")
sys.exit(1)
work = get_work_dirs(input_path)
manifest_path = work["manifest"]
if not manifest_path.exists():
logger.error(f"Manifest not found: {manifest_path}. Run Step 1 first.")
sys.exit(1)
# Load Config
config = load_global_config()
llm_conf = config.get("llm", {})
trans_conf = config.get("translation", {})
api_key = llm_conf.get("api_key")
if not api_key:
logger.error("OPENAI_API_KEY not found in env or config.")
sys.exit(1)
try:
# Load Manifest
manager = ManifestManager(manifest_path)
manager.load()
# Init components
# Allow CLI args to override config if needed (not implemented yet, taking config partial priority)
llm = LLMClient(
api_key=api_key,
base_url=llm_conf.get("base_url"),
model=args.model if args.model else llm_conf.get("model", "gpt-3.5-turbo"),
requests_per_minute=llm_conf.get("requests_per_minute", 60),
concurrent_requests=llm_conf.get("concurrent_requests", 5),
chunk_dir=work["chunks"]
)
# Profile
profiler = BookProfiler(llm)
profile = await profiler.analyze(manager.entries)
logger.info(f"Book Profile: {profile.title} ({profile.genre})")
# Translate
target_chunk_size = trans_conf.get("chunk_size", 4000)
concurrent_reqs = llm_conf.get("concurrent_requests", 5)
translator = Translator(llm, chunk_size=target_chunk_size, max_concurrent=concurrent_reqs)
await translator.translate(manager.entries, profile)
# Save final state
manager.save()
await llm.close()
logger.info("Translation complete.")
except EpubTranslatorError as e:
logger.error(f"Translation failed: {e}")
sys.exit(1)
except Exception as e:
logger.critical(f"Unexpected error: {e}")
sys.exit(1)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Step 2: Translation")
parser.add_argument("--input-epub", help="Path to original EPUB (to derive book name)")
parser.add_argument("--book-name", help="Book name (folder name in work/)")
parser.add_argument("--model", default=None, help="LLM Model (overrides config)")
args = parser.parse_args()
asyncio.run(run_translate(args))