Spaces:
Running
Running
| # src/core/config.py | |
| import os | |
| from urllib.parse import quote_plus | |
| from pydantic_settings import BaseSettings | |
| from pydantic import Field, computed_field | |
| from typing import List, Optional | |
| from functools import lru_cache | |
| from dotenv import load_dotenv, find_dotenv | |
| _ = load_dotenv(find_dotenv()) | |
| class Settings(BaseSettings): | |
| """ | |
| Application settings. | |
| Values can come from: | |
| 1. Environment variables | |
| 2. .env file | |
| 3. Default values in this class | |
| Priority: Environment variables > .env file > defaults | |
| """ | |
| # ===== APP SETTINGS ===== | |
| APP_NAME: str = "Agentic Chatbot" | |
| DEBUG: bool = False | |
| ENVIRONMENT: str = "development" # development, staging, production | |
| # ===== SERVER SETTINGS ===== | |
| HOST: str = "0.0.0.0" | |
| PORT: int = 8000 | |
| WORKERS: int = 4 | |
| # ===== DATABASE (Supabase PostgreSQL) ===== | |
| # Individual DB components for proper URL encoding | |
| DB_USER: str = Field(default="", description="Database username") | |
| DB_PASSWORD: str = Field(default="", description="Database password (will be URL encoded)") | |
| DB_HOST: str = Field(default="", description="Database host") | |
| DB_PORT: int = Field(default=6543, description="Database port") | |
| DB_NAME: str = Field(default="postgres", description="Database name") | |
| # Raw DATABASE_URL (fallback if components not provided) | |
| DATABASE_URL_RAW: str = Field( | |
| default="", | |
| alias="DATABASE_URL", | |
| description="Raw DATABASE_URL (use DB_* components instead for special chars)" | |
| ) | |
| def DATABASE_URL(self) -> str: | |
| """Build DATABASE_URL with properly encoded password.""" | |
| # If individual components are provided, build URL from them | |
| if self.DB_USER and self.DB_PASSWORD and self.DB_HOST: | |
| encoded_password = quote_plus(self.DB_PASSWORD) | |
| return f"postgresql+asyncpg://{self.DB_USER}:{encoded_password}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}" | |
| # Fallback to raw DATABASE_URL | |
| return self.DATABASE_URL_RAW | |
| # ===== SUPABASE ===== | |
| SUPABASE_URL: str = Field(default="https://hsmtojoigweyexzczjap.supabase.co", description="Supabase project URL") | |
| SUPABASE_API_KEY: str = Field(default="sb_publishable_BD9CDK3YcHSUmC0gXRUSdw_V2G5cwIW", description="Supabase anon/public API key") | |
| # ===== REDIS ===== | |
| REDIS_URL: str = Field(default=os.getenv("REDIS_URL", "redis://localhost:6379/0"), description="Redis connection string") | |
| # ===== SECURITY ===== | |
| SECRET_KEY: str = Field(default=os.getenv("SECRET_KEY", "your-super-secret-key-at-least-32-characters-long"), description="JWT secret key") | |
| JWT_ALGORITHM: str = "HS256" | |
| ACCESS_TOKEN_EXPIRE_MINUTES: int = 30 | |
| # ===== OPTIONAL SETTINGS ===== | |
| CORS_ORIGINS: List[str] = Field(default=["http://localhost:3000", "http://localhost:8080"], description="CORS allowed origins") | |
| LOG_LEVEL: str = "INFO" | |
| class Config: | |
| # Tell Pydantic to read from .env file | |
| env_file = ".env" | |
| env_file_encoding = "utf-8" | |
| # Make field names case-sensitive | |
| case_sensitive = True | |
| # Allow extra fields from .env without raising validation error | |
| extra = "ignore" | |
| # CACHE THE SETTINGS | |
| # lru_cache means "only create this once, then reuse" | |
| def get_settings() -> Settings: | |
| """ | |
| Get cached settings instance. | |
| Why cache? Settings are read from files/environment, | |
| which is slow. We only need to do it once. | |
| """ | |
| return Settings() | |
| # For easy import | |
| settings = get_settings() |