use crate::{HardwareInfo, Result};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemOverview {
pub cpu: SimpleCPU,
pub memory_gb: f64,
pub gpu: Option<SimpleGPU>,
pub storage: SimpleStorage,
pub health: SystemHealth,
pub environment: String,
pub performance_score: u8,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SimpleCPU {
pub name: String,
pub cores: u32,
pub threads: u32,
pub vendor: String,
pub ai_capable: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SimpleGPU {
pub name: String,
pub vram_gb: f64,
pub vendor: String,
pub ai_capable: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SimpleStorage {
pub total_gb: f64,
pub available_gb: f64,
pub drive_type: String,
pub health: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemHealth {
pub status: HealthStatus,
pub temperature: TemperatureStatus,
pub power: PowerStatus,
pub warnings: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum HealthStatus {
Excellent,
Good,
Fair,
Poor,
Critical,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum TemperatureStatus {
Normal,
Warm,
Hot,
Critical,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum PowerStatus {
Low,
Normal,
High,
VeryHigh,
}
impl SystemOverview {
pub fn quick() -> Result<Self> {
let hw_info = HardwareInfo::query()?;
Self::from_hardware_info(hw_info)
}
pub fn from_hardware_info(hw_info: HardwareInfo) -> Result<Self> {
let cpu = SimpleCPU {
name: hw_info.cpu().model_name().to_string(),
cores: hw_info.cpu().physical_cores(),
threads: hw_info.cpu().logical_cores(),
vendor: hw_info.cpu().vendor().to_string(),
ai_capable: Self::check_cpu_ai_capabilities(&hw_info),
};
let memory_gb = hw_info.memory().total_gb();
let gpu = if !hw_info.gpus().is_empty() {
let primary_gpu = &hw_info.gpus()[0];
Some(SimpleGPU {
name: primary_gpu.model_name().to_string(),
vram_gb: primary_gpu.memory_gb(),
vendor: primary_gpu.vendor().to_string(),
ai_capable: Self::check_gpu_ai_capabilities(primary_gpu),
})
} else {
None
};
let storage = Self::calculate_storage_summary(&hw_info)?;
let health = Self::assess_system_health(&hw_info)?;
let environment = hw_info.virtualization().environment_type.to_string();
let performance_score = Self::calculate_performance_score(&hw_info);
Ok(Self {
cpu,
memory_gb,
gpu,
storage,
health,
environment,
performance_score,
})
}
pub fn is_ai_ready(&self) -> bool {
self.cpu.ai_capable ||
self.gpu.as_ref().map_or(false, |gpu| gpu.ai_capable) ||
self.memory_gb >= 8.0
}
pub fn ai_score(&self) -> u8 {
let mut score = 0;
if let Some(gpu) = &self.gpu {
if gpu.ai_capable {
score += 30;
if gpu.vram_gb >= 8.0 {
score += 15;
} else if gpu.vram_gb >= 4.0 {
score += 10;
} else {
score += 5;
}
}
}
if self.cpu.ai_capable {
score += 15;
}
if self.cpu.cores >= 8 {
score += 10;
} else if self.cpu.cores >= 4 {
score += 5;
}
if self.memory_gb >= 32.0 {
score += 25;
} else if self.memory_gb >= 16.0 {
score += 20;
} else if self.memory_gb >= 8.0 {
score += 15;
} else {
score += 5;
}
score.min(100)
}
pub fn get_recommendations(&self) -> Vec<String> {
let mut recommendations = Vec::new();
if self.memory_gb < 16.0 {
recommendations.push("Consider upgrading to 16GB+ RAM for better performance".to_string());
}
if self.gpu.is_none() {
recommendations.push("Add a dedicated GPU for AI/ML acceleration".to_string());
} else if let Some(gpu) = &self.gpu {
if gpu.vram_gb < 4.0 {
recommendations.push("Consider a GPU with more VRAM for large AI models".to_string());
}
}
if self.storage.drive_type.to_lowercase().contains("hdd") {
recommendations.push("Upgrade to SSD for faster data access".to_string());
}
for warning in &self.health.warnings {
recommendations.push(warning.clone());
}
recommendations
}
fn check_cpu_ai_capabilities(hw_info: &HardwareInfo) -> bool {
let cpu = hw_info.cpu();
cpu.has_feature("avx2") ||
cpu.has_feature("avx512") ||
cpu.has_feature("amx") ||
!hw_info.npus().is_empty()
}
fn check_gpu_ai_capabilities(gpu: &crate::GPUInfo) -> bool {
let vendor = gpu.vendor().to_string().to_lowercase();
let name = gpu.model_name().to_lowercase();
if vendor.contains("nvidia") {
return true;
}
if vendor.contains("amd") && (name.contains("rx") || name.contains("radeon")) {
return true;
}
if vendor.contains("intel") && name.contains("arc") {
return true;
}
false
}
fn calculate_storage_summary(hw_info: &HardwareInfo) -> Result<SimpleStorage> {
let storage_devices = hw_info.storage_devices();
if storage_devices.is_empty() {
return Ok(SimpleStorage {
total_gb: 0.0,
available_gb: 0.0,
drive_type: "Unknown".to_string(),
health: "Unknown".to_string(),
});
}
let total_gb: f64 = storage_devices.iter()
.map(|device| device.capacity_gb())
.sum();
let available_gb: f64 = storage_devices.iter()
.map(|device| device.available_gb())
.sum();
let drive_type = storage_devices[0].drive_type().to_string();
let health = if available_gb / total_gb < 0.1 {
"Critical - Low space".to_string()
} else if available_gb / total_gb < 0.2 {
"Warning - Low space".to_string()
} else {
"Good".to_string()
};
Ok(SimpleStorage {
total_gb,
available_gb,
drive_type,
health,
})
}
fn assess_system_health(hw_info: &HardwareInfo) -> Result<SystemHealth> {
let mut warnings = Vec::new();
let thermal = hw_info.thermal();
let temperature = if let Some(max_temp) = thermal.max_temperature() {
if max_temp >= 90.0 {
warnings.push("High CPU/GPU temperatures detected".to_string());
TemperatureStatus::Critical
} else if max_temp >= 80.0 {
warnings.push("Elevated temperatures detected".to_string());
TemperatureStatus::Hot
} else if max_temp >= 70.0 {
TemperatureStatus::Warm
} else {
TemperatureStatus::Normal
}
} else {
TemperatureStatus::Normal
};
let power = if let Some(power_profile) = hw_info.power_profile() {
if let Some(power_draw) = power_profile.total_power_draw {
if power_draw > 200.0 {
PowerStatus::VeryHigh
} else if power_draw > 100.0 {
PowerStatus::High
} else if power_draw > 50.0 {
PowerStatus::Normal
} else {
PowerStatus::Low
}
} else {
PowerStatus::Normal
}
} else {
PowerStatus::Normal
};
let status = match (&temperature, &power, warnings.len()) {
(TemperatureStatus::Critical, _, _) => HealthStatus::Critical,
(TemperatureStatus::Hot, PowerStatus::VeryHigh, _) => HealthStatus::Poor,
(TemperatureStatus::Hot, _, _) => HealthStatus::Fair,
(_, PowerStatus::VeryHigh, _) => HealthStatus::Fair,
(_, _, n) if n > 2 => HealthStatus::Poor,
(_, _, n) if n > 0 => HealthStatus::Fair,
(TemperatureStatus::Normal, PowerStatus::Normal | PowerStatus::Low, 0) => HealthStatus::Excellent,
_ => HealthStatus::Good,
};
Ok(SystemHealth {
status,
temperature,
power,
warnings,
})
}
fn calculate_performance_score(hw_info: &HardwareInfo) -> u8 {
let mut score = 0;
let cpu_cores = hw_info.cpu().logical_cores();
score += match cpu_cores {
cores if cores >= 16 => 30,
cores if cores >= 8 => 25,
cores if cores >= 4 => 20,
_ => 10,
};
let memory_gb = hw_info.memory().total_gb();
score += match memory_gb {
mem if mem >= 32.0 => 25,
mem if mem >= 16.0 => 20,
mem if mem >= 8.0 => 15,
_ => 5,
};
if !hw_info.gpus().is_empty() {
let gpu = &hw_info.gpus()[0];
let vram = gpu.memory_gb();
score += match vram {
vram if vram >= 12.0 => 30,
vram if vram >= 8.0 => 25,
vram if vram >= 4.0 => 20,
_ => 10,
};
}
let storage_devices = hw_info.storage_devices();
if !storage_devices.is_empty() {
let storage_type = storage_devices[0].drive_type().to_string().to_lowercase();
score += if storage_type.contains("nvme") {
15
} else if storage_type.contains("ssd") {
12
} else {
5
};
}
let virt_factor = hw_info.virtualization().get_performance_factor();
score = ((score as f64) * virt_factor) as u8;
score.min(100)
}
}
impl std::fmt::Display for HealthStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
HealthStatus::Excellent => write!(f, "Excellent"),
HealthStatus::Good => write!(f, "Good"),
HealthStatus::Fair => write!(f, "Fair"),
HealthStatus::Poor => write!(f, "Poor"),
HealthStatus::Critical => write!(f, "Critical"),
}
}
}
impl std::fmt::Display for TemperatureStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TemperatureStatus::Normal => write!(f, "Normal"),
TemperatureStatus::Warm => write!(f, "Warm"),
TemperatureStatus::Hot => write!(f, "Hot"),
TemperatureStatus::Critical => write!(f, "Critical"),
}
}
}
impl std::fmt::Display for PowerStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PowerStatus::Low => write!(f, "Low"),
PowerStatus::Normal => write!(f, "Normal"),
PowerStatus::High => write!(f, "High"),
PowerStatus::VeryHigh => write!(f, "Very High"),
}
}
}