petter2025's picture
Update config/settings.py
f899610 verified
raw
history blame
4.84 kB
"""
Configuration management for ARF Demo
Updated for Pydantic v2 with pydantic-settings
"""
from typing import Optional, Dict, Any, List
from enum import Enum
import os
import logging
logger = logging.getLogger(__name__)
# Try to import from pydantic-settings, fallback to pydantic
try:
from pydantic_settings import BaseSettings
from pydantic import Field, validator
PYDANTIC_V2 = True
logger.info("Using pydantic-settings for BaseSettings")
except ImportError:
try:
from pydantic import BaseSettings, Field, validator
PYDANTIC_V2 = False
logger.info("Using pydantic.BaseSettings (older version)")
except ImportError as e:
logger.error(f"Failed to import pydantic: {e}")
# Create minimal fallback
class BaseSettings:
def __init__(self, **kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
class Field:
@staticmethod
def default(value):
return value
def validator(*args, **kwargs):
def decorator(func):
return func
return decorator
PYDANTIC_V2 = False
class ARFMode(str, Enum):
"""ARF operation modes"""
DEMO = "demo"
OSS = "oss"
ENTERPRISE = "enterprise"
class SafetyMode(str, Enum):
"""Safety modes for execution"""
ADVISORY = "advisory"
APPROVAL = "approval"
AUTONOMOUS = "autonomous"
class Settings(BaseSettings):
"""
Application settings with environment variable support
"""
# ===== System Mode =====
arf_mode: ARFMode = Field(
default=ARFMode.DEMO,
description="ARF operation mode"
)
use_mock_arf: bool = Field(
default=True,
description="Use mock ARF implementation (for demo mode)"
)
# ===== ARF Configuration =====
arf_api_key: Optional[str] = Field(
default=None,
description="ARF API key for real integration"
)
arf_base_url: str = Field(
default="https://api.arf.dev",
description="ARF API base URL"
)
# ===== Business Configuration =====
engineer_hourly_rate: float = Field(
default=150.0,
description="Engineer hourly rate in USD"
)
engineer_annual_cost: float = Field(
default=125000.0,
description="Engineer annual cost in USD"
)
default_savings_rate: float = Field(
default=0.82,
description="Default savings rate with ARF"
)
# ===== UI Configuration =====
auto_refresh_seconds: int = Field(
default=30,
description="Auto-refresh interval in seconds"
)
max_history_items: int = Field(
default=100,
description="Maximum history items to display"
)
# ===== Demo Configuration =====
default_scenario: str = Field(
default="Cache Miss Storm",
description="Default incident scenario"
)
scenario_config_path: str = Field(
default="config/scenarios",
description="Path to scenario configuration files"
)
# ===== Safety Configuration =====
default_safety_mode: SafetyMode = Field(
default=SafetyMode.ADVISORY,
description="Default safety mode"
)
require_approval: bool = Field(
default=True,
description="Require human approval for execution"
)
# ===== Validation =====
@validator("arf_api_key")
def validate_api_key(cls, v: Optional[str], values: Dict[str, Any]) -> Optional[str]:
if values.get("arf_mode") == ARFMode.ENTERPRISE and not v:
raise ValueError("ARF API key required for Enterprise mode")
return v
@validator("use_mock_arf")
def validate_mock_mode(cls, v: bool, values: Dict[str, Any]) -> bool:
if values.get("arf_mode") == ARFMode.DEMO:
return True
return v
class Config:
env_file = ".env"
env_file_encoding = "utf-8"
case_sensitive = False
use_enum_values = True
# Global settings instance with fallback
try:
settings = Settings()
except Exception as e:
logger.warning(f"Failed to load settings from .env: {e}, using defaults")
settings = Settings(
arf_mode=ARFMode.DEMO,
use_mock_arf=True,
engineer_hourly_rate=150.0,
engineer_annual_cost=125000.0,
default_savings_rate=0.82,
auto_refresh_seconds=30,
max_history_items=100,
default_scenario="Cache Miss Storm",
scenario_config_path="config/scenarios",
default_safety_mode=SafetyMode.ADVISORY,
require_approval=True
)
def get_settings() -> Settings:
"""Get settings instance (singleton pattern)"""
return settings