Eliecerrr commited on
Commit
3f8ae48
·
verified ·
1 Parent(s): 79fb83e

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +40 -42
  2. requirements.txt +1 -1
app.py CHANGED
@@ -1,16 +1,8 @@
1
  # app.py
2
- # Hugging Face Space (Gradio) - Formulario numérico + GIF + fuentes
3
- #
4
- # Coloca estos archivos en el repo del Space (misma carpeta que app.py):
5
- # - rf_win_model.pkl
6
- # - input_schema.json
7
- # - model_metadata.json
8
- # - faker.gif
9
- # - requirements.txt
10
- #
11
- # Nota: para que el GIF se anime, se usa gr.HTML con <img src="file=faker.gif">.
12
 
13
  import json
 
14
  import joblib
15
  import pandas as pd
16
  import gradio as gr
@@ -18,10 +10,28 @@ import gradio as gr
18
  MODEL_PKL = "rf_win_model.pkl"
19
  SCHEMA_JSON = "input_schema.json"
20
  META_JSON = "model_metadata.json"
 
21
 
22
- # Si True: recorta inputs al rango observado min-max antes de predecir
23
  CLIP_TO_OBSERVED = True
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  # -------------------------
26
  # Load artifacts
27
  # -------------------------
@@ -36,7 +46,6 @@ with open(META_JSON, "r", encoding="utf-8") as f:
36
  FEATURES = meta["features_order"]
37
  feat_map = {f["name"]: f for f in schema["features"]}
38
 
39
- # Etiquetas humanas
40
  UI_LABELS = {
41
  "TeamTotalGold": "Oro total del equipo",
42
  "TeamXp": "Experiencia total del equipo",
@@ -48,16 +57,12 @@ UI_LABELS = {
48
  "TeamControlWardsPlaced": "Wards de control colocados",
49
  }
50
 
51
- # Agrupar inputs para UI
52
  GROUPS = {
53
  "Economía y pelea": ["TeamTotalGold", "TeamXp", "TeamTotalKills"],
54
  "Objetivos": ["TeamDragonKills", "TeamHeraldKills", "TeamTurretPlatesDestroyed"],
55
  "Visión": ["TeamWardsPlaced", "TeamControlWardsPlaced"],
56
  }
57
 
58
- def fmt_int(x: float) -> str:
59
- return f"{int(round(x))}"
60
-
61
  def reset_values():
62
  return [float(feat_map[c]["ui_default"]) for c in FEATURES]
63
 
@@ -117,13 +122,12 @@ def predict(*vals):
117
  return proba, verdict, warn_text
118
 
119
  # -------------------------
120
- # Build inputs (gr.Number) con rango en label, sin min/max
121
  # -------------------------
122
  input_components_by_col = {}
123
 
124
  for col in FEATURES:
125
  info = feat_map[col]
126
-
127
  rec_min = float(info["p05"])
128
  rec_max = float(info["p95"])
129
  obs_min = float(info["min"])
@@ -176,10 +180,20 @@ CSS = """
176
 
177
  theme = gr.themes.Soft()
178
 
179
- with gr.Blocks(css=CSS, theme=theme, title="Predicción de victoria (demo)") as demo:
180
- with gr.Column(elem_id="wrap"):
 
 
 
 
 
 
 
 
 
181
 
182
- # Header con GIF a la derecha
 
183
  with gr.Row():
184
  with gr.Column(scale=3):
185
  gr.Markdown(
@@ -189,26 +203,12 @@ Formulario para estimar probabilidad de ganar a partir de métricas del equipo e
189
  """.strip()
190
  )
191
  gr.Markdown(
192
- "<div class='small'>Ingresa valores y presiona <b>Predecir</b>. Si te sales de rangos típicos, la app te avisa (y puede ajustar al rango observado).</div>"
193
  )
194
-
195
  with gr.Column(scale=2):
196
- gr.HTML(
197
- """
198
- <div class="gifbox">
199
- <img src="file=faker.gif" alt="Faker GIF">
200
- <div class="muted" style="margin-top:8px;">
201
- Fuente del GIF:
202
- <a href="https://thegamehaus.com/league-of-legends/league-of-legends-faker-history-of-success/2019/04/14/" target="_blank" rel="noopener noreferrer">
203
- TheGameHaus (2019)
204
- </a>
205
- </div>
206
- </div>
207
- """.strip()
208
- )
209
 
210
  with gr.Row():
211
- # Inputs
212
  with gr.Column(scale=3):
213
  with gr.Column(elem_classes="card"):
214
  gr.Markdown("## Ingresa los valores de cada variable")
@@ -222,7 +222,6 @@ Formulario para estimar probabilidad de ganar a partir de métricas del equipo e
222
  btn_predict = gr.Button("Predecir", variant="primary")
223
  btn_reset = gr.Button("Restaurar valores típicos", variant="secondary")
224
 
225
- # Outputs
226
  with gr.Column(scale=2):
227
  with gr.Column(elem_classes="card"):
228
  gr.Markdown("## Resultado")
@@ -236,9 +235,8 @@ Formulario para estimar probabilidad de ganar a partir de métricas del equipo e
236
  """
237
  <div class="small">
238
  El modelo fue entrenado con el dataset de Kaggle:
239
- <a href="https://www.kaggle.com/datasets/karlorusovan/league-of-legends-soloq-matches-at-10-minutes-2024/data" target="_blank" rel="noopener noreferrer">
240
- League of Legends SoloQ Matches at 10 Minutes (2024)
241
- </a>.
242
  </div>
243
  """.strip()
244
  )
@@ -255,4 +253,4 @@ League of Legends SoloQ Matches at 10 Minutes (2024)
255
  outputs=inputs_in_order,
256
  )
257
 
258
- demo.launch()
 
1
  # app.py
2
+ # Gradio Space: formulario numérico + GIF embebido (base64) + créditos
 
 
 
 
 
 
 
 
 
3
 
4
  import json
5
+ import base64
6
  import joblib
7
  import pandas as pd
8
  import gradio as gr
 
10
  MODEL_PKL = "rf_win_model.pkl"
11
  SCHEMA_JSON = "input_schema.json"
12
  META_JSON = "model_metadata.json"
13
+ GIF_PATH = "faker.gif"
14
 
 
15
  CLIP_TO_OBSERVED = True
16
 
17
+ # -------------------------
18
+ # Helpers
19
+ # -------------------------
20
+ def gif_data_uri(path: str) -> str:
21
+ """
22
+ Devuelve un data URI base64 para un GIF local.
23
+ Si el archivo no existe, devuelve string vacío.
24
+ """
25
+ try:
26
+ with open(path, "rb") as f:
27
+ b64 = base64.b64encode(f.read()).decode("utf-8")
28
+ return f"data:image/gif;base64,{b64}"
29
+ except FileNotFoundError:
30
+ return ""
31
+
32
+ def fmt_int(x: float) -> str:
33
+ return f"{int(round(x))}"
34
+
35
  # -------------------------
36
  # Load artifacts
37
  # -------------------------
 
46
  FEATURES = meta["features_order"]
47
  feat_map = {f["name"]: f for f in schema["features"]}
48
 
 
49
  UI_LABELS = {
50
  "TeamTotalGold": "Oro total del equipo",
51
  "TeamXp": "Experiencia total del equipo",
 
57
  "TeamControlWardsPlaced": "Wards de control colocados",
58
  }
59
 
 
60
  GROUPS = {
61
  "Economía y pelea": ["TeamTotalGold", "TeamXp", "TeamTotalKills"],
62
  "Objetivos": ["TeamDragonKills", "TeamHeraldKills", "TeamTurretPlatesDestroyed"],
63
  "Visión": ["TeamWardsPlaced", "TeamControlWardsPlaced"],
64
  }
65
 
 
 
 
66
  def reset_values():
67
  return [float(feat_map[c]["ui_default"]) for c in FEATURES]
68
 
 
122
  return proba, verdict, warn_text
123
 
124
  # -------------------------
125
+ # Build inputs (Number) con rangos en label (sin min/max)
126
  # -------------------------
127
  input_components_by_col = {}
128
 
129
  for col in FEATURES:
130
  info = feat_map[col]
 
131
  rec_min = float(info["p05"])
132
  rec_max = float(info["p95"])
133
  obs_min = float(info["min"])
 
180
 
181
  theme = gr.themes.Soft()
182
 
183
+ gif_uri = gif_data_uri(GIF_PATH)
184
+ gif_html = f"""
185
+ <div class="gifbox">
186
+ {"<img src='" + gif_uri + "' alt='Faker GIF'>" if gif_uri else "<div class='muted'>No se encontró faker.gif en el repo.</div>"}
187
+ <div class="muted" style="margin-top:8px;">
188
+ Fuente del GIF:
189
+ <a href="https://thegamehaus.com/league-of-legends/league-of-legends-faker-history-of-success/2019/04/14/"
190
+ target="_blank" rel="noopener noreferrer">TheGameHaus (2019)</a>
191
+ </div>
192
+ </div>
193
+ """.strip()
194
 
195
+ with gr.Blocks(title="Predicción de victoria (demo)") as demo:
196
+ with gr.Column(elem_id="wrap"):
197
  with gr.Row():
198
  with gr.Column(scale=3):
199
  gr.Markdown(
 
203
  """.strip()
204
  )
205
  gr.Markdown(
206
+ "<div class='small'>Ingresa valores y presiona Predecir. Si te sales de rangos típicos, la app te avisa (y puede ajustar al rango observado).</div>"
207
  )
 
208
  with gr.Column(scale=2):
209
+ gr.HTML(gif_html)
 
 
 
 
 
 
 
 
 
 
 
 
210
 
211
  with gr.Row():
 
212
  with gr.Column(scale=3):
213
  with gr.Column(elem_classes="card"):
214
  gr.Markdown("## Ingresa los valores de cada variable")
 
222
  btn_predict = gr.Button("Predecir", variant="primary")
223
  btn_reset = gr.Button("Restaurar valores típicos", variant="secondary")
224
 
 
225
  with gr.Column(scale=2):
226
  with gr.Column(elem_classes="card"):
227
  gr.Markdown("## Resultado")
 
235
  """
236
  <div class="small">
237
  El modelo fue entrenado con el dataset de Kaggle:
238
+ <a href="https://www.kaggle.com/datasets/karlorusovan/league-of-legends-soloq-matches-at-10-minutes-2024/data"
239
+ target="_blank" rel="noopener noreferrer">League of Legends SoloQ Matches at 10 Minutes (2024)</a>.
 
240
  </div>
241
  """.strip()
242
  )
 
253
  outputs=inputs_in_order,
254
  )
255
 
256
+ demo.launch(css=CSS, theme=theme, ssr_mode=False)
requirements.txt CHANGED
@@ -1,6 +1,6 @@
1
  gradio
2
  pandas
3
  numpy
4
- scikit-learn
5
  joblib
6
  openpyxl
 
1
  gradio
2
  pandas
3
  numpy
4
+ scikit-learn==1.4.2
5
  joblib
6
  openpyxl