Files
ProfessorNovaandClaude Opus 5 784b76baf7 Pablan, as it stands
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
2026-09-04 09:21:37 +02:00

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()