chatbot / src /core /config /config.py
jawadsaghir12's picture
Add application file
a8a2cf5
# 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)"
)
@computed_field
@property
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"
@lru_cache()
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()