| |
| """Run the conservative lower-third person bootstrap pass.""" |
|
|
| from __future__ import annotations |
|
|
| import argparse |
| import json |
| import os |
| import sys |
|
|
| REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
| BACKEND_ROOT = os.path.join(REPO_ROOT, "backend") |
| sys.path.insert(0, BACKEND_ROOT) |
|
|
| from face_search import get_face_search_instance |
| from lower_third_person_bootstrap import DEFAULT_MIN_SCORE, bootstrap_lower_third_people |
| from media_metadata import get_all_media |
| from runtime_paths import get_image_db_path |
|
|
|
|
| def parse_args() -> argparse.Namespace: |
| parser = argparse.ArgumentParser(description=__doc__) |
| parser.add_argument("--apply", action="store_true", help="Create/link people instead of dry-running") |
| parser.add_argument("--language", default="E", help="JW language code") |
| parser.add_argument("--limit", type=int, default=100, help="Maximum candidates to inspect") |
| parser.add_argument("--min-score", type=float, default=DEFAULT_MIN_SCORE, help="Lower-third label score floor") |
| parser.add_argument("--ocr", action="store_true", help="Use RapidOCR when the title does not name a person") |
| parser.add_argument( |
| "--resolve-conflicts", |
| action="store_true", |
| help="Allow high-confidence lower-third evidence to replace an existing face assignment", |
| ) |
| return parser.parse_args() |
|
|
|
|
| def main() -> int: |
| args = parse_args() |
| summary = bootstrap_lower_third_people( |
| image_db_path=get_image_db_path(), |
| face_search=get_face_search_instance(), |
| media_items=get_all_media(args.language), |
| min_score=args.min_score, |
| limit=args.limit, |
| dry_run=not args.apply, |
| use_ocr=args.ocr, |
| resolve_conflicts=args.resolve_conflicts, |
| ) |
| print(json.dumps(summary.to_dict(), indent=2, ensure_ascii=False)) |
| return 0 |
|
|
|
|
| if __name__ == "__main__": |
| raise SystemExit(main()) |
|
|