chore: remove legacy src/ directory
This commit is contained in:
parent
4f5c5679d5
commit
c87b37ad64
6 changed files with 0 additions and 283 deletions
|
|
@ -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()),
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue