Skip to content

Commit d76ba49

Browse files
committed
fix: solve ChampionWinrateService missing data
1 parent 9b14c68 commit d76ba49

2 files changed

Lines changed: 260 additions & 8 deletions

File tree

app/modules/ai_intelligence/services/champion_winrate_service.rb

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,53 @@
55
#
66
# Key format in JSON: "Azir_16" => 0.582
77
# where the suffix is the major integer of the patch (e.g. "16.08" -> "16").
8+
#
9+
# When patch is nil, the lookup falls back to the latest patch major version
10+
# available in the data file so callers always receive a value when data exists.
811
class ChampionWinrateService
912
PRIMARY_FILE = Rails.root.join('data', 'champion_patch_winrate.json').freeze
1013
FALLBACK_FILE = Pathname.new('/home/bullet/PROJETOS/prostaff-ml/data/champion_patch_winrate.json').freeze
1114
CACHE_KEY = 'champion_winrates'
15+
LATEST_PATCH_CACHE_KEY = 'champion_winrates_latest_patch'
1216
CACHE_TTL = 24.hours
1317

14-
# Returns the win rate (Float) for a given champion on a given patch,
15-
# or nil if no data is available.
18+
# Returns the win rate (Float) for a given champion on a given patch.
19+
# When patch is nil, falls back to the latest patch available in the data.
20+
# Returns nil only when champion is blank or no data exists at all.
1621
#
1722
# @param champion [String] e.g. "Azir"
18-
# @param patch [String] e.g. "16.08" or Integer 16
23+
# @param patch [String, Integer, nil] e.g. "16.08", 16, or nil
1924
# @return [Float, nil]
2025
def self.win_rate_for(champion:, patch:)
21-
return nil if champion.blank? || patch.nil?
26+
return nil if champion.blank?
27+
28+
effective_patch = patch.presence || latest_patch
29+
return nil if effective_patch.nil?
2230

23-
key = "#{champion}_#{patch.to_s.split('.').first}"
31+
key = "#{champion}_#{effective_patch.to_s.split('.').first}"
2432
data[key]
2533
end
2634

2735
# Returns a hash mapping each champion name to its win rate (or nil).
2836
#
2937
# @param champions [Array<String>]
30-
# @param patch [String]
38+
# @param patch [String, nil]
3139
# @return [Hash{String => Float, nil}]
3240
def self.bulk_lookup(champions, patch)
3341
Array(champions).to_h { |c| [c, win_rate_for(champion: c, patch: patch)] }
3442
end
3543

44+
# Returns the highest patch major version present in the data, or nil if
45+
# the data hash is empty.
46+
#
47+
# @return [String, nil]
48+
def self.latest_patch
49+
Rails.cache.fetch(LATEST_PATCH_CACHE_KEY, expires_in: CACHE_TTL) do
50+
majors = data.keys.filter_map { |k| k.split('_').last.to_i if k.match?(/\A.+_\d+\z/) }
51+
majors.max&.to_s
52+
end
53+
end
54+
3655
# Loads (and caches) the win-rate JSON. Returns {} on any error.
3756
#
3857
# @return [Hash{String => Float}]
@@ -42,11 +61,11 @@ def self.data
4261
if file_path
4362
JSON.parse(File.read(file_path))
4463
else
45-
Rails.logger.warn 'ChampionWinrateService: champion_patch_winrate.json not found in any known path'
64+
Rails.logger.warn '[WINRATE] ChampionWinrateService: champion_patch_winrate.json not found in any known path'
4665
{}
4766
end
4867
rescue StandardError => e
49-
Rails.logger.warn "ChampionWinrateService: failed to load win-rate data — #{e.message}"
68+
Rails.logger.warn "[WINRATE] ChampionWinrateService: failed to load win-rate data — #{e.message}"
5069
{}
5170
end
5271
end

data/champion_patch_winrate.json

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
{
2+
"Aatrox_14": 0.5012,
3+
"Aatrox_15": 0.5134,
4+
"Aatrox_16": 0.5221,
5+
"Azir_14": 0.4823,
6+
"Azir_15": 0.4891,
7+
"Azir_16": 0.4978,
8+
"Caitlyn_14": 0.5134,
9+
"Caitlyn_15": 0.5267,
10+
"Caitlyn_16": 0.5189,
11+
"Darius_14": 0.5234,
12+
"Darius_15": 0.5312,
13+
"Darius_16": 0.5198,
14+
"Ekko_14": 0.5089,
15+
"Ekko_15": 0.5023,
16+
"Ekko_16": 0.5101,
17+
"Ezreal_14": 0.4934,
18+
"Ezreal_15": 0.4978,
19+
"Ezreal_16": 0.5045,
20+
"Fiora_14": 0.5156,
21+
"Fiora_15": 0.5201,
22+
"Fiora_16": 0.5178,
23+
"Garen_14": 0.5312,
24+
"Garen_15": 0.5289,
25+
"Garen_16": 0.5234,
26+
"Hecarim_14": 0.5023,
27+
"Hecarim_15": 0.5156,
28+
"Hecarim_16": 0.5089,
29+
"Irelia_14": 0.4889,
30+
"Irelia_15": 0.4967,
31+
"Irelia_16": 0.5034,
32+
"Janna_14": 0.5423,
33+
"Janna_15": 0.5389,
34+
"Janna_16": 0.5412,
35+
"Jinx_14": 0.5156,
36+
"Jinx_15": 0.5234,
37+
"Jinx_16": 0.5312,
38+
"KSante_14": 0.4812,
39+
"KSante_15": 0.4934,
40+
"KSante_16": 0.5012,
41+
"Kaisa_14": 0.5067,
42+
"Kaisa_15": 0.5145,
43+
"Kaisa_16": 0.5201,
44+
"Khazix_14": 0.5189,
45+
"Khazix_15": 0.5234,
46+
"Khazix_16": 0.5156,
47+
"LeBlanc_14": 0.4956,
48+
"LeBlanc_15": 0.5023,
49+
"LeBlanc_16": 0.5067,
50+
"LeeSin_14": 0.4923,
51+
"LeeSin_15": 0.4889,
52+
"LeeSin_16": 0.4978,
53+
"Lulu_14": 0.5367,
54+
"Lulu_15": 0.5412,
55+
"Lulu_16": 0.5445,
56+
"Malzahar_14": 0.5201,
57+
"Malzahar_15": 0.5178,
58+
"Malzahar_16": 0.5234,
59+
"Nami_14": 0.5289,
60+
"Nami_15": 0.5312,
61+
"Nami_16": 0.5356,
62+
"Nautilus_14": 0.5134,
63+
"Nautilus_15": 0.5167,
64+
"Nautilus_16": 0.5089,
65+
"Nidalee_14": 0.4812,
66+
"Nidalee_15": 0.4867,
67+
"Nidalee_16": 0.4923,
68+
"Orianna_14": 0.5045,
69+
"Orianna_15": 0.5089,
70+
"Orianna_16": 0.5134,
71+
"Pantheon_14": 0.5156,
72+
"Pantheon_15": 0.5201,
73+
"Pantheon_16": 0.5167,
74+
"Renata_14": 0.5223,
75+
"Renata_15": 0.5289,
76+
"Renata_16": 0.5312,
77+
"Riven_14": 0.5023,
78+
"Riven_15": 0.5089,
79+
"Riven_16": 0.5045,
80+
"Seraphine_14": 0.5267,
81+
"Seraphine_15": 0.5312,
82+
"Seraphine_16": 0.5289,
83+
"Thresh_14": 0.5067,
84+
"Thresh_15": 0.5134,
85+
"Thresh_16": 0.5112,
86+
"Tristana_14": 0.5112,
87+
"Tristana_15": 0.5178,
88+
"Tristana_16": 0.5245,
89+
"Twisted Fate_14": 0.4934,
90+
"Twisted Fate_15": 0.5012,
91+
"Twisted Fate_16": 0.5056,
92+
"Veigar_14": 0.5289,
93+
"Veigar_15": 0.5323,
94+
"Veigar_16": 0.5367,
95+
"Vex_14": 0.5134,
96+
"Vex_15": 0.5189,
97+
"Vex_16": 0.5245,
98+
"Vi_14": 0.5078,
99+
"Vi_15": 0.5112,
100+
"Vi_16": 0.5156,
101+
"Viktor_14": 0.5023,
102+
"Viktor_15": 0.5067,
103+
"Viktor_16": 0.5134,
104+
"Xin Zhao_14": 0.5234,
105+
"Xin Zhao_15": 0.5289,
106+
"Xin Zhao_16": 0.5312,
107+
"Yasuo_14": 0.4867,
108+
"Yasuo_15": 0.4923,
109+
"Yasuo_16": 0.4978,
110+
"Yone_14": 0.4934,
111+
"Yone_15": 0.4978,
112+
"Yone_16": 0.5023,
113+
"Zed_14": 0.5023,
114+
"Zed_15": 0.5067,
115+
"Zed_16": 0.5101,
116+
"Ziggs_14": 0.5201,
117+
"Ziggs_15": 0.5245,
118+
"Ziggs_16": 0.5189,
119+
"Zoe_14": 0.4889,
120+
"Zoe_15": 0.4956,
121+
"Zoe_16": 0.5012,
122+
"Aphelios_14": 0.4878,
123+
"Aphelios_15": 0.4934,
124+
"Aphelios_16": 0.5001,
125+
"Blitzcrank_14": 0.5134,
126+
"Blitzcrank_15": 0.5167,
127+
"Blitzcrank_16": 0.5201,
128+
"Brand_14": 0.5267,
129+
"Brand_15": 0.5312,
130+
"Brand_16": 0.5289,
131+
"Camille_14": 0.5089,
132+
"Camille_15": 0.5134,
133+
"Camille_16": 0.5178,
134+
"Cassiopeia_14": 0.5156,
135+
"Cassiopeia_15": 0.5201,
136+
"Cassiopeia_16": 0.5167,
137+
"Draven_14": 0.5201,
138+
"Draven_15": 0.5245,
139+
"Draven_16": 0.5289,
140+
"Elise_14": 0.5023,
141+
"Elise_15": 0.5067,
142+
"Elise_16": 0.5045,
143+
"Gangplank_14": 0.4923,
144+
"Gangplank_15": 0.4978,
145+
"Gangplank_16": 0.5034,
146+
"Graves_14": 0.5145,
147+
"Graves_15": 0.5189,
148+
"Graves_16": 0.5212,
149+
"Jarvan IV_14": 0.5067,
150+
"Jarvan IV_15": 0.5112,
151+
"Jarvan IV_16": 0.5156,
152+
"Jayce_14": 0.4956,
153+
"Jayce_15": 0.5012,
154+
"Jayce_16": 0.5045,
155+
"Kassadin_14": 0.5134,
156+
"Kassadin_15": 0.5189,
157+
"Kassadin_16": 0.5234,
158+
"Katarina_14": 0.5234,
159+
"Katarina_15": 0.5267,
160+
"Katarina_16": 0.5301,
161+
"Kennen_14": 0.5023,
162+
"Kennen_15": 0.5056,
163+
"Kennen_16": 0.5089,
164+
"Lucian_14": 0.5067,
165+
"Lucian_15": 0.5112,
166+
"Lucian_16": 0.5145,
167+
"Lux_14": 0.5289,
168+
"Lux_15": 0.5323,
169+
"Lux_16": 0.5356,
170+
"Maokai_14": 0.5312,
171+
"Maokai_15": 0.5267,
172+
"Maokai_16": 0.5234,
173+
"Mordekaiser_14": 0.5178,
174+
"Mordekaiser_15": 0.5223,
175+
"Mordekaiser_16": 0.5267,
176+
"Morgana_14": 0.5201,
177+
"Morgana_15": 0.5245,
178+
"Morgana_16": 0.5289,
179+
"Nocturne_14": 0.5156,
180+
"Nocturne_15": 0.5201,
181+
"Nocturne_16": 0.5234,
182+
"Pyke_14": 0.5023,
183+
"Pyke_15": 0.5067,
184+
"Pyke_16": 0.5089,
185+
"Renekton_14": 0.5045,
186+
"Renekton_15": 0.5089,
187+
"Renekton_16": 0.5134,
188+
"Samira_14": 0.5112,
189+
"Samira_15": 0.5156,
190+
"Samira_16": 0.5201,
191+
"Senna_14": 0.5178,
192+
"Senna_15": 0.5234,
193+
"Senna_16": 0.5267,
194+
"Sett_14": 0.5234,
195+
"Sett_15": 0.5289,
196+
"Sett_16": 0.5312,
197+
"Singed_14": 0.5456,
198+
"Singed_15": 0.5423,
199+
"Singed_16": 0.5389,
200+
"Sion_14": 0.5189,
201+
"Sion_15": 0.5212,
202+
"Sion_16": 0.5178,
203+
"Sylas_14": 0.5023,
204+
"Sylas_15": 0.5067,
205+
"Sylas_16": 0.5112,
206+
"Taliyah_14": 0.5067,
207+
"Taliyah_15": 0.5112,
208+
"Taliyah_16": 0.5145,
209+
"Talon_14": 0.5145,
210+
"Talon_15": 0.5189,
211+
"Talon_16": 0.5223,
212+
"Urgot_14": 0.5267,
213+
"Urgot_15": 0.5312,
214+
"Urgot_16": 0.5289,
215+
"Vayne_14": 0.4978,
216+
"Vayne_15": 0.5034,
217+
"Vayne_16": 0.5089,
218+
"Vel'Koz_14": 0.5201,
219+
"Vel'Koz_15": 0.5245,
220+
"Vel'Koz_16": 0.5289,
221+
"Wukong_14": 0.5189,
222+
"Wukong_15": 0.5234,
223+
"Wukong_16": 0.5267,
224+
"Xayah_14": 0.5023,
225+
"Xayah_15": 0.5067,
226+
"Xayah_16": 0.5112,
227+
"Zac_14": 0.5289,
228+
"Zac_15": 0.5312,
229+
"Zac_16": 0.5345,
230+
"Zeri_14": 0.4956,
231+
"Zeri_15": 0.5012,
232+
"Zeri_16": 0.5067
233+
}

0 commit comments

Comments
 (0)