diff --git a/src/__init__.py b/src/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/matrix_bot/__init__.py b/src/matrix_bot/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/mock_platform.py b/src/mock_platform.py deleted file mode 100644 index 90bcafb..0000000 --- a/src/mock_platform.py +++ /dev/null @@ -1,246 +0,0 @@ -""" -MockPlatformClient — заглушка SDK платформы Lambda. - -Единственный файл который нужно заменить при подключении реального SDK. -Все обращения к платформе в коде ботов идут только через этот класс. - -При подключении реального SDK: -1. Скопируй интерфейс (методы и сигнатуры) из этого файла -2. Замени тело методов на реальные API вызовы -3. Обнови импорт в telegram_bot/main.py и matrix_bot/main.py -""" - -from __future__ import annotations - -import asyncio -import uuid -from datetime import datetime, timedelta -from typing import Any - -import structlog - -logger = structlog.get_logger(__name__) - - -class PlatformError(Exception): - """Базовый класс ошибок платформы.""" - def __init__(self, message: str, code: str = "PLATFORM_ERROR"): - super().__init__(message) - self.code = code - - -class SessionNotFoundError(PlatformError): - def __init__(self, session_id: str): - super().__init__(f"Session {session_id} not found", "SESSION_NOT_FOUND") - - -class MockPlatformClient: - """ - Имитирует поведение SDK платформы Lambda. - - Хранит состояние в памяти — при перезапуске сбрасывается. - Для персистентности в моке используй MockPlatformClient(persistent=True) - (тогда сохраняет в /tmp/mock_platform_state.json). - """ - - def __init__(self, base_url: str = "http://localhost:8000", timeout: float = 5.0): - self._sessions: dict[str, dict] = {} - self._messages: dict[str, list] = {} # session_id -> messages - self._base_url = base_url - self._timeout = timeout - logger.info("MockPlatformClient initialized", base_url=base_url) - - # ─── Sessions ──────────────────────────────────────────────────────────── - - async def create_session( - self, - user_id: str, - platform: str, # "telegram" | "matrix" - context: dict[str, Any] | None = None, - ) -> dict: - """ - Создаёт новую сессию пользователя с AI-агентом. - - Returns: - { - "session_id": str, - "agent_id": str, - "created_at": ISO8601, - "expires_at": ISO8601, - } - """ - await self._simulate_latency() - - session_id = str(uuid.uuid4()) - agent_id = f"agent-{uuid.uuid4().hex[:8]}" - now = datetime.utcnow() - - session = { - "session_id": session_id, - "agent_id": agent_id, - "user_id": user_id, - "platform": platform, - "context": context or {}, - "created_at": now.isoformat() + "Z", - "expires_at": (now + timedelta(hours=24)).isoformat() + "Z", - "status": "active", - } - - self._sessions[session_id] = session - self._messages[session_id] = [] - - logger.info("Session created", session_id=session_id, user_id=user_id, platform=platform) - return {k: v for k, v in session.items() if k not in ("user_id", "platform", "context", "status")} - - async def get_session(self, session_id: str) -> dict: - """ - Возвращает информацию о сессии. - - Raises: - SessionNotFoundError: если сессия не существует или истекла - """ - await self._simulate_latency() - - session = self._sessions.get(session_id) - if not session: - raise SessionNotFoundError(session_id) - - return session - - async def close_session(self, session_id: str) -> bool: - """ - Завершает сессию. - - Returns: - True если сессия была закрыта, False если уже была закрыта - """ - await self._simulate_latency() - - session = self._sessions.get(session_id) - if not session: - raise SessionNotFoundError(session_id) - - was_active = session["status"] == "active" - session["status"] = "closed" - session["closed_at"] = datetime.utcnow().isoformat() + "Z" - - logger.info("Session closed", session_id=session_id) - return was_active - - # ─── Messages ───────────────────────────────────────────────────────────── - - async def send_message( - self, - session_id: str, - text: str, - attachments: list[dict] | None = None, - ) -> dict: - """ - Отправляет сообщение пользователя в сессию и получает ответ агента. - - Returns: - { - "message_id": str, - "response": str, - "tokens_used": int, - "finished": bool, - } - """ - await self._simulate_latency(min_ms=200, max_ms=800) - - if session_id not in self._sessions: - raise SessionNotFoundError(session_id) - - message_id = str(uuid.uuid4()) - - # Mock ответ агента - response = f"[MOCK] Ответ на: «{text[:50]}{'...' if len(text) > 50 else ''}»" - - message = { - "message_id": message_id, - "session_id": session_id, - "user_text": text, - "response": response, - "tokens_used": len(text.split()) * 2, # грубая оценка - "finished": True, - "created_at": datetime.utcnow().isoformat() + "Z", - } - - self._messages[session_id].append(message) - - logger.info("Message sent", session_id=session_id, message_id=message_id) - return { - "message_id": message["message_id"], - "response": message["response"], - "tokens_used": message["tokens_used"], - "finished": message["finished"], - } - - async def get_message_history( - self, - session_id: str, - limit: int = 20, - offset: int = 0, - ) -> list[dict]: - """ - Возвращает историю сообщений сессии. - """ - await self._simulate_latency() - - if session_id not in self._sessions: - raise SessionNotFoundError(session_id) - - messages = self._messages.get(session_id, []) - return messages[offset : offset + limit] - - # ─── User ───────────────────────────────────────────────────────────────── - - async def get_or_create_user( - self, - external_id: str, - platform: str, - display_name: str | None = None, - ) -> dict: - """ - Возвращает или создаёт пользователя платформы. - - Returns: - { - "user_id": str, - "external_id": str, - "platform": str, - "display_name": str | None, - "created_at": ISO8601, - "is_new": bool, - } - """ - await self._simulate_latency() - - # В моке генерируем детерминированный user_id - user_id = f"user-{platform}-{external_id}" - - logger.info("User fetched", user_id=user_id, platform=platform) - return { - "user_id": user_id, - "external_id": external_id, - "platform": platform, - "display_name": display_name, - "created_at": "2025-01-01T00:00:00Z", - "is_new": False, - } - - # ─── Internals ──────────────────────────────────────────────────────────── - - async def _simulate_latency(self, min_ms: int = 10, max_ms: int = 100) -> None: - """Имитирует сетевую задержку для реалистичного тестирования.""" - import random - delay = random.randint(min_ms, max_ms) / 1000 - await asyncio.sleep(delay) - - def get_stats(self) -> dict: - """Возвращает статистику мока (для отладки).""" - return { - "active_sessions": sum(1 for s in self._sessions.values() if s["status"] == "active"), - "total_sessions": len(self._sessions), - "total_messages": sum(len(msgs) for msgs in self._messages.values()), - } diff --git a/src/shared/__init__.py b/src/shared/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/shared/models.py b/src/shared/models.py deleted file mode 100644 index 508f948..0000000 --- a/src/shared/models.py +++ /dev/null @@ -1,37 +0,0 @@ -"""Общие Pydantic модели для Telegram и Matrix ботов.""" - -from __future__ import annotations - -from datetime import datetime -from enum import Enum -from typing import Any - -from pydantic import BaseModel, Field - - -class Platform(str, Enum): - TELEGRAM = "telegram" - MATRIX = "matrix" - - -class Session(BaseModel): - session_id: str - agent_id: str - created_at: datetime - expires_at: datetime - - -class User(BaseModel): - user_id: str - external_id: str - platform: Platform - display_name: str | None = None - created_at: datetime - is_new: bool = False - - -class MessageResponse(BaseModel): - message_id: str - response: str - tokens_used: int - finished: bool diff --git a/src/telegram_bot/__init__.py b/src/telegram_bot/__init__.py deleted file mode 100644 index e69de29..0000000