lifeos / config.py
awaisaziz's picture
Add config, model status, and VLM support
0c4cd3b
Raw
History Blame Contribute Delete
3.79 kB
"""Central configuration for LifeOS.
All environment-driven knobs live here so the rest of the code never reaches
into os.environ directly. Values are read once at import. A local .env file (if
present, gitignored) is loaded first — no external dependency, just a tiny
KEY=VALUE parser — so secrets and machine-specific paths stay out of the code.
Copy .env.example to .env to override any of these.
"""
import os
ROOT = os.path.dirname(os.path.abspath(__file__))
def _load_dotenv(path: str) -> None:
"""Minimal .env loader: KEY=VALUE lines, # comments, optional quotes.
Does not overwrite variables already set in the real environment."""
if not os.path.exists(path):
return
with open(path, "r", encoding="utf-8") as f:
for raw in f:
line = raw.strip()
if not line or line.startswith("#") or "=" not in line:
continue
key, val = line.split("=", 1)
key = key.strip()
val = val.strip().strip('"').strip("'")
os.environ.setdefault(key, val)
_load_dotenv(os.path.join(ROOT, ".env"))
def _flag(name: str, default: bool = False) -> bool:
return os.environ.get(name, "1" if default else "0").lower() in ("1", "true", "yes", "on")
def _int(name: str, default: int) -> int:
try:
return int(os.environ.get(name, default))
except (TypeError, ValueError):
return default
# --- runtime mode ------------------------------------------------------
# Demo mode seeds a sample persona + long-term notes so the app looks alive
# for screenshots/demos. Real installs leave this off and start blank.
DEMO = _flag("LIFEOS_DEMO", default=False)
# --- inference ---------------------------------------------------------
# GPU offload layers for llama.cpp: -1 = all, 0 = CPU only. Needs a CUDA/Metal
# build of llama-cpp-python; the plain CPU wheel ignores it.
GPU_LAYERS = _int("LIFEOS_GPU_LAYERS", -1)
# The vision model is occasional (one shot per food photo) and would otherwise
# fight the always-resident text model for VRAM — on a small card loading both
# on the GPU OOMs. Default it to CPU so it never disrupts the interactive chat
# path; set LIFEOS_VLM_GPU_LAYERS=-1 on a large-VRAM card for faster photos.
VLM_GPU_LAYERS = _int("LIFEOS_VLM_GPU_LAYERS", 0)
# Text reasoning model (Nemotron-3-Nano-4B).
MODEL_REPO = os.environ.get("LIFEOS_MODEL_REPO", "nvidia/NVIDIA-Nemotron-3-Nano-4B-GGUF")
MODEL_FILE = os.environ.get("LIFEOS_MODEL_FILE", "NVIDIA-Nemotron3-Nano-4B-Q4_K_M.gguf")
# Vision model for food-photo recognition (Qwen2.5-VL-3B).
VLM_REPO = os.environ.get("LIFEOS_VLM_REPO", "ggml-org/Qwen2.5-VL-3B-Instruct-GGUF")
VLM_FILE = os.environ.get("LIFEOS_VLM_FILE", "Qwen2.5-VL-3B-Instruct-Q4_K_M.gguf")
VLM_MMPROJ_FILE = os.environ.get("LIFEOS_VLM_MMPROJ_FILE", "mmproj-Qwen2.5-VL-3B-Instruct-f16.gguf")
# Longest-side pixel cap for photos sent to the VLM. Full-res photos decode
# ~1000 image tokens on the CPU path (~30s); 768px is ~4x faster with no loss
# in food-recognition quality. Raise it if you offload the VLM to a big GPU.
VLM_MAX_IMAGE_SIDE = _int("LIFEOS_VLM_MAX_IMAGE_SIDE", 768)
# Embedding model for long-term RAG (nomic-embed-text-v1.5).
EMBED_REPO = os.environ.get("LIFEOS_EMBED_REPO", "nomic-ai/nomic-embed-text-v1.5-GGUF")
EMBED_FILE = os.environ.get("LIFEOS_EMBED_FILE", "nomic-embed-text-v1.5.Q8_0.gguf")
# Use the GPU for OCR (EasyOCR) when a CUDA torch build is present.
OCR_GPU = _flag("LIFEOS_OCR_GPU", default=True)
# --- server ------------------------------------------------------------
# Bind host: defaults to 0.0.0.0 on Hugging Face Spaces, else Gradio's loopback.
HOST = os.environ.get("LIFEOS_HOST") or ("0.0.0.0" if os.environ.get("SPACE_ID") else None)
PORT = _int("LIFEOS_PORT", 7860)