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,338
Folders
408
Scanned Size
3.84 GB
PHP Files
890
Editable Text Files
12,599
File viewer
guarded to /htdocs
/live/ai_engine.php
<?php declare(strict_types=1); require_once __DIR__ . '/bootstrap.php'; const SIMON_AI_STORE_FILE = SIMON_DATA_DIR . '/events.ndjson'; const SIMON_AI_INDEX_FILE = SIMON_DATA_DIR . '/event_index.json'; function simon_ai_stopwords(): array { return array_fill_keys(str_getcsv('the,a,an,and,or,but,for,with,from,that,this,these,those,into,over,under,about,after,before,between,while,when,where,why,how,what,which,who,will,would,could,should,can,may,might,are,was,were,is,be,been,being,to,of,in,on,at,as,by,it,its,not,no,new,more,less,than,then,there,their,they,them,you,your,our,has,have,had,said,says,say,via,using,use,used'), true); } function simon_ai_words(string $text): array { $text = strtolower(strip_tags(html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8'))); preg_match_all('/[a-z][a-z0-9\-]{2,}/u', $text, $m); return $m[0] ?? []; } function simon_ai_keywords(string $title, string $summary, int $limit = 12): array { $stop = simon_ai_stopwords(); $counts = []; foreach (simon_ai_words($title . ' ' . $title . ' ' . $summary) as $w) { if (isset($stop[$w]) || strlen($w) < 3) continue; $counts[$w] = ($counts[$w] ?? 0) + 1; } arsort($counts); return array_slice(array_keys($counts), 0, $limit); } function simon_ai_entities(string $text): array { $entities = []; preg_match_all('/\b([A-Z][a-z]+(?:\s+[A-Z][a-z]+){0,3}|[A-Z]{2,}(?:\s+[A-Z]{2,})*)\b/u', $text, $m); foreach (($m[1] ?? []) as $e) { $e = trim($e); if (strlen($e) < 3) continue; if (in_array(strtolower($e), ['the','and','for','with','from','news','live'], true)) continue; $entities[$e] = ($entities[$e] ?? 0) + 1; } arsort($entities); return array_slice(array_keys($entities), 0, 15); } function simon_ai_sentiment(string $text): array { $positive = ['gain','gains','growth','good','great','win','wins','positive','recover','recovery','launch','approved','success','safe','healthy','strong','record','breakthrough','peace','benefit','improve','improved']; $negative = ['loss','losses','drop','drops','down','bad','risk','risks','warning','alert','fail','failed','failure','attack','dead','death','crisis','storm','severe','earthquake','war','lawsuit','recall','breach','outage','danger']; $words = simon_ai_words($text); $pos = 0; $neg = 0; foreach ($words as $w) { if (in_array($w, $positive, true)) $pos++; if (in_array($w, $negative, true)) $neg++; } $score = $pos - $neg; $label = $score > 1 ? 'positive' : ($score < -1 ? 'negative' : 'neutral'); return ['label'=>$label, 'score'=>$score, 'positive'=>$pos, 'negative'=>$neg]; } function simon_ai_summary(string $title, string $summary, int $max = 260): string { $base = trim($summary) !== '' ? trim($summary) : trim($title); $base = preg_replace('/\s+/', ' ', strip_tags(html_entity_decode($base, ENT_QUOTES | ENT_HTML5, 'UTF-8'))) ?? $base; if (mb_strlen($base) <= $max) return $base; $cut = mb_substr($base, 0, $max - 1); $last = max(mb_strrpos($cut, '. ') ?: 0, mb_strrpos($cut, ' ') ?: 0); if ($last > 80) $cut = mb_substr($cut, 0, $last); return rtrim($cut, ' ,.;:') . '…'; } function simon_ai_importance(array $event, array $keywords, array $sentiment): int { $score = (float)($event['score'] ?? 50); $cat = strtolower((string)($event['category'] ?? '')); if (in_array($cat, ['alert','quake','weather','security'], true)) $score += 12; $text = strtolower(($event['title'] ?? '') . ' ' . ($event['summary'] ?? '')); foreach (['breaking','urgent','severe','critical','recall','outage','breach','earthquake','storm','warning','lawsuit','launch','approved'] as $w) { if (str_contains($text, $w)) $score += 4; } if (($sentiment['label'] ?? '') === 'negative') $score += 4; if (count($keywords) >= 8) $score += 2; return max(0, min(100, (int)round($score))); } function simon_ai_enrich_event(array $event, string $mode = 'local'): array { $title = (string)($event['title'] ?? ''); $summary = (string)($event['summary'] ?? ''); $text = trim($title . ' ' . $summary); $keywords = simon_ai_keywords($title, $summary); $sentiment = simon_ai_sentiment($text); $aiSummary = simon_ai_summary($title, $summary); $entities = simon_ai_entities($text); $importance = simon_ai_importance($event, $keywords, $sentiment); $signature = sha1(strtolower(preg_replace('/[^a-z0-9]+/i', ' ', $title . ' ' . parse_url((string)($event['url'] ?? ''), PHP_URL_HOST)) ?? $title)); $event['ai'] = [ 'mode' => $mode, 'summary' => $aiSummary, 'keywords' => $keywords, 'entities' => $entities, 'sentiment' => $sentiment, 'importance' => $importance, 'duplicate_signature' => $signature, 'actions' => simon_ai_suggest_actions($event, $importance, $sentiment), 'processed_at' => gmdate('c'), ]; $event['score'] = max((float)($event['score'] ?? 0), $importance); return $event; } function simon_ai_suggest_actions(array $event, int $importance, array $sentiment): array { $cat = strtolower((string)($event['category'] ?? '')); $actions = []; if ($importance >= 85) $actions[] = 'Surface in Top 100 / Alert rail'; if (in_array($cat, ['alert','quake','weather'], true)) $actions[] = 'Check location impact'; if ($cat === 'market') $actions[] = 'Compare against market watchlist'; if ($cat === 'tech') $actions[] = 'Review for Web360/SIMON relevance'; if (($sentiment['label'] ?? '') === 'negative') $actions[] = 'Monitor follow-up sources'; if (!$actions) $actions[] = 'Archive and make searchable'; return $actions; } function simon_ai_enrich_events(array $events, string $mode = 'local'): array { $out = []; foreach ($events as $event) if (is_array($event)) $out[] = simon_ai_enrich_event($event, $mode); return $out; } function simon_ai_store_events(array $events): int { if (!is_dir(SIMON_DATA_DIR)) @mkdir(SIMON_DATA_DIR, 0775, true); $existing = simon_ai_load_index(); $added = 0; $fh = @fopen(SIMON_AI_STORE_FILE, 'ab'); if (!$fh) return 0; foreach ($events as $event) { $id = (string)($event['id'] ?? sha1(json_encode($event))); if (isset($existing[$id])) continue; $event['stored_at'] = gmdate('c'); fwrite($fh, json_encode($event, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "\n"); $existing[$id] = ['stored_at'=>$event['stored_at'], 'title'=>$event['title'] ?? '', 'category'=>$event['category'] ?? '', 'published'=>$event['published'] ?? '']; $added++; } fclose($fh); simon_write_json_file(SIMON_AI_INDEX_FILE, $existing); return $added; } function simon_ai_load_index(): array { $idx = simon_read_json_file(SIMON_AI_INDEX_FILE, []); return is_array($idx) ? $idx : []; } function simon_ai_recent_events(int $limit = 100, string $q = '', string $category = ''): array { if (!is_file(SIMON_AI_STORE_FILE)) return []; $lines = file(SIMON_AI_STORE_FILE, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: []; $lines = array_slice($lines, -max(1, min(1000, $limit * 4))); $out = []; foreach (array_reverse($lines) as $line) { $event = json_decode($line, true); if (!is_array($event)) continue; if ($category !== '' && ($event['category'] ?? '') !== $category) continue; if ($q !== '') { $hay = strtolower(($event['title'] ?? '') . ' ' . ($event['summary'] ?? '') . ' ' . json_encode($event['ai'] ?? [])); if (!str_contains($hay, strtolower($q))) continue; } $out[] = $event; if (count($out) >= $limit) break; } return $out; } function simon_ai_stats(): array { $events = simon_ai_recent_events(1000); $cats = []; $sent = ['positive'=>0,'neutral'=>0,'negative'=>0]; $important = 0; foreach ($events as $e) { $cat = (string)($e['category'] ?? 'general'); $cats[$cat] = ($cats[$cat] ?? 0) + 1; $s = $e['ai']['sentiment']['label'] ?? 'neutral'; if (isset($sent[$s])) $sent[$s]++; if (($e['ai']['importance'] ?? 0) >= 80) $important++; } arsort($cats); return ['count'=>count($events), 'categories'=>$cats, 'sentiment'=>$sent, 'important'=>$important, 'store'=>SIMON_AI_STORE_FILE]; }
Save file
Quick jump
open a path
Open