tts-voice-creator-clone-and.../scripts/backup_characters.py
2026-09-03 16:12:02 +02:00

63 lines
2.5 KiB
Python

#!/usr/bin/env python3
"""Snapshot a book's character-library records to a JSON file for later comparison.
python3 scripts/backup_characters.py "<book title>" characters_auto.json
python3 scripts/backup_characters.py "<book title>" characters_manual.json --base-url http://127.0.0.1:7890
Matches records the same way the app does: exact `book` field OR `book`
present in the comma-separated `tags` field (case-insensitive) — this mirrors
`_characters_for_title` in routes/reader.py / clGetAllByTagOrBook in
characters-library.js, so the snapshot contains exactly what the UI would
show for that book.
Run this once right after "Define Characters" (step 5) for each version you
want to compare — e.g. once for the automatic pass, once for the manually
corrected KONTROLLE version — before either one gets overwritten by a later
run. compare_characters.py then diffs two such snapshots.
"""
import argparse
import json
import sys
import requests
def characters_for_title(all_chars: list[dict], title: str) -> list[dict]:
key = title.strip().lower()
out = []
for rec in all_chars:
book = str(rec.get("book") or "").strip().lower()
tags = [t.strip().lower() for t in str(rec.get("tags") or "").split(",")]
if book == key or key in tags:
out.append(rec)
return out
def main() -> None:
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
ap.add_argument("book", help="Book title as it appears in the character's `book` field / tags")
ap.add_argument("outfile", help="Path to write the JSON snapshot to")
ap.add_argument("--base-url", default="http://127.0.0.1:7890")
args = ap.parse_args()
resp = requests.get(f"{args.base_url}/api/characters", timeout=60)
resp.raise_for_status()
all_chars = resp.json()
if isinstance(all_chars, dict):
all_chars = all_chars.get("characters") or all_chars.get("items") or []
matched = characters_for_title(all_chars, args.book)
if not matched:
print(f"No characters found for book {args.book!r}. Known books: "
f"{sorted({str(c.get('book') or '') for c in all_chars} - {''})}", file=sys.stderr)
sys.exit(1)
matched.sort(key=lambda r: str(r.get("name") or "").lower())
with open(args.outfile, "w", encoding="utf-8") as f:
json.dump(matched, f, ensure_ascii=False, indent=2)
print(f"Wrote {len(matched)} characters for {args.book!r} -> {args.outfile}")
if __name__ == "__main__":
main()