SPB Git forge

spb/llm-api

Public
0commits 0branches 0releases
0 Bsize
maindefault branch
—last push
4.9 KB · 123 lines python
Raw Blame History
1"""Application settings (environment variables, .env)."""23from __future__ import annotations45import os6from functools import lru_cache7from pathlib import Path89from pydantic import Field10from pydantic_settings import BaseSettings, SettingsConfigDict111213def _default_root() -> Path:14    return Path(os.environ.get("LLM_API_ROOT", str(Path.home() / "llm-api")))151617class Settings(BaseSettings):18    model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore")1920    app_env: str = Field(default="development", alias="APP_ENV")21    domain: str = Field(default="www.llm-api.io", alias="DOMAIN")22    public_url: str = Field(default="https://www.llm-api.io", alias="PUBLIC_URL")2324    host: str = Field(default="127.0.0.1", alias="HOST")25    port: int = Field(default=8300, alias="PORT")26    web_url: str = Field(default="http://127.0.0.1:8301", alias="WEB_URL")2728    # Storage29    root: Path = Field(default_factory=_default_root, alias="LLM_API_ROOT")30    model_root: Path | None = Field(default=None, alias="MODEL_ROOT")31    data_dir: Path | None = Field(default=None, alias="DATA_DIR")32    log_dir: Path | None = Field(default=None, alias="LOG_DIR")33    database_path: Path | None = Field(default=None, alias="DATABASE_PATH")3435    # Memory policy (GB)36    max_model_memory_gb: float = Field(default=45.0, alias="MAX_MODEL_MEMORY_GB")37    absolute_max_memory_gb: float = Field(default=50.0, alias="ABSOLUTE_MAX_MEMORY_GB")38    macos_reserve_gb: float = Field(default=8.0, alias="MACOS_RESERVE_GB")39    min_free_disk_gb: float = Field(default=100.0, alias="MIN_FREE_DISK_GB")4041    max_simultaneous_models: int = Field(default=1, alias="MAX_SIMULTANEOUS_MODELS")42    model_idle_timeout_minutes: int = Field(default=30, alias="MODEL_IDLE_TIMEOUT_MINUTES")43    small_model_resident_gb: float = Field(default=3.0, alias="SMALL_MODEL_RESIDENT_GB")44    load_timeout_seconds: int = Field(default=900, alias="LOAD_TIMEOUT_SECONDS")45    generation_timeout_seconds: int = Field(default=1800, alias="GENERATION_TIMEOUT_SECONDS")46    preload_model: str = Field(default="none", alias="PRELOAD_MODEL")4748    enable_mlx: bool = Field(default=True, alias="ENABLE_MLX")49    enable_gguf: bool = Field(default=True, alias="ENABLE_GGUF")50    allow_downloads: bool = Field(default=True, alias="ALLOW_DOWNLOADS")51    log_prompts: bool = Field(default=False, alias="LOG_PROMPTS")5253    default_max_tokens: int = Field(default=2048, alias="DEFAULT_MAX_TOKENS")54    default_context: int = Field(default=16384, alias="DEFAULT_CONTEXT")5556    hf_token: str | None = Field(default=None, alias="HF_TOKEN")57    llama_server_bin: str = Field(default="llama-server", alias="LLAMA_SERVER_BIN")58    worker_python: str | None = Field(default=None, alias="WORKER_PYTHON")59    worker_port_start: int = Field(default=8310, alias="WORKER_PORT_START")60    worker_port_end: int = Field(default=8399, alias="WORKER_PORT_END")6162    secret_key: str = Field(default="", alias="SECRET_KEY")63    admin_email: str | None = Field(default=None, alias="ADMIN_EMAIL")64    admin_password: str | None = Field(default=None, alias="ADMIN_PASSWORD")65    session_hours: int = Field(default=24 * 14, alias="SESSION_HOURS")66    secure_cookies: bool = Field(default=False, alias="SECURE_COOKIES")6768    metrics_interval_seconds: int = Field(default=15, alias="METRICS_INTERVAL_SECONDS")69    metrics_retention_days: int = Field(default=30, alias="METRICS_RETENTION_DAYS")70    max_body_bytes: int = Field(default=20 * 1024 * 1024, alias="MAX_BODY_BYTES")7172    # ---- derived paths -------------------------------------------------73    @property74    def models_dir(self) -> Path:75        return (self.model_root or self.root / "models").expanduser()7677    @property78    def data_path(self) -> Path:79        return (self.data_dir or self.root / "data").expanduser()8081    @property82    def logs_path(self) -> Path:83        return (self.log_dir or self.root / "logs").expanduser()8485    @property86    def db_path(self) -> Path:87        return (self.database_path or self.data_path / "llm-api.db").expanduser()8889    @property90    def secret(self) -> str:91        if self.secret_key:92            return self.secret_key93        # Persist a generated secret so sessions survive restarts.94        p = self.data_path / ".secret"95        p.parent.mkdir(parents=True, exist_ok=True)96        if p.exists():97            return p.read_text().strip()98        import secrets99100        s = secrets.token_hex(32)101        p.write_text(s)102        os.chmod(p, 0o600)103        return s104105    def ensure_dirs(self) -> None:106        for d in (107            self.models_dir,108            self.models_dir / "mlx",109            self.models_dir / "gguf",110            self.models_dir / "embeddings",111            self.models_dir / "rerankers",112            self.models_dir / "vision",113            self.models_dir / "manifests",114            self.data_path,115            self.logs_path,116        ):117            d.mkdir(parents=True, exist_ok=True)118119120@lru_cache121def get_settings() -> Settings:122    return Settings()123