diff --git a/database/L3/L3_Features.sqlite b/database/L3/L3_Features.sqlite index bf53e97..9a525ea 100644 Binary files a/database/L3/L3_Features.sqlite and b/database/L3/L3_Features.sqlite differ diff --git a/database/L3/schema.sql b/database/L3/schema.sql index 97ab170..eabd6ee 100644 --- a/database/L3/schema.sql +++ b/database/L3/schema.sql @@ -32,6 +32,10 @@ CREATE TABLE IF NOT EXISTS dm_player_features ( basic_avg_revenge_kill REAL, basic_avg_awp_kill REAL, basic_avg_jump_count REAL, + basic_avg_mvps REAL, + basic_avg_plants REAL, + basic_avg_defuses REAL, + basic_avg_flash_assists REAL, -- ========================================== -- 1. STA: Stability & Time Series diff --git a/web/routes/players.py b/web/routes/players.py index 541a2f2..23a8af7 100644 --- a/web/routes/players.py +++ b/web/routes/players.py @@ -101,18 +101,25 @@ def detail(steam_id): # Ensure basic stats fallback if features missing or incomplete basic = StatsService.get_player_basic_stats(steam_id) + from collections import defaultdict + if not features: + # Fallback to defaultdict with basic stats + features = defaultdict(lambda: None) if basic: - features = { + features.update({ 'basic_avg_rating': basic.get('rating', 0), 'basic_avg_kd': basic.get('kd', 0), 'basic_avg_kast': basic.get('kast', 0), - 'basic_avg_adr': basic.get('adr', 0), # Pass ADR - } + 'basic_avg_adr': basic.get('adr', 0), + }) else: + # Convert to defaultdict to handle missing keys gracefully (e.g. newly added columns) + # Use lambda: None so that Jinja can check 'if value is not none' + features = defaultdict(lambda: None, dict(features)) + # If features exist but ADR is missing (not in L3), try to patch it from basic - if 'basic_avg_adr' not in features: - features = dict(features) # Convert to dict if row + if 'basic_avg_adr' not in features or features['basic_avg_adr'] is None: features['basic_avg_adr'] = basic.get('adr', 0) if basic else 0 comments = WebService.get_comments('player', steam_id) diff --git a/web/services/feature_service.py b/web/services/feature_service.py index e61d7a2..8111cbd 100644 --- a/web/services/feature_service.py +++ b/web/services/feature_service.py @@ -280,6 +280,14 @@ class FeatureService: SUM(revenge_kill) as sum_revenge, SUM(awp_kill) as sum_awp, SUM(jump_count) as sum_jump, + SUM(mvp_count) as sum_mvps, + SUM(planted_bomb) as sum_plants, + SUM(defused_bomb) as sum_defuses, + SUM(CASE + WHEN flash_assists > 0 THEN flash_assists + WHEN assists > assisted_kill THEN assists - assisted_kill + ELSE 0 + END) as sum_flash_assists, SUM(throw_harm) as sum_util_dmg, SUM(flash_time) as sum_flash_time, SUM(flash_enemy) as sum_flash_enemy, @@ -312,6 +320,10 @@ class FeatureService: df['basic_avg_revenge_kill'] = df['sum_revenge'] / df['matches_played'] df['basic_avg_awp_kill'] = df['sum_awp'] / df['matches_played'] df['basic_avg_jump_count'] = df['sum_jump'] / df['matches_played'] + df['basic_avg_mvps'] = df['sum_mvps'] / df['matches_played'] + df['basic_avg_plants'] = df['sum_plants'] / df['matches_played'] + df['basic_avg_defuses'] = df['sum_defuses'] / df['matches_played'] + df['basic_avg_flash_assists'] = df['sum_flash_assists'] / df['matches_played'] # UTIL Basic df['util_avg_nade_dmg'] = df['sum_util_dmg'] / df['matches_played'] diff --git a/web/services/stats_service.py b/web/services/stats_service.py index 9cc1546..92832eb 100644 --- a/web/services/stats_service.py +++ b/web/services/stats_service.py @@ -632,12 +632,13 @@ class StatsService: metrics = [ 'basic_avg_rating', 'basic_avg_kd', 'basic_avg_kast', 'basic_avg_rws', 'basic_avg_adr', 'basic_avg_headshot_kills', 'basic_headshot_rate', 'basic_avg_assisted_kill', 'basic_avg_awp_kill', 'basic_avg_jump_count', + 'basic_avg_mvps', 'basic_avg_plants', 'basic_avg_defuses', 'basic_avg_flash_assists', 'basic_avg_first_kill', 'basic_avg_first_death', 'basic_first_kill_rate', 'basic_first_death_rate', 'basic_avg_kill_2', 'basic_avg_kill_3', 'basic_avg_kill_4', 'basic_avg_kill_5', 'basic_avg_perfect_kill', 'basic_avg_revenge_kill', # L3 Advanced Dimensions 'sta_last_30_rating', 'sta_win_rating', 'sta_loss_rating', 'sta_rating_volatility', 'sta_time_rating_corr', - 'bat_kd_diff_high_elo', 'bat_avg_duel_win_rate', 'bat_avg_duel_freq', + 'bat_kd_diff_high_elo', 'bat_avg_duel_win_rate', 'hps_clutch_win_rate_1v1', 'hps_clutch_win_rate_1v3_plus', 'hps_match_point_win_rate', 'hps_pressure_entry_rate', 'hps_comeback_kd_diff', 'ptl_pistol_kills', 'ptl_pistol_win_rate', 'ptl_pistol_kd', 'side_rating_ct', 'side_rating_t', 'side_first_kill_rate_ct', 'side_first_kill_rate_t', 'side_kd_diff_ct_t', diff --git a/web/templates/players/profile.html b/web/templates/players/profile.html index 8be5a52..6fa41d7 100644 --- a/web/templates/players/profile.html +++ b/web/templates/players/profile.html @@ -203,20 +203,27 @@ {{ detail_item('AWP Kills (狙击击杀)', features['basic_avg_awp_kill'], 'basic_avg_awp_kill') }} {{ detail_item('Jumps (场均跳跃)', features['basic_avg_jump_count'], 'basic_avg_jump_count', '{:.1f}') }} - + + {{ detail_item('MVP (最有价值)', features['basic_avg_mvps'], 'basic_avg_mvps') }} + {{ detail_item('Plants (下包)', features['basic_avg_plants'], 'basic_avg_plants') }} + {{ detail_item('Defuses (拆包)', features['basic_avg_defuses'], 'basic_avg_defuses') }} + {{ detail_item('Flash Assist (闪光助攻)', features['basic_avg_flash_assists'], 'basic_avg_flash_assists') }} +
+ + {{ detail_item('First Kill (场均首杀)', features['basic_avg_first_kill'], 'basic_avg_first_kill') }} {{ detail_item('First Death (场均首死)', features['basic_avg_first_death'], 'basic_avg_first_death') }} {{ detail_item('FK Rate (首杀率)', features['basic_first_kill_rate'], 'basic_first_kill_rate', '{:.1%}') }} {{ detail_item('FD Rate (首死率)', features['basic_first_death_rate'], 'basic_first_death_rate', '{:.1%}') }} - + {{ detail_item('2K Rounds (双杀)', features['basic_avg_kill_2'], 'basic_avg_kill_2') }} {{ detail_item('3K Rounds (三杀)', features['basic_avg_kill_3'], 'basic_avg_kill_3') }} {{ detail_item('4K Rounds (四杀)', features['basic_avg_kill_4'], 'basic_avg_kill_4') }} {{ detail_item('5K Rounds (五杀)', features['basic_avg_kill_5'], 'basic_avg_kill_5') }} - + {{ detail_item('Perfect Kills (无伤杀)', features['basic_avg_perfect_kill'], 'basic_avg_perfect_kill') }} {{ detail_item('Revenge Kills (复仇杀)', features['basic_avg_revenge_kill'], 'basic_avg_revenge_kill') }} @@ -245,7 +252,6 @@ {{ detail_item('High Elo KD Diff (高分抗压)', features['bat_kd_diff_high_elo'], 'bat_kd_diff_high_elo') }} {{ detail_item('Duel Win% (对枪胜率)', features['bat_avg_duel_win_rate'], 'bat_avg_duel_win_rate', '{:.1%}') }} - {{ detail_item('Duel Freq (对枪频率)', features['bat_avg_duel_freq'], 'bat_avg_duel_freq', '{:.1%}') }}