SIMON Master Console Rebuild
True command center for SIMON + WEB360
This rebuild gives you a cleaner production spine: interactive tree, live viewer, guarded editor, dynamic graphics, architecture map, and note storage. It is designed to sit beside your existing
console.php
and become the stronger replacement path.
Dashboard
Tree
Viewer
System Map
File Registry
Notes
Files
15,335
Folders
408
Scanned Size
3.84 GB
PHP Files
887
Editable Text Files
12,596
File viewer
guarded to /htdocs
/connlink/test1/ui/old/graph_engine.php
<?php declare(strict_types=1); require_once __DIR__ . '/ai_engine.php'; const SIMON_GRAPH_FILE = SIMON_DATA_DIR . '/graph.json'; const SIMON_GRAPH_CACHE_TTL = 300; function simon_graph_norm(string $value): string { $value = strtolower(trim(strip_tags(html_entity_decode($value, ENT_QUOTES | ENT_HTML5, 'UTF-8')))); $value = preg_replace('/[^a-z0-9]+/i', '-', $value) ?? $value; return trim($value, '-'); } function simon_graph_add_node(array &$nodes, string $id, string $label, string $type, float $score = 1.0, array $meta = []): void { if ($id === '') return; if (!isset($nodes[$id])) { $nodes[$id] = [ 'id' => $id, 'label' => $label, 'type' => $type, 'score' => 0, 'count' => 0, 'meta' => $meta, ]; } $nodes[$id]['score'] += $score; $nodes[$id]['count'] += 1; if ($meta) $nodes[$id]['meta'] = array_merge($nodes[$id]['meta'] ?? [], $meta); } function simon_graph_add_edge(array &$edges, string $from, string $to, string $type, float $weight = 1.0, array $meta = []): void { if ($from === '' || $to === '' || $from === $to) return; $key = $from . '|' . $to . '|' . $type; if (!isset($edges[$key])) { $edges[$key] = [ 'id' => sha1($key), 'from' => $from, 'to' => $to, 'type' => $type, 'weight' => 0, 'count' => 0, 'meta' => $meta, ]; } $edges[$key]['weight'] += $weight; $edges[$key]['count'] += 1; if ($meta) $edges[$key]['meta'] = array_merge($edges[$key]['meta'] ?? [], $meta); } function simon_graph_event_node_id(array $event): string { return 'event:' . (string)($event['id'] ?? sha1(json_encode($event))); } function simon_graph_extract_domain(string $url): string { $host = (string)(parse_url($url, PHP_URL_HOST) ?: ''); return preg_replace('/^www\./', '', strtolower($host)) ?? $host; } function simon_graph_build(array $events, int $limit = 500): array { $nodes = []; $edges = []; $events = array_slice($events, 0, max(1, min(2000, $limit))); simon_graph_add_node($nodes, 'simon:core', 'SIMON', 'system', 20, ['description'=>'Central intelligence layer']); foreach ($events as $event) { if (!is_array($event)) continue; $eventId = simon_graph_event_node_id($event); $title = (string)($event['title'] ?? '(untitled)'); $category = (string)($event['category'] ?? 'general'); $source = (string)($event['source'] ?? $event['feed_id'] ?? $event['provider'] ?? 'unknown'); $url = (string)($event['url'] ?? ''); $importance = (float)($event['ai']['importance'] ?? $event['score'] ?? 50); $published = (string)($event['published'] ?? $event['at'] ?? $event['stored_at'] ?? ''); $domain = $url !== '' ? simon_graph_extract_domain($url) : ''; simon_graph_add_node($nodes, $eventId, mb_strlen($title) > 80 ? mb_substr($title, 0, 77) . '…' : $title, 'event', max(1, $importance / 20), [ 'title'=>$title, 'url'=>$url, 'summary'=>$event['ai']['summary'] ?? $event['summary'] ?? '', 'published'=>$published, 'category'=>$category, 'source'=>$source, 'importance'=>$importance, 'sentiment'=>$event['ai']['sentiment']['label'] ?? 'neutral', ]); simon_graph_add_edge($edges, 'simon:core', $eventId, 'observed', max(1, $importance / 50)); $catId = 'category:' . simon_graph_norm($category ?: 'general'); simon_graph_add_node($nodes, $catId, $category ?: 'general', 'category', 4); simon_graph_add_edge($edges, $eventId, $catId, 'in_category', 2); $sourceId = 'source:' . simon_graph_norm($source ?: 'unknown'); simon_graph_add_node($nodes, $sourceId, $source ?: 'unknown', 'source', 3); simon_graph_add_edge($edges, $eventId, $sourceId, 'from_source', 2); if ($domain !== '') { $domainId = 'domain:' . simon_graph_norm($domain); simon_graph_add_node($nodes, $domainId, $domain, 'domain', 2); simon_graph_add_edge($edges, $sourceId, $domainId, 'publishes_on', 1.5); simon_graph_add_edge($edges, $eventId, $domainId, 'linked_domain', 1); } $sentiment = (string)($event['ai']['sentiment']['label'] ?? 'neutral'); if ($sentiment !== '') { $sentId = 'sentiment:' . simon_graph_norm($sentiment); simon_graph_add_node($nodes, $sentId, ucfirst($sentiment), 'sentiment', 1.5); simon_graph_add_edge($edges, $eventId, $sentId, 'sentiment', 1); } $keywords = $event['ai']['keywords'] ?? []; if (is_array($keywords)) { foreach (array_slice($keywords, 0, 8) as $kw) { $kw = trim((string)$kw); if ($kw === '') continue; $kwId = 'keyword:' . simon_graph_norm($kw); simon_graph_add_node($nodes, $kwId, $kw, 'keyword', 1.2); simon_graph_add_edge($edges, $eventId, $kwId, 'has_keyword', 1.1); simon_graph_add_edge($edges, $catId, $kwId, 'category_topic', 0.35); } } $entities = $event['ai']['entities'] ?? []; if (is_array($entities)) { foreach (array_slice($entities, 0, 8) as $ent) { $ent = trim((string)$ent); if ($ent === '') continue; $entId = 'entity:' . simon_graph_norm($ent); simon_graph_add_node($nodes, $entId, $ent, 'entity', 1.8); simon_graph_add_edge($edges, $eventId, $entId, 'mentions_entity', 1.4); simon_graph_add_edge($edges, $sourceId, $entId, 'source_mentions', 0.4); } } $place = (string)($event['location'] ?? $event['place'] ?? $event['geo']['place'] ?? ''); if ($place !== '') { $placeId = 'location:' . simon_graph_norm($place); simon_graph_add_node($nodes, $placeId, $place, 'location', 2); simon_graph_add_edge($edges, $eventId, $placeId, 'located_at', 1.5); } if ($published !== '') { $ts = strtotime($published); if ($ts) { $day = gmdate('Y-m-d', $ts); $timeId = 'time:' . $day; simon_graph_add_node($nodes, $timeId, $day, 'time', 0.6); simon_graph_add_edge($edges, $eventId, $timeId, 'published_on', 0.6); } } } $nodesList = array_values($nodes); usort($nodesList, fn($a,$b) => ($b['score'] <=> $a['score'])); $edgesList = array_values($edges); usort($edgesList, fn($a,$b) => ($b['weight'] <=> $a['weight'])); return [ 'ok' => true, 'builtAt' => gmdate('c'), 'stats' => [ 'events' => count($events), 'nodes' => count($nodesList), 'edges' => count($edgesList), 'nodeTypes' => simon_graph_count_by($nodesList, 'type'), 'edgeTypes' => simon_graph_count_by($edgesList, 'type'), ], 'nodes' => $nodesList, 'edges' => $edgesList, ]; } function simon_graph_count_by(array $rows, string $field): array { $out = []; foreach ($rows as $r) { $v = (string)($r[$field] ?? 'unknown'); $out[$v] = ($out[$v] ?? 0) + 1; } arsort($out); return $out; } function simon_graph_save(array $graph): void { simon_write_json_file(SIMON_GRAPH_FILE, $graph); } function simon_graph_load(bool $fresh = false, int $limit = 500): array { if (!$fresh && is_file(SIMON_GRAPH_FILE) && (time() - filemtime(SIMON_GRAPH_FILE) < SIMON_GRAPH_CACHE_TTL)) { $cached = simon_read_json_file(SIMON_GRAPH_FILE, []); if (is_array($cached) && !empty($cached['nodes'])) return $cached; } $events = simon_ai_recent_events($limit); $graph = simon_graph_build($events, $limit); simon_graph_save($graph); return $graph; } function simon_graph_neighbors(string $id, int $limit = 60): array { $graph = simon_graph_load(false, 800); $nodeMap = []; foreach ($graph['nodes'] as $n) $nodeMap[$n['id']] = $n; $nodes = []; $edges = []; if (isset($nodeMap[$id])) $nodes[$id] = $nodeMap[$id]; foreach ($graph['edges'] as $e) { if (($e['from'] ?? '') === $id || ($e['to'] ?? '') === $id) { $edges[] = $e; if (isset($nodeMap[$e['from']])) $nodes[$e['from']] = $nodeMap[$e['from']]; if (isset($nodeMap[$e['to']])) $nodes[$e['to']] = $nodeMap[$e['to']]; if (count($edges) >= $limit) break; } } return ['ok'=>true, 'center'=>$id, 'nodes'=>array_values($nodes), 'edges'=>$edges, 'count'=>count($edges)]; }
Save file
Quick jump
open a path
Open