"""Configuration settings for AI Software Factory.""" import os from typing import Optional from pathlib import Path from pydantic import Field from pydantic_settings import BaseSettings class Settings(BaseSettings): """Application settings loaded from environment variables.""" # Server settings HOST: str = "0.0.0.0" PORT: int = 8000 LOG_LEVEL: str = "INFO" # Ollama settings computed from environment OLLAMA_URL: str = "http://ollama:11434" OLLAMA_MODEL: str = "llama3" # Gitea settings GITEA_URL: str = "https://gitea.yourserver.com" GITEA_TOKEN: str = "" GITEA_OWNER: str = "ai-software-factory" GITEA_REPO: str = "ai-software-factory" # n8n settings N8N_WEBHOOK_URL: str = "" N8N_API_URL: str = "" N8N_USER: str = "" N8N_PASSWORD: str = "" # Telegram settings TELEGRAM_BOT_TOKEN: str = "" TELEGRAM_CHAT_ID: str = "" # PostgreSQL settings POSTGRES_HOST: str = "localhost" POSTGRES_PORT: int = 5432 POSTGRES_USER: str = "postgres" POSTGRES_PASSWORD: str = "" POSTGRES_DB: str = "ai_software_factory" POSTGRES_TEST_DB: str = "ai_software_factory_test" POSTGRES_URL: Optional[str] = None # Optional direct PostgreSQL connection URL # SQLite settings for testing USE_SQLITE: bool = True # Enable SQLite by default for testing SQLITE_DB_PATH: str = "sqlite.db" # Database connection pool settings (only for PostgreSQL) DB_POOL_SIZE: int = 10 DB_MAX_OVERFLOW: int = 20 DB_POOL_RECYCLE: int = 3600 DB_POOL_TIMEOUT: int = 30 @property def pool(self) -> dict: """Get database pool configuration.""" return { "pool_size": self.DB_POOL_SIZE, "max_overflow": self.DB_MAX_OVERFLOW, "pool_recycle": self.DB_POOL_RECYCLE, "pool_timeout": self.DB_POOL_TIMEOUT } @property def database_url(self) -> str: """Get database connection URL.""" if self.USE_SQLITE: return f"sqlite:///{self.SQLITE_DB_PATH}" return ( f"postgresql://{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}" f"@{self.POSTGRES_HOST}:{self.POSTGRES_PORT}/{self.POSTGRES_DB}" ) @property def test_database_url(self) -> str: """Get test database connection URL.""" if self.USE_SQLITE: return f"sqlite:///{self.SQLITE_DB_PATH}" return ( f"postgresql://{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}" f"@{self.POSTGRES_HOST}:{self.POSTGRES_PORT}/{self.POSTGRES_TEST_DB}" ) @property def ollama_url(self) -> str: """Get Ollama URL with trimmed whitespace.""" return self.OLLAMA_URL.strip() @property def gitea_url(self) -> str: """Get Gitea URL with trimmed whitespace.""" return self.GITEA_URL.strip() @property def gitea_token(self) -> str: """Get Gitea token with trimmed whitespace.""" return self.GITEA_TOKEN.strip() @property def n8n_webhook_url(self) -> str: """Get n8n webhook URL with trimmed whitespace.""" return self.N8N_WEBHOOK_URL.strip() @property def telegram_bot_token(self) -> str: """Get Telegram bot token with trimmed whitespace.""" return self.TELEGRAM_BOT_TOKEN.strip() @property def telegram_chat_id(self) -> str: """Get Telegram chat ID with trimmed whitespace.""" return self.TELEGRAM_CHAT_ID.strip() @property def postgres_host(self) -> str: """Get PostgreSQL host.""" return self.POSTGRES_HOST.strip() @property def postgres_port(self) -> int: """Get PostgreSQL port as integer.""" return int(self.POSTGRES_PORT) @property def postgres_user(self) -> str: """Get PostgreSQL user.""" return self.POSTGRES_USER.strip() @property def postgres_password(self) -> str: """Get PostgreSQL password.""" return self.POSTGRES_PASSWORD.strip() @property def postgres_db(self) -> str: """Get PostgreSQL database name.""" return self.POSTGRES_DB.strip() @property def postgres_test_db(self) -> str: """Get test PostgreSQL database name.""" return self.POSTGRES_TEST_DB.strip() class Config: env_file = ".env" env_file_encoding = "utf-8" extra = "ignore" # Create instance for module-level access settings = Settings()