OmniSub / src /omnisub /cli.py
STBack23's picture
Upload OmniSub source
b5c8312 verified
Raw
History Blame Contribute Delete
4.78 kB
"""CLI cho OmniSub.
Ví dụ:
# Kiểm tra nhanh Bước 1 (không nạp model): parse + gom cảnh
python -m omnisub.cli prepare phim.srt
# Toàn bộ pipeline trên Colab (có video + Qwen3-Omni)
python -m omnisub.cli run phim.srt --video phim.mp4 --config config.yaml
"""
from __future__ import annotations
import argparse
import logging
import sys
from pathlib import Path
from .config import Config
from .pipeline import prepare_subtitles, run_pipeline
def _force_utf8() -> None:
"""Ép stdout/stderr sang UTF-8 (console Windows mặc định cp1252 không in được tiếng Việt)."""
for stream in (sys.stdout, sys.stderr):
reconfigure = getattr(stream, "reconfigure", None)
if reconfigure is not None:
try:
reconfigure(encoding="utf-8")
except (ValueError, OSError):
pass
def _setup_logging(verbose: bool) -> None:
_force_utf8()
logging.basicConfig(
level=logging.DEBUG if verbose else logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
datefmt="%H:%M:%S",
)
def _build_backend(config: Config, args):
"""Khởi tạo backend Qwen3-Omni (lazy import để Bước 1 không cần GPU).
`--backend none` chỉ chạy Bước 1 (chuẩn bị SRT) để kiểm tra nhanh, không nạp model.
"""
if args.backend == "none":
return None
if args.backend == "qwen":
from .backends.transformers_qwen import TransformersQwenOmniBackend
return TransformersQwenOmniBackend(
model_name=config.models["omni"],
quant=config.models["quant"],
cache_dir=args.cache_dir,
)
raise SystemExit(f"Backend không hỗ trợ: {args.backend}")
def cmd_prepare(args) -> int:
config = Config.load(args.config)
cues, scenes = prepare_subtitles(args.srt, config)
print(f"Cue: {len(cues)} | Cảnh: {len(scenes)}")
for sc in scenes[: args.preview]:
print(f" Cảnh #{sc.scene_id} [{sc.start:.1f}-{sc.end:.1f}s] {len(sc.cues)} cue")
for c in sc.cues:
print(f" [{c.index}] {c.text[:60]}")
if args.out:
from .srt import write_srt
write_srt(cues, args.out)
print(f"Đã ghi cue đã gom cảnh ra: {args.out}")
return 0
def cmd_run(args) -> int:
config = Config.load(args.config)
backend = _build_backend(config, args)
result = run_pipeline(
args.srt,
video=args.video,
config=config,
backend=backend,
work_dir=args.work_dir,
hf_token=args.hf_token,
do_diarize=not args.no_diarize,
do_profile=not args.no_profile,
do_translate=not args.no_translate,
)
print(f"Xong. Output: {result.output_srt}")
print(f"Report: {result.report_path}")
return 0
def build_parser() -> argparse.ArgumentParser:
p = argparse.ArgumentParser(
prog="omnisub",
description="Dịch phụ đề SRT ZH→VI bằng Qwen3-Omni (đa phương thức).",
)
p.add_argument("-v", "--verbose", action="store_true", help="log chi tiết")
p.add_argument("--config", default="config.yaml", help="đường dẫn config.yaml")
sub = p.add_subparsers(dest="command", required=True)
pp = sub.add_parser("prepare", help="Bước 1: parse + gom cảnh (không cần model)")
pp.add_argument("srt", help="file SRT nguồn (ZH)")
pp.add_argument("--out", help="ghi cue đã gom cảnh ra file SRT (tùy chọn)")
pp.add_argument("--preview", type=int, default=5, help="số cảnh in thử")
pp.set_defaults(func=cmd_prepare)
pr = sub.add_parser("run", help="Chạy pipeline đầy đủ (Bước 1→5)")
pr.add_argument("srt", help="file SRT nguồn (ZH)")
pr.add_argument("--video", help="file video tương ứng (mp4...)")
pr.add_argument(
"--backend", choices=["none", "qwen"], default="qwen",
help="backend model (none = chỉ chạy Bước 1)",
)
pr.add_argument("--cache-dir", help="thư mục cache model (Drive/Cache)")
pr.add_argument("--work-dir", help="thư mục làm việc tạm (frame/audio)")
pr.add_argument("--hf-token", help="HuggingFace token cho pyannote")
pr.add_argument("--no-diarize", action="store_true", help="bỏ Bước 2")
pr.add_argument("--no-profile", action="store_true", help="bỏ Bước 3")
pr.add_argument("--no-translate", action="store_true", help="bỏ Bước 4")
pr.set_defaults(func=cmd_run)
return p
def main(argv=None) -> int:
_force_utf8()
parser = build_parser()
args = parser.parse_args(argv)
_setup_logging(getattr(args, "verbose", False))
return args.func(args)
if __name__ == "__main__":
sys.exit(main())