""" File with environment variables and general configuration logic. Environment variables are loaded from `.env`, with default values as fallback. For project metadata, pyproject.toml is used. Complex types like lists are read as JSON-encoded strings. """ import tomllib from pathlib import Path from typing import Literal from urllib.parse import quote_plus from environs import Env from pydantic import validator from pydantic_settings import BaseSettings from structlog.stdlib import BoundLogger from app.core.logger import Logger PROJECT_DIR = Path(__file__).parent.parent.parent with open(f"{PROJECT_DIR}/pyproject.toml", "rb") as f: PYPROJECT_CONTENT = tomllib.load(f)["tool"]["poetry"] env = Env() env.read_env() CORS_ALLOWED_HEADERS = list(map(str.strip, env.list("CORS_ALLOWED_HEADERS", ["*"]))) CORS_ORIGINS = list(map(str.strip, env.list("CORS_ORIGINS", ["http://localhost:3000"]))) class Settings(BaseSettings): # CORE SETTINGS ENVIRONMENT: Literal["DEV", "STG", "PROD"] = env.str("ENVIRONMENT", "DEV").upper() # CORS SETTINGS # BACKEND_CORS_ORIGINS: list[str] = env.list("BACKEND_CORS_ORIGINS", ["http://localhost:3000"]) # BACKEND_CORS_HEADERS: list[str] = env.list("BACKEND_CORS_HEADERS", ["*"]) # ALLOWED_HOSTS: list[str] = env.list("ALLOWED_HOSTS", ["*"]) # LOG SETTINGS LOG_LEVEL: Literal["INFO", "DEBUG", "WARN", "ERROR"] = env.str("LOG_LEVEL", "INFO") LOG_JSON_FORMAT: bool = env.bool("LOG_JSON_FORMAT", False) # PROJECT NAME, VERSION AND DESCRIPTION PROJECT_NAME: str = PYPROJECT_CONTENT["name"] VERSION: str = PYPROJECT_CONTENT["version"] DESCRIPTION: str = PYPROJECT_CONTENT["description"] ROOT_PATH: str = env.str("ROOT_PATH", "") # DOCS SETTINGS DOCS_URL: str = f"{ROOT_PATH}/docs" OPENAPI_URL: str = f"{ROOT_PATH}/openapi.json" # POSTGRESQL DATABASE SETTINGS DATABASE_HOSTNAME: str = env.str("DATABASE_HOSTNAME") DATABASE_USER: str = env.str("DATABASE_USER") DATABASE_PASSWORD: str = env.str("DATABASE_PASSWORD") DATABASE_PORT: str = env.str("DATABASE_PORT", "5432") DATABASE_DB: str = env.str("DATABASE_DB") SQLALCHEMY_DATABASE_URI: str = "" @validator("SQLALCHEMY_DATABASE_URI") def _assemble_db_connection(cls, v: str, values: dict[str, str]) -> str: return "postgresql+asyncpg://{}:{}@{}:{}/{}".format( values["DATABASE_USER"], quote_plus(values["DATABASE_PASSWORD"]), values["DATABASE_HOSTNAME"], values["DATABASE_PORT"], values["DATABASE_DB"], ) # UVICORN SETTINGS UVICORN_HOST: str = env.str("UVICORN_HOST", "0.0.0.0") UVICORN_PORT: int = env.int("UVICORN_PORT", 5001) CACHE_HOST: str = env.str("CACHE_HOST", "localhost") CACHE_PORT: int = env.int("CACHE_PORT", 11211) CACHE_TTL: int = env.int("CACHE_TTL", 300) BEDROCK_MODEL_ID: str = env.str("BEDROCK_MODEL_ID", "anthropic.claude-v2") BEDROCK_PROVIDER: str = env.str("BEDROCK_PROVIDER", "anthropic") AWS_ACCESS_KEY: str = env.str("AWS_ACCESS_KEY", "") AWS_SECRET_KEY: str = env.str("AWS_SECRET_KEY", "") AWS_REGION: str = env.str("AWS_REGION", "us-east-1") TOKENIZER_MODEL: str = env.str("TOKENIZER_MODEL") TOKEN_LIMIT_PER_REQUEST: int = env.int("TOKEN_LIMIT_PER_REQUEST", 20000) settings: Settings = Settings() # type: ignore log: BoundLogger = Logger( json_logs=settings.LOG_JSON_FORMAT, log_level=settings.LOG_LEVEL ).setup_logging()