1use crate::{HardwareInfo, Result};
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct SystemOverview {
13 pub cpu: SimpleCPU,
15 pub memory_gb: f64,
17 pub gpu: Option<SimpleGPU>,
19 pub storage: SimpleStorage,
21 pub health: SystemHealth,
23 pub environment: String,
25 pub performance_score: u8,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct SimpleCPU {
32 pub name: String,
34 pub cores: u32,
36 pub threads: u32,
38 pub vendor: String,
40 pub ai_capable: bool,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct SimpleGPU {
47 pub name: String,
49 pub vram_gb: f64,
51 pub vendor: String,
53 pub ai_capable: bool,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct SimpleStorage {
60 pub total_gb: f64,
62 pub available_gb: f64,
64 pub drive_type: String,
66 pub health: String,
68}
69
70#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct SystemHealth {
73 pub status: HealthStatus,
75 pub temperature: TemperatureStatus,
77 pub power: PowerStatus,
79 pub warnings: Vec<String>,
81}
82
83#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
85pub enum HealthStatus {
86 Excellent,
88 Good,
90 Fair,
92 Poor,
94 Critical,
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
100pub enum TemperatureStatus {
101 Normal,
103 Warm,
105 Hot,
107 Critical,
109}
110
111#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
113pub enum PowerStatus {
114 Low,
116 Normal,
118 High,
120 VeryHigh,
122}
123
124impl SystemOverview {
126 pub fn quick() -> Result<Self> {
128 let hw_info = HardwareInfo::query()?;
129 Self::from_hardware_info(hw_info)
130 }
131
132 pub fn from_hardware_info(hw_info: HardwareInfo) -> Result<Self> {
134 let cpu = SimpleCPU {
135 name: hw_info.cpu().model_name().to_string(),
136 cores: hw_info.cpu().physical_cores(),
137 threads: hw_info.cpu().logical_cores(),
138 vendor: hw_info.cpu().vendor().to_string(),
139 ai_capable: Self::check_cpu_ai_capabilities(&hw_info),
140 };
141
142 let memory_gb = hw_info.memory().total_gb();
143
144 let gpu = if !hw_info.gpus().is_empty() {
145 let primary_gpu = &hw_info.gpus()[0];
146 Some(SimpleGPU {
147 name: primary_gpu.model_name().to_string(),
148 vram_gb: primary_gpu.memory_gb(),
149 vendor: primary_gpu.vendor().to_string(),
150 ai_capable: Self::check_gpu_ai_capabilities(primary_gpu),
151 })
152 } else {
153 None
154 };
155
156 let storage = Self::calculate_storage_summary(&hw_info)?;
157 let health = Self::assess_system_health(&hw_info)?;
158 let environment = hw_info.virtualization().environment_type.to_string();
159 let performance_score = Self::calculate_performance_score(&hw_info);
160
161 Ok(Self {
162 cpu,
163 memory_gb,
164 gpu,
165 storage,
166 health,
167 environment,
168 performance_score,
169 })
170 }
171
172 pub fn is_ai_ready(&self) -> bool {
174 self.cpu.ai_capable ||
176 self.gpu.as_ref().map_or(false, |gpu| gpu.ai_capable) ||
177 self.memory_gb >= 8.0
178 }
179
180 pub fn ai_score(&self) -> u8 {
182 let mut score = 0;
183
184 if let Some(gpu) = &self.gpu {
186 if gpu.ai_capable {
187 score += 30;
188 if gpu.vram_gb >= 8.0 {
189 score += 15;
190 } else if gpu.vram_gb >= 4.0 {
191 score += 10;
192 } else {
193 score += 5;
194 }
195 }
196 }
197
198 if self.cpu.ai_capable {
200 score += 15;
201 }
202 if self.cpu.cores >= 8 {
203 score += 10;
204 } else if self.cpu.cores >= 4 {
205 score += 5;
206 }
207
208 if self.memory_gb >= 32.0 {
210 score += 25;
211 } else if self.memory_gb >= 16.0 {
212 score += 20;
213 } else if self.memory_gb >= 8.0 {
214 score += 15;
215 } else {
216 score += 5;
217 }
218
219 score.min(100)
220 }
221
222 pub fn get_recommendations(&self) -> Vec<String> {
224 let mut recommendations = Vec::new();
225
226 if self.memory_gb < 16.0 {
228 recommendations.push("Consider upgrading to 16GB+ RAM for better performance".to_string());
229 }
230
231 if self.gpu.is_none() {
233 recommendations.push("Add a dedicated GPU for AI/ML acceleration".to_string());
234 } else if let Some(gpu) = &self.gpu {
235 if gpu.vram_gb < 4.0 {
236 recommendations.push("Consider a GPU with more VRAM for large AI models".to_string());
237 }
238 }
239
240 if self.storage.drive_type.to_lowercase().contains("hdd") {
242 recommendations.push("Upgrade to SSD for faster data access".to_string());
243 }
244
245 for warning in &self.health.warnings {
247 recommendations.push(warning.clone());
248 }
249
250 recommendations
251 }
252
253 fn check_cpu_ai_capabilities(hw_info: &HardwareInfo) -> bool {
254 let cpu = hw_info.cpu();
255 cpu.has_feature("avx2") ||
257 cpu.has_feature("avx512") ||
258 cpu.has_feature("amx") ||
259 !hw_info.npus().is_empty()
260 }
261
262 fn check_gpu_ai_capabilities(gpu: &crate::GPUInfo) -> bool {
263 let vendor = gpu.vendor().to_string().to_lowercase();
265 let name = gpu.model_name().to_lowercase();
266
267 if vendor.contains("nvidia") {
269 return true;
270 }
271
272 if vendor.contains("amd") && (name.contains("rx") || name.contains("radeon")) {
274 return true;
275 }
276
277 if vendor.contains("intel") && name.contains("arc") {
279 return true;
280 }
281
282 false
283 }
284
285 fn calculate_storage_summary(hw_info: &HardwareInfo) -> Result<SimpleStorage> {
286 let storage_devices = hw_info.storage_devices();
287
288 if storage_devices.is_empty() {
289 return Ok(SimpleStorage {
290 total_gb: 0.0,
291 available_gb: 0.0,
292 drive_type: "Unknown".to_string(),
293 health: "Unknown".to_string(),
294 });
295 }
296
297 let total_gb: f64 = storage_devices.iter()
298 .map(|device| device.capacity_gb())
299 .sum();
300
301 let available_gb: f64 = storage_devices.iter()
302 .map(|device| device.available_gb())
303 .sum();
304
305 let drive_type = storage_devices[0].drive_type().to_string();
307
308 let health = if available_gb / total_gb < 0.1 {
310 "Critical - Low space".to_string()
311 } else if available_gb / total_gb < 0.2 {
312 "Warning - Low space".to_string()
313 } else {
314 "Good".to_string()
315 };
316
317 Ok(SimpleStorage {
318 total_gb,
319 available_gb,
320 drive_type,
321 health,
322 })
323 }
324
325 fn assess_system_health(hw_info: &HardwareInfo) -> Result<SystemHealth> {
326 let mut warnings = Vec::new();
327
328 let thermal = hw_info.thermal();
330 let temperature = if let Some(max_temp) = thermal.max_temperature() {
331 if max_temp >= 90.0 {
332 warnings.push("High CPU/GPU temperatures detected".to_string());
333 TemperatureStatus::Critical
334 } else if max_temp >= 80.0 {
335 warnings.push("Elevated temperatures detected".to_string());
336 TemperatureStatus::Hot
337 } else if max_temp >= 70.0 {
338 TemperatureStatus::Warm
339 } else {
340 TemperatureStatus::Normal
341 }
342 } else {
343 TemperatureStatus::Normal
344 };
345
346 let power = if let Some(power_profile) = hw_info.power_profile() {
348 if let Some(power_draw) = power_profile.total_power_draw {
349 if power_draw > 200.0 {
350 PowerStatus::VeryHigh
351 } else if power_draw > 100.0 {
352 PowerStatus::High
353 } else if power_draw > 50.0 {
354 PowerStatus::Normal
355 } else {
356 PowerStatus::Low
357 }
358 } else {
359 PowerStatus::Normal
360 }
361 } else {
362 PowerStatus::Normal
363 };
364
365 let status = match (&temperature, &power, warnings.len()) {
367 (TemperatureStatus::Critical, _, _) => HealthStatus::Critical,
368 (TemperatureStatus::Hot, PowerStatus::VeryHigh, _) => HealthStatus::Poor,
369 (TemperatureStatus::Hot, _, _) => HealthStatus::Fair,
370 (_, PowerStatus::VeryHigh, _) => HealthStatus::Fair,
371 (_, _, n) if n > 2 => HealthStatus::Poor,
372 (_, _, n) if n > 0 => HealthStatus::Fair,
373 (TemperatureStatus::Normal, PowerStatus::Normal | PowerStatus::Low, 0) => HealthStatus::Excellent,
374 _ => HealthStatus::Good,
375 };
376
377 Ok(SystemHealth {
378 status,
379 temperature,
380 power,
381 warnings,
382 })
383 }
384
385 fn calculate_performance_score(hw_info: &HardwareInfo) -> u8 {
386 let mut score = 0;
387
388 let cpu_cores = hw_info.cpu().logical_cores();
390 score += match cpu_cores {
391 cores if cores >= 16 => 30,
392 cores if cores >= 8 => 25,
393 cores if cores >= 4 => 20,
394 _ => 10,
395 };
396
397 let memory_gb = hw_info.memory().total_gb();
399 score += match memory_gb {
400 mem if mem >= 32.0 => 25,
401 mem if mem >= 16.0 => 20,
402 mem if mem >= 8.0 => 15,
403 _ => 5,
404 };
405
406 if !hw_info.gpus().is_empty() {
408 let gpu = &hw_info.gpus()[0];
409 let vram = gpu.memory_gb();
410 score += match vram {
411 vram if vram >= 12.0 => 30,
412 vram if vram >= 8.0 => 25,
413 vram if vram >= 4.0 => 20,
414 _ => 10,
415 };
416 }
417
418 let storage_devices = hw_info.storage_devices();
420 if !storage_devices.is_empty() {
421 let storage_type = storage_devices[0].drive_type().to_string().to_lowercase();
422 score += if storage_type.contains("nvme") {
423 15
424 } else if storage_type.contains("ssd") {
425 12
426 } else {
427 5
428 };
429 }
430
431 let virt_factor = hw_info.virtualization().get_performance_factor();
433 score = ((score as f64) * virt_factor) as u8;
434
435 score.min(100)
436 }
437}
438
439impl std::fmt::Display for HealthStatus {
441 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
442 match self {
443 HealthStatus::Excellent => write!(f, "Excellent"),
444 HealthStatus::Good => write!(f, "Good"),
445 HealthStatus::Fair => write!(f, "Fair"),
446 HealthStatus::Poor => write!(f, "Poor"),
447 HealthStatus::Critical => write!(f, "Critical"),
448 }
449 }
450}
451
452impl std::fmt::Display for TemperatureStatus {
453 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
454 match self {
455 TemperatureStatus::Normal => write!(f, "Normal"),
456 TemperatureStatus::Warm => write!(f, "Warm"),
457 TemperatureStatus::Hot => write!(f, "Hot"),
458 TemperatureStatus::Critical => write!(f, "Critical"),
459 }
460 }
461}
462
463impl std::fmt::Display for PowerStatus {
464 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
465 match self {
466 PowerStatus::Low => write!(f, "Low"),
467 PowerStatus::Normal => write!(f, "Normal"),
468 PowerStatus::High => write!(f, "High"),
469 PowerStatus::VeryHigh => write!(f, "Very High"),
470 }
471 }
472}