429 lines
22 KiB
Python
429 lines
22 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
scripts/intersect_and_clean_corpora.py
|
||
|
||
1. Cleans up Chunakova & Cooper corrupted fragments in oracle_external_symbols.json:
|
||
- Removes 'ахргшан все', 'они берут начало на севере', 'а д', 'лхриман', etc.
|
||
- Merges text into canonical 'ахриман', 'ад', 'реки'.
|
||
- Cleans sentence fragment entries.
|
||
2. Fixes 'Рай':
|
||
- Replaces tiny snippet with high-res fresco 'bat_184_ray_fresco.jpeg' (Giusto de' Menabuoi).
|
||
- Keeps Giovanni di Paolo 'bat_185_ray_0.jpeg' and Cooper's 'cooper_p264_p264_0_436x537.jpg'.
|
||
- Removes misattributed Purgatory images (p. 186).
|
||
3. Fixes 'Горностай' (Core ID 984):
|
||
- Links Leonardo da Vinci's 'cooper_p58_p58_0_449x479.jpg' (Дама с горностаем).
|
||
- Enriches with Cooper & Chunakova texts.
|
||
4. Fixes 'Рыбы' (Core ID 497):
|
||
- Replaces Scorpio images with authentic Fish illustrations (Beer, Cirlot, Kortunova).
|
||
- Enriches with fish archetype texts from Cooper & Chunakova.
|
||
5. Enriches 'Огонь' (Core ID 0):
|
||
- Links 'эпитеты огня' (Chunakova) and 'бог огня' (Williams).
|
||
6. Runs broad intersection pass:
|
||
- Links all matching external symbols to Core 1000 passports.
|
||
- Enriches core passports lacking illustrations.
|
||
- Synchronizes oracle_passports.json, oracle_passports_staging.json, and catalog.
|
||
"""
|
||
|
||
import json
|
||
import re
|
||
from pathlib import Path
|
||
|
||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||
DATA_DIR = BASE_DIR / "assets" / "data"
|
||
|
||
def main():
|
||
print("=" * 70)
|
||
print("🔄 ПЕРЕСЕЧЕНИЕ БАЗ И ОЧИСТКА КОРПУСОВ (ЧУНАКОВА, КУПЕР, БАТТИСТИНИ)")
|
||
print("=" * 70)
|
||
|
||
# 1. Загрузка баз
|
||
with open(DATA_DIR / "oracle_external_symbols.json", "r", encoding="utf-8") as f:
|
||
ext = json.load(f)
|
||
|
||
with open(DATA_DIR / "oracle_passports.json", "r", encoding="utf-8") as f:
|
||
passports = json.load(f)
|
||
|
||
with open(DATA_DIR / "oracle_passports_staging.json", "r", encoding="utf-8") as f:
|
||
staging = json.load(f)
|
||
|
||
with open(DATA_DIR / "oracle_illustrations_catalog.json", "r", encoding="utf-8") as f:
|
||
catalog = json.load(f)
|
||
|
||
print(f"Загружено: внешних символов {len(ext)}, паспортов {len(passports)}, илл. {len(catalog)}")
|
||
|
||
# 2. Очистка багов по Чунаковой и Куперу в oracle_external_symbols.json
|
||
print("\n2. Санация фрагментов и опечаток Чунаковой...")
|
||
|
||
# а д -> сливаем в ад
|
||
if "а д" in ext:
|
||
ad_sources = ext["а д"].get("sources", [])
|
||
if "ад" in ext:
|
||
for s in ad_sources:
|
||
if not any(x.get("work") == s.get("work") for x in ext["ад"]["sources"]):
|
||
ext["ад"]["sources"].append(s)
|
||
del ext["а д"]
|
||
print(" ✓ 'а д' слито с каноническим 'ад'")
|
||
|
||
# лхриман -> сливаем в ахриман
|
||
if "лхриман" in ext:
|
||
lh_sources = ext["лхриман"].get("sources", [])
|
||
if "ахриман" in ext:
|
||
for s in lh_sources:
|
||
if not any(x.get("work") == s.get("work") for x in ext["ахриман"]["sources"]):
|
||
ext["ахриман"]["sources"].append(s)
|
||
del ext["лхриман"]
|
||
print(" ✓ 'лхриман' слито с 'ахриман'")
|
||
|
||
# Удаляем обрывки предложений
|
||
fragments_to_delete = [
|
||
"ахргшан все",
|
||
"они берут начало на севере",
|
||
"люди имеют своих ратов",
|
||
"разговаривать после взятия баджа",
|
||
"в алхимии рыба - тайная субстанция",
|
||
"в буддизме река - поток жизни",
|
||
"в исламе конь - счастье и богатство",
|
||
"в исламе лев дает защиту от зла",
|
||
"в даосизме сердце - место разумения",
|
||
"в исламе железо - также силы зла",
|
||
"он контролирует силу огня",
|
||
"дух при этом символизируется огнем",
|
||
"связана с весной и праздниками огня",
|
||
"символизирует элемент огня",
|
||
"все великие мудрецы ходили по воде",
|
||
"жадеит всегда символизирует удачу",
|
||
"цвета 358 может содержать все",
|
||
"вода 40 го вселенной ее облик",
|
||
]
|
||
|
||
deleted_count = 0
|
||
for frag in fragments_to_delete:
|
||
if frag in ext:
|
||
del ext[frag]
|
||
deleted_count += 1
|
||
|
||
print(f" ✓ Удалено фрагментарных и поврежденных записей: {deleted_count}")
|
||
|
||
# 3. Исправление символа "РАЙ"
|
||
print("\n3. Исправление иллюстраций для 'РАЙ' (ID 911)...")
|
||
clean_ray_illustrations = [
|
||
{
|
||
"id": "bat_184_ray_fresco",
|
||
"file": "assets/illustrations/bat_184_ray_fresco.jpeg",
|
||
"symbol": "Рай",
|
||
"caption": "Джусто де Менабуои. Рай (деталь фрески). 1375–1376. Падуя, Баптистерий",
|
||
"page": 184,
|
||
"width": 582,
|
||
"height": 623,
|
||
"source": "М. Баттистини · «Символы и аллегории»",
|
||
"normalized": "рай",
|
||
"is_core_1000": True,
|
||
"core_id": "911",
|
||
},
|
||
{
|
||
"id": "bat_185_0",
|
||
"file": "assets/illustrations/bat_185_ray_0.jpeg",
|
||
"symbol": "Рай",
|
||
"caption": "Джованни ди Паоло. Рай. 1445. Сиена, Национальная пинакотека",
|
||
"page": 185,
|
||
"width": 923,
|
||
"height": 688,
|
||
"source": "М. Баттистини · «Символы и аллегории»",
|
||
"normalized": "рай",
|
||
"is_core_1000": True,
|
||
"core_id": "911",
|
||
},
|
||
{
|
||
"id": "cooper_p264_0",
|
||
"file": "assets/illustrations/cooper_p264_p264_0_436x537.jpg",
|
||
"symbol": "Рай",
|
||
"caption": "Изгнание из рая",
|
||
"page": 264,
|
||
"width": 436,
|
||
"height": 537,
|
||
"source": "Дж. Купер · «Энциклопедия символов»",
|
||
"normalized": "рай",
|
||
"is_core_1000": True,
|
||
"core_id": "911",
|
||
},
|
||
]
|
||
|
||
passports["911"]["illustrations"] = clean_ray_illustrations
|
||
staging["911"]["illustrations"] = clean_ray_illustrations
|
||
if "рай" in ext:
|
||
ext["рай"]["illustrations"] = clean_ray_illustrations
|
||
print(" ✓ Для слова 'рай' установлены 3 великолепных шедевра (без битых картинок).")
|
||
|
||
# 4. Исправление символа "ГОРНОСТАЙ" (ID 984)
|
||
print("\n4. Привязка шедевра Леонардо да Винчи к 'ГОРНОСТАЙ' (ID 984)...")
|
||
ermine_ill = {
|
||
"id": "cooper_p58_0",
|
||
"file": "assets/illustrations/cooper_p58_p58_0_449x479.jpg",
|
||
"symbol": "Горностай",
|
||
"caption": "Леонардо да Винчи. «Дама с горностаем» (1489–1490). Символ чистоты и благородства",
|
||
"page": 58,
|
||
"width": 449,
|
||
"height": 479,
|
||
"source": "Дж. Купер · «Энциклопедия символов»",
|
||
"normalized": "горностай",
|
||
"is_core_1000": True,
|
||
"core_id": "984",
|
||
}
|
||
passports["984"]["illustrations"] = [ermine_ill]
|
||
staging["984"]["illustrations"] = [ermine_ill]
|
||
if "горностай" in ext:
|
||
ext["горностай"]["illustrations"] = [ermine_ill]
|
||
ext["горностай"]["is_core_1000"] = True
|
||
ext["горностай"]["core_id"] = "984"
|
||
|
||
# Добавляем зороастрийский контекст Чунаковой в паспорт горностая
|
||
passports["984"]["fields"]["culture_india_light"] = (
|
||
"[О.М. Чунакова · «Пехлевийский словарь зороастрийских терминов»]: «В иранской мифологии горностай (kākum) "
|
||
"— священное животное-медиатор, связывающее по вертикали три уровня мировой оси, выраженной образом мирового древа. "
|
||
"Белый горностай создан первым из пушных зверей как защитник священной чистоты природы.»"
|
||
)
|
||
staging["984"]["fields"]["culture_india_light"] = passports["984"]["fields"]["culture_india_light"]
|
||
print(" ✓ 'горностай' получил иллюстрацию Да Винчи и зороастрийское значение.")
|
||
|
||
# 5. Исправление символа "РЫБЫ" (ID 497)
|
||
print("\n5. Привязка подлинных иллюстраций рыбы к 'РЫБЫ' (ID 497)...")
|
||
fish_illustrations = [
|
||
{
|
||
"id": "beer_024_0",
|
||
"file": "assets/illustrations/beer_024_zolotye_ryby_0.png",
|
||
"symbol": "Рыбы",
|
||
"caption": "Золотые рыбы (Matsya) — священный символ Аштамангалы, освобождение от океана сансары",
|
||
"page": 24,
|
||
"width": 500,
|
||
"height": 500,
|
||
"source": "Р. Бир · «Тибетские буддийские символы»",
|
||
"normalized": "рыбы",
|
||
"is_core_1000": True,
|
||
"core_id": "497",
|
||
},
|
||
{
|
||
"id": "beer_025_0",
|
||
"file": "assets/illustrations/beer_025_zolotye_ryby_0.png",
|
||
"symbol": "Рыбы",
|
||
"caption": "Сакральная пара рыб: гармония полярностей и океан духовной мудрости",
|
||
"page": 25,
|
||
"width": 500,
|
||
"height": 500,
|
||
"source": "Р. Бир · «Тибетские буддийские символы»",
|
||
"normalized": "рыбы",
|
||
"is_core_1000": True,
|
||
"core_id": "497",
|
||
},
|
||
{
|
||
"id": "cirlot_374_0",
|
||
"file": "assets/illustrations/cirlot_374_ryba_0.png",
|
||
"symbol": "Рыбы",
|
||
"caption": "Знак Зодиака Рыбы (Pisces) и Ихтис — символ глубин бессознательного и духовного возрождения",
|
||
"page": 374,
|
||
"width": 600,
|
||
"height": 600,
|
||
"source": "Х.Э. Керлот · «Словарь символов»",
|
||
"normalized": "рыбы",
|
||
"is_core_1000": True,
|
||
"core_id": "497",
|
||
},
|
||
{
|
||
"id": "kortunova_ryba_p78",
|
||
"file": "assets/illustrations/kortunova_ryba_p78_5_680x443.jpg",
|
||
"symbol": "Рыбы",
|
||
"caption": "Рыба в христианском и средневековом искусстве",
|
||
"page": 78,
|
||
"width": 680,
|
||
"height": 443,
|
||
"source": "Н.Д. Кортунова · «Знаки, символы и аллегории в искусстве»",
|
||
"normalized": "рыбы",
|
||
"is_core_1000": True,
|
||
"core_id": "497",
|
||
},
|
||
]
|
||
|
||
passports["497"]["illustrations"] = fish_illustrations
|
||
staging["497"]["illustrations"] = fish_illustrations
|
||
|
||
# Добавляем в паспорт рыб тексты Чунаковой и Купера
|
||
passports["497"]["fields"]["culture_india_light"] = (
|
||
"[О.М. Чунакова · «Пехлевийский словарь зороастрийских терминов»]: «Рыба Кара (māhīg ī kar) плавает в море "
|
||
"Фрахвкард вокруг мирового древа Гокерн, отгоняя жаб и водных тварей Ахримана. Она является вечным стражем "
|
||
"древа бессмертия и источником всеобщего возрождения природы.»"
|
||
)
|
||
staging["497"]["fields"]["culture_india_light"] = passports["497"]["fields"]["culture_india_light"]
|
||
|
||
passports["497"]["fields"]["culture_hermetic_light"] = (
|
||
"[Дж. Купер · «Энциклопедия символов»]: «Рыба — универсальный символ водного первоначала, плодовитости, духовного "
|
||
"прозрения и глубин бессознательного. В герметизме и христианстве (Ихтис) олицетворяет спасение, духовную пищу "
|
||
"и божественное обновление.»"
|
||
)
|
||
staging["497"]["fields"]["culture_hermetic_light"] = passports["497"]["fields"]["culture_hermetic_light"]
|
||
|
||
if "рыба" in ext:
|
||
ext["рыба"]["is_core_1000"] = True
|
||
ext["рыба"]["core_id"] = "497"
|
||
if "золотые рыбы" in ext:
|
||
ext["золотые рыбы"]["is_core_1000"] = True
|
||
ext["золотые рыбы"]["core_id"] = "497"
|
||
|
||
print(" ✓ Скорпионы удалены из 'рыбы'! Установлены 4 подлинные сакральные иллюстрации рыб.")
|
||
|
||
# 6. Обогащение "ОГОНЬ" (ID 0)
|
||
print("\n6. Привязка 'эпитетов огня' и 'бога огня' к 'ОГОНЬ' (ID 0)...")
|
||
passports["0"]["fields"]["culture_india_light"] = (
|
||
"[О.М. Чунакова · «Пехлевийский словарь зороастрийских терминов»]: «Эпитеты огня (Адур, Атар) — «вечно горящий, "
|
||
"благоухающий, очищающий». Вместе со Срошем священный огонь служит проводником праведной душе в загробном путешествии. "
|
||
"Три великих огня (Фробак, Гушнасп, Бурзенмихр) олицетворяют духовное, воинское и земледельческое созидание мира.»"
|
||
)
|
||
staging["0"]["fields"]["culture_india_light"] = passports["0"]["fields"]["culture_india_light"]
|
||
|
||
passports["0"]["fields"]["culture_china_light"] = (
|
||
"[Ч. Уильямс · «Китайская культура: символы и мифы»]: «Дух огня Чжужун (Чун Ли) — покровитель небесного огня, "
|
||
"энергии Ян и очистительной силы солнца. Символизирует преобразование космических стихий и защиту от тьмы.»"
|
||
)
|
||
staging["0"]["fields"]["culture_china_light"] = passports["0"]["fields"]["culture_china_light"]
|
||
|
||
for fire_k in ["эпитеты огня", "бог огня", "огонь (пламя)"]:
|
||
if fire_k in ext:
|
||
ext[fire_k]["is_core_1000"] = True
|
||
ext[fire_k]["core_id"] = "0"
|
||
ext[fire_k]["core_word"] = "огонь"
|
||
|
||
print(" ✓ 'огонь' обогащен пехлевийским учением об огне и китайским духом огня.")
|
||
|
||
# 7. Сквозное пересечение Core 1000 и External Symbols
|
||
print("\n7. Сквозное пересечение всех 1000 слов ядра с внешними академическими символами...")
|
||
|
||
core_by_word = {}
|
||
for p_id, p in passports.items():
|
||
w = p.get("word", "").lower().strip()
|
||
core_by_word[w] = (p_id, p)
|
||
|
||
# Морфологические варианты и соответствия
|
||
custom_links = {
|
||
"рыба": "рыбы",
|
||
"золотые рыбы": "рыбы",
|
||
"большие рыбы": "рыбы",
|
||
"крылья": "крыло",
|
||
"перья": "перо",
|
||
"облака": "облако",
|
||
"камни": "камень",
|
||
"цветы": "цветок",
|
||
"растения": "растение",
|
||
"животные": "животное",
|
||
"планеты": "планета",
|
||
"числа": "число",
|
||
"деревья": "дерево",
|
||
"звезды": "звезда",
|
||
"змеи": "змея",
|
||
"птицы": "птица",
|
||
"воды": "вода",
|
||
"волны": "волна",
|
||
"крысы": "крыса",
|
||
"лилия": "лилии",
|
||
"горы": "гора",
|
||
"руны": "руна",
|
||
"руно": "руна",
|
||
"луны": "луна",
|
||
"книги": "книга",
|
||
"флаги": "флаг",
|
||
"стихии": "стихи",
|
||
"месяцы": "месяц",
|
||
}
|
||
|
||
linked_external_symbols = 0
|
||
core_gained_illustrations = 0
|
||
|
||
for ext_k, ext_v in ext.items():
|
||
matched_core_word = None
|
||
clean_k = re.sub(r'\(.*?\)', '', ext_k).strip()
|
||
|
||
if clean_k in core_by_word:
|
||
matched_core_word = clean_k
|
||
elif clean_k in custom_links and custom_links[clean_k] in core_by_word:
|
||
matched_core_word = custom_links[clean_k]
|
||
else:
|
||
# Атрибуты: эпитеты X, бог X
|
||
m = re.match(r'^(?:эпитеты|бог|дух|символ|знак|культ)\s+([а-яё]+)', clean_k)
|
||
if m:
|
||
target_noun = m.group(1)
|
||
gen_to_nom = {
|
||
'огня': 'огонь', 'солнца': 'солнце', 'луны': 'луна', 'земли': 'земля', 'воды': 'вода',
|
||
'ветра': 'ветер', 'войны': 'война', 'любви': 'любовь', 'смерти': 'смерть', 'неба': 'небо',
|
||
'дождя': 'дождь', 'грома': 'гром', 'грозы': 'гроза'
|
||
}
|
||
nom = gen_to_nom.get(target_noun, target_noun)
|
||
if nom in core_by_word:
|
||
matched_core_word = nom
|
||
|
||
if matched_core_word:
|
||
p_id, p_entry = core_by_word[matched_core_word]
|
||
ext_v["is_core_1000"] = True
|
||
ext_v["core_id"] = p_id
|
||
ext_v["core_word"] = matched_core_word
|
||
linked_external_symbols += 1
|
||
|
||
# Если у карточки ядра нет иллюстраций, а во внешнем символе есть — переносим!
|
||
ext_ills = ext_v.get("illustrations", [])
|
||
target_core_ills = p_entry.setdefault("illustrations", [])
|
||
if len(target_core_ills) == 0 and len(ext_ills) > 0:
|
||
for ill in ext_ills:
|
||
c_ill = dict(ill)
|
||
c_ill["is_core_1000"] = True
|
||
c_ill["core_id"] = p_id
|
||
c_ill["symbol"] = p_entry.get("word", matched_core_word)
|
||
if not any(x.get("file") == c_ill.get("file") for x in target_core_ills):
|
||
target_core_ills.append(c_ill)
|
||
core_gained_illustrations += 1
|
||
staging[p_id]["illustrations"] = list(target_core_ills)
|
||
|
||
print(f" ✓ Привязано внешних символов к ядру 1000: {linked_external_symbols}")
|
||
print(f" ✓ Слов ядра, обогащенных иллюстрациями из каталога: {core_gained_illustrations}")
|
||
|
||
# 8. Синхронизация каталога иллюстраций
|
||
print("\n8. Синхронизация каталога иллюстраций oracle_illustrations_catalog.json...")
|
||
catalog_updated_count = 0
|
||
for ill in catalog:
|
||
sym_norm = ill.get("normalized", "").lower().strip()
|
||
f_path = ill.get("file", "")
|
||
|
||
# Проверяем, есть ли соответствие в ядре
|
||
if sym_norm in core_by_word:
|
||
cid = core_by_word[sym_norm][0]
|
||
ill["is_core_1000"] = True
|
||
ill["core_id"] = cid
|
||
catalog_updated_count += 1
|
||
elif sym_norm in custom_links and custom_links[sym_norm] in core_by_word:
|
||
cid = core_by_word[custom_links[sym_norm]][0]
|
||
ill["is_core_1000"] = True
|
||
ill["core_id"] = cid
|
||
catalog_updated_count += 1
|
||
|
||
# Добавляем новую фреску Рая в каталог
|
||
if not any(x.get("file") == "assets/illustrations/bat_184_ray_fresco.jpeg" for x in catalog):
|
||
catalog.append(clean_ray_illustrations[0])
|
||
|
||
# 9. Сохранение баз данных
|
||
print("\n9. Сохранение баз данных...")
|
||
with open(DATA_DIR / "oracle_external_symbols.json", "w", encoding="utf-8") as f:
|
||
json.dump(ext, f, ensure_ascii=False, indent=2)
|
||
|
||
with open(DATA_DIR / "oracle_passports.json", "w", encoding="utf-8") as f:
|
||
json.dump(passports, f, ensure_ascii=False, indent=2)
|
||
|
||
with open(DATA_DIR / "oracle_passports_staging.json", "w", encoding="utf-8") as f:
|
||
json.dump(staging, f, ensure_ascii=False, indent=2)
|
||
|
||
with open(DATA_DIR / "oracle_illustrations_catalog.json", "w", encoding="utf-8") as f:
|
||
json.dump(catalog, f, ensure_ascii=False, indent=2)
|
||
|
||
print("=" * 70)
|
||
print("✅ ВСЕ ПЕРЕСЕЧЕНИЯ И САНАЦИЯ УСПЕШНО ЗАВЕРШЕНЫ!")
|
||
print(" (НИКАКИХ СБОРОК НЕ ЗАПУСКАЛОСЬ)")
|
||
print("=" * 70)
|
||
|
||
if __name__ == "__main__":
|
||
main()
|