feed_hunting_to_graph.py
1 #!/usr/bin/env python3 2 """ 3 Sovereign OS - Feed Hunting Party Results to Knowledge Graph 4 ============================================================= 5 6 This script bridges the hunting party extractors to the knowledge graph, 7 completing the extraction → graph loop. 8 9 Usage: 10 python3 scripts/feed_hunting_to_graph.py # Feed once 11 python3 scripts/feed_hunting_to_graph.py --watch # Watch and feed continuously 12 """ 13 14 import json 15 import sys 16 import time 17 from pathlib import Path 18 from datetime import datetime 19 20 # Import the graph feeder 21 sys.path.insert(0, str(Path(__file__).parent.parent / "scripts")) 22 from graph_feeder import KnowledgeGraph, update_graph_files, publish_to_mesh 23 24 # Paths 25 HUNTING_EXPORT = Path.home() / ".sovereign" / "hunting-export.json" 26 HUNTING_STATE = Path.home() / ".sovereign" / "hunting-state.json" 27 28 29 def feed_hunting_to_graph(): 30 """Feed hunting party results into the knowledge graph.""" 31 if not HUNTING_EXPORT.exists(): 32 print("No hunting export found. Run hunting party first.") 33 return 0, 0 34 35 # Load hunting export 36 with open(HUNTING_EXPORT) as f: 37 hunting_data = json.load(f) 38 39 # Load graph 40 graph = KnowledgeGraph() 41 initial_nodes = len(graph.nodes) 42 initial_edges = len(graph.edges) 43 44 nodes_added = 0 45 edges_added = 0 46 47 # Add nodes 48 for node_data in hunting_data.get('nodes', []): 49 node_id = node_data['id'] 50 if node_id not in graph.nodes: 51 # Use the graph's add_insight method for most types 52 if node_data['node_type'] == 'insight': 53 if graph.add_insight( 54 node_data['content'], 55 node_data['axioms'][0] if node_data['axioms'] else None, 56 node_data.get('importance', 0.7), 57 'hunting_party' 58 ): 59 nodes_added += 1 60 elif node_data['node_type'] == 'decision': 61 # Create decision node directly 62 from graph_feeder import GraphNode 63 graph.nodes[node_id] = GraphNode( 64 id=node_id, 65 label=node_data['content'][:30], 66 node_type='decision', 67 content=node_data['content'], 68 axioms=node_data.get('axioms', []), 69 importance=node_data.get('importance', 0.8), 70 created_at=datetime.now().isoformat(), 71 source='hunting_party' 72 ) 73 nodes_added += 1 74 elif node_data['node_type'] == 'question': 75 # Questions are potential gravity wells 76 from graph_feeder import GraphNode 77 graph.nodes[node_id] = GraphNode( 78 id=node_id, 79 label=node_data['content'][:30], 80 node_type='question', 81 content=node_data['content'], 82 axioms=node_data.get('axioms', []), 83 importance=node_data.get('importance', 0.9), 84 created_at=datetime.now().isoformat(), 85 source='hunting_party' 86 ) 87 nodes_added += 1 88 elif node_data['node_type'] == 'concept': 89 # Concepts from [[links]] 90 from graph_feeder import GraphNode 91 graph.nodes[node_id] = GraphNode( 92 id=node_id, 93 label=node_data['content'][:30], 94 node_type='concept', 95 content=node_data['content'], 96 axioms=node_data.get('axioms', []), 97 importance=node_data.get('importance', 1.0), 98 created_at=datetime.now().isoformat(), 99 source='hunting_party' 100 ) 101 nodes_added += 1 102 103 # Add edges 104 from graph_feeder import GraphEdge 105 existing_edges = {(e.source_id, e.target_id) for e in graph.edges} 106 107 for edge_data in hunting_data.get('edges', []): 108 key = (edge_data['source_id'], edge_data['target_id']) 109 if key not in existing_edges: 110 # Only add if both nodes exist 111 if edge_data['source_id'] in graph.nodes and edge_data['target_id'] in graph.nodes: 112 graph.edges.append(GraphEdge( 113 source_id=edge_data['source_id'], 114 target_id=edge_data['target_id'], 115 edge_type=edge_data.get('edge_type', 'relates_to'), 116 strength=edge_data.get('strength', 0.5), 117 created_at=datetime.now().isoformat() 118 )) 119 edges_added += 1 120 existing_edges.add(key) 121 122 # Save and update 123 graph.save() 124 update_graph_files(graph) 125 126 # Publish to mesh 127 publish_to_mesh("hunting_to_graph", { 128 "nodes_added": nodes_added, 129 "edges_added": edges_added, 130 "total_nodes": len(graph.nodes), 131 "total_edges": len(graph.edges) 132 }) 133 134 return nodes_added, edges_added 135 136 137 def run_once(): 138 """Run the feed once.""" 139 print("Feeding hunting party results to graph...") 140 nodes, edges = feed_hunting_to_graph() 141 print(f"Added: {nodes} nodes, {edges} edges") 142 143 144 def run_watch(): 145 """Watch for changes and feed continuously.""" 146 print("Watching for hunting party updates...") 147 print("Press Ctrl+C to stop\n") 148 149 last_mtime = 0 150 151 while True: 152 try: 153 if HUNTING_EXPORT.exists(): 154 mtime = HUNTING_EXPORT.stat().st_mtime 155 if mtime > last_mtime: 156 print(f"[{datetime.now().strftime('%H:%M:%S')}] Change detected...") 157 nodes, edges = feed_hunting_to_graph() 158 print(f" Added: {nodes} nodes, {edges} edges") 159 last_mtime = mtime 160 161 time.sleep(10) 162 163 except KeyboardInterrupt: 164 print("\nStopped.") 165 break 166 except Exception as e: 167 print(f"Error: {e}") 168 time.sleep(30) 169 170 171 if __name__ == "__main__": 172 if len(sys.argv) > 1 and sys.argv[1] == "--watch": 173 run_watch() 174 else: 175 run_once()