add per-game accuracy and outcome table to stats/notifications
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:
vrubelroman 2026-07-03 09:38:51 +00:00
parent 4a783225af
commit d479e14bf9
8 changed files with 364 additions and 75 deletions

View file

@ -93,7 +93,9 @@ TRANSLATIONS = {
'stats_title': "📊 Statistics {username}{date_range}\n\n",
'puzzles_section': "🧩 Puzzles: {total} (✅ {solved} - ❌ {unsolved})\n\n",
'games_section': "{emoji} {game_type}{games_count} games • {rating_change}\nRating: {rating}\n✅ Wins: {wins}\n❌ Losses: {losses}\n🤝 Draws: {draws}\n\n",
'games_section_with_accuracy': "{emoji} {game_type}{games_count} games • {rating_change}\nRating: {rating}\n✅ Wins: {wins}\n❌ Losses: {losses}\n🤝 Draws: {draws}\n🎯 Accuracy: {accuracy}\n\n",
'game_rows_heading': "{emoji} {game_type} games:\n",
# Set period
'select_gamer_for_period': "⏱️ <b>Select player to set notification period:</b>\n\n",
'select_period': "⏱️ Select period for player {username}:\n📱 Notifications will be sent to personal messages",
@ -110,7 +112,7 @@ TRANSLATIONS = {
'period_puzzles_section': "🧩 Puzzles: {total} (✅ {solved} - ❌ {failed})\n\n",
'period_games_section': "{emoji} {game_type}{games_count} games • {rating_change}\nRating: {rating}\n✅ Wins: {wins}\n❌ Losses: {losses}\n🤝 Draws: {draws}\n\n",
'no_activity': "📭 No activity for this period",
# Last year or 1000 games
'last_year_1000_processing': "⏳ Processing request... This may take a while as requests are very slow.",
'last_year_1000_player_processing': "🔄 Requesting data for player <b>{username}</b>...",
@ -228,7 +230,9 @@ TRANSLATIONS = {
'stats_title': "📊 Статистика {username}{date_range}\n\n",
'puzzles_section': "🧩 Пазлы: {total} (✅ {solved} - ❌ {unsolved})\n\n",
'games_section': "{emoji} {game_type}{games_count} игр • {rating_change}\nРейтинг: {rating}\n✅ Побед: {wins}\n❌ Поражений: {losses}\n🤝 Ничьих: {draws}\n\n",
'games_section_with_accuracy': "{emoji} {game_type}{games_count} игр • {rating_change}\nРейтинг: {rating}\n✅ Побед: {wins}\n❌ Поражений: {losses}\n🤝 Ничьих: {draws}\n🎯 Точность: {accuracy}\n\n",
'game_rows_heading': "{emoji} Партии {game_type}:\n",
# Set period
'select_gamer_for_period': "⏱️ <b>Выберите игрока для установки периода уведомлений:</b>\n\n",
'select_period': "⏱️ Выберите период для игрока {username}:\n📱 Уведомления будут отправляться в личные сообщения",
@ -245,7 +249,7 @@ TRANSLATIONS = {
'period_puzzles_section': "🧩 Пазлы: {total} (✅ {solved} - ❌ {failed})\n\n",
'period_games_section': "{emoji} {game_type}{games_count} игр • {rating_change}\nРейтинг: {rating}\n✅ Побед: {wins}\n❌ Поражений: {losses}\n🤝 Ничьих: {draws}\n\n",
'no_activity': "📭 Нет активности за этот период",
# Last year or 1000 games
'last_year_1000_processing': "⏳ Обработка запроса... Это может занять некоторое время, так как запросы очень медленные.",
'last_year_1000_player_processing': "🔄 Запрос данных для игрока <b>{username}</b>...",