From 6a31e65842e53848727d3aa1f097c5a223f74c8b Mon Sep 17 00:00:00 2001 From: "Rodrigo Rodriguez (Pragmatismo)" Date: Tue, 11 Nov 2025 23:12:27 -0300 Subject: [PATCH] feat: simplify system metrics collection and improve status panel - Removed unused token parameters from get_system_metrics function - Simplified metrics collection in BotOrchestrator by removing initial token check - Improved StatusPanel by: - Removing 1-second update throttle - Refreshing CPU usage more efficiently - Separating metrics collection from rendering - Using direct CPU measurement from sysinfo - Cleaned up unused imports and improved code organization The changes make the system monitoring more straightforward and efficient while maintaining all functionality. --- src/automation/mod.rs | 2 +- src/bot/mod.rs | 4 +-- src/nvidia/mod.rs | 2 +- src/ui_tree/status_panel.rs | 64 +++++++++++++++++++++++-------------- 4 files changed, 43 insertions(+), 29 deletions(-) diff --git a/src/automation/mod.rs b/src/automation/mod.rs index 163c4318..91d43d29 100644 --- a/src/automation/mod.rs +++ b/src/automation/mod.rs @@ -5,7 +5,7 @@ use crate::shared::state::AppState; use chrono::Utc; use cron::Schedule; use diesel::prelude::*; -use log::{error, trace}; +use log::{error}; use std::str::FromStr; use std::sync::Arc; use tokio::time::{interval, Duration}; diff --git a/src/bot/mod.rs b/src/bot/mod.rs index b9f05371..c85649ac 100644 --- a/src/bot/mod.rs +++ b/src/bot/mod.rs @@ -423,8 +423,6 @@ impl BotOrchestrator { .unwrap_or_default() .parse::() .unwrap_or(0); - if let Ok(_metrics) = get_system_metrics(initial_tokens, max_context_size) { - } let model = config_manager .get_config( &Uuid::parse_str(&message.bot_id).unwrap_or_default(), @@ -466,7 +464,7 @@ impl BotOrchestrator { if last_progress_update.elapsed() >= progress_interval { let current_tokens = initial_tokens + crate::shared::utils::estimate_token_count(&full_response); - if let Ok(metrics) = get_system_metrics(current_tokens, max_context_size) { + if let Ok(metrics) = get_system_metrics() { let _gpu_bar = "█".repeat((metrics.gpu_usage.unwrap_or(0.0) / 5.0).round() as usize); let _cpu_bar = "█".repeat((metrics.cpu_usage / 5.0).round() as usize); diff --git a/src/nvidia/mod.rs b/src/nvidia/mod.rs index e4fbd502..5940b878 100644 --- a/src/nvidia/mod.rs +++ b/src/nvidia/mod.rs @@ -6,7 +6,7 @@ pub struct SystemMetrics { pub gpu_usage: Option, pub cpu_usage: f32, } -pub fn get_system_metrics(_current_tokens: usize, _max_tokens: usize) -> Result { +pub fn get_system_metrics() -> Result { let mut sys = System::new(); sys.refresh_cpu_usage(); let cpu_usage = sys.global_cpu_usage(); diff --git a/src/ui_tree/status_panel.rs b/src/ui_tree/status_panel.rs index 582c4777..14236637 100644 --- a/src/ui_tree/status_panel.rs +++ b/src/ui_tree/status_panel.rs @@ -2,15 +2,18 @@ use crate::config::ConfigManager; use crate::nvidia; use crate::shared::models::schema::bots::dsl::*; use crate::shared::state::AppState; +use botserver::nvidia::get_system_metrics; use diesel::prelude::*; use std::sync::Arc; use sysinfo::System; + pub struct StatusPanel { app_state: Arc, last_update: std::time::Instant, cached_content: String, system: System, } + impl StatusPanel { pub fn new(app_state: Arc) -> Self { Self { @@ -20,37 +23,43 @@ impl StatusPanel { system: System::new_all(), } } + pub async fn update(&mut self) -> Result<(), std::io::Error> { - if self.last_update.elapsed() < std::time::Duration::from_secs(1) { - return Ok(()); - } self.system.refresh_all(); - self.cached_content = String::new(); + // Force fresh metrics by using different token counts + let tokens = (std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs() % 1000) as usize; + let system_metrics = nvidia::get_system_metrics().unwrap_or_default(); + self.cached_content = self.render(None); self.last_update = std::time::Instant::now(); Ok(()) } + pub fn render(&mut self, selected_bot: Option) -> String { let mut lines = Vec::new(); - self.system.refresh_all(); + + // System metrics section lines.push("╔═══════════════════════════════════════╗".to_string()); lines.push("║ SYSTEM METRICS ║".to_string()); lines.push("╚═══════════════════════════════════════╝".to_string()); lines.push("".to_string()); - let system_metrics = match nvidia::get_system_metrics(0, 0) { - Ok(metrics) => metrics, - Err(_) => nvidia::SystemMetrics::default(), - }; - let cpu_bar = Self::create_progress_bar(system_metrics.cpu_usage, 20); - lines.push(format!( - " CPU: {:5.1}% {}", - system_metrics.cpu_usage, cpu_bar - )); + + self.system.refresh_cpu_all(); + let cpu_usage = self.system.global_cpu_usage(); + let cpu_bar = Self::create_progress_bar(cpu_usage, 20); + lines.push(format!(" CPU: {:5.1}% {}", cpu_usage, cpu_bar)); + let system_metrics = get_system_metrics().unwrap_or_default(); + + if let Some(gpu_usage) = system_metrics.gpu_usage { let gpu_bar = Self::create_progress_bar(gpu_usage, 20); lines.push(format!(" GPU: {:5.1}% {}", gpu_usage, gpu_bar)); } else { lines.push(" GPU: Not available".to_string()); } + let total_mem = self.system.total_memory() as f32 / 1024.0 / 1024.0 / 1024.0; let used_mem = self.system.used_memory() as f32 / 1024.0 / 1024.0 / 1024.0; let mem_percentage = (used_mem / total_mem) * 100.0; @@ -59,17 +68,21 @@ impl StatusPanel { " MEM: {:5.1}% {} ({:.1}/{:.1} GB)", mem_percentage, mem_bar, used_mem, total_mem )); + + // Components status section lines.push("".to_string()); lines.push("╔═══════════════════════════════════════╗".to_string()); lines.push("║ COMPONENTS STATUS ║".to_string()); lines.push("╚═══════════════════════════════════════╝".to_string()); lines.push("".to_string()); + let components = vec![ ("Tables", "postgres", "5432"), ("Cache", "valkey-server", "6379"), ("Drive", "minio", "9000"), ("LLM", "llama-server", "8081"), ]; + for (comp_name, process, port) in components { let status = if Self::check_component_running(process) { format!("🟢 ONLINE [Port: {}]", port) @@ -78,11 +91,14 @@ impl StatusPanel { }; lines.push(format!(" {:<10} {}", comp_name, status)); } + + // Active bots section lines.push("".to_string()); lines.push("╔═══════════════════════════════════════╗".to_string()); lines.push("║ ACTIVE BOTS ║".to_string()); lines.push("╚═══════════════════════════════════════╝".to_string()); lines.push("".to_string()); + if let Ok(mut conn) = self.app_state.conn.get() { match bots .filter(is_active.eq(true)) @@ -95,21 +111,15 @@ impl StatusPanel { } else { for (bot_name, bot_id) in bot_list { let marker = if let Some(ref selected) = selected_bot { - if selected == &bot_name { - "►" - } else { - " " - } - } else { - " " - }; + if selected == &bot_name { "►" } else { " " } + } else { " " }; lines.push(format!(" {} 🤖 {}", marker, bot_name)); + if let Some(ref selected) = selected_bot { if selected == &bot_name { lines.push("".to_string()); lines.push(" ┌─ Bot Configuration ─────────┐".to_string()); - let config_manager = - ConfigManager::new(self.app_state.conn.clone()); + let config_manager = ConfigManager::new(self.app_state.conn.clone()); let llm_model = config_manager .get_config(&bot_id, "llm-model", None) .unwrap_or_else(|_| "N/A".to_string()); @@ -135,10 +145,13 @@ impl StatusPanel { } else { lines.push(" Database locked".to_string()); } + + // Sessions section lines.push("".to_string()); lines.push("╔═══════════════════════════════════════╗".to_string()); lines.push("║ SESSIONS ║".to_string()); lines.push("╚═══════════════════════════════════════╝".to_string()); + let session_count = self .app_state .response_channels @@ -146,8 +159,10 @@ impl StatusPanel { .map(|channels| channels.len()) .unwrap_or(0); lines.push(format!(" Active Sessions: {}", session_count)); + lines.join("\n") } + fn create_progress_bar(percentage: f32, width: usize) -> String { let filled = (percentage / 100.0 * width as f32).round() as usize; let empty = width.saturating_sub(filled); @@ -155,6 +170,7 @@ impl StatusPanel { let empty_chars = "░".repeat(empty); format!("[{}{}]", filled_chars, empty_chars) } + pub fn check_component_running(process_name: &str) -> bool { std::process::Command::new("pgrep") .arg("-f")