diff --git a/docs/TOOL-BESZEL-OPENWEBUI.md b/docs/TOOL-BESZEL-OPENWEBUI.md index 33dae76..85963a0 100644 --- a/docs/TOOL-BESZEL-OPENWEBUI.md +++ b/docs/TOOL-BESZEL-OPENWEBUI.md @@ -28,7 +28,7 @@ class Tools: ) beszel_user: str = Field( default="admin", - description="Beszel username", + description="Beszel username (email)", ) beszel_password: str = Field( default="", @@ -41,12 +41,16 @@ class Tools: def _login(self): try: response = requests.post( - f"{self.valves.beszel_url}/api/auth/login", - json={"identity": self.valves.beszel_user, "password": self.valves.beszel_password}, + f"{self.valves.beszel_url}/api/collections/users/auth-with-password", + json={ + "identity": self.valves.beszel_user, + "password": self.valves.beszel_password + }, timeout=10 ) if response.status_code == 200: - return response.json().get("token") + data = response.json() + return data.get("token") return None except Exception: return None @@ -56,10 +60,18 @@ class Tools: if not token: return None try: - headers = {"Authorization": f"Bearer {token}"} - response = requests.get(f"{self.valves.beszel_url}/api/systems", headers=headers, timeout=10) + headers = { + "Authorization": f"{token}", + "Content-Type": "application/json" + } + response = requests.get( + f"{self.valves.beszel_url}/api/collections/systems/records", + headers=headers, + timeout=10 + ) if response.status_code == 200: - return response.json().get("items", []) + data = response.json() + return data.get("items", []) return None except Exception: return None @@ -69,9 +81,12 @@ class Tools: if not token: return None try: - headers = {"Authorization": f"Bearer {token}"} + headers = { + "Authorization": f"{token}", + "Content-Type": "application/json" + } response = requests.get( - f"{self.valves.beszel_url}/api/systems/{system_id}/stats", + f"{self.valves.beszel_url}/api/collections/systems/records/{system_id}", headers=headers, timeout=10 ) @@ -91,27 +106,33 @@ class Tools: lines.append(f"Swap: {stats.get('swap', 0):.1f}%") if 'disk' in stats: - for disk, info in stats['disk'].items(): - lines.append(f"Disque {disk}: {info.get('used_percent', 0):.1f}%") + disk_data = stats.get('disk', {}) + if isinstance(disk_data, dict): + for disk, info in disk_data.items(): + lines.append(f"Disque {disk}: {info.get('used_percent', 0):.1f}%") if 'load' in stats: - load = stats['load'] - lines.append(f"Load: {load[0]:.2f} {load[1]:.2f} {load[2]:.2f}") + load = stats.get('load', []) + if len(load) >= 3: + lines.append(f"Load: {load[0]:.2f} {load[1]:.2f} {load[2]:.2f}") if 'gpu' in stats and stats['gpu']: lines.append("") lines.append("GPU:") - for gpu_name, gpu_data in stats['gpu'].items(): - vram_used = gpu_data.get('memory_used', 0) / (1024**3) - vram_total = gpu_data.get('memory_total', 0) / (1024**3) - vram_pct = (gpu_data.get('memory_used', 0) / gpu_data.get('memory_total', 1)) * 100 - lines.append(f" {gpu_name}:") - lines.append(f" VRAM: {vram_used:.2f}GB / {vram_total:.2f}GB ({vram_pct:.1f}%)") - lines.append(f" Utilisation GPU: {gpu_data.get('utilization_gpu', 0)}%") - if 'temperature' in gpu_data: - lines.append(f" Température: {gpu_data.get('temperature', 0)}°C") - if 'power_draw' in gpu_data: - lines.append(f" Consommation: {gpu_data.get('power_draw', 0)}W") + gpu_data = stats.get('gpu', {}) + if isinstance(gpu_data, dict): + for gpu_name, gpu_info in gpu_data.items(): + if isinstance(gpu_info, dict): + vram_used = gpu_info.get('memory_used', 0) / (1024**3) + vram_total = gpu_info.get('memory_total', 0) / (1024**3) + vram_pct = (gpu_info.get('memory_used', 0) / max(gpu_info.get('memory_total', 1), 1)) * 100 + lines.append(f" {gpu_name}:") + lines.append(f" VRAM: {vram_used:.2f}GB / {vram_total:.2f}GB ({vram_pct:.1f}%)") + lines.append(f" Utilisation GPU: {gpu_info.get('utilization_gpu', 0)}%") + if 'temperature' in gpu_info: + lines.append(f" Température: {gpu_info.get('temperature', 0)}°C") + if 'power_draw' in gpu_info: + lines.append(f" Consommation: {gpu_info.get('power_draw', 0)}W") if 'containers' in stats and stats['containers']: lines.append("") @@ -139,23 +160,25 @@ class Tools: alerts.append(f"⚠️ Memory elevated: {memory:.1f}%") if 'gpu' in stats and stats['gpu']: - for gpu_name, gpu_data in stats['gpu'].items(): - vram_pct = (gpu_data.get('memory_used', 0) / gpu_data.get('memory_total', 1)) * 100 - if vram_pct > thresholds['vram']: - alerts.append(f"⚠️ VRAM {gpu_name} elevated: {vram_pct:.1f}%") - - util = gpu_data.get('utilization_gpu', 0) - if util > thresholds['vram']: - alerts.append(f"⚠️ GPU {gpu_name} utilization elevated: {util}%") + gpu_data = stats.get('gpu', {}) + if isinstance(gpu_data, dict): + for gpu_name, gpu_info in gpu_data.items(): + if isinstance(gpu_info, dict): + vram_pct = (gpu_info.get('memory_used', 0) / max(gpu_info.get('memory_total', 1), 1)) * 100 + if vram_pct > thresholds['vram']: + alerts.append(f"⚠️ VRAM {gpu_name} elevated: {vram_pct:.1f}%") + + util = gpu_info.get('utilization_gpu', 0) + if util > thresholds['vram']: + alerts.append(f"⚠️ GPU {gpu_name} utilization elevated: {util}%") return alerts def get_all_stats(self): - """Get stats from all monitored systems.""" systems = self._get_systems() if not systems: - return "[ERROR] Cannot connect to Beszel or no systems found" + return "[ERROR] Cannot connect to Beszel. Check URL, username and password." results = [] for sys_info in systems: @@ -171,11 +194,10 @@ class Tools: return "\n\n".join(results) def get_system_stats(self, system_name: str): - """Get stats for a specific system. Options: folzocorp, effiserver, synology-nas""" systems = self._get_systems() if not systems: - return "[ERROR] Cannot connect to Beszel" + return "[ERROR] Cannot connect to Beszel. Check URL, username and password." system_map = { 'folzocorp': 'folzocorp', @@ -184,20 +206,21 @@ class Tools: 'nas': 'synology-nas' } - target_id = system_map.get(system_name.lower(), system_name.lower()) + target_name = system_map.get(system_name.lower(), system_name.lower()) for sys_info in systems: - if sys_info.get('id') == target_id or sys_info.get('name', '').lower() == system_name.lower(): - stats = self._get_system_stats(sys_info.get('id')) + sys_id = sys_info.get('id') + sys_nm = sys_info.get('name', '') + if sys_nm.lower() == target_name or sys_id == target_name: + stats = self._get_system_stats(sys_id) if stats: - return self._format_stats_text(stats, sys_info.get('name', system_name)) + return self._format_stats_text(stats, sys_nm or system_name) return f"[ERROR] Cannot get stats for {system_name}" available = [s.get('name', s.get('id')) for s in systems] return f"[ERROR] System '{system_name}' not found. Available: {', '.join(available)}" def check_alerts(self, system_name: str = "all"): - """Check for resource alerts. Use 'all' or specific system name.""" systems = self._get_systems() if not systems: @@ -225,48 +248,47 @@ class Tools: return "\n".join(alerts) def get_gpu_status(self, system_name: str = "folzocorp"): - """Get GPU status for a specific system. Most useful for folzocorp (AMD RX 7800 XT).""" systems = self._get_systems() if not systems: return "[ERROR] Cannot connect to Beszel" - target_id = None + target_name = system_map.get(system_name.lower(), system_name.lower()) + for sys_info in systems: - if sys_info.get('id') == system_name.lower() or sys_info.get('name', '').lower() == system_name.lower(): - target_id = sys_info.get('id') - break + sys_id = sys_info.get('id') + sys_name = sys_info.get('name', '') + if sys_name.lower() == target_name or sys_id == target_name: + stats = self._get_system_stats(sys_id) + if stats: + if 'gpu' not in stats or not stats['gpu']: + return f"[INFO] No GPU data for {system_name}" + + lines = [f"=== GPU Status: {system_name} ==="] + gpu_data = stats.get('gpu', {}) + if isinstance(gpu_data, dict): + for gpu_name, gpu_info in gpu_data.items(): + if isinstance(gpu_info, dict): + vram_used = gpu_info.get('memory_used', 0) / (1024**3) + vram_total = gpu_info.get('memory_total', 0) / (1024**3) + vram_pct = (gpu_info.get('memory_used', 0) / max(gpu_info.get('memory_total', 1), 1)) * 100 + + lines.append(f"\n{gpu_name}:") + lines.append(f" VRAM: {vram_used:.2f}GB / {vram_total:.2f}GB ({vram_pct:.1f}%)") + lines.append(f" GPU Utilization: {gpu_info.get('utilization_gpu', 0)}%") + + if 'temperature' in gpu_info: + lines.append(f" Temperature: {gpu_info.get('temperature', 0)}°C") + if 'power_draw' in gpu_info: + lines.append(f" Power: {gpu_info.get('power_draw', 0)}W") + + return "\n".join(lines) + return f"[ERROR] Cannot get stats for {system_name}" - if not target_id: - available = [s.get('name', s.get('id')) for s in systems] - return f"[ERROR] System '{system_name}' not found. Available: {', '.join(available)}" - - stats = self._get_system_stats(target_id) - if not stats: - return f"[ERROR] Cannot get stats for {system_name}" - - if 'gpu' not in stats or not stats['gpu']: - return f"[INFO] No GPU data for {system_name}" - - lines = [f"=== GPU Status: {system_name} ==="] - for gpu_name, gpu_data in stats['gpu'].items(): - vram_used = gpu_data.get('memory_used', 0) / (1024**3) - vram_total = gpu_data.get('memory_total', 0) / (1024**3) - vram_pct = (gpu_data.get('memory_used', 0) / gpu_data.get('memory_total', 1)) * 100 - - lines.append(f"\n{gpu_name}:") - lines.append(f" VRAM: {vram_used:.2f}GB / {vram_total:.2f}GB ({vram_pct:.1f}%)") - lines.append(f" GPU Utilization: {gpu_data.get('utilization_gpu', 0)}%") - - if 'temperature' in gpu_data: - lines.append(f" Temperature: {gpu_data.get('temperature', 0)}°C") - if 'power_draw' in gpu_data: - lines.append(f" Power: {gpu_data.get('power_draw', 0)}W") - - return "\n".join(lines) + available = [s.get('name', s.get('id')) for s in systems] + return f"[ERROR] System '{system_name}' not found. Available: {', '.join(available)}" def can_run_comfyui(self): - """Check if there's enough RAM and VRAM to run ComfyUI.""" stats = self._get_system_stats("folzocorp") if not stats: return "[ERROR] Cannot get FolzoCorp stats" @@ -276,12 +298,15 @@ class Tools: vram_info = None vram_pct = 0 if 'gpu' in stats and stats['gpu']: - for gpu_name, gpu_data in stats['gpu'].items(): - vram_total = gpu_data.get('memory_total', 0) / (1024**3) - vram_free = gpu_data.get('memory_total', 0) - gpu_data.get('memory_used', 0) - vram_free_gb = vram_free / (1024**3) - vram_pct = (gpu_data.get('memory_used', 0) / gpu_data.get('memory_total', 1)) * 100 - vram_info = f"{gpu_name}: {vram_free_gb:.1f}GB free ({vram_pct:.1f}% used)" + gpu_data = stats.get('gpu', {}) + if isinstance(gpu_data, dict): + for gpu_name, gpu_info in gpu_data.items(): + if isinstance(gpu_info, dict): + vram_total = gpu_info.get('memory_total', 0) / (1024**3) + vram_free = gpu_info.get('memory_total', 0) - gpu_info.get('memory_used', 0) + vram_free_gb = vram_free / (1024**3) + vram_pct = (gpu_info.get('memory_used', 0) / max(gpu_info.get('memory_total', 1), 1)) * 100 + vram_info = f"{gpu_name}: {vram_free_gb:.1f}GB free ({vram_pct:.1f}% used)" can_run = memory_pct < 85 and vram_pct < 85 @@ -339,9 +364,9 @@ can_run_comfyui() | Variable | Description | |----------|-------------| | `beszel_url` | URL du hub Beszel (défaut: http://192.168.1.25:8090) | -| `beszel_user` | Username admin (défaut: admin) | -| `beszel_password` | Mot de passe admin | +| `beszel_user` | Email utilisateur Beszel | +| `beszel_password` | Mot de passe Beszel | --- -*Created 12 April 2026* +*Created 12 April 2026 - Updated API endpoints for PocketBase*