vitrina / src /config.py
nvikou's picture
Витрина: первый деплой
4448e70 verified
Raw History Blame Contribute Delete
3.69 kB
"""Конфигурация приложения. Всё читается из переменных окружения.
На Hugging Face Spaces значения задаются в Settings → Variables and secrets.
Локально — через .env (см. .env.example).
"""
from __future__ import annotations
import os
from dataclasses import dataclass, field
from pathlib import Path
try: # локальный запуск: подхватываем .env, если он есть
from dotenv import load_dotenv
load_dotenv(override=False)
except ImportError: # на Spaces переменные приходят из окружения
pass
APP_NAME = "Витрина"
APP_TAGLINE = "Иллюстрации и тексты карточек товаров для маркетплейсов"
_TRUE = {"1", "true", "yes", "on", "да"}
def _flag(name: str, default: bool = False) -> bool:
raw = os.getenv(name)
return default if raw is None else raw.strip().lower() in _TRUE
def _int(name: str, default: int) -> int:
try:
return int(os.getenv(name, default))
except (TypeError, ValueError):
return default
@dataclass(frozen=True)
class Settings:
# --- ключи (могут быть пустыми: тогда пользователь вводит свой в интерфейсе) ---
openai_api_key: str = field(default_factory=lambda: os.getenv("OPENAI_API_KEY", "").strip())
groq_api_key: str = field(default_factory=lambda: os.getenv("GROQ_API_KEY", "").strip())
openai_base_url: str | None = field(
default_factory=lambda: os.getenv("OPENAI_BASE_URL", "").strip() or None
)
# --- модели ---
# Названия моделей у провайдеров меняются. Всё вынесено в env,
# чтобы поменять их без правки кода.
image_model: str = field(default_factory=lambda: os.getenv("OPENAI_IMAGE_MODEL", "gpt-image-1"))
image_model_fallback: str = field(
default_factory=lambda: os.getenv("OPENAI_IMAGE_MODEL_FALLBACK", "dall-e-3")
)
groq_text_model: str = field(
default_factory=lambda: os.getenv("GROQ_TEXT_MODEL", "llama-3.3-70b-versatile")
)
groq_vision_model: str = field(
default_factory=lambda: os.getenv(
"GROQ_VISION_MODEL", "meta-llama/llama-4-scout-17b-16e-instruct"
)
)
# --- лимиты ---
max_images: int = field(default_factory=lambda: _int("MAX_IMAGES", 4))
request_timeout: int = field(default_factory=lambda: _int("REQUEST_TIMEOUT", 180))
max_retries: int = field(default_factory=lambda: _int("MAX_RETRIES", 3))
# --- поведение ---
allow_user_keys: bool = field(default_factory=lambda: _flag("ALLOW_USER_KEYS", True))
enable_queue_concurrency: int = field(default_factory=lambda: _int("CONCURRENCY", 2))
output_dir: Path = field(default_factory=lambda: Path(os.getenv("OUTPUT_DIR", "outputs")))
log_level: str = field(default_factory=lambda: os.getenv("LOG_LEVEL", "INFO").upper())
def resolve_openai_key(self, user_key: str | None) -> str:
"""Ключ пользователя приоритетнее серверного, если это разрешено."""
if self.allow_user_keys and user_key and user_key.strip():
return user_key.strip()
return self.openai_api_key
def resolve_groq_key(self, user_key: str | None) -> str:
if self.allow_user_keys and user_key and user_key.strip():
return user_key.strip()
return self.groq_api_key
settings = Settings()
settings.output_dir.mkdir(parents=True, exist_ok=True)