system_monitor.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. """
  2. System Monitor Module
  3. Monitors system status including:
  4. - Camera applications (running/disconnected)
  5. - AI model load state
  6. - GPU usage and information
  7. - RAM usage
  8. """
  9. import psutil
  10. import logging
  11. from typing import Dict, Optional, Any
  12. from utils.process_utils import check_camera_applications
  13. logger = logging.getLogger(__name__)
  14. def get_camera_status() -> Dict[str, Dict[str, Any]]:
  15. """
  16. Get status of all camera applications.
  17. Returns:
  18. Dict mapping camera app name to dict with 'running' status and spec info
  19. Example: {
  20. 'EOS Utility': {'running': True, 'spec': '1920x1080 @ 30fps'},
  21. '2nd Look': {'running': False, 'spec': 'DISCONNECTED'},
  22. 'AnalyzIR': {'running': True, 'spec': 'Thermal @ 60fps'}
  23. }
  24. """
  25. try:
  26. # Check which apps are running
  27. app_status = check_camera_applications()
  28. print(f"[system_monitor] check_camera_applications returned: {app_status}")
  29. logger.info(f"Camera app status: {app_status}")
  30. # Define specs for each camera app
  31. camera_specs = {
  32. 'EOS Utility': '1920x1080 @ 30fps',
  33. '2nd Look': '8-band Near Infrared Multispectral Camera',
  34. 'AnalyzIR': 'FOTRIC 323F 264*198 Thermal Imaging Camera'
  35. }
  36. audio_spec = '44.1kHz, 16-bit'
  37. result = {}
  38. # Build status dict for each camera app
  39. for app_name, running in app_status.items():
  40. spec = camera_specs.get(app_name, 'Unknown')
  41. result[app_name] = {
  42. 'running': running,
  43. 'spec': spec if running else 'DISCONNECTED'
  44. }
  45. # Note: Audio system is checked via EOS Utility presence
  46. # Audio is considered connected if EOS Utility is running
  47. result['Audio System'] = {
  48. 'running': app_status.get('EOS Utility', False),
  49. 'spec': audio_spec if app_status.get('EOS Utility', False) else 'DISCONNECTED'
  50. }
  51. print(f"[system_monitor] Returning camera status: {result}")
  52. return result
  53. except Exception as e:
  54. print(f"[system_monitor] ERROR in get_camera_status: {e}")
  55. logger.error(f"Error getting camera status: {e}", exc_info=True)
  56. return {}
  57. def get_model_load_status(models: Optional[Dict[str, Any]] = None) -> Dict[str, Dict[str, str]]:
  58. """
  59. Get load status of all AI models.
  60. Args:
  61. models: Dictionary of model instances from main_window
  62. If None, returns all models as 'Not Available'
  63. Returns:
  64. Dict mapping model name to dict with 'status' and 'info'
  65. Example: {
  66. 'Ripeness': {'status': 'online', 'info': 'Loaded'},
  67. 'Quality': {'status': 'offline', 'info': 'Failed'},
  68. 'Defect': {'status': 'online', 'info': 'Loaded'},
  69. 'Maturity': {'status': 'online', 'info': 'Loaded'},
  70. 'Shape': {'status': 'offline', 'info': 'Not Loaded'}
  71. }
  72. """
  73. try:
  74. model_names = {
  75. 'audio': 'Ripeness',
  76. 'defect': 'Quality',
  77. 'locule': 'Defect',
  78. 'maturity': 'Maturity',
  79. 'shape': 'Shape'
  80. }
  81. result = {}
  82. for model_key, display_name in model_names.items():
  83. if not models or models.get(model_key) is None:
  84. result[display_name] = {
  85. 'status': 'offline',
  86. 'info': 'Not Loaded'
  87. }
  88. elif hasattr(models[model_key], 'is_loaded') and models[model_key].is_loaded:
  89. result[display_name] = {
  90. 'status': 'online',
  91. 'info': 'Loaded'
  92. }
  93. else:
  94. result[display_name] = {
  95. 'status': 'offline',
  96. 'info': 'Failed'
  97. }
  98. return result
  99. except Exception as e:
  100. logger.error(f"Error getting model load status: {e}", exc_info=True)
  101. return {}
  102. def get_gpu_info() -> Dict[str, Any]:
  103. """
  104. Get GPU information and usage.
  105. Returns:
  106. Dict with GPU info:
  107. {
  108. 'available': True/False,
  109. 'name': 'NVIDIA RTX 3080',
  110. 'usage_percent': 45.2,
  111. 'vram_used_gb': 6.2,
  112. 'vram_total_gb': 12.0,
  113. 'display': 'NVIDIA RTX 3080 | Usage: 45% (6.2GB/12GB)'
  114. }
  115. """
  116. try:
  117. import torch
  118. if not torch.cuda.is_available():
  119. return {
  120. 'available': False,
  121. 'name': 'Not Available',
  122. 'usage_percent': 0,
  123. 'vram_used_gb': 0,
  124. 'vram_total_gb': 0,
  125. 'display': 'GPU: Not Available (Using CPU)'
  126. }
  127. # Get GPU name
  128. gpu_name = torch.cuda.get_device_name(0)
  129. # Get VRAM info
  130. total_vram = torch.cuda.get_device_properties(0).total_memory / (1024**3) # Convert to GB
  131. reserved_vram = torch.cuda.memory_reserved(0) / (1024**3)
  132. allocated_vram = torch.cuda.memory_allocated(0) / (1024**3)
  133. used_vram = max(reserved_vram, allocated_vram)
  134. # Calculate percentage
  135. vram_percent = (used_vram / total_vram * 100) if total_vram > 0 else 0
  136. display_str = f"GPU: {gpu_name} | Usage: {vram_percent:.0f}% ({used_vram:.1f}GB/{total_vram:.1f}GB)"
  137. return {
  138. 'available': True,
  139. 'name': gpu_name,
  140. 'usage_percent': vram_percent,
  141. 'vram_used_gb': used_vram,
  142. 'vram_total_gb': total_vram,
  143. 'display': display_str
  144. }
  145. except Exception as e:
  146. print(f"Error getting GPU info: {e}")
  147. return {
  148. 'available': False,
  149. 'name': 'Error',
  150. 'usage_percent': 0,
  151. 'vram_used_gb': 0,
  152. 'vram_total_gb': 0,
  153. 'display': 'GPU: Error retrieving info'
  154. }
  155. def get_ram_info() -> Dict[str, Any]:
  156. """
  157. Get system RAM usage information.
  158. Returns:
  159. Dict with RAM info:
  160. {
  161. 'usage_percent': 62.5,
  162. 'used_gb': 8.0,
  163. 'total_gb': 16.0,
  164. 'display': 'RAM: 62% (8.0GB/16.0GB)'
  165. }
  166. """
  167. try:
  168. virtual_memory = psutil.virtual_memory()
  169. usage_percent = virtual_memory.percent
  170. used_gb = virtual_memory.used / (1024**3) # Convert bytes to GB
  171. total_gb = virtual_memory.total / (1024**3)
  172. display_str = f"RAM: {usage_percent:.0f}% ({used_gb:.1f}GB/{total_gb:.1f}GB)"
  173. return {
  174. 'usage_percent': usage_percent,
  175. 'used_gb': used_gb,
  176. 'total_gb': total_gb,
  177. 'display': display_str
  178. }
  179. except Exception as e:
  180. print(f"Error getting RAM info: {e}")
  181. return {
  182. 'usage_percent': 0,
  183. 'used_gb': 0,
  184. 'total_gb': 0,
  185. 'display': 'RAM: Error retrieving info'
  186. }
  187. def get_full_system_status(models: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
  188. """
  189. Get complete system status snapshot.
  190. Args:
  191. models: Dictionary of model instances from main_window
  192. Returns:
  193. Dict with all system status information
  194. """
  195. return {
  196. 'cameras': get_camera_status(),
  197. 'models': get_model_load_status(models),
  198. 'gpu': get_gpu_info(),
  199. 'ram': get_ram_info()
  200. }