- 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
92 lines
3.1 KiB
Python
92 lines
3.1 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
|
|
|
|
logger = setup_logger("pipeline_translate")
|
|
|
|
async def run_translate(args):
|
|
# Resolve paths
|
|
if args.book_name:
|
|
book_name = args.book_name
|
|
elif args.input_epub:
|
|
book_name = Path(args.input_epub).stem
|
|
else:
|
|
logger.error("Must provide --book-name or --input-epub")
|
|
sys.exit(1)
|
|
|
|
work_root = Path("work") / book_name
|
|
manifest_path = work_root / "manifest.json"
|
|
|
|
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)
|
|
)
|
|
|
|
# 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)
|
|
translator = Translator(llm, chunk_size=target_chunk_size)
|
|
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))
|