@mytec: iter3.2.5 gpu polish start

This commit is contained in:
2026-02-03 12:33:52 +02:00
parent 20d19d09ae
commit a61753c642
10 changed files with 1125 additions and 2 deletions

498
install_rfcp.py Normal file
View File

@@ -0,0 +1,498 @@
#!/usr/bin/env python3
"""
RFCP Installer — Detects hardware, installs dependencies, sets up GPU acceleration.
Usage:
python install_rfcp.py
The installer handles:
- Python dependency installation
- GPU detection (NVIDIA/Intel/AMD)
- GPU acceleration setup (CuPy for CUDA, PyOpenCL for Intel/AMD)
- Frontend build (if Node.js available)
- Verification of installation
"""
import subprocess
import sys
import platform
import os
import shutil
def print_header(text: str):
"""Print section header."""
print(f"\n{'=' * 60}")
print(f" {text}")
print('=' * 60)
def print_step(text: str):
"""Print step indicator."""
print(f"\n>>> {text}")
def check_python() -> bool:
"""Verify Python 3.10+ is available."""
version = sys.version_info
if version.major < 3 or version.minor < 10:
print(f"[X] Python 3.10+ required, found {version.major}.{version.minor}")
return False
print(f"[OK] Python {version.major}.{version.minor}.{version.micro}")
return True
def check_node() -> bool:
"""Verify Node.js 18+ is available."""
try:
result = subprocess.run(
["node", "--version"],
capture_output=True,
text=True,
timeout=10
)
version = result.stdout.strip().lstrip('v')
major = int(version.split('.')[0])
if major < 18:
print(f"[!] Node.js 18+ recommended, found {version}")
return False
print(f"[OK] Node.js {version}")
return True
except FileNotFoundError:
print("[!] Node.js not found (frontend build will be skipped)")
return False
except Exception as e:
print(f"[!] Node.js check failed: {e}")
return False
def detect_gpu() -> dict:
"""Detect available GPU hardware."""
gpus = {
"nvidia": False,
"nvidia_name": "",
"nvidia_memory_mb": 0,
"intel": False,
"intel_name": "",
"amd": False,
"amd_name": ""
}
# Check NVIDIA via nvidia-smi
try:
result = subprocess.run(
["nvidia-smi", "--query-gpu=name,driver_version,memory.total",
"--format=csv,noheader"],
capture_output=True,
text=True,
timeout=10
)
if result.returncode == 0 and result.stdout.strip():
info = result.stdout.strip()
parts = info.split(",")
gpus["nvidia"] = True
gpus["nvidia_name"] = parts[0].strip()
if len(parts) >= 3:
mem_str = parts[2].strip().replace(" MiB", "").replace(" MB", "")
try:
gpus["nvidia_memory_mb"] = int(mem_str)
except ValueError:
pass
print(f"[OK] NVIDIA GPU: {gpus['nvidia_name']}")
except FileNotFoundError:
pass
except subprocess.TimeoutExpired:
print("[!] nvidia-smi timed out")
except Exception as e:
print(f"[!] NVIDIA detection error: {e}")
# Check Intel/AMD via WMI (Windows) or lspci (Linux)
if platform.system() == "Windows":
try:
result = subprocess.run(
["wmic", "path", "win32_videocontroller", "get",
"name", "/format:csv"],
capture_output=True,
text=True,
timeout=10
)
for line in result.stdout.strip().split('\n'):
line_lower = line.lower()
if 'intel' in line_lower and ('uhd' in line_lower or 'iris' in line_lower or 'hd graphics' in line_lower):
gpus["intel"] = True
# Extract name from CSV
parts = line.split(',')
for part in parts:
if 'Intel' in part:
gpus["intel_name"] = part.strip()
break
if gpus["intel_name"]:
print(f"[OK] Intel GPU: {gpus['intel_name']}")
elif 'amd' in line_lower or 'radeon' in line_lower:
gpus["amd"] = True
parts = line.split(',')
for part in parts:
if 'AMD' in part or 'Radeon' in part:
gpus["amd_name"] = part.strip()
break
if gpus["amd_name"]:
print(f"[OK] AMD GPU: {gpus['amd_name']}")
except Exception:
pass
else:
# Linux: use lspci
try:
result = subprocess.run(
["lspci"],
capture_output=True,
text=True,
timeout=10
)
for line in result.stdout.split('\n'):
if 'VGA' in line or 'Display' in line or '3D' in line:
if 'Intel' in line:
gpus["intel"] = True
gpus["intel_name"] = line.split(':')[-1].strip() if ':' in line else "Intel GPU"
print(f"[OK] Intel GPU: {gpus['intel_name']}")
elif 'AMD' in line or 'Radeon' in line:
gpus["amd"] = True
gpus["amd_name"] = line.split(':')[-1].strip() if ':' in line else "AMD GPU"
print(f"[OK] AMD GPU: {gpus['amd_name']}")
except Exception:
pass
if not gpus["nvidia"] and not gpus["intel"] and not gpus["amd"]:
print("[i] No GPU detected - will use CPU (NumPy)")
return gpus
def install_core_dependencies() -> bool:
"""Install core Python dependencies."""
print_step("Installing core dependencies...")
req_file = os.path.join(os.path.dirname(__file__), "backend", "requirements.txt")
if not os.path.exists(req_file):
print(f"[X] requirements.txt not found at {req_file}")
return False
try:
subprocess.run(
[sys.executable, "-m", "pip", "install", "-r", req_file,
"--quiet", "--no-warn-script-location"],
check=True,
timeout=600
)
print("[OK] Core dependencies installed")
return True
except subprocess.CalledProcessError as e:
print(f"[X] pip install failed: {e}")
return False
except subprocess.TimeoutExpired:
print("[X] pip install timed out (10 min)")
return False
def install_gpu_dependencies(gpus: dict) -> bool:
"""Install GPU-specific dependencies based on detected hardware."""
print_step("Setting up GPU acceleration...")
gpu_installed = False
# NVIDIA - install CuPy (includes CUDA runtime)
if gpus["nvidia"]:
print(f" Installing CuPy for {gpus['nvidia_name']}...")
try:
# Try CUDA 12 first (newer cards, RTX 30xx/40xx)
subprocess.run(
[sys.executable, "-m", "pip", "install", "cupy-cuda12x",
"--quiet", "--no-warn-script-location"],
check=True,
timeout=600
)
print(f" [OK] CuPy (CUDA 12) installed")
gpu_installed = True
except (subprocess.CalledProcessError, subprocess.TimeoutExpired):
try:
# Fallback to CUDA 11 (older cards)
print(" [!] CUDA 12 failed, trying CUDA 11...")
subprocess.run(
[sys.executable, "-m", "pip", "install", "cupy-cuda11x",
"--quiet", "--no-warn-script-location"],
check=True,
timeout=600
)
print(f" [OK] CuPy (CUDA 11) installed")
gpu_installed = True
except Exception as e:
print(f" [X] CuPy installation failed: {e}")
print(f" Manual install: pip install cupy-cuda12x")
# Intel/AMD - install PyOpenCL
if gpus["intel"] or gpus["amd"]:
gpu_name = gpus["intel_name"] or gpus["amd_name"]
print(f" Installing PyOpenCL for {gpu_name}...")
try:
subprocess.run(
[sys.executable, "-m", "pip", "install", "pyopencl",
"--quiet", "--no-warn-script-location"],
check=True,
timeout=300
)
print(f" [OK] PyOpenCL installed")
gpu_installed = True
except Exception as e:
print(f" [X] PyOpenCL installation failed: {e}")
print(f" Manual install: pip install pyopencl")
if not gpu_installed and not gpus["nvidia"] and not gpus["intel"] and not gpus["amd"]:
print(" [i] No GPU acceleration - using CPU (NumPy)")
print(" This is fine! GPU just makes large calculations faster.")
return gpu_installed
def install_frontend(has_node: bool) -> bool:
"""Install frontend dependencies and build."""
if not has_node:
print_step("Skipping frontend build (Node.js not available)")
return False
print_step("Setting up frontend...")
frontend_dir = os.path.join(os.path.dirname(__file__), "frontend")
if not os.path.exists(os.path.join(frontend_dir, "package.json")):
print("[!] Frontend directory not found")
return False
try:
print(" Installing npm packages...")
subprocess.run(
["npm", "install"],
cwd=frontend_dir,
check=True,
timeout=300,
capture_output=True
)
print(" Building frontend...")
subprocess.run(
["npm", "run", "build"],
cwd=frontend_dir,
check=True,
timeout=300,
capture_output=True
)
print("[OK] Frontend built")
return True
except subprocess.CalledProcessError as e:
print(f"[X] Frontend build failed: {e}")
return False
except subprocess.TimeoutExpired:
print("[X] Frontend build timed out")
return False
def create_launcher() -> bool:
"""Create launcher scripts."""
print_step("Creating launcher scripts...")
base_dir = os.path.dirname(os.path.abspath(__file__))
if platform.system() == "Windows":
# Create RFCP.bat
launcher_path = os.path.join(base_dir, "RFCP.bat")
with open(launcher_path, 'w') as f:
f.write('@echo off\n')
f.write('title RFCP - RF Coverage Planner\n')
f.write(f'cd /d "{base_dir}"\n')
f.write('echo Starting RFCP...\n')
f.write('echo Open http://localhost:8090 in your browser\n')
f.write('echo Press Ctrl+C to stop\n')
f.write('echo.\n')
f.write(f'cd backend\n')
f.write(f'"{sys.executable}" -m uvicorn app.main:app --host 0.0.0.0 --port 8090\n')
print(f" [OK] Created: RFCP.bat")
# Create install.bat for first-time setup
install_bat_path = os.path.join(base_dir, "install.bat")
with open(install_bat_path, 'w') as f:
f.write('@echo off\n')
f.write('title RFCP - First Time Setup\n')
f.write('echo ============================================\n')
f.write('echo RFCP - RF Coverage Planner - Setup\n')
f.write('echo ============================================\n')
f.write('echo.\n')
f.write('python --version >nul 2>&1\n')
f.write('if errorlevel 1 (\n')
f.write(' echo ERROR: Python not found!\n')
f.write(' echo Please install Python 3.10+ from python.org\n')
f.write(' pause\n')
f.write(' exit /b 1\n')
f.write(')\n')
f.write(f'cd /d "{base_dir}"\n')
f.write('python install_rfcp.py\n')
f.write('echo.\n')
f.write('echo Setup complete! Run RFCP.bat to start.\n')
f.write('pause\n')
print(f" [OK] Created: install.bat")
else:
# Linux/macOS
launcher_path = os.path.join(base_dir, "rfcp.sh")
with open(launcher_path, 'w') as f:
f.write('#!/bin/bash\n')
f.write(f'cd "{base_dir}"\n')
f.write('echo "Starting RFCP..."\n')
f.write('echo "Open http://localhost:8090 in your browser"\n')
f.write('echo "Press Ctrl+C to stop"\n')
f.write('cd backend\n')
f.write(f'{sys.executable} -m uvicorn app.main:app --host 0.0.0.0 --port 8090\n')
os.chmod(launcher_path, 0o755)
print(f" [OK] Created: rfcp.sh")
return True
def verify_installation() -> bool:
"""Run quick verification tests."""
print_step("Verifying installation...")
checks = []
critical_fail = False
# Check core imports
try:
import numpy as np
checks.append(f"[OK] NumPy {np.__version__}")
except ImportError:
checks.append("[X] NumPy missing")
critical_fail = True
try:
import scipy
checks.append(f"[OK] SciPy {scipy.__version__}")
except ImportError:
checks.append("[X] SciPy missing")
critical_fail = True
try:
import fastapi
checks.append(f"[OK] FastAPI {fastapi.__version__}")
except ImportError:
checks.append("[X] FastAPI missing")
critical_fail = True
try:
import uvicorn
checks.append(f"[OK] Uvicorn {uvicorn.__version__}")
except ImportError:
checks.append("[X] Uvicorn missing")
critical_fail = True
# Check GPU acceleration
try:
import cupy as cp
device_count = cp.cuda.runtime.getDeviceCount()
if device_count > 0:
props = cp.cuda.runtime.getDeviceProperties(0)
name = props["name"]
if isinstance(name, bytes):
name = name.decode()
mem_mb = props["totalGlobalMem"] // (1024 * 1024)
checks.append(f"[OK] CuPy (CUDA) -> {name} ({mem_mb} MB)")
else:
checks.append("[i] CuPy installed but no CUDA devices found")
except ImportError:
checks.append("[i] CuPy not available (NVIDIA GPU acceleration disabled)")
except Exception as e:
checks.append(f"[!] CuPy error: {e}")
try:
import pyopencl as cl
devices = []
for p in cl.get_platforms():
for d in p.get_devices():
devices.append(d.name.strip())
if devices:
checks.append(f"[OK] PyOpenCL -> {', '.join(devices[:2])}")
else:
checks.append("[i] PyOpenCL installed but no devices found")
except ImportError:
checks.append("[i] PyOpenCL not available (Intel/AMD GPU acceleration disabled)")
except Exception as e:
checks.append(f"[!] PyOpenCL error: {e}")
for check in checks:
print(f" {check}")
return not critical_fail
def main():
"""Main installer entry point."""
print_header("RFCP - RF Coverage Planner - Installer")
# Step 1: Check prerequisites
print_step("Checking prerequisites...")
if not check_python():
print("\n[X] Python 3.10+ is required. Please install from python.org")
sys.exit(1)
has_node = check_node()
# Step 2: Detect GPU
print_step("Detecting GPU hardware...")
gpus = detect_gpu()
# Step 3: Install core dependencies
if not install_core_dependencies():
print("\n[X] Core dependency installation failed")
sys.exit(1)
# Step 4: Install GPU dependencies
install_gpu_dependencies(gpus)
# Step 5: Frontend (optional)
install_frontend(has_node)
# Step 6: Create launcher
create_launcher()
# Step 7: Verify
success = verify_installation()
# Summary
print_header("Installation Summary")
if success:
print(" [OK] RFCP installed successfully!")
print()
print(" To start RFCP:")
if platform.system() == "Windows":
print(" Double-click RFCP.bat")
print(" Or run: python -m uvicorn app.main:app --port 8090")
else:
print(" Run: ./rfcp.sh")
print(" Or: python -m uvicorn app.main:app --port 8090")
print()
print(" Then open: http://localhost:8090")
print()
# GPU summary
if gpus["nvidia"]:
print(f" GPU: {gpus['nvidia_name']} (CUDA)")
elif gpus["intel"]:
print(f" GPU: {gpus['intel_name']} (OpenCL)")
elif gpus["amd"]:
print(f" GPU: {gpus['amd_name']} (OpenCL)")
else:
print(" Mode: CPU only (NumPy)")
else:
print(" [!] Installation completed with errors")
print(" Some features may not work correctly")
print()
print('=' * 60)
if __name__ == "__main__":
main()