File size: 5,454 Bytes
af8ac78 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | """Document AI Expert β Central Configuration.
Mode flags are driven by environment variables set by start.sh:
HF_MODE=1 β HuggingFace Spaces low-resource mode (CPU, small models, no Neo4j)
ADMIN_MODE=0 β Disable admin controls (set by -noadmin CLI switch)
"""
import os
from pathlib import Path
import contextvars
BASE_DIR = Path(__file__).parent
current_session = contextvars.ContextVar("current_session", default="admin")
# ββ Operating Mode Flags βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# HF_MODE: True when running in HuggingFace Spaces or via `python app.py -hf`
# Also triggers for SPACE_ID env var (native HF Spaces detection)
_hf_space = bool(os.getenv("SPACE_ID"))
HF_MODE = bool(os.getenv("HF_MODE")) or _hf_space
# ADMIN_MODE: False disables all admin API routes and UI controls.
# Defaults to True (admin enabled) unless explicitly set to "0" or "false".
_admin_env = os.getenv("ADMIN_MODE", "1").lower()
ADMIN_MODE = _admin_env not in ("0", "false", "no")
# ββ LLM generation server ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
LLM_BASE_URL = os.getenv("LLM_BASE_URL", "http://127.0.0.1:8002")
LLM_COMPLETIONS_URL = f"{LLM_BASE_URL}/v1/completions"
# Model selection:
# GPU & HF mode β Jackrong/Qwen3.5-4B-Claude-4.6-Opus-Reasoning-Distilled-GGUF
_default_model = "Jackrong/Qwen3.5-4B-Claude-4.6-Opus-Reasoning-Distilled-GGUF"
LLM_MODEL_ID = os.getenv("LLM_MODEL_ID", _default_model)
LLM_MODEL_FILENAME = os.getenv("LLM_MODEL_FILENAME", "Qwen3.5-4B.Q4_K_M.gguf")
# Token limits: lower in HF mode to keep CPU inference under ~60 s
_default_max_tokens = "512" if HF_MODE else "2048"
LLM_MAX_TOKENS = int(os.getenv("LLM_MAX_TOKENS", _default_max_tokens))
LLM_TEMPERATURE = float(os.getenv("LLM_TEMPERATURE", "0.1"))
LLM_TOP_P = float(os.getenv("LLM_TOP_P", "0.9"))
LLM_TIMEOUT = int(os.getenv("LLM_TIMEOUT", "1200"))
# ββ Embedding server βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
EMBED_BASE_URL = os.getenv("EMBED_BASE_URL", "http://127.0.0.1:8003")
EMBED_EMBEDDINGS_URL = f"{EMBED_BASE_URL}/v1/embeddings"
# Embedding model:
# GPU & HF mode β bge-small-en-v1.5 (~130 MB, 384 dim)
_default_embed_model = "BAAI/bge-small-en-v1.5"
EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL", _default_embed_model)
# Batch size: smaller in HF mode to avoid RAM spikes during ingestion
_default_batch = "2" if HF_MODE else "12"
EMBEDDING_BATCH_SIZE = int(os.getenv("EMBEDDING_BATCH_SIZE", _default_batch))
EMBEDDING_TIMEOUT = int(os.getenv("EMBEDDING_TIMEOUT", "120"))
# KV-cache precompilation: disabled in HF mode (holds full KB text in RAM)
KV_CACHE_ENABLED = not HF_MODE
# ββ ChromaDB & Security ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CHROMA_PERSIST_DIR = os.getenv("CHROMA_PERSIST_DIR", str(BASE_DIR / "data" / "chroma_db"))
CHROMA_COLLECTION = os.getenv("CHROMA_COLLECTION", "Document")
ENCRYPTION_KEY_FILE = os.getenv("ENCRYPTION_KEY_FILE", str(BASE_DIR / "data" / "security.key"))
# ββ Kuzu Graph Database ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
KUZU_DB_PATH = os.getenv("KUZU_DB_PATH", str(BASE_DIR / "data" / "kuzu_db"))
GRAPH_AVAILABLE = True # Kuzu is embedded, works everywhere including HF Spaces
# ββ Flask / Upload βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
UPLOAD_FOLDER = os.getenv("UPLOAD_FOLDER", str(BASE_DIR / "uploads"))
MAX_CONTENT_LENGTH = 5 * 1024 * 1024 # 5 MB limit
ALLOWED_EXTENSIONS = {".txt", ".pdf", ".docx", ".xlsx", ".csv", ".png", ".jpg", ".jpeg", ".webp"}
SECRET_KEY = os.getenv("SECRET_KEY", "healthexpert-dev-key-change-in-prod")
# ββ RAG ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CHUNK_SIZE = int(os.getenv("CHUNK_SIZE", "512"))
CHUNK_OVERLAP = int(os.getenv("CHUNK_OVERLAP", "64"))
TOP_K_VECTOR = int(os.getenv("TOP_K_VECTOR", "10"))
TOP_K_GRAPH = int(os.getenv("TOP_K_GRAPH", "10"))
# ββ HuggingFace model cache ββββββββββββββββββββββββββββββββββββββββββββββββββββ
_models_dir = BASE_DIR.parent / "models"
HF_HOME = str(_models_dir) if _models_dir.exists() else str(BASE_DIR / "models")
os.environ.setdefault("HF_HOME", HF_HOME)
# ββ System info (for resource banner) βββββββββββββββββββββββββββββββββββββββββ
SYSTEM_INFO_ENABLED = True # /api/sysinfo endpoint always active |