MrSimple07's picture
some more fixing text and 5 most weaknesses
627aad0
import chess
import chess.pgn
import io
import re
import logging
from collections import defaultdict
from core.ai_integration import get_comprehensive_analysis
from core.openings import detect_opening, load_opening_database
from core.chess_api import get_user_games_from_chess_com, fetch_lichess_puzzles
logger = logging.getLogger(__name__)
def extract_user_rating(games, username):
ratings = []
username_lower = username.strip().lower()
for game in games:
white_player = game.headers.get("White", "").strip().lower()
black_player = game.headers.get("Black", "").strip().lower()
if username_lower == white_player:
white_elo = game.headers.get("WhiteElo", "")
if white_elo and white_elo.isdigit():
ratings.append(int(white_elo))
elif username_lower == black_player:
black_elo = game.headers.get("BlackElo", "")
if black_elo and black_elo.isdigit():
ratings.append(int(black_elo))
if ratings:
avg_rating = sum(ratings) // len(ratings)
return avg_rating
return 1500
def analyze_games(username_chesscom, pgn_file, username_pgn):
actual_username = None
pgn_content = None
user_rating = 1500 # Default rating
if username_chesscom:
pgn_content, error = get_user_games_from_chess_com(username_chesscom)
if error:
return error, "", "", "", None, None, None, None, None
actual_username = username_chesscom
elif pgn_file:
pgn_content = pgn_file.decode('utf-8') if isinstance(pgn_file, bytes) else pgn_file
if username_pgn and username_pgn.strip():
actual_username = username_pgn.strip()
else:
try:
first_game = chess.pgn.read_game(io.StringIO(pgn_content))
if first_game:
white = first_game.headers.get("White", "")
black = first_game.headers.get("Black", "")
actual_username = white if white else black if black else "Player"
else:
actual_username = "Player"
except:
actual_username = "Player"
else:
return "❌ Chess.com foydalanuvchi nomini kiriting yoki PGN faylni yuklang", "", "", "", None, None, None, None, None
games = parse_pgn_content(pgn_content)
if not games:
return "❌ O'yinlar topilmadi yoki tahlil qilinmadi", "", "", "", None, None, None, None, None
# Extract user rating from games
user_rating = extract_user_rating(games, actual_username)
logger.info(f"Extracted user rating: {user_rating}")
all_analyses = []
opening_stats = defaultdict(lambda: {'wins': 0, 'losses': 0, 'draws': 0, 'total': 0})
color_stats = {
'white': {'wins': 0, 'losses': 0, 'draws': 0},
'black': {'wins': 0, 'losses': 0, 'draws': 0}
}
for game in games:
analysis = analyze_game_detailed(game, actual_username)
all_analyses.append(analysis)
opening = analysis['opening']
user_result = analysis.get('user_result')
user_color = analysis['user_color']
if user_color is not None:
opening_stats[opening]['total'] += 1
if user_result == 'win':
opening_stats[opening]['wins'] += 1
color_key = 'white' if user_color == chess.WHITE else 'black'
color_stats[color_key]['wins'] += 1
elif user_result == 'loss':
opening_stats[opening]['losses'] += 1
color_key = 'white' if user_color == chess.WHITE else 'black'
color_stats[color_key]['losses'] += 1
elif user_result == 'draw':
opening_stats[opening]['draws'] += 1
color_key = 'white' if user_color == chess.WHITE else 'black'
color_stats[color_key]['draws'] += 1
weaknesses = categorize_mistakes(all_analyses)
all_mistakes = []
for analysis in all_analyses:
all_mistakes.extend(analysis.get('mistakes', []))
stats_report = f"## 📊 {len(games)} ta o'yin tahlili\n\n"
stats_report += f"**Sizning o'rtacha reytingingiz:** {user_rating}\n\n"
stats_report += f"**Jami xatolar:** {len(all_mistakes)} ta\n\n"
stats_report += "### 🎯 Eng zaif 5 tomoningiz:\n\n"
if weaknesses:
for i, w in enumerate(weaknesses[:5], 1):
stats_report += f"**{i}. {w['category']}** - {w['count']} marta ({w['percentage']:.1f}%)\n"
else:
stats_report += "Xatolar topilmadi yoki tahlil qilinmadi.\n"
opening_report = "\n\n## 🎭 Debyut Statistikasi\n\n"
sorted_openings = sorted(opening_stats.items(), key=lambda x: x[1]['total'], reverse=True)[:10]
for opening, stats in sorted_openings:
total = stats['total']
wins = stats['wins']
losses = stats['losses']
draws = stats['draws']
win_rate = (wins / total * 100) if total > 0 else 0
opening_report += f"**{opening}** ({total} o'yin)\n"
opening_report += f"- G'alabalar: {wins} ({win_rate:.1f}%) | Yutqazishlar: {losses} | Duranglar: {draws}\n\n"
color_report = "\n\n## ⚪⚫ Rang bo'yicha natijalar\n\n"
white_total = sum(color_stats['white'].values())
black_total = sum(color_stats['black'].values())
if white_total > 0:
white_wr = color_stats['white']['wins'] / white_total * 100
color_report += f"**Oq figuralar bilan:**\n"
color_report += f"- G'alabalar: {color_stats['white']['wins']} ({white_wr:.1f}%)\n"
color_report += f"- Yutqazishlar: {color_stats['white']['losses']}\n"
color_report += f"- Duranglar: {color_stats['white']['draws']}\n\n"
if black_total > 0:
black_wr = color_stats['black']['wins'] / black_total * 100
color_report += f"**Qora figuralar bilan:**\n"
color_report += f"- G'alabalar: {color_stats['black']['wins']} ({black_wr:.1f}%)\n"
color_report += f"- Yutqazishlar: {color_stats['black']['losses']}\n"
color_report += f"- Duranglar: {color_stats['black']['draws']}\n"
full_report = stats_report + opening_report + color_report
ai_analysis = get_comprehensive_analysis(weaknesses, opening_stats, color_stats, len(games))
ai_report = f"## 🤖 AI Murabbiy: To'liq Tahlil va O'quv Rejasi\n\n{ai_analysis}"
weakness_themes = [w['category'] for w in weaknesses[:5]]
puzzles = fetch_lichess_puzzles(weakness_themes, user_rating=user_rating, count=5)
puzzle_text = "## 🧩 Sizning shaxsiy masalalaringiz\n\n"
puzzle_text += f"Sizning reytingingiz: **{user_rating}** - Masalalar shu darajaga moslashtirilgan\n\n"
for i, puzzle in enumerate(puzzles, 1):
theme = puzzle.get('theme', 'Tactics')
rating = puzzle.get('rating', user_rating)
url = puzzle.get('url', 'https://lichess.org/training')
puzzle_text += f"**Puzzle {i}: {theme}** (Rating: {rating})\n"
puzzle_text += f"- [Lichess Training]({url})\n\n"
return (
full_report,
ai_report,
puzzle_text,
"",
None,
"",
None,
"",
None
)
def parse_pgn_content(pgn_content):
games = []
if isinstance(pgn_content, list):
for pgn_text in pgn_content:
try:
game = chess.pgn.read_game(io.StringIO(pgn_text))
if game:
games.append(game)
except:
pass
else:
pgn_io = io.StringIO(pgn_content)
while True:
try:
game = chess.pgn.read_game(pgn_io)
if game is None:
break
games.append(game)
except:
break
return games
def analyze_game_detailed(game, username):
board = game.board()
mistakes = []
move_number = 0
white_player = game.headers.get("White", "").strip().lower()
black_player = game.headers.get("Black", "").strip().lower()
username_lower = username.strip().lower()
user_color = None
if username_lower == white_player:
user_color = chess.WHITE
elif username_lower == black_player:
user_color = chess.BLACK
result = game.headers.get("Result", "*")
opening = detect_opening(game)
user_result = None
if user_color is not None and result != "*":
if result == "1-0":
user_result = "win" if user_color == chess.WHITE else "loss"
elif result == "0-1":
user_result = "win" if user_color == chess.BLACK else "loss"
elif result == "1/2-1/2":
user_result = "draw"
material_values = {chess.PAWN: 1, chess.KNIGHT: 3, chess.BISHOP: 3, chess.ROOK: 5, chess.QUEEN: 9}
def count_material(board):
total = 0
for piece_type in material_values:
total += len(board.pieces(piece_type, chess.WHITE)) * material_values[piece_type]
total -= len(board.pieces(piece_type, chess.BLACK)) * material_values[piece_type]
return total
for move in game.mainline_moves():
move_number += 1
if user_color is not None and board.turn != user_color:
board.push(move)
continue
material_before = count_material(board)
board.push(move)
material_after = count_material(board)
material_loss = abs(material_after - material_before) if board.turn == chess.WHITE else abs(material_before - material_after)
moved_piece = board.piece_at(move.to_square)
mistake_type = None
if material_loss >= 3:
mistake_type = 'blunder'
elif material_loss >= 1:
mistake_type = 'mistake'
elif moved_piece and board.is_attacked_by(not board.turn, move.to_square):
attackers = len(board.attackers(not board.turn, move.to_square))
defenders = len(board.attackers(board.turn, move.to_square))
if attackers > defenders:
mistake_type = 'hanging_piece'
if move_number <= 10:
phase = 'opening'
elif len(board.piece_map()) <= 10:
phase = 'endgame'
else:
phase = 'middlegame'
if mistake_type:
mistakes.append({
'type': mistake_type,
'phase': phase,
'move_number': move_number
})
return {
'mistakes': mistakes,
'opening': opening,
'result': result,
'user_color': user_color,
'user_result': user_result
}
def categorize_mistakes(all_analyses):
if not all_analyses:
return []
blunders = 0
regular_mistakes = 0
hanging = 0
opening = 0
middlegame = 0
endgame = 0
for analysis in all_analyses:
for mistake in analysis.get('mistakes', []):
mistake_type = mistake.get('type')
phase = mistake.get('phase')
if mistake_type == 'blunder':
blunders += 1
elif mistake_type == 'mistake':
regular_mistakes += 1
elif mistake_type == 'hanging_piece':
hanging += 1
if phase == 'opening':
opening += 1
elif phase == 'middlegame':
middlegame += 1
elif phase == 'endgame':
endgame += 1
total = blunders + regular_mistakes + hanging + opening + middlegame + endgame
if total == 0:
return []
weaknesses = []
if blunders > 0:
weaknesses.append({
'category': "Qo'pol xatolar",
'count': blunders,
'percentage': (blunders / total * 100)
})
if regular_mistakes > 0:
weaknesses.append({
'category': 'Kichik xatolar',
'count': regular_mistakes,
'percentage': (regular_mistakes / total * 100)
})
if hanging > 0:
weaknesses.append({
'category': 'Himoyasiz qoldirish',
'count': hanging,
'percentage': (hanging / total * 100)
})
if opening > 0:
weaknesses.append({
'category': 'Debyut xatolari',
'count': opening,
'percentage': (opening / total * 100)
})
if middlegame > 0:
weaknesses.append({
'category': "O'rta o'yin xatolari",
'count': middlegame,
'percentage': (middlegame / total * 100)
})
if endgame > 0:
weaknesses.append({
'category': 'Endshpil xatolari',
'count': endgame,
'percentage': (endgame / total * 100)
})
weaknesses.sort(key=lambda x: x['count'], reverse=True)
return weaknesses