from flask import Blueprint, render_template, request, jsonify from web.services.web_service import WebService from web.services.stats_service import StatsService from web.services.feature_service import FeatureService import json bp = Blueprint('tactics', __name__, url_prefix='/tactics') @bp.route('/') def index(): return render_template('tactics/index.html') # API: Analyze Lineup @bp.route('/api/analyze', methods=['POST']) def api_analyze(): data = request.json steam_ids = data.get('steam_ids', []) if not steam_ids: return jsonify({'error': 'No players selected'}), 400 # 1. Get Basic Info & Stats players = StatsService.get_players_by_ids(steam_ids) player_data = [] total_rating = 0 total_kd = 0 total_adr = 0 count = 0 radar_vectors = [] for p in players: p_dict = dict(p) # Fetch L3 features f = FeatureService.get_player_features(p_dict['steam_id_64']) stats = dict(f) if f else {} p_dict['stats'] = stats player_data.append(p_dict) if stats: rating_val = stats.get('core_avg_rating2') if rating_val is None: rating_val = stats.get('core_avg_rating') if rating_val is None: rating_val = stats.get('basic_avg_rating') total_rating += rating_val or 0 total_kd += stats.get('core_avg_kd', stats.get('basic_avg_kd', 0)) or 0 total_adr += stats.get('core_avg_adr', stats.get('basic_avg_adr', 0)) or 0 count += 1 radar_vectors.append([ float(stats.get('score_aim') or 0), float(stats.get('score_defense') or 0), float(stats.get('score_utility') or 0), float(stats.get('score_clutch') or 0), float(stats.get('score_economy') or 0), float(stats.get('score_pace') or 0), float(stats.get('score_pistol') or 0), float(stats.get('score_stability') or 0) ]) # 2. Shared Matches shared_matches = StatsService.get_shared_matches(steam_ids) # They are already dicts now with 'result_str' and 'is_win' # 3. Aggregates avg_stats = { 'rating': total_rating / count if count else 0, 'kd': total_kd / count if count else 0, 'adr': total_adr / count if count else 0 } chemistry = 0 if len(radar_vectors) >= 2: def cosine_sim(a, b): dot = sum(x * y for x, y in zip(a, b)) na = sum(x * x for x in a) ** 0.5 nb = sum(y * y for y in b) ** 0.5 if na == 0 or nb == 0: return 0 return dot / (na * nb) sims = [] for i in range(len(radar_vectors)): for j in range(i + 1, len(radar_vectors)): sims.append(cosine_sim(radar_vectors[i], radar_vectors[j])) if sims: chemistry = sum(sims) / len(sims) * 100 # 4. Map Stats Calculation map_stats = {} # {map_name: {'count': 0, 'wins': 0}} total_shared_matches = len(shared_matches) for m in shared_matches: map_name = m['map_name'] if map_name not in map_stats: map_stats[map_name] = {'count': 0, 'wins': 0} map_stats[map_name]['count'] += 1 if m['is_win']: map_stats[map_name]['wins'] += 1 # Convert to list for frontend map_stats_list = [] for k, v in map_stats.items(): win_rate = (v['wins'] / v['count'] * 100) if v['count'] > 0 else 0 map_stats_list.append({ 'map_name': k, 'count': v['count'], 'wins': v['wins'], 'win_rate': win_rate }) # Sort by count desc map_stats_list.sort(key=lambda x: x['count'], reverse=True) return jsonify({ 'players': player_data, 'shared_matches': [dict(m) for m in shared_matches], 'avg_stats': avg_stats, 'map_stats': map_stats_list, 'total_shared_matches': total_shared_matches, 'chemistry': chemistry }) # API: Save Board @bp.route('/save_board', methods=['POST']) def save_board(): data = request.json title = data.get('title', 'Untitled Strategy') map_name = data.get('map_name', 'de_mirage') markers = data.get('markers') if not markers: return jsonify({'success': False, 'message': 'No markers to save'}) WebService.save_strategy_board(title, map_name, json.dumps(markers), 'Anonymous') return jsonify({'success': True, 'message': 'Board saved successfully'})