Spaces:
Sleeping
Sleeping
File size: 8,436 Bytes
9f5ee50 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
"""
Application Settings
Design System Extractor v2
Loads configuration from environment variables and YAML files.
"""
import os
from pathlib import Path
from typing import Optional
from dataclasses import dataclass, field
from dotenv import load_dotenv
import yaml
# Load environment variables from .env file
env_path = Path(__file__).parent / ".env"
if env_path.exists():
load_dotenv(env_path)
else:
# Try loading from parent directory (for development)
load_dotenv(Path(__file__).parent.parent / ".env")
@dataclass
class HFSettings:
"""Hugging Face configuration."""
hf_token: str = field(default_factory=lambda: os.getenv("HF_TOKEN", ""))
hf_space_name: str = field(default_factory=lambda: os.getenv("HF_SPACE_NAME", ""))
use_inference_api: bool = field(default_factory=lambda: os.getenv("USE_HF_INFERENCE_API", "true").lower() == "true")
inference_timeout: int = field(default_factory=lambda: int(os.getenv("HF_INFERENCE_TIMEOUT", "120")))
max_new_tokens: int = field(default_factory=lambda: int(os.getenv("HF_MAX_NEW_TOKENS", "2048")))
temperature: float = field(default_factory=lambda: float(os.getenv("HF_TEMPERATURE", "0.3")))
@dataclass
class ModelSettings:
"""Model configuration for each agent — Diverse providers."""
# Agent 1: Rule-based, no LLM needed
# Agent 2 (Normalizer): Fast structured output
# Default: Microsoft Phi (fast, great structured output)
agent2_model: str = field(default_factory=lambda: os.getenv("AGENT2_MODEL", "microsoft/Phi-3.5-mini-instruct"))
# Agent 3 (Advisor): Strong reasoning - MOST IMPORTANT
# Default: Meta Llama 70B (excellent reasoning)
agent3_model: str = field(default_factory=lambda: os.getenv("AGENT3_MODEL", "meta-llama/Llama-3.1-70B-Instruct"))
# Agent 4 (Generator): Code/JSON specialist
# Default: Mistral Codestral (code specialist)
agent4_model: str = field(default_factory=lambda: os.getenv("AGENT4_MODEL", "mistralai/Codestral-22B-v0.1"))
# Fallback
fallback_model: str = field(default_factory=lambda: os.getenv("FALLBACK_MODEL", "mistralai/Mistral-7B-Instruct-v0.3"))
@dataclass
class APISettings:
"""API key configuration (optional alternatives)."""
anthropic_api_key: str = field(default_factory=lambda: os.getenv("ANTHROPIC_API_KEY", ""))
openai_api_key: str = field(default_factory=lambda: os.getenv("OPENAI_API_KEY", ""))
@dataclass
class BrowserSettings:
"""Playwright browser configuration."""
browser_type: str = field(default_factory=lambda: os.getenv("BROWSER_TYPE", "chromium"))
headless: bool = field(default_factory=lambda: os.getenv("BROWSER_HEADLESS", "true").lower() == "true")
timeout: int = field(default_factory=lambda: int(os.getenv("BROWSER_TIMEOUT", "30000")))
network_idle_timeout: int = field(default_factory=lambda: int(os.getenv("NETWORK_IDLE_TIMEOUT", "5000")))
@dataclass
class CrawlSettings:
"""Website crawling configuration."""
max_pages: int = field(default_factory=lambda: int(os.getenv("MAX_PAGES", "20")))
min_pages: int = field(default_factory=lambda: int(os.getenv("MIN_PAGES", "10")))
crawl_delay_ms: int = field(default_factory=lambda: int(os.getenv("CRAWL_DELAY_MS", "1000")))
max_concurrent: int = field(default_factory=lambda: int(os.getenv("MAX_CONCURRENT_CRAWLS", "3")))
respect_robots_txt: bool = field(default_factory=lambda: os.getenv("RESPECT_ROBOTS_TXT", "true").lower() == "true")
@dataclass
class ViewportSettings:
"""Viewport configuration for extraction."""
desktop_width: int = 1440
desktop_height: int = 900
mobile_width: int = 375
mobile_height: int = 812
@dataclass
class StorageSettings:
"""Persistent storage configuration."""
storage_path: str = field(default_factory=lambda: os.getenv("STORAGE_PATH", "/data"))
enable_persistence: bool = field(default_factory=lambda: os.getenv("ENABLE_PERSISTENCE", "true").lower() == "true")
max_versions: int = field(default_factory=lambda: int(os.getenv("MAX_VERSIONS", "10")))
@dataclass
class UISettings:
"""UI configuration."""
server_port: int = field(default_factory=lambda: int(os.getenv("SERVER_PORT", "7860")))
share: bool = field(default_factory=lambda: os.getenv("SHARE", "false").lower() == "true")
theme: str = field(default_factory=lambda: os.getenv("UI_THEME", "soft"))
@dataclass
class FeatureFlags:
"""Feature toggles."""
color_ramps: bool = field(default_factory=lambda: os.getenv("FEATURE_COLOR_RAMPS", "true").lower() == "true")
type_scales: bool = field(default_factory=lambda: os.getenv("FEATURE_TYPE_SCALES", "true").lower() == "true")
a11y_checks: bool = field(default_factory=lambda: os.getenv("FEATURE_A11Y_CHECKS", "true").lower() == "true")
parallel_extraction: bool = field(default_factory=lambda: os.getenv("FEATURE_PARALLEL_EXTRACTION", "true").lower() == "true")
@dataclass
class Settings:
"""Main settings container."""
debug: bool = field(default_factory=lambda: os.getenv("DEBUG", "false").lower() == "true")
log_level: str = field(default_factory=lambda: os.getenv("LOG_LEVEL", "INFO"))
hf: HFSettings = field(default_factory=HFSettings)
models: ModelSettings = field(default_factory=ModelSettings)
api: APISettings = field(default_factory=APISettings)
browser: BrowserSettings = field(default_factory=BrowserSettings)
crawl: CrawlSettings = field(default_factory=CrawlSettings)
viewport: ViewportSettings = field(default_factory=ViewportSettings)
storage: StorageSettings = field(default_factory=StorageSettings)
ui: UISettings = field(default_factory=UISettings)
features: FeatureFlags = field(default_factory=FeatureFlags)
# Agent configuration loaded from YAML
agents_config: dict = field(default_factory=dict)
def __post_init__(self):
"""Load agent configuration from YAML after initialization."""
self.load_agents_config()
def load_agents_config(self):
"""Load agent personas and settings from YAML file."""
yaml_path = Path(__file__).parent / "agents.yaml"
if yaml_path.exists():
with open(yaml_path, "r") as f:
self.agents_config = yaml.safe_load(f)
else:
print(f"Warning: agents.yaml not found at {yaml_path}")
self.agents_config = {}
def get_agent_persona(self, agent_name: str) -> str:
"""Get persona string for an agent."""
agent_key = f"agent_{agent_name}"
if agent_key in self.agents_config:
return self.agents_config[agent_key].get("persona", "")
return ""
def get_agent_config(self, agent_name: str) -> dict:
"""Get full configuration for an agent."""
agent_key = f"agent_{agent_name}"
return self.agents_config.get(agent_key, {})
def get_model_for_agent(self, agent_name: str) -> str:
"""Get the model ID for a specific agent."""
model_map = {
"normalizer": self.models.agent2_model,
"advisor": self.models.agent3_model,
"generator": self.models.agent4_model,
}
return model_map.get(agent_name, self.models.fallback_model)
def validate(self) -> list[str]:
"""Validate settings and return list of errors."""
errors = []
if not self.hf.hf_token:
errors.append("HF_TOKEN is required for model inference")
if self.crawl.max_pages < self.crawl.min_pages:
errors.append("MAX_PAGES must be >= MIN_PAGES")
return errors
# Global settings instance
settings = Settings()
def get_settings() -> Settings:
"""Get the global settings instance."""
return settings
def reload_settings() -> Settings:
"""Reload settings from environment and config files."""
global settings
settings = Settings()
return settings
# Convenience functions
def is_debug() -> bool:
"""Check if debug mode is enabled."""
return settings.debug
def get_hf_token() -> str:
"""Get HuggingFace token."""
return settings.hf.hf_token
def get_agent_persona(agent_name: str) -> str:
"""Get persona for an agent."""
return settings.get_agent_persona(agent_name)
def get_model_for_agent(agent_name: str) -> str:
"""Get model ID for an agent."""
return settings.get_model_for_agent(agent_name)
|