Self-hosted knowledge management for SMEs: a split-screen Markdown editor whose sections an LLM refines while you write, and RAG question answering over the documents that result. FastAPI + Postgres/pgvector on the back, SvelteKit on the front, everything OpenAI-compatible and self-hostable. Squashed into a single commit; the development history stays local. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CA43ZJda8Rbp2hKXNy8f6b
65 lines
2.3 KiB
Python
65 lines
2.3 KiB
Python
from functools import lru_cache
|
|
from pathlib import Path
|
|
from typing import Literal
|
|
|
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
|
|
# Repo-root .env for native dev; inside Docker the file is absent and
|
|
# configuration comes from real environment variables (which take precedence).
|
|
_REPO_ROOT = Path(__file__).resolve().parents[2]
|
|
_ENV_FILE = _REPO_ROOT / ".env"
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
model_config = SettingsConfigDict(
|
|
env_prefix="PABLAN_", env_file=_ENV_FILE, extra="ignore"
|
|
)
|
|
|
|
env: Literal["development", "production"] = "development"
|
|
database_url: str = "postgresql+asyncpg://pablan:change-me@localhost:5432/pablan"
|
|
|
|
# Secure=false is needed for dev over plain http on non-localhost
|
|
# addresses (WireGuard IPs) — see .env.example.
|
|
cookie_secure: bool = True
|
|
auth_session_ttl_days: int = 14
|
|
|
|
query_retention_days: int = 90
|
|
|
|
# The shipped template catalog (repo templates/ in dev; the customer
|
|
# stack mounts the directory and overrides this path).
|
|
templates_dir: str = str(_REPO_ROOT / "templates")
|
|
help_dir: str = str(_REPO_ROOT / "help")
|
|
|
|
# The instance's own language: which blueprint variant the first-install
|
|
# starter set uses, and the fallback when a visitor states no preference.
|
|
# Per-user choice lives on users.locale and wins over this.
|
|
default_locale: Literal["de", "en"] = "de"
|
|
|
|
log_level: str = "INFO"
|
|
# Content debug logging (prompts/responses) — NEVER in production.
|
|
debug_log_prompts: bool = False
|
|
llm_timeout_seconds: float = 120.0
|
|
# How many requests Pablan lets one endpoint see at once, and how long a
|
|
# request waits for a free slot before it is answered with "busy". Match
|
|
# llm_max_parallel to the server's parallel slots (llama.cpp: --parallel).
|
|
# See app/llm/gate.py.
|
|
llm_max_parallel: int = 4
|
|
llm_queue_wait_seconds: float = 20.0
|
|
llm_max_queued: int = 24
|
|
job_poll_seconds: float = 1.0
|
|
|
|
chat_base_url: str = "http://localhost:8001/v1"
|
|
chat_api_key: str = "none"
|
|
chat_model: str = ""
|
|
utility_base_url: str = "http://localhost:8001/v1"
|
|
utility_api_key: str = "none"
|
|
utility_model: str = ""
|
|
embedding_base_url: str = "http://localhost:8002/v1"
|
|
embedding_api_key: str = "none"
|
|
embedding_model: str = ""
|
|
|
|
|
|
@lru_cache
|
|
def get_settings() -> Settings:
|
|
return Settings()
|