e4dcfc49aa
Tests / Import Check (Python 3.13) (push) Has been cancelled
Tests / Import Check (Python 3.14) (push) Has been cancelled
Tests / Python Tests (Python 3.11) (push) Has been cancelled
Tests / Python Tests (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.14) (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
Tests / Lint and Format (push) Has been cancelled
Tests / Web Node Tests (push) Has been cancelled
Tests / Import Check (Python 3.11) (push) Has been cancelled
Tests / Import Check (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.13) (push) Has been cancelled
201 lines
6.1 KiB
Python
201 lines
6.1 KiB
Python
"""Per-engine environment preflight checks.
|
|
|
|
Powers the "check whether this engine can run right now" affordance on each
|
|
engine's detail page. Every check is best-effort and never raises — a failed
|
|
import or missing config becomes a failed/optional check, not an exception.
|
|
|
|
A check is ``{key, label, ok, detail, optional}``. Overall ``ok`` is true when
|
|
every *required* (non-optional) check passes.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from .factory import (
|
|
DEFAULT_PROVIDER,
|
|
GRAPHRAG_PROVIDER,
|
|
LIGHTRAG_PROVIDER,
|
|
PAGEINDEX_PROVIDER,
|
|
normalize_provider_name,
|
|
)
|
|
|
|
|
|
def _check(key: str, label: str, ok: bool, detail: str = "", *, optional: bool = False) -> dict:
|
|
return {"key": key, "label": label, "ok": bool(ok), "detail": detail, "optional": optional}
|
|
|
|
|
|
def _active_chat_model() -> tuple[str | None, str]:
|
|
"""Return ``(model, binding)`` for the active chat LLM, or ``(None, "")``."""
|
|
try:
|
|
from deeptutor.services.config import resolve_llm_runtime_config
|
|
|
|
cfg = resolve_llm_runtime_config()
|
|
return getattr(cfg, "model", None), str(getattr(cfg, "binding", "") or "")
|
|
except Exception:
|
|
return None, ""
|
|
|
|
|
|
def _active_embedding() -> tuple[str | None, int]:
|
|
"""Return ``(model, dim)`` for the active embedding model, or ``(None, 0)``."""
|
|
try:
|
|
from deeptutor.services.embedding import get_embedding_config
|
|
|
|
cfg = get_embedding_config()
|
|
return getattr(cfg, "model", None), int(getattr(cfg, "dim", 0) or 0)
|
|
except Exception:
|
|
return None, 0
|
|
|
|
|
|
def _llamaindex_preflight() -> dict:
|
|
emb_model, emb_dim = _active_embedding()
|
|
checks = [
|
|
_check(
|
|
"embedding",
|
|
"Active embedding model",
|
|
bool(emb_model) and emb_dim > 0,
|
|
f"{emb_model} · {emb_dim}d" if emb_model else "Configure one in the model catalog.",
|
|
)
|
|
]
|
|
try:
|
|
from .pipelines.llamaindex.retrievers import _import_bm25_retriever
|
|
|
|
bm25_ok = _import_bm25_retriever() is not None
|
|
except Exception:
|
|
bm25_ok = False
|
|
checks.append(
|
|
_check(
|
|
"bm25",
|
|
"BM25 hybrid retrieval",
|
|
bm25_ok,
|
|
"Installed." if bm25_ok else "Not installed — hybrid falls back to vector-only.",
|
|
optional=True,
|
|
)
|
|
)
|
|
return _finalize(checks)
|
|
|
|
|
|
def _pageindex_preflight() -> dict:
|
|
try:
|
|
from .pipelines.pageindex.config import DEFAULT_API_BASE_URL, get_pageindex_config
|
|
|
|
cfg = get_pageindex_config(require_key=False)
|
|
configured = bool(cfg.api_key)
|
|
base = cfg.api_base_url or DEFAULT_API_BASE_URL
|
|
except Exception:
|
|
configured, base = False, ""
|
|
return _finalize(
|
|
[
|
|
_check(
|
|
"api_key",
|
|
"API key configured",
|
|
configured,
|
|
base if configured else "Add a PageIndex API key under Credentials.",
|
|
)
|
|
]
|
|
)
|
|
|
|
|
|
def _graphrag_preflight() -> dict:
|
|
try:
|
|
from .pipelines.graphrag.config import is_graphrag_available
|
|
|
|
installed = is_graphrag_available()
|
|
except Exception:
|
|
installed = False
|
|
emb_model, emb_dim = _active_embedding()
|
|
chat_model, _ = _active_chat_model()
|
|
return _finalize(
|
|
[
|
|
_check(
|
|
"package",
|
|
"GraphRAG package installed",
|
|
installed,
|
|
"Installed." if installed else "pip install 'deeptutor[graphrag]'",
|
|
),
|
|
_check(
|
|
"chat",
|
|
"Active chat model",
|
|
bool(chat_model),
|
|
chat_model or "Configure one in the model catalog.",
|
|
),
|
|
_check(
|
|
"embedding",
|
|
"Active embedding model",
|
|
bool(emb_model) and emb_dim > 0,
|
|
f"{emb_model} · {emb_dim}d" if emb_model else "Configure one in the model catalog.",
|
|
),
|
|
]
|
|
)
|
|
|
|
|
|
def _lightrag_preflight() -> dict:
|
|
try:
|
|
from .pipelines.lightrag.config import is_lightrag_available
|
|
|
|
installed = is_lightrag_available()
|
|
except Exception:
|
|
installed = False
|
|
emb_model, emb_dim = _active_embedding()
|
|
chat_model, binding = _active_chat_model()
|
|
vision_ok = False
|
|
if chat_model:
|
|
try:
|
|
from deeptutor.services.llm.capabilities import supports_vision
|
|
|
|
vision_ok = supports_vision(binding, chat_model)
|
|
except Exception:
|
|
vision_ok = False
|
|
return _finalize(
|
|
[
|
|
_check(
|
|
"package",
|
|
"RAG-Anything package installed",
|
|
installed,
|
|
"Installed." if installed else "pip install 'deeptutor[rag-lightrag]'",
|
|
),
|
|
_check(
|
|
"chat",
|
|
"Active chat model",
|
|
bool(chat_model),
|
|
chat_model or "Configure one in the model catalog.",
|
|
),
|
|
_check(
|
|
"embedding",
|
|
"Active embedding model",
|
|
bool(emb_model) and emb_dim > 0,
|
|
f"{emb_model} · {emb_dim}d" if emb_model else "Configure one in the model catalog.",
|
|
),
|
|
_check(
|
|
"vision",
|
|
"Vision model for multimodal",
|
|
vision_ok,
|
|
"Active chat model supports vision."
|
|
if vision_ok
|
|
else "Active chat model has no vision — multimodal documents fall back to text.",
|
|
optional=True,
|
|
),
|
|
]
|
|
)
|
|
|
|
|
|
def _finalize(checks: list[dict]) -> dict:
|
|
ok = all(c["ok"] for c in checks if not c["optional"])
|
|
return {"ok": ok, "checks": checks}
|
|
|
|
|
|
_PREFLIGHTS = {
|
|
DEFAULT_PROVIDER: _llamaindex_preflight,
|
|
PAGEINDEX_PROVIDER: _pageindex_preflight,
|
|
GRAPHRAG_PROVIDER: _graphrag_preflight,
|
|
LIGHTRAG_PROVIDER: _lightrag_preflight,
|
|
}
|
|
|
|
|
|
def engine_preflight(provider: str) -> dict[str, Any]:
|
|
"""Run the requirement checks for ``provider`` and return the report."""
|
|
return _PREFLIGHTS[normalize_provider_name(provider)]()
|
|
|
|
|
|
__all__ = ["engine_preflight"]
|