feat: complete academic symbol lexicon heal, 2-column Cooper extraction, and updated assets

This commit is contained in:
2026-10-09 15:26:58 +05:00
parent 7f91366201
commit 0b12e4583b
244 changed files with 611461 additions and 1617 deletions
+119
View File
@@ -0,0 +1,119 @@
#!/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()