feat: complete academic symbol lexicon heal, 2-column Cooper extraction, and updated assets
This commit is contained in:
Executable
+164
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
scripts/import_user_edits.py
|
||||
|
||||
Imports custom edits made on a mobile device (exported from Oracle 999 app)
|
||||
into the desktop repository:
|
||||
- Updates the respective dossiers in oracle_enricher/out/dossiers/
|
||||
- Updates oracle_enricher/out/oracle_kb.json
|
||||
- Automatically regenerates assets/data/oracle_kb.json via sync_kb_asset.py
|
||||
- Preserves git traceability with timestamps and user_edited flags
|
||||
|
||||
Usage:
|
||||
# From a file:
|
||||
python3 scripts/import_user_edits.py edits.json
|
||||
|
||||
# Interactive paste:
|
||||
python3 scripts/import_user_edits.py
|
||||
"""
|
||||
|
||||
import sys
|
||||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
ENRICHER = ROOT / 'oracle_enricher'
|
||||
DOSSIERS_DIR = ENRICHER / 'out' / 'dossiers'
|
||||
KB_FILE = ENRICHER / 'out' / 'oracle_kb.json'
|
||||
SYNC_SCRIPT = ROOT / 'scripts' / 'sync_kb_asset.py'
|
||||
|
||||
def load_input_json():
|
||||
if len(sys.argv) > 1 and sys.argv[1] not in ('-', '--stdin'):
|
||||
p = Path(sys.argv[1])
|
||||
if not p.exists():
|
||||
print(f"Error: File not found: {p}")
|
||||
sys.exit(1)
|
||||
return json.loads(p.read_text(encoding='utf-8'))
|
||||
|
||||
if not sys.stdin.isatty():
|
||||
return json.loads(sys.stdin.read())
|
||||
|
||||
print("=== Импорт пользовательских правок из Оракула 999 ===")
|
||||
print("Вставьте JSON с телефона (скопированный через кнопку 'Скопировать JSON правок')")
|
||||
print("После вставки введите строку с 'EOF' или нажмите Ctrl+D:")
|
||||
lines = []
|
||||
try:
|
||||
while True:
|
||||
line = input()
|
||||
if line.strip() == 'EOF':
|
||||
break
|
||||
lines.append(line)
|
||||
except EOFError:
|
||||
pass
|
||||
|
||||
raw = '\n'.join(lines).strip()
|
||||
if not raw:
|
||||
print("Отмена: входные данные пусты.")
|
||||
sys.exit(0)
|
||||
return json.loads(raw)
|
||||
|
||||
def main():
|
||||
data = load_input_json()
|
||||
if not isinstance(data, dict):
|
||||
print("Ошибка: ожидался словарь вида { 'слово': { ... } }")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Найдено правок для импорта: {len(data)} слов")
|
||||
|
||||
# Index existing dossiers
|
||||
word_to_dossier = {}
|
||||
if DOSSIERS_DIR.exists():
|
||||
for p in DOSSIERS_DIR.glob('*.json'):
|
||||
try:
|
||||
d = json.loads(p.read_text(encoding='utf-8'))
|
||||
w = d.get('word')
|
||||
if w:
|
||||
word_to_dossier[w.lower().strip()] = p
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
kb = json.loads(KB_FILE.read_text(encoding='utf-8')) if KB_FILE.exists() else {}
|
||||
|
||||
now_iso = datetime.now(timezone.utc).isoformat()
|
||||
updated_words = []
|
||||
|
||||
for raw_word, edits in data.items():
|
||||
w = raw_word.lower().strip()
|
||||
if not isinstance(edits, dict):
|
||||
continue
|
||||
|
||||
core = edits.get('core', '').strip()
|
||||
oracle = edits.get('oracle', '').strip()
|
||||
shadow = edits.get('shadow', '').strip()
|
||||
asks = edits.get('asks', '').strip()
|
||||
step = edits.get('step', '').strip()
|
||||
|
||||
# 1. Update dossier if exists
|
||||
p = word_to_dossier.get(w)
|
||||
if p and p.exists():
|
||||
try:
|
||||
dossier = json.loads(p.read_text(encoding='utf-8'))
|
||||
except Exception:
|
||||
dossier = {'word': w}
|
||||
else:
|
||||
p = DOSSIERS_DIR / f"{w}.json"
|
||||
dossier = {'word': w}
|
||||
|
||||
if 'canon' not in dossier or not isinstance(dossier['canon'], dict):
|
||||
dossier['canon'] = {'word': w}
|
||||
|
||||
canon = dossier['canon']
|
||||
if core:
|
||||
canon['core'] = core
|
||||
if oracle:
|
||||
canon['oracle'] = oracle
|
||||
if shadow:
|
||||
canon['shadow'] = shadow
|
||||
if asks:
|
||||
canon['asks'] = asks
|
||||
if step:
|
||||
canon['step'] = step
|
||||
|
||||
canon['user_edited'] = True
|
||||
canon['via'] = 'user_edit'
|
||||
canon['updated_at'] = edits.get('updatedAt') or now_iso
|
||||
|
||||
p.parent.mkdir(parents=True, exist_ok=True)
|
||||
p.write_text(json.dumps(dossier, ensure_ascii=False, indent=2), encoding='utf-8')
|
||||
|
||||
# 2. Update oracle_kb.json
|
||||
if w not in kb or not isinstance(kb[w], dict):
|
||||
kb[w] = canon
|
||||
else:
|
||||
kb[w].update({
|
||||
'core': canon.get('core', ''),
|
||||
'oracle': canon.get('oracle', ''),
|
||||
'shadow': canon.get('shadow', ''),
|
||||
'asks': canon.get('asks', ''),
|
||||
'step': canon.get('step', ''),
|
||||
'user_edited': True,
|
||||
'via': 'user_edit',
|
||||
'updated_at': canon.get('updated_at'),
|
||||
})
|
||||
|
||||
updated_words.append(w)
|
||||
|
||||
KB_FILE.parent.mkdir(parents=True, exist_ok=True)
|
||||
KB_FILE.write_text(json.dumps(kb, ensure_ascii=False, indent=2), encoding='utf-8')
|
||||
|
||||
print(f"Обновлено досье и KB для {len(updated_words)} слов: {', '.join(updated_words[:10])}{'...' if len(updated_words) > 10 else ''}")
|
||||
|
||||
# 3. Synchronize assets/data/oracle_kb.json
|
||||
print("Синхронизация assets/data/oracle_kb.json...")
|
||||
subprocess.run([sys.executable, str(SYNC_SCRIPT)], check=True)
|
||||
|
||||
print("\n✅ УСПЕШНО! Все правки зафиксированы в кодовой базе.")
|
||||
print("Теперь они станут частью базового канона во всех будущих релизах приложения.")
|
||||
print("Чтобы закоммитить в git:")
|
||||
print(" git add oracle_enricher/ assets/data/oracle_kb.json")
|
||||
print(" git commit -m 'feat: import user canon edits from mobile app'")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user