1use crate::{HardwareInfo, Result};
23use serde::{Deserialize, Serialize};
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct SystemOverview {
28 pub cpu: SimpleCPU,
30 pub memory_gb: f64,
32 pub gpu: Option<SimpleGPU>,
34 pub storage: SimpleStorage,
36 pub health: SystemHealth,
38 pub environment: String,
40 pub performance_score: u8,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct SimpleCPU {
47 pub name: String,
49 pub cores: u32,
51 pub threads: u32,
53 pub vendor: String,
55 pub ai_capable: bool,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct SimpleGPU {
62 pub name: String,
64 pub vram_gb: f64,
66 pub vendor: String,
68 pub ai_capable: bool,
70}
71
72#[derive(Debug, Clone, Serialize, Deserialize)]
74pub struct SimpleStorage {
75 pub total_gb: f64,
77 pub available_gb: f64,
79 pub drive_type: String,
81 pub health: String,
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct SystemHealth {
88 pub status: HealthStatus,
90 pub temperature: TemperatureStatus,
92 pub power: PowerStatus,
94 pub warnings: Vec<String>,
96}
97
98#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
100pub enum HealthStatus {
101 Excellent,
103 Good,
105 Fair,
107 Poor,
109 Critical,
111}
112
113#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
115pub enum TemperatureStatus {
116 Normal,
118 Warm,
120 Hot,
122 Critical,
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
128pub enum PowerStatus {
129 Low,
131 Normal,
133 High,
135 VeryHigh,
137}
138
139impl SystemOverview {
141 pub fn quick() -> Result<Self> {
175 let hw_info = HardwareInfo::query()?;
176 Self::from_hardware_info(hw_info)
177 }
178
179 pub fn from_hardware_info(hw_info: HardwareInfo) -> Result<Self> {
181 let cpu = SimpleCPU {
182 name: hw_info.cpu().model_name().to_string(),
183 cores: hw_info.cpu().physical_cores(),
184 threads: hw_info.cpu().logical_cores(),
185 vendor: hw_info.cpu().vendor().to_string(),
186 ai_capable: Self::check_cpu_ai_capabilities(&hw_info),
187 };
188
189 let memory_gb = hw_info.memory().total_gb();
190
191 let gpu = if !hw_info.gpus().is_empty() {
192 let primary_gpu = &hw_info.gpus()[0];
193 Some(SimpleGPU {
194 name: primary_gpu.model_name().to_string(),
195 vram_gb: primary_gpu.memory_gb(),
196 vendor: primary_gpu.vendor().to_string(),
197 ai_capable: Self::check_gpu_ai_capabilities(primary_gpu),
198 })
199 } else {
200 None
201 };
202
203 let storage = Self::calculate_storage_summary(&hw_info)?;
204 let health = Self::assess_system_health(&hw_info)?;
205 let environment = hw_info.virtualization().environment_type.to_string();
206 let performance_score = Self::calculate_performance_score(&hw_info);
207
208 Ok(Self {
209 cpu,
210 memory_gb,
211 gpu,
212 storage,
213 health,
214 environment,
215 performance_score,
216 })
217 }
218
219 pub fn is_ai_ready(&self) -> bool {
221 self.cpu.ai_capable ||
223 self.gpu.as_ref().map_or(false, |gpu| gpu.ai_capable) ||
224 self.memory_gb >= 8.0
225 }
226
227 pub fn ai_score(&self) -> u8 {
229 let mut score = 0;
230
231 if let Some(gpu) = &self.gpu {
233 if gpu.ai_capable {
234 score += 30;
235 if gpu.vram_gb >= 8.0 {
236 score += 15;
237 } else if gpu.vram_gb >= 4.0 {
238 score += 10;
239 } else {
240 score += 5;
241 }
242 }
243 }
244
245 if self.cpu.ai_capable {
247 score += 15;
248 }
249 if self.cpu.cores >= 8 {
250 score += 10;
251 } else if self.cpu.cores >= 4 {
252 score += 5;
253 }
254
255 if self.memory_gb >= 32.0 {
257 score += 25;
258 } else if self.memory_gb >= 16.0 {
259 score += 20;
260 } else if self.memory_gb >= 8.0 {
261 score += 15;
262 } else {
263 score += 5;
264 }
265
266 score.min(100)
267 }
268
269 pub fn get_recommendations(&self) -> Vec<String> {
271 let mut recommendations = Vec::new();
272
273 if self.memory_gb < 16.0 {
275 recommendations.push("Consider upgrading to 16GB+ RAM for better performance".to_string());
276 }
277
278 if self.gpu.is_none() {
280 recommendations.push("Add a dedicated GPU for AI/ML acceleration".to_string());
281 } else if let Some(gpu) = &self.gpu {
282 if gpu.vram_gb < 4.0 {
283 recommendations.push("Consider a GPU with more VRAM for large AI models".to_string());
284 }
285 }
286
287 if self.storage.drive_type.to_lowercase().contains("hdd") {
289 recommendations.push("Upgrade to SSD for faster data access".to_string());
290 }
291
292 for warning in &self.health.warnings {
294 recommendations.push(warning.clone());
295 }
296
297 recommendations
298 }
299
300 fn check_cpu_ai_capabilities(hw_info: &HardwareInfo) -> bool {
301 let cpu = hw_info.cpu();
302 cpu.has_feature("avx2") ||
304 cpu.has_feature("avx512") ||
305 cpu.has_feature("amx") ||
306 !hw_info.npus().is_empty()
307 }
308
309 fn check_gpu_ai_capabilities(gpu: &crate::GPUInfo) -> bool {
310 let vendor = gpu.vendor().to_string().to_lowercase();
312 let name = gpu.model_name().to_lowercase();
313
314 if vendor.contains("nvidia") {
316 return true;
317 }
318
319 if vendor.contains("amd") && (name.contains("rx") || name.contains("radeon")) {
321 return true;
322 }
323
324 if vendor.contains("intel") && name.contains("arc") {
326 return true;
327 }
328
329 false
330 }
331
332 fn calculate_storage_summary(hw_info: &HardwareInfo) -> Result<SimpleStorage> {
333 let storage_devices = hw_info.storage_devices();
334
335 if storage_devices.is_empty() {
336 return Ok(SimpleStorage {
337 total_gb: 0.0,
338 available_gb: 0.0,
339 drive_type: "Unknown".to_string(),
340 health: "Unknown".to_string(),
341 });
342 }
343
344 let total_gb: f64 = storage_devices.iter()
345 .map(|device| device.capacity_gb())
346 .sum();
347
348 let available_gb: f64 = storage_devices.iter()
349 .map(|device| device.available_gb())
350 .sum();
351
352 let drive_type = storage_devices[0].drive_type().to_string();
354
355 let health = if available_gb / total_gb < 0.1 {
357 "Critical - Low space".to_string()
358 } else if available_gb / total_gb < 0.2 {
359 "Warning - Low space".to_string()
360 } else {
361 "Good".to_string()
362 };
363
364 Ok(SimpleStorage {
365 total_gb,
366 available_gb,
367 drive_type,
368 health,
369 })
370 }
371
372 fn assess_system_health(hw_info: &HardwareInfo) -> Result<SystemHealth> {
373 let mut warnings = Vec::new();
374
375 let thermal = hw_info.thermal();
377 let temperature = if let Some(max_temp) = thermal.max_temperature() {
378 if max_temp >= 90.0 {
379 warnings.push("High CPU/GPU temperatures detected".to_string());
380 TemperatureStatus::Critical
381 } else if max_temp >= 80.0 {
382 warnings.push("Elevated temperatures detected".to_string());
383 TemperatureStatus::Hot
384 } else if max_temp >= 70.0 {
385 TemperatureStatus::Warm
386 } else {
387 TemperatureStatus::Normal
388 }
389 } else {
390 TemperatureStatus::Normal
391 };
392
393 let power = if let Some(power_profile) = hw_info.power_profile() {
395 if let Some(power_draw) = power_profile.total_power_draw {
396 if power_draw > 200.0 {
397 PowerStatus::VeryHigh
398 } else if power_draw > 100.0 {
399 PowerStatus::High
400 } else if power_draw > 50.0 {
401 PowerStatus::Normal
402 } else {
403 PowerStatus::Low
404 }
405 } else {
406 PowerStatus::Normal
407 }
408 } else {
409 PowerStatus::Normal
410 };
411
412 let status = match (&temperature, &power, warnings.len()) {
414 (TemperatureStatus::Critical, _, _) => HealthStatus::Critical,
415 (TemperatureStatus::Hot, PowerStatus::VeryHigh, _) => HealthStatus::Poor,
416 (TemperatureStatus::Hot, _, _) => HealthStatus::Fair,
417 (_, PowerStatus::VeryHigh, _) => HealthStatus::Fair,
418 (_, _, n) if n > 2 => HealthStatus::Poor,
419 (_, _, n) if n > 0 => HealthStatus::Fair,
420 (TemperatureStatus::Normal, PowerStatus::Normal | PowerStatus::Low, 0) => HealthStatus::Excellent,
421 _ => HealthStatus::Good,
422 };
423
424 Ok(SystemHealth {
425 status,
426 temperature,
427 power,
428 warnings,
429 })
430 }
431
432 fn calculate_performance_score(hw_info: &HardwareInfo) -> u8 {
433 let mut score = 0;
434
435 let cpu_cores = hw_info.cpu().logical_cores();
437 score += match cpu_cores {
438 cores if cores >= 16 => 30,
439 cores if cores >= 8 => 25,
440 cores if cores >= 4 => 20,
441 _ => 10,
442 };
443
444 let memory_gb = hw_info.memory().total_gb();
446 score += match memory_gb {
447 mem if mem >= 32.0 => 25,
448 mem if mem >= 16.0 => 20,
449 mem if mem >= 8.0 => 15,
450 _ => 5,
451 };
452
453 if !hw_info.gpus().is_empty() {
455 let gpu = &hw_info.gpus()[0];
456 let vram = gpu.memory_gb();
457 score += match vram {
458 vram if vram >= 12.0 => 30,
459 vram if vram >= 8.0 => 25,
460 vram if vram >= 4.0 => 20,
461 _ => 10,
462 };
463 }
464
465 let storage_devices = hw_info.storage_devices();
467 if !storage_devices.is_empty() {
468 let storage_type = storage_devices[0].drive_type().to_string().to_lowercase();
469 score += if storage_type.contains("nvme") {
470 15
471 } else if storage_type.contains("ssd") {
472 12
473 } else {
474 5
475 };
476 }
477
478 let virt_factor = hw_info.virtualization().get_performance_factor();
480 score = ((score as f64) * virt_factor) as u8;
481
482 score.min(100)
483 }
484}
485
486impl std::fmt::Display for HealthStatus {
488 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
489 match self {
490 HealthStatus::Excellent => write!(f, "Excellent"),
491 HealthStatus::Good => write!(f, "Good"),
492 HealthStatus::Fair => write!(f, "Fair"),
493 HealthStatus::Poor => write!(f, "Poor"),
494 HealthStatus::Critical => write!(f, "Critical"),
495 }
496 }
497}
498
499impl std::fmt::Display for TemperatureStatus {
500 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
501 match self {
502 TemperatureStatus::Normal => write!(f, "Normal"),
503 TemperatureStatus::Warm => write!(f, "Warm"),
504 TemperatureStatus::Hot => write!(f, "Hot"),
505 TemperatureStatus::Critical => write!(f, "Critical"),
506 }
507 }
508}
509
510impl std::fmt::Display for PowerStatus {
511 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
512 match self {
513 PowerStatus::Low => write!(f, "Low"),
514 PowerStatus::Normal => write!(f, "Normal"),
515 PowerStatus::High => write!(f, "High"),
516 PowerStatus::VeryHigh => write!(f, "Very High"),
517 }
518 }
519}