add per-game accuracy and outcome table to stats/notifications
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 31s
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 31s
Games-of-period responses can now include a per-game breakdown
(include_games) with Lichess post-analysis accuracy, plus which side
the tracked player was on and their rating change for that game.
- lichess_client.py requests accuracy=true from Lichess; stats_service
computes per-mode average accuracy and builds GameRow entries
(tracked_is_white, tracked_rating_diff) for blitz/rapid/classical
- /games/{username}/period gained an include_games query param
- formatters.py renders a column-aligned monospace table per game:
outcome circle (win/loss/draw relative to the tracked player),
rating change, accuracy, names/ratings, result — for today/yesterday
and periodic notifications; week keeps an aggregate accuracy line
- usernames are Markdown-escaped before formatting since messages are
now sent with parse_mode='Markdown'
This commit is contained in:
parent
4a783225af
commit
d479e14bf9
8 changed files with 364 additions and 75 deletions
|
|
@ -13,7 +13,7 @@ Lichess Statistics API - Модели данных
|
|||
"""
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Dict, Optional, Any
|
||||
from typing import Dict, List, Optional, Any
|
||||
|
||||
# =============================================================================
|
||||
# МОДЕЛИ СТАТИСТИКИ ЗАДАЧ (ПАЗЛОВ)
|
||||
|
|
@ -125,6 +125,7 @@ class GamePlayer(BaseModel):
|
|||
user: Optional[Dict[str, Any]] = Field(None, description="Информация о пользователе")
|
||||
rating: Optional[int] = Field(None, description="Рейтинг игрока")
|
||||
ratingDiff: Optional[int] = Field(None, description="Изменение рейтинга")
|
||||
analysis: Optional[Dict[str, Any]] = Field(None, description="Пост-анализ партии (только если игрок запускал анализ на Lichess), содержит поле 'accuracy'")
|
||||
|
||||
class Game(BaseModel):
|
||||
"""
|
||||
|
|
@ -147,6 +148,23 @@ class Game(BaseModel):
|
|||
winner: Optional[str] = Field(None, description="Победитель (white, black или null)")
|
||||
moves: str = Field(..., description="Ходы игры в PGN формате")
|
||||
|
||||
class GameRow(BaseModel):
|
||||
"""
|
||||
Одна отдельная партия для построчного разбора (today/yesterday/периодические уведомления).
|
||||
|
||||
Порядок игроков — как в партии (белые/чёрные), а не "отслеживаемый пользователь/соперник".
|
||||
"""
|
||||
white_name: str = Field(..., description="Имя игрока белыми")
|
||||
black_name: str = Field(..., description="Имя игрока чёрными")
|
||||
white_rating: Optional[int] = Field(None, description="Рейтинг белых")
|
||||
black_rating: Optional[int] = Field(None, description="Рейтинг чёрных")
|
||||
white_accuracy: Optional[float] = Field(None, description="Точность белых, если партия анализировалась")
|
||||
black_accuracy: Optional[float] = Field(None, description="Точность чёрных, если партия анализировалась")
|
||||
result: str = Field(..., description="Результат партии: '1-0', '0-1' или '1/2-1/2'")
|
||||
created_at: int = Field(..., description="Время создания партии (Unix timestamp в миллисекундах)")
|
||||
tracked_is_white: Optional[bool] = Field(None, description="True, если отслеживаемый пользователь играл белыми; False — чёрными; None — не удалось определить сторону")
|
||||
tracked_rating_diff: Optional[int] = Field(None, description="Изменение рейтинга отслеживаемого пользователя по итогам этой партии")
|
||||
|
||||
class GameStats(BaseModel):
|
||||
"""
|
||||
Статистика игр по конкретному типу (Bullet, Blitz, Rapid и т.д.).
|
||||
|
|
@ -163,6 +181,8 @@ class GameStats(BaseModel):
|
|||
draws: int = Field(..., description="Количество ничьих", example=1)
|
||||
rating_change: int = Field(..., description="Общее изменение рейтинга", example=15)
|
||||
rating: Optional[int] = Field(None, description="Итоговый рейтинг после последней игры (только если games_played > 0)", example=2850)
|
||||
accuracy: Optional[float] = Field(None, description="Средняя точность отслеживаемого пользователя по проанализированным партиям этого режима; None если нет проанализированных партий", example=82.5)
|
||||
games: Optional[List[GameRow]] = Field(None, description="Построчный список отдельных партий (только blitz/rapid/classical), заполняется только если запрошено include_games=True")
|
||||
|
||||
class GamesOfPeriodStats(BaseModel):
|
||||
"""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue