Spaces:
Sleeping
Sleeping
File size: 4,742 Bytes
aeb3f7c d7f7508 aeb3f7c d7f7508 aeb3f7c f277022 aeb3f7c f277022 aeb3f7c aec570d aeb3f7c |
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 |
"""Configuration management using Pydantic settings."""
import os
from typing import List, Literal
from pydantic import Field, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
"""
Application settings with environment variable support.
Settings are loaded from (in order of precedence):
1. Environment variables
2. .env file (if present)
3. Default values
Works without .env file for HuggingFace Spaces and containerized deployments.
"""
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False,
extra="ignore",
# Don't error if .env file is missing (for HF Spaces, Docker, etc.)
env_ignore_empty=True,
)
# Application Settings
app_name: str = Field(default="AI Writing Studio", description="Application name")
app_version: str = Field(default="1.0.0", description="Application version")
environment: Literal["development", "staging", "production"] = Field(
default="development", description="Runtime environment"
)
debug: bool = Field(default=False, description="Enable debug mode")
# Server Configuration
host: str = Field(default="0.0.0.0", description="Server host")
port: int = Field(default=7860, ge=1, le=65535, description="Server port")
server_workers: int = Field(default=4, ge=1, description="Number of worker processes")
# Model Configuration
default_model: str = Field(
default="google/flan-t5-base",
description="Default HuggingFace model (instruction-tuned for revision)"
)
max_model_length: int = Field(default=512, ge=1, description="Maximum model input length")
default_max_length: int = Field(default=512, ge=1, description="Default generation length")
default_num_sequences: int = Field(default=1, ge=1, description="Number of sequences")
# Security
allowed_origins: str = Field(
default="http://localhost:7860,http://127.0.0.1:7860",
description="Comma-separated CORS origins",
)
rate_limit_per_minute: int = Field(default=10, ge=1, description="Rate limit per minute")
max_text_length: int = Field(
default=10000, ge=1, description="Maximum input text length"
)
enable_auth: bool = Field(default=False, description="Enable authentication")
secret_key: str = Field(default="", description="Secret key for sessions")
# Logging
log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = Field(
default="INFO", description="Logging level"
)
log_format: Literal["json", "text"] = Field(default="json", description="Log format")
log_file_path: str = Field(default="./logs/app.log", description="Log file path")
log_max_bytes: int = Field(default=10485760, ge=1, description="Max log file size")
log_backup_count: int = Field(default=5, ge=0, description="Number of log backups")
# Monitoring
enable_metrics: bool = Field(default=True, description="Enable Prometheus metrics")
metrics_port: int = Field(default=8000, ge=1, le=65535, description="Metrics port")
# Cache Configuration
enable_cache: bool = Field(default=True, description="Enable caching")
cache_ttl: int = Field(default=3600, ge=1, description="Cache TTL in seconds")
cache_max_size: int = Field(default=100, ge=1, description="Maximum cache entries")
# Feature Flags
enable_diff_highlighting: bool = Field(default=True, description="Enable diff view")
enable_rubric_scoring: bool = Field(default=True, description="Enable rubric scoring")
enable_prompt_packs: bool = Field(default=True, description="Enable prompt packs")
@field_validator("allowed_origins")
@classmethod
def parse_origins(cls, v: str) -> List[str]:
"""Parse comma-separated origins into a list."""
if isinstance(v, str):
return [origin.strip() for origin in v.split(",") if origin.strip()]
return v
@field_validator("log_file_path")
@classmethod
def ensure_directory_exists(cls, v: str) -> str:
"""Ensure directory exists for file paths."""
directory = os.path.dirname(v) if os.path.splitext(v)[1] else v
if directory and not os.path.exists(directory):
os.makedirs(directory, exist_ok=True)
return v
@property
def is_production(self) -> bool:
"""Check if running in production."""
return self.environment == "production"
@property
def is_development(self) -> bool:
"""Check if running in development."""
return self.environment == "development"
# Global settings instance
settings = Settings()
|