This commit is contained in:
2025-12-30 23:19:02 -08:00
parent a97657a757
commit 3bbaa28fb4
17 changed files with 1735 additions and 558 deletions

119
SYS/optional_deps.py Normal file
View File

@@ -0,0 +1,119 @@
from __future__ import annotations
import importlib
import os
import subprocess
import sys
from typing import Any, Dict, Iterable, List, Optional, Tuple
from SYS.logger import log
from SYS.rich_display import stdout_console
def _as_bool(value: Any, default: bool = False) -> bool:
if value is None:
return default
if isinstance(value, bool):
return value
s = str(value).strip().lower()
if s in {"1", "true", "yes", "on"}:
return True
if s in {"0", "false", "no", "off"}:
return False
return default
def _is_pytest() -> bool:
return bool(os.environ.get("PYTEST_CURRENT_TEST"))
def _try_import(module: str) -> bool:
try:
importlib.import_module(module)
return True
except Exception:
return False
def florencevision_missing_modules() -> List[str]:
missing: List[str] = []
# pillow is already in requirements, but keep the check for robustness.
if not _try_import("transformers"):
missing.append("transformers")
if not _try_import("torch"):
missing.append("torch")
if not _try_import("PIL"):
missing.append("pillow")
# Florence-2 remote code frequently requires these extras.
if not _try_import("einops"):
missing.append("einops")
if not _try_import("timm"):
missing.append("timm")
return missing
def _pip_install(requirements: List[str]) -> Tuple[bool, str]:
if not requirements:
return True, "No requirements"
cmd = [sys.executable, "-m", "pip", "install", "--upgrade", *requirements]
try:
proc = subprocess.run(
cmd,
check=False,
capture_output=True,
text=True,
)
if proc.returncode == 0:
importlib.invalidate_caches()
return True, proc.stdout.strip() or "Installed"
out = (proc.stdout or "") + "\n" + (proc.stderr or "")
return False, out.strip() or f"pip exited with code {proc.returncode}"
except Exception as exc:
return False, str(exc)
def maybe_auto_install_configured_tools(config: Dict[str, Any]) -> None:
"""Best-effort dependency auto-installer for configured tools.
This is intentionally conservative:
- Only acts when a tool block is enabled.
- Skips under pytest.
Current supported tool(s): florencevision
"""
if _is_pytest():
return
tool_cfg = (config or {}).get("tool")
if not isinstance(tool_cfg, dict):
return
fv = tool_cfg.get("florencevision")
if isinstance(fv, dict) and _as_bool(fv.get("enabled"), False):
auto_install = _as_bool(fv.get("auto_install"), True)
if not auto_install:
return
missing = florencevision_missing_modules()
if not missing:
return
names = ", ".join(missing)
try:
with stdout_console().status(
f"Installing FlorenceVision dependencies: {names}",
spinner="dots",
):
ok, detail = _pip_install(missing)
except Exception:
log(f"[startup] FlorenceVision dependencies missing ({names}). Attempting auto-install...")
ok, detail = _pip_install(missing)
if ok:
log("[startup] FlorenceVision dependency install OK")
else:
log(f"[startup] FlorenceVision dependency auto-install failed. {detail}")
__all__ = ["maybe_auto_install_configured_tools", "florencevision_missing_modules"]