FairValue commited on
Commit
54ac3b6
·
1 Parent(s): 778ab74

style: polish SHAP labels and optimize NLP cache retry logic

Browse files
Files changed (1) hide show
  1. api/main.py +29 -3
api/main.py CHANGED
@@ -160,6 +160,24 @@ def startup_event():
160
  model_global.load_model(MODEL_PATH)
161
  expected_cols_global = model_global.feature_names_in_
162
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
 
164
  # ── NLP Intelligence Cache (TTL = 1 hour) ────────────────────────────────────
165
  # Fixed: previously ran 3 live DDGS searches on every API call — caused
@@ -178,8 +196,16 @@ def _fetch_nlp_intelligence(
178
  """
179
  cache_key = f"{player_name.lower()}|{current_club.lower()}"
180
  cached = _nlp_cache.get(cache_key)
181
- if cached and (time.time() - cached.get('_ts', 0)) < _NLP_CACHE_TTL:
182
- return {**cached, '_from_cache': True}
 
 
 
 
 
 
 
 
183
 
184
  ddgs = DDGS()
185
  axes = {
@@ -327,7 +353,7 @@ async def evaluate_player(req: PlayerEvaluateRequest):
327
  # ── SHAP Feature Contribution Table ──────────────────────────────────────
328
  shap_data = sorted(
329
  [
330
- {"feature": f.replace('_', ' ').title(), "impact": float(s)}
331
  for f, s in zip(expected_cols_global, feature_shaps)
332
  ],
333
  key=lambda x: abs(x['impact']),
 
160
  model_global.load_model(MODEL_PATH)
161
  expected_cols_global = model_global.feature_names_in_
162
 
163
+ def _format_feature_label(f: str) -> str:
164
+ """Converts raw model feature names to boardroom-ready English."""
165
+ mapping = {
166
+ 'Highest_Market_Value_In_Eur': 'Peak Historical Valuation',
167
+ 'Highest MarketValue In Eur': 'Peak Historical Valuation',
168
+ 'Contract_Years_Left': 'Contractual Duration',
169
+ 'Contract YearsLeft': 'Contractual Duration',
170
+ 'Injury_Days_Total_24m': 'Physical Availability Risk',
171
+ 'Injury Days Total 24M': 'Physical Availability Risk',
172
+ 'League_Index': 'League Quality Index',
173
+ 'height_in_cm': 'Aerial/Physical Profile',
174
+ 'Height In Cm': 'Aerial/Physical Profile',
175
+ 'international_caps': 'International Experience',
176
+ 'market_value_in_eur': 'Baseline Market Valuation',
177
+ }
178
+ # Fallback to Title Case with underscores replaced by spaces
179
+ return mapping.get(f, f.replace('_', ' ').title())
180
+
181
 
182
  # ── NLP Intelligence Cache (TTL = 1 hour) ────────────────────────────────────
183
  # Fixed: previously ran 3 live DDGS searches on every API call — caused
 
196
  """
197
  cache_key = f"{player_name.lower()}|{current_club.lower()}"
198
  cached = _nlp_cache.get(cache_key)
199
+
200
+ # Logic: If we have a cached result with real data, keep it for 1 hour.
201
+ # If the cached result was "Empty" (no news found), allow a retry after 5 mins.
202
+ if cached:
203
+ age = time.time() - cached.get('_ts', 0)
204
+ has_signals = cached.get('_found_any', False)
205
+
206
+ if age < _NLP_CACHE_TTL:
207
+ if has_signals or age < 300: # 300s = 5 mins
208
+ return {**cached, '_from_cache': True}
209
 
210
  ddgs = DDGS()
211
  axes = {
 
353
  # ── SHAP Feature Contribution Table ──────────────────────────────────────
354
  shap_data = sorted(
355
  [
356
+ {"feature": _format_feature_label(f), "impact": float(s)}
357
  for f, s in zip(expected_cols_global, feature_shaps)
358
  ],
359
  key=lambda x: abs(x['impact']),