Инициализировать репозиторий «Дейл»
Первый коммит: модульный монолит ядра (.NET 10) и gRPC-сервисы ai/ml/telegram, фронтенд Vue 3/Vite/Tailwind, документация (ТЗ, инструкция пользователя, техдокументация, код-стайл), бэклог, скрипты развёртывания и архив прототипа LeadRadar.
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
"""Конфигурация из переменных окружения.
|
||||
|
||||
По ТЗ в env выносятся ТОЛЬКО неконфиденциальные параметры:
|
||||
порты, пути к БД/данным/сессиям. Секреты (Telegram api_id/hash,
|
||||
ключи AI, пароль дашборда) живут в базе и задаются через UI.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def _bool(name: str, default: bool = False) -> bool:
|
||||
raw = os.getenv(name)
|
||||
if raw is None:
|
||||
return default
|
||||
return raw.strip().lower() in {"1", "true", "yes", "on"}
|
||||
|
||||
|
||||
def _int(name: str, default: int) -> int:
|
||||
try:
|
||||
return int(os.getenv(name, str(default)))
|
||||
except ValueError:
|
||||
return default
|
||||
|
||||
|
||||
# Корень данных (том в docker-compose). Внутри лежат leadradar.duckdb,
|
||||
# telegram-сессии, файлы вложений (позже — MinIO), секрет подписи сессий.
|
||||
DATA_DIR = Path(os.getenv("LEADRADAR_DATA", str(Path(__file__).resolve().parent.parent / "data"))).resolve()
|
||||
DB_PATH = DATA_DIR / os.getenv("LEADRADAR_DB_NAME", "leadradar.duckdb")
|
||||
SESSIONS_DIR = DATA_DIR / "telegram_sessions"
|
||||
FILES_DIR = DATA_DIR / "attachments"
|
||||
SECRET_FILE = DATA_DIR / "session_secret.key"
|
||||
|
||||
# Хост/порт HTTP-сервера
|
||||
HOST = os.getenv("LEADRADAR_HOST", "0.0.0.0")
|
||||
PORT = _int("LEADRADAR_PORT", 8000)
|
||||
|
||||
# Через env допустимо задать стартовый секрет (например, из секрет-менеджера),
|
||||
# но если он не задан — будет создан случайный и сохранён в SECRET_FILE.
|
||||
SESSION_SECRET = os.getenv("LEADRADAR_SESSION_SECRET", "") or None
|
||||
|
||||
# Учётные данные первого входа можно выставить и в env (удобно для развёртывания),
|
||||
# НО по умолчанию система стартует с admin/admin и требует смены пароля.
|
||||
BOOTSTRAP_LOGIN = os.getenv("LEADRADAR_BOOTSTRAP_LOGIN", "admin")
|
||||
BOOTSTRAP_PASSWORD = os.getenv("LEADRADAR_BOOTSTRAP_PASSWORD", "admin")
|
||||
|
||||
# Шифрование секретов в БД. По договорённости ключ живёт в env;
|
||||
# при локальной разработке без env создаётся файл data/encryption.key.
|
||||
ENCRYPTION_KEY = os.getenv("LEADRADAR_ENCRYPTION_KEY", "") or None
|
||||
ENCRYPTION_KEY_FILE = DATA_DIR / "encryption.key"
|
||||
|
||||
# MinIO (вложения; креды по договорённости — в env)
|
||||
MINIO_ENDPOINT = os.getenv("LEADRADAR_MINIO_ENDPOINT", "")
|
||||
MINIO_ACCESS_KEY = os.getenv("LEADRADAR_MINIO_ACCESS_KEY", "")
|
||||
MINIO_SECRET_KEY = os.getenv("LEADRADAR_MINIO_SECRET_KEY", "")
|
||||
MINIO_BUCKET = os.getenv("LEADRADAR_MINIO_BUCKET", "leadradar")
|
||||
MINIO_SECURE = _bool("LEADRADAR_MINIO_SECURE", False)
|
||||
|
||||
# Автономный ML-сервис (отдельный контейнер). Если недоступен — модель не
|
||||
# используется в пайплайне, а события обучения копятся в outbox до его возврата.
|
||||
ML_URL = os.getenv("LEADRADAR_ML_URL", "http://127.0.0.1:8100").rstrip("/")
|
||||
ML_TIMEOUT = _int("LEADRADAR_ML_TIMEOUT", 30) # обучение батчами — тяжёлое, таймаут щедрый
|
||||
|
||||
# Куки
|
||||
COOKIE_NAME = "leadradar_session"
|
||||
SESSION_DAYS = 30
|
||||
|
||||
# Telegram-сессия (Telethon)
|
||||
SESSION_PREFIX = "user"
|
||||
|
||||
# Путь к статике фронтенда (собранный dist). Если папки нет — API работает
|
||||
# отдельно (фронт поднимается dev-сервером), статика просто не раздаётся.
|
||||
FRONTEND_DIST = Path(os.getenv("LEADRADAR_FRONTEND_DIST", str(Path(__file__).resolve().parent.parent.parent / "frontend" / "dist"))).resolve()
|
||||
|
||||
# Логи
|
||||
LOG_LEVEL = os.getenv("LEADRADAR_LOG_LEVEL", "INFO")
|
||||
|
||||
# Демо-эндпоинты (simulate-lead, age-lead). В проде выключено;
|
||||
# включается только для локальных тестов разработчика: LEADRADAR_DEMO=1
|
||||
DEMO_ENABLED = _bool("LEADRADAR_DEMO", False)
|
||||
|
||||
|
||||
def ensure_dirs() -> None:
|
||||
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
||||
SESSIONS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
FILES_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
def get_or_create_secret() -> str:
|
||||
if SESSION_SECRET:
|
||||
return SESSION_SECRET
|
||||
if SECRET_FILE.exists():
|
||||
return SECRET_FILE.read_text(encoding="utf-8").strip()
|
||||
import secrets
|
||||
|
||||
secret = secrets.token_hex(32)
|
||||
SECRET_FILE.write_text(secret, encoding="utf-8")
|
||||
return secret
|
||||
Reference in New Issue
Block a user