Spaces:
Sleeping
Sleeping
| """Environment verification script for the Multilingual Code-Switching Chatbot. | |
| Checks Python version, CUDA availability, GPU info, available disk space, | |
| and prints a clean summary table. Run this before installing dependencies. | |
| """ | |
| from __future__ import annotations | |
| import os | |
| import platform | |
| import shutil | |
| import subprocess | |
| import sys | |
| from typing import Any | |
| # --------------------------------------------------------------------------- | |
| # Individual checks | |
| # --------------------------------------------------------------------------- | |
| def check_python_version() -> dict[str, Any]: | |
| """Check that Python version is 3.9 or newer.""" | |
| major, minor = sys.version_info.major, sys.version_info.minor | |
| ok = (major, minor) >= (3, 9) | |
| return { | |
| "name": "Python version", | |
| "value": f"{major}.{minor}.{sys.version_info.micro}", | |
| "ok": ok, | |
| "detail": "needs >= 3.9" if not ok else "", | |
| } | |
| def check_platform() -> dict[str, Any]: | |
| """Report basic OS/platform info (always considered OK).""" | |
| return { | |
| "name": "Platform", | |
| "value": f"{platform.system()} {platform.release()} ({platform.machine()})", | |
| "ok": True, | |
| "detail": "", | |
| } | |
| def check_pip() -> dict[str, Any]: | |
| """Check that pip is available.""" | |
| try: | |
| out = subprocess.run( | |
| [sys.executable, "-m", "pip", "--version"], | |
| capture_output=True, text=True, check=True, | |
| ) | |
| return { | |
| "name": "pip", | |
| "value": out.stdout.strip().split(" (")[0], | |
| "ok": True, | |
| "detail": "", | |
| } | |
| except Exception as exc: # noqa: BLE001 | |
| return { | |
| "name": "pip", | |
| "value": "NOT FOUND", | |
| "ok": False, | |
| "detail": str(exc), | |
| } | |
| def check_torch_and_cuda() -> list[dict[str, Any]]: | |
| """Check whether torch is installed and whether CUDA is visible. | |
| Returns multiple rows: torch presence, CUDA availability, GPU details. | |
| """ | |
| rows: list[dict[str, Any]] = [] | |
| try: | |
| import torch # type: ignore | |
| rows.append({ | |
| "name": "PyTorch", | |
| "value": torch.__version__, | |
| "ok": True, | |
| "detail": "", | |
| }) | |
| cuda_ok = torch.cuda.is_available() | |
| rows.append({ | |
| "name": "CUDA available", | |
| "value": "yes" if cuda_ok else "no (CPU only)", | |
| "ok": True, # CPU-only is acceptable, just informational | |
| "detail": "", | |
| }) | |
| if cuda_ok: | |
| rows.append({ | |
| "name": "CUDA version (torch)", | |
| "value": torch.version.cuda or "unknown", | |
| "ok": True, | |
| "detail": "", | |
| }) | |
| n = torch.cuda.device_count() | |
| for i in range(n): | |
| props = torch.cuda.get_device_properties(i) | |
| vram_gb = props.total_memory / (1024 ** 3) | |
| rows.append({ | |
| "name": f"GPU {i}", | |
| "value": f"{props.name} | {vram_gb:.1f} GB VRAM | CC {props.major}.{props.minor}", | |
| "ok": True, | |
| "detail": "", | |
| }) | |
| except ImportError: | |
| rows.append({ | |
| "name": "PyTorch", | |
| "value": "NOT INSTALLED", | |
| "ok": False, | |
| "detail": "will be installed in setup/install.py", | |
| }) | |
| # Fall back to nvidia-smi to still report the GPU if present | |
| rows.extend(_nvidia_smi_fallback()) | |
| except Exception as exc: # noqa: BLE001 | |
| rows.append({ | |
| "name": "PyTorch", | |
| "value": "ERROR", | |
| "ok": False, | |
| "detail": str(exc), | |
| }) | |
| return rows | |
| def _nvidia_smi_fallback() -> list[dict[str, Any]]: | |
| """If torch is unavailable, try nvidia-smi to report GPU presence.""" | |
| rows: list[dict[str, Any]] = [] | |
| if shutil.which("nvidia-smi") is None: | |
| rows.append({ | |
| "name": "nvidia-smi", | |
| "value": "not found (no NVIDIA GPU detected, or driver not installed)", | |
| "ok": True, | |
| "detail": "", | |
| }) | |
| return rows | |
| try: | |
| out = subprocess.run( | |
| ["nvidia-smi", "--query-gpu=name,memory.total,driver_version", | |
| "--format=csv,noheader"], | |
| capture_output=True, text=True, check=True, | |
| ) | |
| for idx, line in enumerate(out.stdout.strip().splitlines()): | |
| parts = [p.strip() for p in line.split(",")] | |
| if len(parts) >= 2: | |
| name = parts[0] | |
| mem = parts[1] | |
| drv = parts[2] if len(parts) > 2 else "?" | |
| rows.append({ | |
| "name": f"GPU {idx} (nvidia-smi)", | |
| "value": f"{name} | {mem} | driver {drv}", | |
| "ok": True, | |
| "detail": "", | |
| }) | |
| except Exception as exc: # noqa: BLE001 | |
| rows.append({ | |
| "name": "nvidia-smi", | |
| "value": "ERROR", | |
| "ok": False, | |
| "detail": str(exc), | |
| }) | |
| return rows | |
| def check_disk_space(path: str = ".") -> dict[str, Any]: | |
| """Report free / total disk space at the given path.""" | |
| try: | |
| usage = shutil.disk_usage(os.path.abspath(path)) | |
| free_gb = usage.free / (1024 ** 3) | |
| total_gb = usage.total / (1024 ** 3) | |
| # 10 GB recommended minimum for models + datasets | |
| ok = free_gb >= 10 | |
| return { | |
| "name": "Disk space (cwd)", | |
| "value": f"{free_gb:.1f} GB free / {total_gb:.1f} GB total", | |
| "ok": ok, | |
| "detail": "" if ok else "recommend >= 10 GB free", | |
| } | |
| except Exception as exc: # noqa: BLE001 | |
| return { | |
| "name": "Disk space (cwd)", | |
| "value": "ERROR", | |
| "ok": False, | |
| "detail": str(exc), | |
| } | |
| def check_ram() -> dict[str, Any]: | |
| """Best-effort RAM check via /proc/meminfo (Linux) or psutil if available.""" | |
| # Try /proc/meminfo first | |
| meminfo = "/proc/meminfo" | |
| if os.path.exists(meminfo): | |
| try: | |
| with open(meminfo) as f: | |
| lines = f.readlines() | |
| total_kb = 0 | |
| avail_kb = 0 | |
| for ln in lines: | |
| if ln.startswith("MemTotal:"): | |
| total_kb = int(ln.split()[1]) | |
| elif ln.startswith("MemAvailable:"): | |
| avail_kb = int(ln.split()[1]) | |
| total_gb = total_kb / (1024 ** 2) | |
| avail_gb = avail_kb / (1024 ** 2) | |
| return { | |
| "name": "RAM", | |
| "value": f"{avail_gb:.1f} GB available / {total_gb:.1f} GB total", | |
| "ok": total_gb >= 4, | |
| "detail": "" if total_gb >= 4 else "recommend >= 4 GB", | |
| } | |
| except Exception: # noqa: BLE001 | |
| pass | |
| return { | |
| "name": "RAM", | |
| "value": "unknown", | |
| "ok": True, | |
| "detail": "could not read /proc/meminfo", | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Pretty-printer | |
| # --------------------------------------------------------------------------- | |
| def print_table(rows: list[dict[str, Any]]) -> None: | |
| """Print a clean fixed-width summary table.""" | |
| name_w = max(len(r["name"]) for r in rows) + 2 | |
| val_w = max(len(str(r["value"])) for r in rows) + 2 | |
| name_w = max(name_w, 22) | |
| val_w = max(val_w, 30) | |
| sep = "+" + "-" * (name_w + 2) + "+" + "-" * (val_w + 2) + "+--------+" | |
| print(sep) | |
| print(f"| {'CHECK'.ljust(name_w)} | {'VALUE'.ljust(val_w)} | STATUS |") | |
| print(sep) | |
| for r in rows: | |
| status = " OK " if r["ok"] else " FAIL " | |
| print(f"| {r['name'].ljust(name_w)} | {str(r['value']).ljust(val_w)} | {status} |") | |
| if r["detail"]: | |
| print(f"| {''.ljust(name_w)} | -> {r['detail'][:val_w-3].ljust(val_w-3)} | |") | |
| print(sep) | |
| # --------------------------------------------------------------------------- | |
| # Main | |
| # --------------------------------------------------------------------------- | |
| def main() -> int: | |
| """Run all environment checks and return non-zero on hard failure.""" | |
| print("=" * 70) | |
| print("Multilingual Chatbot — Environment Check") | |
| print("=" * 70) | |
| rows: list[dict[str, Any]] = [] | |
| rows.append(check_python_version()) | |
| rows.append(check_platform()) | |
| rows.append(check_pip()) | |
| rows.extend(check_torch_and_cuda()) | |
| rows.append(check_ram()) | |
| rows.append(check_disk_space(".")) | |
| print_table(rows) | |
| failures = [r for r in rows if not r["ok"]] | |
| if failures: | |
| print("\nHard failures:") | |
| for r in failures: | |
| print(f" - {r['name']}: {r['value']} ({r['detail']})") | |
| # Only Python version + pip are truly blocking. Torch missing is OK. | |
| blocking = [r for r in failures if r["name"] in ("Python version", "pip")] | |
| if blocking: | |
| print("\nBlocking issues found. Please fix before continuing.") | |
| return 1 | |
| print("\nNon-blocking issues only — safe to continue to install.py.") | |
| else: | |
| print("\nAll checks passed.") | |
| print("\nSummary:") | |
| print(f" - Working dir : {os.getcwd()}") | |
| print(f" - Python exe : {sys.executable}") | |
| return 0 | |
| if __name__ == "__main__": | |
| try: | |
| sys.exit(main()) | |
| except KeyboardInterrupt: | |
| print("\nAborted by user.") | |
| sys.exit(130) | |