fix: Restore Brain Monitor HTML dashboard and API stats route

This commit is contained in:
Riz Ashraf committed 2026-09-09 03:43:28 +01:00
1 parent b2cda6c9cc
commit 5703e54b88
2 files changed
+103

No files matched your search

+73
View File
@@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<title>Brain Monitor</title>
<style>
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; padding: 40px; background-color: #f0f2f5; color: #333; }
h1 { color: #2c3e50; text-align: center; margin-bottom: 30px; }
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; max-width: 800px; margin: 0 auto; }
.stat-card { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.05); text-align: center; transition: transform 0.2s ease; }
.stat-card:hover { transform: translateY(-5px); }
.stat-value { font-size: 2.5em; font-weight: bold; color: #3498db; margin: 10px 0; }
.stat-label { font-size: 1.1em; color: #7f8c8d; text-transform: uppercase; letter-spacing: 1px; }
.status-dot { display: inline-block; width: 10px; height: 10px; background-color: #2ecc71; border-radius: 50%; margin-right: 8px; box-shadow: 0 0 5px #2ecc71; }
.header-bar { max-width: 800px; margin: 0 auto 20px; display: flex; justify-content: space-between; align-items: center; }
</style>
</head>
<body>
<div class="header-bar">
<h1>🧠 Antigravity Brain Monitor</h1>
<div><span class="status-dot"></span>System Online</div>
</div>
<div class="grid">
<div class="stat-card">
<div class="stat-label">Entities</div>
<div class="stat-value" id="val-entities">-</div>
</div>
<div class="stat-card">
<div class="stat-label">Relations</div>
<div class="stat-value" id="val-relations">-</div>
</div>
<div class="stat-card">
<div class="stat-label">Active Tasks</div>
<div class="stat-value" id="val-tasks">-</div>
</div>
<div class="stat-card">
<div class="stat-label">Snippets</div>
<div class="stat-value" id="val-snippets">-</div>
</div>
<div class="stat-card">
<div class="stat-label">Tech Debt</div>
<div class="stat-value" id="val-tech_debts">-</div>
</div>
<div class="stat-card">
<div class="stat-label">ADRs</div>
<div class="stat-value" id="val-adrs">-</div>
</div>
</div>
<script>
async function fetchStats() {
try {
const response = await fetch('/api/stats');
const data = await response.json();
document.getElementById('val-entities').innerText = data.entities;
document.getElementById('val-relations').innerText = data.relations;
document.getElementById('val-tasks').innerText = data.tasks;
document.getElementById('val-snippets').innerText = data.snippets;
document.getElementById('val-tech_debts').innerText = data.tech_debts;
document.getElementById('val-adrs').innerText = data.adrs;
} catch (err) {
console.error("Failed to fetch stats:", err);
}
}
// Initial fetch
fetchStats();
// Poll every 2 seconds
setInterval(fetchStats, 2000);
</script>
</body>
</html>
+30
View File
@@ -139,6 +139,32 @@ fn run_server(state: Arc<MemoryState>) -> Result<(), Box<dyn std::error::Error>>
let app = Router::new() let app = Router::new()
.route("/sse", get(sse_handler)) .route("/sse", get(sse_handler))
.route("/messages", post(message_handler)) .route("/messages", post(message_handler))
.route("/health", get(health_handler))
.route("/dashboard", get(|| async move {
axum::response::Html(include_str!("dashboard.html"))
}))
.route("/api/stats", get({
let state_clone = app_state.handler.state.clone();
move || async move {
let (entities, relations) = {
let graph = state_clone.get_full_graph();
(graph.entities.len(), graph.relations.len())
};
let tasks = state_clone.tasks.read().len();
let snippets = state_clone.snippets.read().len();
let tech_debts = state_clone.tech_debts.read().len();
let adrs = state_clone.adrs.read().len();
axum::Json(serde_json::json!({
"entities": entities,
"relations": relations,
"tasks": tasks,
"snippets": snippets,
"tech_debts": tech_debts,
"adrs": adrs
}))
}
}))
.with_state(app_state); .with_state(app_state);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
@@ -162,6 +188,10 @@ async fn sse_handler(
Sse::new(stream).keep_alive(axum::response::sse::KeepAlive::new()) Sse::new(stream).keep_alive(axum::response::sse::KeepAlive::new())
} }
async fn health_handler() -> &'static str {
"OK"
}
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
struct SessionQuery { struct SessionQuery {
#[serde(rename = "sessionId")] #[serde(rename = "sessionId")]