#!/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()