#!/usr/bin/env python3 """Build assets/data/tarot_majors.json from scraped corpus + unified texts.""" from __future__ import annotations import json from pathlib import Path ROOT = Path(__file__).resolve().parents[1] CORPUS = ROOT / "oracle_enricher" / "data" / "sources" / "tarot_majors_corpus.json" UNIFIED = ROOT / "oracle_enricher" / "out" / "tarot_unify" / "unified.json" CANON = ROOT / "oracle_enricher" / "data" / "traditions_canon.json" ASSET_CANON = ROOT / "assets" / "data" / "traditions_canon.json" OUT = ROOT / "assets" / "data" / "tarot_majors.json" HTML = ROOT / "lexicon_viewer.html" ROMAN = ["0", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX", "XXI"] def main() -> None: if not CORPUS.exists(): raise SystemExit("нет tarot_majors_corpus.json — сначала scrape_tarot_majors.py") corpus = json.loads(CORPUS.read_text(encoding="utf-8")) unified = {} if UNIFIED.exists(): unified = json.loads(UNIFIED.read_text(encoding="utf-8")) canon = json.loads(CANON.read_text(encoding="utf-8")) ID_MAP = {"wheel": "wheel_of_fortune"} by_id = {s["id"]: s for s in canon["tarot"]["stations"]} cards_out = [] for n in range(22): cc = corpus["cards"][str(n)] st = by_id.get(ID_MAP.get(cc["id"], cc["id"]), {}) uc = (unified.get("cards") or {}).get(str(n)) or {} umeaning = (uc.get("meaning") or "").strip() pairs = [] for other in range(22): if other == n: continue key = f"{min(n, other):02d}-{max(n, other):02d}" bucket = (corpus.get("pairs") or {}).get(key) or {} readings = bucket.get("readings") or [] up = (unified.get("pairs") or {}).get(key) or {} utext = (up.get("text") or "").strip() preview = utext[:157] + "…" if len(utext) > 160 else utext if not preview and readings: preview = (readings[0].get("text") or "")[:160] ost = by_id.get(corpus["cards"][str(other)]["id"], {}) pairs.append( { "n": other, "id": corpus["cards"][str(other)]["id"], "name": corpus["cards"][str(other)]["name"], "symbol": ost.get("symbol", ""), "preview": preview, "text": utext, "readings": [] if utext else readings, } ) cards_out.append( { "n": n, "id": cc["id"], "name": cc["name"], "symbol": st.get("symbol", ""), "lore": (uc.get("core") or st.get("lore") or ""), "group": f"Старшие Арканы · {ROMAN[n]} {cc['name']}", "meaning": umeaning, "shadow": (uc.get("shadow") or "").strip(), "meanings": [] if umeaning else cc.get("meanings") or [], "pairs": pairs, } ) # fix canon groups for st in canon["tarot"]["stations"]: # id fool → n 0 n = next((c["n"] for c in cards_out if c["id"] == st["id"]), None) if n is None: continue st["group"] = f"Старшие Арканы · {ROMAN[n]} {cards_out[n]['name']}" if cards_out[n]["lore"]: st["lore"] = cards_out[n]["lore"] canon["tarot"]["description"] = ( "22 Старших Аркана: одно сводное значение и сочетания друг с другом " "(карусель, magya, эзопланета сведены в один текст)." ) text_c = json.dumps(canon, ensure_ascii=False, indent=2) + "\n" CANON.write_text(text_c, encoding="utf-8") ASSET_CANON.write_text(text_c, encoding="utf-8") blob = { "system": "tarot_majors", "card_count": 22, "pair_count": sum(len(c["pairs"]) for c in cards_out) // 2, "cards": cards_out, } OUT.parent.mkdir(parents=True, exist_ok=True) OUT.write_text(json.dumps(blob, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") if HTML.exists(): html = HTML.read_text(encoding="utf-8") start = html.find(" const TRADITIONS_CANON = ") end = html.find(" const WORDS_DATA = ") if start > 0 and end > start: html = ( html[:start] + " const TRADITIONS_CANON = " + json.dumps(canon, ensure_ascii=False, indent=2) + ";\n\n" + html[end:] ) HTML.write_text(html, encoding="utf-8") print("wrote", OUT, "pairs", blob["pair_count"]) if __name__ == "__main__": main()