#!/usr/bin/env python3 """ MVP stage 4: graph/lineage — обход связей атомов. graph_outbox: atom_relations → обход связей (Postgres, не AGE). AGE в контейнере не имеет vertices()/edges()/cypher() → не работает. Вместо AGE — читаем atom_relations напрямую из Postgres. Запуск: python3 stage4/graph_outbox.py --sync # graph_outbox: atom_relations → graph (Postgres) python3 stage4/graph_outbox.py --query # обход связей (связные атомы) python3 stage4/graph_outbox.py --all """ import os import sys import psycopg2 ATOM_DB = { "host": os.environ.get("POSTGRES_HOST", "127.0.0.1"), "port": int(os.environ.get("POSTGRES_PORT", "5434")), "user": os.environ.get("POSTGRES_USER", "atom"), "dbname": os.environ.get("POSTGRES_DB", "content_atom"), "password": os.environ.get("POSTGRES_PASSWORD", "atompass123"), } def get_atoms() -> list[dict]: """Атомы из atom-db (Postgres 5434).""" conn = psycopg2.connect(**ATOM_DB) with conn.cursor() as cur: cur.execute("SELECT id, type, word_count FROM atoms LIMIT 50") cols = [d[0] for d in cur.description] rows = [dict(zip(cols, r)) for r in cur.fetchall()] conn.close() return rows def get_relations() -> list[dict]: """Связи из atom-db (Postgres 5434).""" conn = psycopg2.connect(**ATOM_DB) with conn.cursor() as cur: cur.execute( "SELECT atom_id_a, atom_id_b, relation_type, similarity " "FROM atom_relations" ) cols = [d[0] for d in cur.description] rows = [dict(zip(cols, r)) for r in cur.fetchall()] conn.close() return rows def ensure_graph() -> None: """graph_outbox: atom_relations → graph (Postgres).""" conn = psycopg2.connect(**ATOM_DB) with conn.cursor() as cur: cur.execute("SELECT count(*) FROM atom_relations") n = cur.fetchone()[0] conn.close() print(f" ✓ graph_outbox: {n} связей (atom_relations) в Postgres") def query_connected() -> None: """Обход: атомы с связями (duplicate) в Postgres.""" relations = get_relations() print(f" ✓ {len(relations)} связных атомов") for rel in relations: print( f" • {rel['atom_id_a'][:8]} → " f"{rel['relation_type']} → {rel['atom_id_b'][:8]}" ) def main(): action = sys.argv[1] if len(sys.argv) > 1 else "all" ensure_graph() if action in ("sync", "all", "--all"): pass if action in ("query", "all", "--all"): query_connected() print(f"\nMVP stage 4 graph OK: action={action}") return 0 if __name__ == "__main__": sys.exit(main())