pablogrois Claude Opus 4.8 commited on
Commit
77bf160
·
1 Parent(s): ffe78f2

Fix arranque en HF: import de goalkicks opcional (feature WIP no commiteada) + re-aplicar p=2 y plegables

Browse files

El deploy fallaba (ModuleNotFoundError: routes_goalkicks) porque app.py importaba la
feature de goalkicks (en desarrollo local, sin commitear). Ahora el import es opcional.
Se re-aplican similitud p=2 y los plegables de perfil/similares.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

src/racing_reports/team_vars.py CHANGED
@@ -289,8 +289,8 @@ def similar_teams(league: str, season: str, team: str, variables: list[str],
289
  dist = dist[~is_self.values]
290
  order = dist.sort_values().head(top).index
291
  # Similitud 0-100% calibrada: d̄ = distancia promedio entre TODOS los pares del pool
292
- # (referencia del 50%). sim = 100·2^(-d/d̄) cada de distancia, se divide por dos.
293
- # 100% en d=0; 84% en 0.25·d̄; 71% en 0.5·d̄; 50% en d̄; 25% en 2·d̄.
294
  from scipy.spatial.distance import pdist
295
  Z = zmat.to_numpy()
296
  if len(Z) > 1500: # cota para pools enormes (scope "todas")
@@ -299,7 +299,7 @@ def similar_teams(league: str, season: str, team: str, variables: list[str],
299
  dbar = float(pdist(Z).mean()) if len(Z) > 1 else 0.0
300
 
301
  def _sim(d):
302
- return round(100.0 * (2.0 ** (-float(d) / dbar)), 1) if dbar > 1e-9 else (100.0 if d < 1e-9 else 0.0)
303
 
304
  teams = [{
305
  "equipo": str(pool.loc[i, "equipo"]),
 
289
  dist = dist[~is_self.values]
290
  order = dist.sort_values().head(top).index
291
  # Similitud 0-100% calibrada: d̄ = distancia promedio entre TODOS los pares del pool
292
+ # (referencia del 50%). sim = 100·2^(-(d/d̄)²) (p=2: aplana cerca de 0, cae fuerte lejos).
293
+ # 100% en d=0; 95.8% en 0.25·d̄; 84.1% en 0.5·d̄; 50% en d̄; 6.25% en 2·d̄.
294
  from scipy.spatial.distance import pdist
295
  Z = zmat.to_numpy()
296
  if len(Z) > 1500: # cota para pools enormes (scope "todas")
 
299
  dbar = float(pdist(Z).mean()) if len(Z) > 1 else 0.0
300
 
301
  def _sim(d):
302
+ return round(100.0 * (2.0 ** (-(float(d) / dbar) ** 2)), 1) if dbar > 1e-9 else (100.0 if d < 1e-9 else 0.0)
303
 
304
  teams = [{
305
  "equipo": str(pool.loc[i, "equipo"]),
src/racing_reports/web/app.py CHANGED
@@ -22,7 +22,10 @@ from racing_reports.api.routes_meta import router as api_meta_router
22
  from racing_reports.api.routes_reports import router as api_reports_router
23
  from racing_reports.api.routes_team_vars import router as api_team_vars_router
24
  from racing_reports.api.routes_ejes import router as api_ejes_router
25
- from racing_reports.api.routes_goalkicks import router as api_goalkicks_router
 
 
 
26
  from racing_reports.api.routes_lowblock import router as api_lowblock_router
27
  from racing_reports.config import DEFAULT_SETTINGS
28
  from racing_reports.datastore import DataStore
@@ -51,7 +54,8 @@ app.include_router(api_reports_router)
51
  app.include_router(api_jobs_router)
52
  app.include_router(api_team_vars_router)
53
  app.include_router(api_ejes_router)
54
- app.include_router(api_goalkicks_router)
 
55
  app.include_router(api_lowblock_router)
56
 
57
  # Estado en memoria (single container en HF Space). Re-export para retrocompat.
 
22
  from racing_reports.api.routes_reports import router as api_reports_router
23
  from racing_reports.api.routes_team_vars import router as api_team_vars_router
24
  from racing_reports.api.routes_ejes import router as api_ejes_router
25
+ try: # feature en desarrollo (archivos pueden no estar en el deploy)
26
+ from racing_reports.api.routes_goalkicks import router as api_goalkicks_router
27
+ except Exception: # noqa: BLE001
28
+ api_goalkicks_router = None
29
  from racing_reports.api.routes_lowblock import router as api_lowblock_router
30
  from racing_reports.config import DEFAULT_SETTINGS
31
  from racing_reports.datastore import DataStore
 
54
  app.include_router(api_jobs_router)
55
  app.include_router(api_team_vars_router)
56
  app.include_router(api_ejes_router)
57
+ if api_goalkicks_router is not None:
58
+ app.include_router(api_goalkicks_router)
59
  app.include_router(api_lowblock_router)
60
 
61
  # Estado en memoria (single container en HF Space). Re-export para retrocompat.
src/racing_reports/web/templates/home.html CHANGED
@@ -441,9 +441,12 @@
441
  <p class="text-xs text-red-300 mt-2" x-show="tvpError" x-text="tvpError"></p>
442
 
443
  <!-- gráfico de z-scores (barras centradas en 0, banda ±1 sombreada) -->
444
- <div x-show="tvpResult && tvpResult.items && tvpResult.items.length" class="mt-5">
445
- <div class="text-sm font-medium mb-1"><span x-text="tvpResult?.equipo"></span>
 
 
446
  <span class="text-xs text-gray-400" x-text="'('+tvpResult?.competencia+' · '+tvpResult?.temporada+') · vs '+tvpResult?.scope+' · '+tvpResult?.pool_size+' equipos'"></span></div>
 
447
  <div class="space-y-1.5">
448
  <template x-for="it in (tvpResult?.items || [])" :key="it.variable">
449
  <div class="flex items-center gap-2 text-xs">
@@ -489,6 +492,7 @@
489
  <img :src="tvpResult?.radar_b64 ? 'data:image/png;base64,'+tvpResult.radar_b64 : ''" alt="Radar" class="rounded-lg max-w-md w-full"/>
490
  </div>
491
  <p x-show="tvpResult && tvpResult.items && tvpResult.items.length && !tvpResult.radar_b64" class="text-xs text-gray-500 mt-2">El radar necesita al menos 3 variables.</p>
 
492
  </div>
493
  </section>
494
 
@@ -530,9 +534,11 @@
530
  </div>
531
  <p class="text-xs text-gray-500 mt-1" x-show="tvsPool.length">Con pool armado, "Buscar en" queda ignorado: los similares se buscan en esas ligas-temporadas.</p>
532
  <p class="text-xs text-red-300 mt-2" x-show="tvsError" x-text="tvsError"></p>
533
- <div x-show="tvsResult && tvsResult.teams" class="mt-3">
534
- <div class="text-xs text-gray-400 mb-1">Más parecidos a <span class="text-gray-200" x-text="tvsResult?.equipo"></span> · vs <span x-text="tvsResult?.scope"></span> (<span x-text="tvsResult?.pool_size"></span> equipos)</div>
535
- <table class="w-full text-xs">
 
 
536
  <thead><tr class="text-gray-400 text-left"><th class="py-1">#</th><th>Equipo</th><th>Liga</th><th>Temp.</th><th class="text-right">Similitud</th></tr></thead>
537
  <tbody>
538
  <template x-for="(t, i) in (tvsResult?.teams || [])" :key="t.competencia+t.temporada+t.equipo">
 
441
  <p class="text-xs text-red-300 mt-2" x-show="tvpError" x-text="tvpError"></p>
442
 
443
  <!-- gráfico de z-scores (barras centradas en 0, banda ±1 sombreada) -->
444
+ <div x-show="tvpResult && tvpResult.items && tvpResult.items.length" class="mt-5" x-data="{ pOpen: true }">
445
+ <div class="text-sm font-medium mb-1 cursor-pointer select-none flex items-center gap-2" @click="pOpen=!pOpen">
446
+ <span class="text-xs transition-transform" :class="pOpen ? 'rotate-90' : ''">▶</span>
447
+ <span x-text="tvpResult?.equipo"></span>
448
  <span class="text-xs text-gray-400" x-text="'('+tvpResult?.competencia+' · '+tvpResult?.temporada+') · vs '+tvpResult?.scope+' · '+tvpResult?.pool_size+' equipos'"></span></div>
449
+ <div x-show="pOpen">
450
  <div class="space-y-1.5">
451
  <template x-for="it in (tvpResult?.items || [])" :key="it.variable">
452
  <div class="flex items-center gap-2 text-xs">
 
492
  <img :src="tvpResult?.radar_b64 ? 'data:image/png;base64,'+tvpResult.radar_b64 : ''" alt="Radar" class="rounded-lg max-w-md w-full"/>
493
  </div>
494
  <p x-show="tvpResult && tvpResult.items && tvpResult.items.length && !tvpResult.radar_b64" class="text-xs text-gray-500 mt-2">El radar necesita al menos 3 variables.</p>
495
+ </div>
496
  </div>
497
  </section>
498
 
 
534
  </div>
535
  <p class="text-xs text-gray-500 mt-1" x-show="tvsPool.length">Con pool armado, "Buscar en" queda ignorado: los similares se buscan en esas ligas-temporadas.</p>
536
  <p class="text-xs text-red-300 mt-2" x-show="tvsError" x-text="tvsError"></p>
537
+ <div x-show="tvsResult && tvsResult.teams" class="mt-3" x-data="{ sOpen: true }">
538
+ <div class="text-xs text-gray-400 mb-1 cursor-pointer select-none flex items-center gap-2" @click="sOpen=!sOpen">
539
+ <span class="transition-transform" :class="sOpen ? 'rotate-90' : ''">▶</span>
540
+ Más parecidos a <span class="text-gray-200" x-text="tvsResult?.equipo"></span> · vs <span x-text="tvsResult?.scope"></span> (<span x-text="tvsResult?.pool_size"></span> equipos)</div>
541
+ <table class="w-full text-xs" x-show="sOpen">
542
  <thead><tr class="text-gray-400 text-left"><th class="py-1">#</th><th>Equipo</th><th>Liga</th><th>Temp.</th><th class="text-right">Similitud</th></tr></thead>
543
  <tbody>
544
  <template x-for="(t, i) in (tvsResult?.teams || [])" :key="t.competencia+t.temporada+t.equipo">