""" Lichess Statistics API - Модели данных Этот модуль содержит все Pydantic модели для валидации и сериализации данных. Модели используются для: - Валидации входных параметров API - Сериализации ответов API - Документации в Swagger UI - Типизации данных в коде Автор: Lichess Web Services Team Версия: 1.0.0 """ from pydantic import BaseModel, Field from typing import Dict, Optional, Any # ============================================================================= # МОДЕЛИ СТАТИСТИКИ ЗАДАЧ (ПАЗЛОВ) # ============================================================================= class TaskStats(BaseModel): """ Статистика решения задач (пазлов) пользователя. Содержит информацию о том, сколько задач пользователь решил, сколько решил правильно и сколько не решил или решил неправильно. """ total: int = Field(..., description="Общее количество решенных задач", example=15) solved: int = Field(..., description="Количество правильно решенных задач", example=12) unsolved: int = Field(..., description="Количество нерешенных или неправильно решенных задач", example=3) # ============================================================================= # МОДЕЛИ СТАТИСТИКИ ИГР # ============================================================================= class GameModeStats(BaseModel): """ Статистика игр для конкретного режима (Bullet, Blitz, Rapid и т.д.). Содержит полную статистику по играм в определенном временном формате: - Количество сыгранных игр - Изменение рейтинга за период - Текущий рейтинг - Результаты игр (победы, поражения, ничьи) """ games_played: int = Field(..., description="Общее количество сыгранных игр", example=8) rating_change: int = Field(..., description="Изменение рейтинга (может быть отрицательным)", example=15) final_rating: int = Field(..., description="Текущий рейтинг игрока", example=2850) wins: int = Field(..., description="Количество побед", example=5) losses: int = Field(..., description="Количество поражений", example=2) draws: int = Field(..., description="Количество ничьих", example=1) class GamesStats(BaseModel): """ Статистика игр по всем режимам. Агрегирует статистику игр по всем временным форматам: - Bullet: быстрые игры (1-3 минуты) - Blitz: блиц игры (3-10 минут) - Rapid: рапид игры (10+ минут) """ bullet: GameModeStats = Field(..., description="Статистика Bullet игр (1-3 минуты)") blitz: GameModeStats = Field(..., description="Статистика Blitz игр (3-10 минут)") rapid: GameModeStats = Field(..., description="Статистика Rapid игр (10+ минут)") class UserStats(BaseModel): """ Полная статистика пользователя. Содержит всю доступную статистику по пользователю: - Статистику решения задач (пазлов) - Статистику игр по всем режимам """ username: str = Field(..., description="Имя пользователя на Lichess", example="magnus") tasks: TaskStats = Field(..., description="Статистика решения задач") games: GamesStats = Field(..., description="Статистика игр по всем режимам") # ============================================================================= # МОДЕЛИ ОТВЕТОВ API # ============================================================================= class ActivityResponse(BaseModel): """ Стандартный ответ API с результатами запроса статистики. Используется для всех эндпоинтов статистики (сегодня, вчера, неделя). Содержит сообщение о результате и данные статистики пользователя. """ message: str = Field(..., description="Сообщение о результате запроса", example="Статистика за сегодняшний день") data: Optional[UserStats] = Field(None, description="Данные статистики пользователя (null если пользователь не найден или неактивен)") class ErrorResponse(BaseModel): """ Модель для стандартизированных ошибок API. Используется для возврата структурированных ошибок с дополнительной информацией. """ detail: str = Field(..., description="Описание ошибки", example="Пользователь не найден") error_code: Optional[str] = Field(None, description="Код ошибки", example="USER_NOT_FOUND") timestamp: Optional[str] = Field(None, description="Время возникновения ошибки", example="2024-01-15T10:30:00Z") class HealthResponse(BaseModel): """ Ответ для health check эндпоинта. Используется для мониторинга состояния сервиса и проверки его работоспособности. """ status: str = Field(..., description="Статус сервиса", example="healthy") timestamp: str = Field(..., description="Время проверки", example="2024-01-15T10:30:00Z") service: str = Field(..., description="Название сервиса", example="Lichess Statistics API") # ============================================================================= # МОДЕЛИ ДЛЯ ЭНДПОИНТА СТАТИСТИКИ ИГР ЗА ПЕРИОД # ============================================================================= class GamePlayer(BaseModel): """ Информация об игроке в партии. Содержит данные о пользователе, его рейтинге и изменении рейтинга в конкретной игре. """ user: Optional[Dict[str, Any]] = Field(None, description="Информация о пользователе") rating: Optional[int] = Field(None, description="Рейтинг игрока") ratingDiff: Optional[int] = Field(None, description="Изменение рейтинга") class Game(BaseModel): """ Модель игры из Lichess API. Содержит полную информацию об игре, включая: - Метаданные игры (ID, время создания, статус) - Информацию об игроках и их рейтингах - Результат игры и ходы в PGN формате """ id: str = Field(..., description="ID игры") rated: bool = Field(..., description="Рейтинговая ли игра") variant: str = Field(..., description="Вариант игры") speed: str = Field(..., description="Скорость игры (bullet, blitz, rapid, classical, correspondence)") perf: str = Field(..., description="Тип производительности") createdAt: int = Field(..., description="Время создания игры (timestamp)") lastMoveAt: int = Field(..., description="Время последнего хода (timestamp)") status: str = Field(..., description="Статус игры") players: Dict[str, GamePlayer] = Field(..., description="Игроки (white, black)") winner: Optional[str] = Field(None, description="Победитель (white, black или null)") moves: str = Field(..., description="Ходы игры в PGN формате") class GameStats(BaseModel): """ Статистика игр по конкретному типу (Bullet, Blitz, Rapid и т.д.). Содержит агрегированную статистику по играм определенного типа: - Количество сыгранных игр - Результаты игр (победы, поражения, ничьи) - Общее изменение рейтинга - Итоговый рейтинг после последней игры """ games_played: int = Field(..., description="Общее количество сыгранных игр", example=10) wins: int = Field(..., description="Количество побед", example=6) losses: int = Field(..., description="Количество поражений", example=3) draws: int = Field(..., description="Количество ничьих", example=1) rating_change: int = Field(..., description="Общее изменение рейтинга", example=15) rating: Optional[int] = Field(None, description="Итоговый рейтинг после последней игры (только если games_played > 0)", example=2850) class GamesOfPeriodStats(BaseModel): """ Статистика игр за период по всем типам. Агрегирует статистику игр по всем временным форматам: - Bullet, Blitz, Rapid, Classical, Correspondence - Общая статистика по всем типам """ bullet: GameStats = Field(..., description="Статистика Bullet игр") blitz: GameStats = Field(..., description="Статистика Blitz игр") rapid: GameStats = Field(..., description="Статистика Rapid игр") classical: GameStats = Field(..., description="Статистика Classical игр") correspondence: GameStats = Field(..., description="Статистика Correspondence игр") total: GameStats = Field(..., description="Общая статистика по всем типам") class GamesOfPeriodResponse(BaseModel): """ Ответ API с результатами запроса статистики игр за период. Содержит метаинформацию о запросе и агрегированную статистику игр. """ message: str = Field(..., description="Сообщение о результате запроса", example="Статистика игр за период") username: str = Field(..., description="Имя пользователя", example="magnus") period_start: int = Field(..., description="Начало периода (Unix timestamp)", example=1640995200) period_end: int = Field(..., description="Конец периода (Unix timestamp)", example=1641081600) games_count: int = Field(..., description="Общее количество игр", example=25) data: Optional[GamesOfPeriodStats] = Field(None, description="Данные статистики игр") # ============================================================================= # МОДЕЛИ ДЛЯ ЭНДПОИНТА СТАТИСТИКИ ЗАДАЧ ЗА ПЕРИОД # ============================================================================= class PuzzleActivity(BaseModel): """ Активность по решению задачи (пазла) из Lichess API. Содержит информацию о попытке решения задачи пользователем: - ID задачи и время решения - Результат решения (решена/не решена) - Дополнительная информация о задаче """ id: str = Field(..., description="ID задачи", example="abc123") createdAt: int = Field(..., description="Время создания активности (timestamp в миллисекундах)", example=1640995200000) win: bool = Field(..., description="Решена ли задача правильно", example=True) puzzle: Dict[str, Any] = Field(..., description="Информация о задаче") class PuzzleStats(BaseModel): """ Агрегированная статистика решения задач за период. Содержит сводную информацию о решении задач: - Общее количество попыток - Количество успешных и неуспешных решений - Процент успешности """ total_attempts: int = Field(..., description="Общее количество попыток решения", example=25) solved: int = Field(..., description="Количество решенных задач", example=18) failed: int = Field(..., description="Количество нерешенных задач", example=7) success_rate: float = Field(..., description="Процент успешных решений", example=72.0) class PuzzleOfPeriodResponse(BaseModel): """ Ответ API с результатами запроса статистики решения задач за период. Содержит метаинформацию о запросе и агрегированную статистику решения задач. """ message: str = Field(..., description="Сообщение о результате запроса", example="Статистика решения задач за период") period_start: int = Field(..., description="Начало периода (Unix timestamp в миллисекундах)", example=1640995200000) period_end: int = Field(..., description="Конец периода (Unix timestamp в миллисекундах)", example=1641081600000) max_puzzles: int = Field(..., description="Максимальное количество задач для получения", example=50) puzzles_in_period: int = Field(..., description="Количество задач в указанном периоде", example=15) data: Optional[PuzzleStats] = Field(None, description="Данные статистики решения задач")