Files
library-desk/src/config.py
T
jpmschweitzerandClaude Opus 4.5 3deed7cbcb chore: add version management and changelog
- Add pyproject.toml with project metadata and version (1.1.0)
- Update config.py to read version from pyproject.toml
- Update main.py to use centralized version in FastAPI app
- Add CHANGELOG.md documenting v1.0.0 and v1.1.0 changes

Version is now the single source of truth in pyproject.toml and is
displayed in the health check endpoint and API docs.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-11 20:23:56 +01:00

110 lines
4.8 KiB
Python

"""
Application configuration using Pydantic Settings.
Following best practices: modular settings, environment-based config.
"""
from functools import lru_cache
from pathlib import Path
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
# Read version from pyproject.toml
try:
import tomllib
_pyproject_path = Path(__file__).parent.parent / "pyproject.toml"
with open(_pyproject_path, "rb") as f:
_pyproject = tomllib.load(f)
__version__ = _pyproject["project"]["version"]
except Exception:
__version__ = "0.0.0" # Fallback if pyproject.toml not found
class Settings(BaseSettings):
"""Application settings loaded from environment variables."""
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False,
extra="ignore",
)
# API Configuration
library_api_key: str = Field(..., description="API key for authentication")
# Neo4j Configuration
neo4j_uri: str = Field(default="bolt://neo4j:7687", description="Neo4j Bolt URI")
neo4j_user: str = Field(default="neo4j", description="Neo4j username")
neo4j_password: str = Field(..., description="Neo4j password")
# Qdrant Configuration
qdrant_host: str = Field(default="qdrant", description="Qdrant host")
qdrant_port: int = Field(default=6333, description="Qdrant port")
# Wiki.js Configuration
wikijs_url: str = Field(default="http://wiki:3000", description="Wiki.js URL")
wikijs_username: str = Field(..., description="Wiki.js username")
wikijs_password: str = Field(..., description="Wiki.js password")
# Wiki.js Database Configuration (for change listener)
wikijs_db_host: str = Field(default="postgres-shared", description="Wiki.js PostgreSQL host")
wikijs_db_port: int = Field(default=5432, description="Wiki.js PostgreSQL port")
wikijs_db_name: str = Field(default="library", description="Wiki.js database name")
wikijs_db_user: str = Field(default="library_desk_listener", description="Wiki.js database user (read-only)")
wikijs_db_password: str = Field(..., description="Wiki.js database password")
wikijs_change_listener_debounce_seconds: int = Field(
default=5,
ge=1,
le=60,
description="Debounce duration to prevent processing duplicate notifications"
)
# SearXNG Configuration
searxng_url: str = Field(default="http://searxng:8080", description="SearXNG URL")
# Ollama Configuration (for embeddings)
ollama_url: str = Field(default="http://ollama:11434", description="Ollama URL")
ollama_model: str = Field(default="nomic-embed-text", description="Ollama embedding model")
# HybridRAG Configuration
reranker_model: str = Field(default="mistral-nemo", description="Model for LLM re-ranking")
reranker_enabled: bool = Field(default=True, description="Enable LLM re-ranking")
hybrid_rag_vector_limit: int = Field(default=10, ge=1, le=50, description="Vector search limit")
hybrid_rag_graph_limit: int = Field(default=10, ge=1, le=50, description="Graph search limit")
hybrid_rag_web_limit: int = Field(default=5, ge=1, le=20, description="Web search limit")
# Entity Linking Fuzzy Matching Configuration
entity_linking_min_confidence: float = Field(default=0.70, ge=0.0, le=1.0, description="Minimum confidence for entity-document matching")
entity_linking_min_entity_length: int = Field(default=5, ge=1, le=50, description="Minimum entity name length for matching")
entity_linking_min_containment_ratio: float = Field(default=0.30, ge=0.0, le=1.0, description="Minimum containment ratio for substring matching")
entity_linking_min_token_overlap: float = Field(default=0.60, ge=0.0, le=1.0, description="Minimum token overlap ratio for matching")
# Redis Configuration (for job tracking - separate DB from wiki)
redis_host: str = Field(default="redis-shared", description="Redis host")
redis_port: int = Field(default=6379, description="Redis port")
redis_db: int = Field(default=4, description="Redis database number (4 for library-desk jobs)")
# Application
app_name: str = Field(default="Library Desk", description="Application name")
app_version: str = Field(default=__version__, description="Application version")
debug: bool = Field(default=False, description="Debug mode")
@property
def qdrant_url(self) -> str:
"""Computed Qdrant URL."""
return f"http://{self.qdrant_host}:{self.qdrant_port}"
@property
def redis_url(self) -> str:
"""Computed Redis URL."""
return f"redis://{self.redis_host}:{self.redis_port}/{self.redis_db}"
@lru_cache
def get_settings() -> Settings:
"""
Get cached settings instance.
Uses lru_cache to ensure single instance across app.
"""
return Settings()