2.0.0 Alpha: Data Refinery

This commit is contained in:
2026-08-08 21:31:56 +08:00
parent fa75081d4d
commit 562775e5db
48 changed files with 4172 additions and 661 deletions
+36 -44
View File
@@ -1,15 +1,16 @@
from flask import Blueprint, render_template, request, jsonify, redirect, url_for, flash, current_app, session
from web.services.stats_service import StatsService
from web.services.feature_service import FeatureService
from web.services.player_profile_service import PlayerProfileService
from web.services.web_service import WebService
from web.database import execute_db, query_db
from web.config import Config
from datetime import datetime
import os
import json
from werkzeug.utils import secure_filename
bp = Blueprint('players', __name__, url_prefix='/players')
ALLOWED_AVATAR_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.webp'}
@bp.route('/')
def index():
@@ -41,7 +42,12 @@ def detail(steam_id):
# Use steam_id as filename to ensure uniqueness per player
# Preserve extension
ext = os.path.splitext(file.filename)[1].lower()
if not ext: ext = '.jpg'
if (
ext not in ALLOWED_AVATAR_EXTENSIONS
or not (file.mimetype or '').startswith('image/')
):
flash('Avatar must be a JPG, PNG, or WebP image.', 'error')
return redirect(url_for('players.detail', steam_id=steam_id))
filename = f"{steam_id}{ext}"
upload_folder = os.path.join(current_app.root_path, 'static', 'avatars')
@@ -177,33 +183,9 @@ def detail(steam_id):
history_asc = StatsService.get_player_trend(steam_id, limit=1000)
history = history_asc[::-1] if history_asc else []
# Calculate Map Stats
map_stats = {}
for match in history:
m_name = match['map_name']
if m_name not in map_stats:
map_stats[m_name] = {'matches': 0, 'wins': 0, 'adr_sum': 0, 'rating_sum': 0}
map_stats[m_name]['matches'] += 1
if match['is_win']:
map_stats[m_name]['wins'] += 1
map_stats[m_name]['adr_sum'] += (match['adr'] or 0)
map_stats[m_name]['rating_sum'] += (match['rating'] or 0)
map_stats_list = []
for m_name, data in map_stats.items():
cnt = data['matches']
map_stats_list.append({
'map_name': m_name,
'matches': cnt,
'win_rate': data['wins'] / cnt,
'adr': data['adr_sum'] / cnt,
'rating': data['rating_sum'] / cnt
})
map_stats_list.sort(key=lambda x: x['matches'], reverse=True)
# --- New: Recent Performance Stats ---
# recent_stats = StatsService.get_recent_performance_stats(steam_id)
map_stats_list = PlayerProfileService.get_map_stats(steam_id)
period_stats = PlayerProfileService.get_period_stats(steam_id)
records = PlayerProfileService.get_records(steam_id)
return render_template('players/profile.html',
player=player,
@@ -213,6 +195,8 @@ def detail(steam_id):
history=history,
distribution=distribution,
map_stats=map_stats_list,
period_stats=period_stats,
records=records,
l2_stats=l2_stats,
side_stats=side_stats)
@@ -223,9 +207,13 @@ def like_comment(comment_id):
@bp.route('/<steam_id>/charts_data')
def charts_data(steam_id):
# ... (existing code) ...
# Trend Data
trends = StatsService.get_player_trend(steam_id, limit=1000)
period_key = request.args.get('period', 'last_20')
if period_key not in PlayerProfileService.PERIOD_KEYS:
period_key = 'last_20'
trends = PlayerProfileService.get_period_history(steam_id, period_key)
if not trends:
trends = StatsService.get_player_trend(steam_id, limit=20)
period_summary = PlayerProfileService.get_period(steam_id, period_key)
# Radar Data (Construct from features)
features = FeatureService.get_player_features(steam_id)
@@ -234,17 +222,11 @@ def charts_data(steam_id):
# Task 1: Strict Team Average Calculation
team_avg_radar = None
lineups = WebService.get_lineups()
if lineups:
target_lineup = None
try:
p_ids = [str(i) for i in json.loads(lineups[0].get("player_ids_json") or "[]")]
if str(steam_id) in p_ids:
target_lineup = p_ids
except:
target_lineup = None
if target_lineup:
from web.services.team_context_service import TeamContextService
active_roster_ids = TeamContextService.get_active_roster_ids()
target_lineup = active_roster_ids if str(steam_id) in active_roster_ids else None
if target_lineup:
# Calculate strict average for this lineup
team_sums = {
'score_aim': 0.0, 'score_defense': 0.0, 'score_utility': 0.0,
@@ -303,9 +285,19 @@ def charts_data(steam_id):
'trend': {'labels': trend_labels, 'values': trend_values},
'radar': radar_data,
'radar_dist': radar_dist,
'team_avg_radar': team_avg_radar
'team_avg_radar': team_avg_radar,
'period': period_summary,
})
@bp.route('/<steam_id>/period_stats')
def period_stats(steam_id):
period_key = request.args.get('period', 'last_20')
period = PlayerProfileService.get_period(steam_id, period_key)
if not period:
return jsonify({'error': 'Unknown period or player'}), 404
return jsonify(period)
# --- API for Comparison ---
@bp.route('/api/search')
def api_search():