feat: complete academic symbol lexicon heal, 2-column Cooper extraction, and updated assets
This commit is contained in:
Executable
+153
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
staging_inspect.py
|
||||
==================
|
||||
Инспектор и анализатор ТЕСТОВОЙ базы данных (oracle_passports_staging.json).
|
||||
Позволяет сравнивать тестовую базу с основной, просматривать карточки и делать выгрузки.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from typing import Dict, Any
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from oracle_enricher.enricher.passport_schema import (
|
||||
PROMPTS_78,
|
||||
render_passport_markdown,
|
||||
count_filled_fields,
|
||||
)
|
||||
|
||||
MAIN_DB_PATH = PROJECT_ROOT / "assets" / "data" / "oracle_passports.json"
|
||||
STAGING_DB_PATH = PROJECT_ROOT / "assets" / "data" / "oracle_passports_staging.json"
|
||||
OUT_DIR = PROJECT_ROOT / "out" / "staging_cards"
|
||||
|
||||
def load_db(path: Path) -> Dict[str, Dict[str, Any]]:
|
||||
if not path.exists():
|
||||
print(f"[ERROR] База не найдена: {path}")
|
||||
sys.exit(1)
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
def print_comparison_stats(main_db: Dict[str, Any], staging_db: Dict[str, Any]) -> None:
|
||||
total_words = len(staging_db)
|
||||
|
||||
main_filled = sum(e.get("filled_count", 0) for e in main_db.values())
|
||||
staging_filled = sum(e.get("filled_count", 0) for e in staging_db.values())
|
||||
delta = staging_filled - main_filled
|
||||
max_total = total_words * 78
|
||||
|
||||
main_complete = sum(1 for e in main_db.values() if e.get("filled_count", 0) >= 78)
|
||||
staging_complete = sum(1 for e in staging_db.values() if e.get("filled_count", 0) >= 78)
|
||||
|
||||
print("\n" + "═" * 70)
|
||||
print("📊 СРАВНИТЕЛЬНЫЙ АНАЛИЗ: ОСНОВНАЯ БАЗА vs ТЕСТОВАЯ БАЗА (STAGING)")
|
||||
print("═" * 70)
|
||||
print(f" Всего знаков в реестре: {total_words}")
|
||||
print(f" Заполнено ячеек в ОСНОВНОЙ: {main_filled} / {max_total} ({main_filled/max_total*100:.2f}%)")
|
||||
print(f" Заполнено ячеек в ТЕСТОВОЙ: {staging_filled} / {max_total} ({staging_filled/max_total*100:.2f}%)")
|
||||
print(f" Прирост данных в тестовой базе: +{delta} ячеек (+{delta/max_total*100:.2f}% всего каталога)")
|
||||
print(f" Полных карточек (78/78): ОСНОВНАЯ: {main_complete} | ТЕСТОВАЯ: {staging_complete}")
|
||||
print("─" * 70)
|
||||
print(f"{'РАЗДЕЛ КАТАЛОГА':<40} {'ОСНОВНАЯ':>12} {'ТЕСТОВАЯ':>12} {'ПРИРОСТ':>10}")
|
||||
print("─" * 70)
|
||||
|
||||
for sec in ["I", "II", "III", "IV", "V", "VI"]:
|
||||
sec_fields = [p.key for p in PROMPTS_78 if p.section_num == sec]
|
||||
sec_max = len(sec_fields) * total_words
|
||||
|
||||
cnt_main = sum(1 for e in main_db.values() for k in sec_fields if e.get("fields", {}).get(k))
|
||||
cnt_staging = sum(1 for e in staging_db.values() for k in sec_fields if e.get("fields", {}).get(k))
|
||||
sec_delta = cnt_staging - cnt_main
|
||||
|
||||
sec_name = f"Раздел {sec}"
|
||||
print(f"{sec_name:<40} {cnt_main:>6}/{sec_max} {cnt_staging:>6}/{sec_max} {f'+{sec_delta}':>10}")
|
||||
|
||||
print("═" * 70 + "\n")
|
||||
|
||||
def find_entry(db: Dict[str, Any], query: str) -> Optional[Dict[str, Any]]:
|
||||
q = query.strip().lower()
|
||||
if q.isdigit():
|
||||
idx_str = str(int(q))
|
||||
if idx_str in db:
|
||||
return db[idx_str]
|
||||
for e in db.values():
|
||||
if e.get("word", "").lower() == q:
|
||||
return e
|
||||
return None
|
||||
|
||||
def show_diff(main_db: Dict[str, Any], staging_db: Dict[str, Any], query: str) -> None:
|
||||
main_e = find_entry(main_db, query)
|
||||
stag_e = find_entry(staging_db, query)
|
||||
|
||||
if not stag_e:
|
||||
print(f"[ERROR] Знак «{query}» не найден в тестовой базе.")
|
||||
return
|
||||
|
||||
word = stag_e.get("word", "")
|
||||
idx = stag_e.get("id", 0)
|
||||
|
||||
print(f"\n═ Построчный DIFF для #{idx:03d} «{word.upper()}» (Основная -> Тестовая) ═")
|
||||
main_fields = main_e.get("fields", {}) if main_e else {}
|
||||
stag_fields = stag_e.get("fields", {})
|
||||
|
||||
diff_count = 0
|
||||
for p in PROMPTS_78:
|
||||
mv = main_fields.get(p.key, "")
|
||||
sv = stag_fields.get(p.key, "")
|
||||
if mv != sv:
|
||||
diff_count += 1
|
||||
print(f"\n[#{p.index:02d} | Раздел {p.section_num}] {p.title}:")
|
||||
if mv:
|
||||
print(f" ОСНОВНАЯ : {mv}")
|
||||
else:
|
||||
print(" ОСНОВНАЯ : (пусто)")
|
||||
print(f" ТЕСТОВАЯ : {sv}")
|
||||
|
||||
print(f"\nВсего различий: {diff_count} полей из 78.\n")
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Инспектор тестовой базы данных Оракула 999")
|
||||
parser.add_argument("--stats", action="store_true", help="Сравнить статистику основной и тестовой базы")
|
||||
parser.add_argument("--view", type=str, help="Просмотреть канонический Markdown карточки из тестовой базы (ID или слово)")
|
||||
parser.add_argument("--diff", type=str, help="Показать построчный diff между основной и тестовой базой для знака")
|
||||
parser.add_argument("--export-card", type=str, help="Экспортировать карточку из тестовой базы в файл out/staging_cards/...")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
main_db = load_db(MAIN_DB_PATH)
|
||||
staging_db = load_db(STAGING_DB_PATH)
|
||||
|
||||
if args.stats or (not args.view and not args.diff and not args.export_card):
|
||||
print_comparison_stats(main_db, staging_db)
|
||||
|
||||
if args.view:
|
||||
e = find_entry(staging_db, args.view)
|
||||
if e:
|
||||
print(render_passport_markdown(e))
|
||||
else:
|
||||
print(f"[ERROR] Знак «{args.view}» не найден.")
|
||||
|
||||
if args.diff:
|
||||
show_diff(main_db, staging_db, args.diff)
|
||||
|
||||
if args.export_card:
|
||||
e = find_entry(staging_db, args.export_card)
|
||||
if e:
|
||||
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
idx_str = f"{e.get('id', 0):03d}"
|
||||
word = e.get("word", "")
|
||||
out_file = OUT_DIR / f"{idx_str}_{word}_staging.md"
|
||||
with open(out_file, "w", encoding="utf-8") as f:
|
||||
f.write(render_passport_markdown(e))
|
||||
print(f"✓ Карточка сохранена в: {out_file}")
|
||||
else:
|
||||
print(f"[ERROR] Знак «{args.export_card}» не найден.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user