"""Application settings using pydantic-settings.""" from pydantic_settings import BaseSettings, SettingsConfigDict from typing import Optional, Dict class Settings(BaseSettings): """Application settings loaded from environment variables.""" # API Keys openai_api_key: str mistralai_api_key: str # JWT Security jwt_secret_key: str jwt_algorithm: str = "HS256" jwt_expiration_minutes: int = 60 # API Config api_title: str = "CAPL Routeur IA API" api_version: str = "1.0.0" environment: str = "development" # LangSmith (optional) langchain_tracing_v2: bool = False langchain_api_key: Optional[str] = None langchain_project: str = "routeur-ia" # Supabase / RAG supabase_url: Optional[str] = None supabase_key: Optional[str] = None supabase_table: str = "documents" supabase_match_fn: str = "match_documents" rag_top_k: int = 5 # Multi-index (logical index name -> Supabase table + match function) # Can be overridden via .env using a JSON structure if desired vector_indexes: Dict[str, Dict[str, str]] = { "default": {"table": "documents", "query_name": "match_documents"}, # Example additional indexes (create corresponding table and function in Supabase) "projects": {"table": "project_documents", "query_name": "match_project_documents"}, # "formations": {"table": "formations", "query_name": "match_formations"}, } # Upload & chunking (PDF ingestion) max_upload_mb_pdf: int = 50 chunk_size: int = 1000 chunk_overlap: int = 100 doc_default_type: str = "project_doc" # Post-processing pipeline configuration postprocessors_enabled: list[str] = [ "carbon_impact", "pricing", "equivalences", ] currency: str = "USD" # Pricing per 1,000,000 tokens (input/output) pricing: dict = { # Complete or override in .env via nested JSON if needed "mistral-medium-latest": {"input_per_1m": 0.40, "output_per_1m": 2.00}, "mistral-small-latest": {"input_per_1m": 0.10, "output_per_1m": 0.30}, "mistral-large-latest": {"input_per_1m": 2.00, "output_per_1m": 6.00}, "magistral-small-latest": {"input_per_1m": 0.50, "output_per_1m": 1.50}, "magistral-medium-latest": {"input_per_1m": 2.00, "output_per_1m": 5.00}, } # Equivalence ratios using kgCO2eq as input equivalence_ratios: dict = { # https://impactco2.fr/outils/comparateur # Ratios expressed as UNITS per kgCO2eq (invert of kgCO2 per unit) # smartphone: 85.9 kgCO2 per unit → 1 / 85.9 ≈ 0.011643 smartphones per kgCO2 "smartphone_per_kgCO2eq": 0.011643, # car (km): 219 g CO2 per km → 0.219 kg per km → 1 / 0.219 ≈ 4.566210 km per kgCO2 "car_km_per_kgCO2eq": 4.566210, # tgv (km): 2.93 g CO2 per km → 0.00293 kg per km → 1 / 0.00293 ≈ 341.296928 km per kgCO2 "tgv_km_per_kgCO2eq": 341.296928, # water (l): 321 g CO2 per liter → 0.321 kg per liter → 1 / 0.321 ≈ 3.115265 liters per kgCO2 "water_l_per_kgCO2eq": 3.115265, } # Voice / Pipecat voice_enabled: bool = True voice_stt_model: str = "whisper-1" voice_stt_language: str = "fr" voice_tts_voice: str = "alloy" voice_tts_model: str = "tts-1" voice_default_model: str = "mistral-large-latest" voice_max_response_length: int = 500 # VAD (Voice Activity Detection) defaults - overridable via client request_data voice_vad_stop_secs: float = 0.2 voice_vad_start_secs: float = 0.2 voice_vad_confidence: float = 0.7 voice_vad_min_volume: float = 0.6 # Voice / WebRTC ICE servers (TURN/STUN for NAT traversal) # Option 1: Static JSON array in VOICE_ICE_SERVERS (e.g. from Metered dashboard) voice_ice_servers: Optional[str] = None # Option 2: Twilio TURN - often works on HF Spaces (streamlit-webrtc examples) twilio_account_sid: Optional[str] = None twilio_auth_token: Optional[str] = None # Option 3: Metered API - fetch dynamically at startup metered_app_name: Optional[str] = None metered_api_key: Optional[str] = None # Voice / Daily.co (alternative transport for HF Spaces, NAT traversal) daily_api_key: Optional[str] = None model_config = SettingsConfigDict( env_file=".env", env_file_encoding="utf-8", case_sensitive=False, extra="ignore" ) # Singleton instance settings = Settings()