/ scripts / feed_hunting_to_graph.py
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()