/
gr.ev.vl
/
TestGen
Обзор
Документация
Войти
/
gr.ev.vl
/
TestGen
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master2
backend/scripts/create_superuser.py
182 строки
6 KB
gr.ev.vl
Initial commit
06 июн 2026, 02:41
06 июн 2026, 02:41
02fb1fb
Код
Авторство
О чём код?
""" Централизованная конфигурация приложения. Все настройки загружаются из переменных окружения и .env файла. """ import os from pathlib import Path from typing import Literal from pydantic import Field, field_validator from pydantic_settings import BaseSettings, SettingsConfigDict class DatabaseSettings(BaseSettings): """Настройки подключения к PostgreSQL.""" HOST: str = Field(default="localhost", alias="DB_HOST") PORT: int = Field(default=5432, alias="DB_PORT") USER: str = Field(default="testgen", alias="DB_USER") PASSWORD: str = Field(default="1234", alias="DB_PASSWORD") NAME: str = Field(default="testgen", alias="DB_NAME") POOL_SIZE: int = Field(default=20, alias="DB_POOL_SIZE") MAX_OVERFLOW: int = Field(default=10, alias="DB_MAX_OVERFLOW") POOL_RECYCLE: int = Field(default=3600, alias="DB_POOL_RECYCLE") ECHO: bool = Field(default=False, alias="DB_ECHO") @property def url(self) -> str: """Асинхронный URL для SQLAlchemy + psycopg.""" return ( f"postgresql+asyncpg://" f"{self.USER}:{self.PASSWORD}@" f"{self.HOST}:{self.PORT}/" f"{self.NAME}" ) @property def sync_url(self) -> str: """Синхронный URL для Alembic.""" return ( f"postgresql://" f"{self.USER}:{self.PASSWORD}@" f"{self.HOST}:{self.PORT}/" f"{self.NAME}" ) class RedisSettings(BaseSettings): """Настройки подключения к Redis.""" HOST: str = Field(default="localhost", alias="REDIS_HOST") PORT: int = Field(default=6379, alias="REDIS_PORT") DB: int = Field(default=0, alias="REDIS_DB") PASSWORD: str | None = Field(default=None, alias="REDIS_PASSWORD") MAX_CONNECTIONS: int = Field(default=50, alias="REDIS_MAX_CONNECTIONS") @property def url(self) -> str: """Формирует URL для подключения к Redis.""" auth = f":{self.PASSWORD}@" if self.PASSWORD else "" return f"redis://{auth}{self.HOST}:{self.PORT}/{self.DB}" class CelerySettings(BaseSettings): """Настройки Celery.""" BROKER_DB: int = Field(default=1, alias="CELERY_BROKER_DB") RESULT_BACKEND_DB: int = Field(default=2, alias="CELERY_RESULT_DB") TASK_TRACK_STARTED: bool = True TASK_TIME_LIMIT: int = 600 TASK_SOFT_TIME_LIMIT: int = 540 WORKER_PREFETCH_MULTIPLIER: int = 1 WORKER_MAX_TASKS_PER_CHILD: int = 100 @property def broker_url(self) -> str: """URL брокера Celery (Redis).""" redis = RedisSettings() return f"redis://{redis.HOST}:{redis.PORT}/{self.BROKER_DB}" @property def result_backend(self) -> str: """URL backend для результатов (Redis).""" redis = RedisSettings() return f"redis://{redis.HOST}:{redis.PORT}/{self.RESULT_BACKEND_DB}" class SecuritySettings(BaseSettings): """Настройки безопасности.""" SECRET_KEY: str = Field(default="change-me-to-a-random-secret-key", alias="SECRET_KEY") ALGORITHM: str = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES: int = 30 REFRESH_TOKEN_EXPIRE_DAYS: int = 30 BCRYPT_ROUNDS: int = 12 ENCRYPTION_KEY: str = Field(default="a" * 32, alias="ENCRYPTION_KEY") @field_validator("ENCRYPTION_KEY") @classmethod def validate_encryption_key(cls, v: str) -> str: """Проверяет, что ключ шифрования имеет длину 32 байта.""" if len(v.encode()) != 32: raise ValueError("ENCRYPTION_KEY must be exactly 32 bytes") return v class LLMSettings(BaseSettings): """Настройки LLM-провайдеров.""" DEFAULT_TIMEOUT_SECONDS: int = 60 MAX_RETRIES: int = 3 RETRY_BACKOFF_FACTOR: float = 2.0 RETRY_BACKOFF_MAX: int = 120 CIRCUIT_BREAKER_THRESHOLD: int = 5 CIRCUIT_BREAKER_RECOVERY_SECONDS: int = 60 CIRCUIT_BREAKER_HALF_OPEN_MAX_REQUESTS: int = 3 RATE_LIMIT_REDIS_PREFIX: str = "ratelimit" EMBEDDING_MODEL: str = "text-embedding-3-small" EMBEDDING_DIMENSIONS: int = 1536 SEMANTIC_SIMILARITY_THRESHOLD: float = 0.85 SEMANTIC_DISTANCE_THRESHOLD: float = 0.2 class StorageSettings(BaseSettings): """Настройки файлового хранилища.""" PATH: str = "./storage" MAX_UPLOAD_SIZE_MB: int = 50 EXPORT_DIR: str = "exports" DATASET_DIR: str = "datasets" class CORSSettings(BaseSettings): """Настройки CORS.""" ORIGINS: list[str] = Field( default=["http://localhost:5173", "http://localhost:3000"], alias="CORS_ORIGINS", ) ALLOW_CREDENTIALS: bool = True ALLOW_METHODS: list[str] = ["GET", "POST", "PUT", "DELETE", "PATCH"] ALLOW_HEADERS: list[str] = ["*"] class LoggingSettings(BaseSettings): """Настройки логирования.""" LEVEL: str = "INFO" FORMAT: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" JSON_FORMAT: bool = True class Settings(BaseSettings): """Корневые настройки приложения.""" APP_NAME: str = "TestGen" APP_VERSION: str = "0.1.0" DEBUG: bool = False ENVIRONMENT: Literal["development", "staging", "production"] = "production" BASE_DIR: Path = Path(__file__).resolve().parent.parent # Подсистемы database: DatabaseSettings = DatabaseSettings() redis: RedisSettings = RedisSettings() celery: CelerySettings = CelerySettings() security: SecuritySettings = SecuritySettings() llm: LLMSettings = LLMSettings() storage: StorageSettings = StorageSettings() cors: CORSSettings = CORSSettings() logging: LoggingSettings = LoggingSettings() model_config = SettingsConfigDict( env_file=".env", env_file_encoding="utf-8", case_sensitive=False, extra="ignore", ) # Глобальный экземпляр настроек settings = Settings()