Spaces:
Runtime error
Runtime error
Update api/config.py
Browse files- api/config.py +25 -131
api/config.py
CHANGED
|
@@ -58,7 +58,6 @@ class Settings(BaseSettings):
|
|
| 58 |
BACKUP_PATH: str = Field(default="./data/backups", env="BACKUP_PATH")
|
| 59 |
|
| 60 |
MAX_UPLOAD_SIZE_MB: int = Field(default=500, env="MAX_UPLOAD_SIZE_MB")
|
| 61 |
-
ALLOWED_EXTENSIONS: List[str] = [".jsonl", ".json", ".txt"]
|
| 62 |
|
| 63 |
# ========================================================================
|
| 64 |
# LLM PROVIDERS API KEYS
|
|
@@ -94,22 +93,20 @@ class Settings(BaseSettings):
|
|
| 94 |
LOG_FORMAT: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
| 95 |
LOG_FILE_ENABLED: bool = Field(default=True, env="LOG_FILE_ENABLED")
|
| 96 |
LOG_FILE_PATH: str = Field(default="./logs", env="LOG_FILE_PATH")
|
| 97 |
-
LOG_FILE_MAX_BYTES: int = Field(default=10485760, env="LOG_FILE_MAX_BYTES")
|
| 98 |
LOG_FILE_BACKUP_COUNT: int = Field(default=5, env="LOG_FILE_BACKUP_COUNT")
|
| 99 |
|
| 100 |
# ========================================================================
|
| 101 |
# SECURITY SETTINGS
|
| 102 |
# ========================================================================
|
| 103 |
-
# CORS
|
| 104 |
-
CORS_ORIGINS:
|
| 105 |
CORS_ALLOW_CREDENTIALS: bool = True
|
| 106 |
-
CORS_ALLOW_METHODS: List[str] = ["*"]
|
| 107 |
-
CORS_ALLOW_HEADERS: List[str] = ["*"]
|
| 108 |
|
| 109 |
-
# API Keys
|
| 110 |
API_KEY_HEADER: str = Field(default="X-API-Key", env="API_KEY_HEADER")
|
| 111 |
REQUIRE_API_KEY: bool = Field(default=False, env="REQUIRE_API_KEY")
|
| 112 |
-
VALID_API_KEYS:
|
| 113 |
|
| 114 |
# Rate limiting
|
| 115 |
RATE_LIMIT_ENABLED: bool = Field(default=False, env="RATE_LIMIT_ENABLED")
|
|
@@ -120,7 +117,7 @@ class Settings(BaseSettings):
|
|
| 120 |
# ========================================================================
|
| 121 |
ENABLE_CACHE: bool = Field(default=False, env="ENABLE_CACHE")
|
| 122 |
CACHE_TTL_SECONDS: int = Field(default=3600, env="CACHE_TTL_SECONDS")
|
| 123 |
-
CACHE_BACKEND: str = Field(default="memory", env="CACHE_BACKEND")
|
| 124 |
REDIS_URL: Optional[str] = Field(default=None, env="REDIS_URL")
|
| 125 |
|
| 126 |
# ========================================================================
|
|
@@ -136,10 +133,6 @@ class Settings(BaseSettings):
|
|
| 136 |
# ========================================================================
|
| 137 |
# PROCESSORS SETTINGS
|
| 138 |
# ========================================================================
|
| 139 |
-
# Quais processadores habilitar (1-9)
|
| 140 |
-
ENABLED_PROCESSORS: List[int] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
| 141 |
-
|
| 142 |
-
# Confidence thresholds
|
| 143 |
MIN_CONFIDENCE_THRESHOLD: float = Field(default=0.7, env="MIN_CONFIDENCE_THRESHOLD")
|
| 144 |
|
| 145 |
# ========================================================================
|
|
@@ -152,18 +145,14 @@ class Settings(BaseSettings):
|
|
| 152 |
# ========================================================================
|
| 153 |
# ADVANCED SETTINGS
|
| 154 |
# ========================================================================
|
| 155 |
-
# Request tracking
|
| 156 |
ENABLE_REQUEST_ID: bool = Field(default=True, env="ENABLE_REQUEST_ID")
|
| 157 |
REQUEST_ID_HEADER: str = "X-Request-ID"
|
| 158 |
|
| 159 |
-
# Compression
|
| 160 |
ENABLE_GZIP: bool = Field(default=True, env="ENABLE_GZIP")
|
| 161 |
GZIP_MIN_SIZE: int = Field(default=1000, env="GZIP_MIN_SIZE")
|
| 162 |
|
| 163 |
-
# Timeouts
|
| 164 |
HTTP_TIMEOUT_SECONDS: int = Field(default=300, env="HTTP_TIMEOUT_SECONDS")
|
| 165 |
|
| 166 |
-
# Task retention
|
| 167 |
TASK_RETENTION_HOURS: int = Field(default=24, env="TASK_RETENTION_HOURS")
|
| 168 |
AUTO_CLEANUP_ENABLED: bool = Field(default=True, env="AUTO_CLEANUP_ENABLED")
|
| 169 |
|
|
@@ -172,18 +161,25 @@ class Settings(BaseSettings):
|
|
| 172 |
env_file = ".env"
|
| 173 |
env_file_encoding = "utf-8"
|
| 174 |
case_sensitive = True
|
|
|
|
| 175 |
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
# Parse CORS_ORIGINS se vier como string
|
| 181 |
if isinstance(self.CORS_ORIGINS, str):
|
| 182 |
-
self.CORS_ORIGINS
|
|
|
|
|
|
|
|
|
|
| 183 |
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 187 |
|
| 188 |
@property
|
| 189 |
def is_production(self) -> bool:
|
|
@@ -230,7 +226,7 @@ class Settings(BaseSettings):
|
|
| 230 |
|
| 231 |
def to_dict(self) -> dict:
|
| 232 |
"""Converte settings para dict (sem expor secrets)."""
|
| 233 |
-
data = self.
|
| 234 |
|
| 235 |
# Mascarar informações sensíveis
|
| 236 |
sensitive_keys = [
|
|
@@ -244,10 +240,7 @@ class Settings(BaseSettings):
|
|
| 244 |
|
| 245 |
for key in sensitive_keys:
|
| 246 |
if key in data and data[key]:
|
| 247 |
-
|
| 248 |
-
data[key] = "***HIDDEN***"
|
| 249 |
-
elif isinstance(data[key], list):
|
| 250 |
-
data[key] = ["***HIDDEN***"] * len(data[key])
|
| 251 |
|
| 252 |
return data
|
| 253 |
|
|
@@ -280,16 +273,7 @@ def get_settings() -> Settings:
|
|
| 280 |
# ============================================================================
|
| 281 |
|
| 282 |
def get_env(key: str, default: any = None) -> any:
|
| 283 |
-
"""
|
| 284 |
-
Helper para pegar variável de ambiente.
|
| 285 |
-
|
| 286 |
-
Args:
|
| 287 |
-
key: Nome da variável
|
| 288 |
-
default: Valor padrão se não existir
|
| 289 |
-
|
| 290 |
-
Returns:
|
| 291 |
-
Valor da variável ou default
|
| 292 |
-
"""
|
| 293 |
return os.getenv(key, default)
|
| 294 |
|
| 295 |
|
|
@@ -301,93 +285,3 @@ def is_production() -> bool:
|
|
| 301 |
def is_development() -> bool:
|
| 302 |
"""Verifica se está rodando em desenvolvimento."""
|
| 303 |
return get_settings().is_development
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
# ============================================================================
|
| 307 |
-
# CONFIGURAÇÃO DE EXEMPLO (.env)
|
| 308 |
-
# ============================================================================
|
| 309 |
-
|
| 310 |
-
ENV_EXAMPLE = """
|
| 311 |
-
# ============================================================================
|
| 312 |
-
# para.AI API - Configuração de Ambiente
|
| 313 |
-
# ============================================================================
|
| 314 |
-
|
| 315 |
-
# API Settings
|
| 316 |
-
APP_ENV=production
|
| 317 |
-
DEBUG=false
|
| 318 |
-
|
| 319 |
-
# Server
|
| 320 |
-
HOST=0.0.0.0
|
| 321 |
-
PORT=8000
|
| 322 |
-
WORKERS=4
|
| 323 |
-
|
| 324 |
-
# Database
|
| 325 |
-
DATABASE_URL=postgresql://para_ai:SUA_SENHA@localhost:5432/para_ai
|
| 326 |
-
DB_POOL_SIZE=20
|
| 327 |
-
DB_MAX_OVERFLOW=40
|
| 328 |
-
|
| 329 |
-
# LLM Providers (configure pelo menos um)
|
| 330 |
-
GROQ_API_KEY=gsk_...
|
| 331 |
-
OPENAI_API_KEY=sk-...
|
| 332 |
-
ANTHROPIC_API_KEY=sk-ant-...
|
| 333 |
-
|
| 334 |
-
DEFAULT_LLM_PROVIDER=groq
|
| 335 |
-
DEFAULT_MODEL_TYPE=balanced
|
| 336 |
-
|
| 337 |
-
# Files & Storage
|
| 338 |
-
FILES_BASE_PATH=./data/files
|
| 339 |
-
UPLOAD_PATH=./data/uploads
|
| 340 |
-
OUTPUT_PATH=./data/outputs
|
| 341 |
-
MAX_UPLOAD_SIZE_MB=500
|
| 342 |
-
|
| 343 |
-
# Processing
|
| 344 |
-
MAX_CONCURRENT_PROCESSES=5
|
| 345 |
-
PROCESS_TIMEOUT_SECONDS=600
|
| 346 |
-
ENABLE_PARALLEL=true
|
| 347 |
-
DEFAULT_MAX_WORKERS=3
|
| 348 |
-
|
| 349 |
-
# Logging
|
| 350 |
-
LOG_LEVEL=INFO
|
| 351 |
-
LOG_FILE_ENABLED=true
|
| 352 |
-
|
| 353 |
-
# Security (IMPORTANTE EM PRODUÇÃO!)
|
| 354 |
-
REQUIRE_API_KEY=false
|
| 355 |
-
VALID_API_KEYS=key1,key2,key3
|
| 356 |
-
CORS_ORIGINS=https://seudominio.com,https://app.seudominio.com
|
| 357 |
-
|
| 358 |
-
# Cache (opcional - requer Redis)
|
| 359 |
-
ENABLE_CACHE=false
|
| 360 |
-
REDIS_URL=redis://localhost:6379/0
|
| 361 |
-
|
| 362 |
-
# Monitoring
|
| 363 |
-
ENABLE_METRICS=true
|
| 364 |
-
PROMETHEUS_ENABLED=false
|
| 365 |
-
"""
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
def generate_env_file(path: str = ".env.example"):
|
| 369 |
-
"""
|
| 370 |
-
Gera arquivo .env.example com todas as variáveis.
|
| 371 |
-
|
| 372 |
-
Args:
|
| 373 |
-
path: Caminho onde salvar o arquivo
|
| 374 |
-
"""
|
| 375 |
-
with open(path, "w") as f:
|
| 376 |
-
f.write(ENV_EXAMPLE)
|
| 377 |
-
print(f"✅ Arquivo {path} criado com sucesso!")
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
if __name__ == "__main__":
|
| 381 |
-
# Quando executado diretamente, gera .env.example
|
| 382 |
-
generate_env_file()
|
| 383 |
-
|
| 384 |
-
# Mostra configurações atuais
|
| 385 |
-
settings = get_settings()
|
| 386 |
-
print("\n" + "=" * 70)
|
| 387 |
-
print("CONFIGURAÇÕES ATUAIS - para.AI API")
|
| 388 |
-
print("=" * 70)
|
| 389 |
-
print(f"Environment: {settings.APP_ENV}")
|
| 390 |
-
print(f"Debug: {settings.DEBUG}")
|
| 391 |
-
print(f"Database: {settings.database_url_masked}")
|
| 392 |
-
print(f"LLM Providers: {settings.get_llm_providers_status()}")
|
| 393 |
-
print("=" * 70)
|
|
|
|
| 58 |
BACKUP_PATH: str = Field(default="./data/backups", env="BACKUP_PATH")
|
| 59 |
|
| 60 |
MAX_UPLOAD_SIZE_MB: int = Field(default=500, env="MAX_UPLOAD_SIZE_MB")
|
|
|
|
| 61 |
|
| 62 |
# ========================================================================
|
| 63 |
# LLM PROVIDERS API KEYS
|
|
|
|
| 93 |
LOG_FORMAT: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
| 94 |
LOG_FILE_ENABLED: bool = Field(default=True, env="LOG_FILE_ENABLED")
|
| 95 |
LOG_FILE_PATH: str = Field(default="./logs", env="LOG_FILE_PATH")
|
| 96 |
+
LOG_FILE_MAX_BYTES: int = Field(default=10485760, env="LOG_FILE_MAX_BYTES")
|
| 97 |
LOG_FILE_BACKUP_COUNT: int = Field(default=5, env="LOG_FILE_BACKUP_COUNT")
|
| 98 |
|
| 99 |
# ========================================================================
|
| 100 |
# SECURITY SETTINGS
|
| 101 |
# ========================================================================
|
| 102 |
+
# CORS - usar string ao invés de List para evitar erro de parsing
|
| 103 |
+
CORS_ORIGINS: str = Field(default="*", env="CORS_ORIGINS")
|
| 104 |
CORS_ALLOW_CREDENTIALS: bool = True
|
|
|
|
|
|
|
| 105 |
|
| 106 |
+
# API Keys - usar string ao invés de List
|
| 107 |
API_KEY_HEADER: str = Field(default="X-API-Key", env="API_KEY_HEADER")
|
| 108 |
REQUIRE_API_KEY: bool = Field(default=False, env="REQUIRE_API_KEY")
|
| 109 |
+
VALID_API_KEYS: str = Field(default="", env="VALID_API_KEYS")
|
| 110 |
|
| 111 |
# Rate limiting
|
| 112 |
RATE_LIMIT_ENABLED: bool = Field(default=False, env="RATE_LIMIT_ENABLED")
|
|
|
|
| 117 |
# ========================================================================
|
| 118 |
ENABLE_CACHE: bool = Field(default=False, env="ENABLE_CACHE")
|
| 119 |
CACHE_TTL_SECONDS: int = Field(default=3600, env="CACHE_TTL_SECONDS")
|
| 120 |
+
CACHE_BACKEND: str = Field(default="memory", env="CACHE_BACKEND")
|
| 121 |
REDIS_URL: Optional[str] = Field(default=None, env="REDIS_URL")
|
| 122 |
|
| 123 |
# ========================================================================
|
|
|
|
| 133 |
# ========================================================================
|
| 134 |
# PROCESSORS SETTINGS
|
| 135 |
# ========================================================================
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
MIN_CONFIDENCE_THRESHOLD: float = Field(default=0.7, env="MIN_CONFIDENCE_THRESHOLD")
|
| 137 |
|
| 138 |
# ========================================================================
|
|
|
|
| 145 |
# ========================================================================
|
| 146 |
# ADVANCED SETTINGS
|
| 147 |
# ========================================================================
|
|
|
|
| 148 |
ENABLE_REQUEST_ID: bool = Field(default=True, env="ENABLE_REQUEST_ID")
|
| 149 |
REQUEST_ID_HEADER: str = "X-Request-ID"
|
| 150 |
|
|
|
|
| 151 |
ENABLE_GZIP: bool = Field(default=True, env="ENABLE_GZIP")
|
| 152 |
GZIP_MIN_SIZE: int = Field(default=1000, env="GZIP_MIN_SIZE")
|
| 153 |
|
|
|
|
| 154 |
HTTP_TIMEOUT_SECONDS: int = Field(default=300, env="HTTP_TIMEOUT_SECONDS")
|
| 155 |
|
|
|
|
| 156 |
TASK_RETENTION_HOURS: int = Field(default=24, env="TASK_RETENTION_HOURS")
|
| 157 |
AUTO_CLEANUP_ENABLED: bool = Field(default=True, env="AUTO_CLEANUP_ENABLED")
|
| 158 |
|
|
|
|
| 161 |
env_file = ".env"
|
| 162 |
env_file_encoding = "utf-8"
|
| 163 |
case_sensitive = True
|
| 164 |
+
extra = "ignore" # Ignorar variáveis extras
|
| 165 |
|
| 166 |
+
@property
|
| 167 |
+
def cors_origins_list(self) -> List[str]:
|
| 168 |
+
"""Retorna CORS_ORIGINS como lista."""
|
|
|
|
|
|
|
| 169 |
if isinstance(self.CORS_ORIGINS, str):
|
| 170 |
+
if self.CORS_ORIGINS == "*":
|
| 171 |
+
return ["*"]
|
| 172 |
+
return [origin.strip() for origin in self.CORS_ORIGINS.split(",") if origin.strip()]
|
| 173 |
+
return [self.CORS_ORIGINS]
|
| 174 |
|
| 175 |
+
@property
|
| 176 |
+
def valid_api_keys_list(self) -> List[str]:
|
| 177 |
+
"""Retorna VALID_API_KEYS como lista."""
|
| 178 |
+
if not self.VALID_API_KEYS:
|
| 179 |
+
return []
|
| 180 |
+
if isinstance(self.VALID_API_KEYS, str):
|
| 181 |
+
return [key.strip() for key in self.VALID_API_KEYS.split(",") if key.strip()]
|
| 182 |
+
return []
|
| 183 |
|
| 184 |
@property
|
| 185 |
def is_production(self) -> bool:
|
|
|
|
| 226 |
|
| 227 |
def to_dict(self) -> dict:
|
| 228 |
"""Converte settings para dict (sem expor secrets)."""
|
| 229 |
+
data = self.model_dump()
|
| 230 |
|
| 231 |
# Mascarar informações sensíveis
|
| 232 |
sensitive_keys = [
|
|
|
|
| 240 |
|
| 241 |
for key in sensitive_keys:
|
| 242 |
if key in data and data[key]:
|
| 243 |
+
data[key] = "***HIDDEN***"
|
|
|
|
|
|
|
|
|
|
| 244 |
|
| 245 |
return data
|
| 246 |
|
|
|
|
| 273 |
# ============================================================================
|
| 274 |
|
| 275 |
def get_env(key: str, default: any = None) -> any:
|
| 276 |
+
"""Helper para pegar variável de ambiente."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 277 |
return os.getenv(key, default)
|
| 278 |
|
| 279 |
|
|
|
|
| 285 |
def is_development() -> bool:
|
| 286 |
"""Verifica se está rodando em desenvolvimento."""
|
| 287 |
return get_settings().is_development
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|