Spaces:
Build error
Build error
Update app.py
Browse files
app.py
CHANGED
|
@@ -13,8 +13,8 @@ def load_excel(file):
|
|
| 13 |
"""
|
| 14 |
Reads the Excel file and normalizes header names.
|
| 15 |
Expected headers (row 1): "Player", "Role 1", "Role 2", "Role 3", "xB90".
|
| 16 |
-
Returns six Dropdown components: three for
|
| 17 |
-
populated with the union of roles from all three
|
| 18 |
"""
|
| 19 |
global df
|
| 20 |
logging.debug("load_excel: Received file %s", file.name)
|
|
@@ -39,7 +39,7 @@ def load_excel(file):
|
|
| 39 |
df["role2"] = df["role2"].astype(str).str.strip()
|
| 40 |
df["role3"] = df["role3"].astype(str).str.strip()
|
| 41 |
df["xb90"] = pd.to_numeric(df["xb90"], errors="coerce")
|
| 42 |
-
# Get union of roles
|
| 43 |
roles = pd.concat([df["role1"], df["role2"], df["role3"]]).dropna().unique().tolist()
|
| 44 |
roles = sorted(roles)
|
| 45 |
roles = [""] + roles # Prepend blank.
|
|
@@ -73,10 +73,18 @@ def update_players(selected_role):
|
|
| 73 |
logging.debug("Players for role %s: %s", selected_role, players)
|
| 74 |
return gr.Dropdown(choices=players, interactive=True)
|
| 75 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
def get_xb90_value(role, player):
|
| 77 |
"""
|
| 78 |
-
Returns the xB90 value (as a string) for the given player
|
| 79 |
-
Searches rows where the player's name matches and the role appears in any column.
|
| 80 |
"""
|
| 81 |
global df
|
| 82 |
logging.debug("get_xb90_value: role=%s, player=%s", role, player)
|
|
@@ -111,22 +119,27 @@ def compute_exchange(role1, player1, pref1, role2, player2, pref2, role3, player
|
|
| 111 |
Computes exchange proposals:
|
| 112 |
- Actual value: sum of selected players’ xB90.
|
| 113 |
- Target: actual * multiplier.
|
| 114 |
-
- For each selected player,
|
| 115 |
(a) the candidate has the selected role (in any column), and
|
| 116 |
(b) if a preferred proposal role is provided, candidate must have it.
|
| 117 |
-
If no candidate meets the
|
| 118 |
- Excludes any candidate that is among the selected players.
|
| 119 |
- Generates candidate combinations and selects up to three proposals ensuring no candidate
|
| 120 |
is repeated across proposals.
|
| 121 |
-
-
|
|
|
|
| 122 |
"""
|
| 123 |
global df
|
| 124 |
logging.debug("compute_exchange: Starting computation")
|
| 125 |
selected = []
|
| 126 |
for i, (r, p, pref) in enumerate([(role1, player1, pref1), (role2, player2, pref2), (role3, player3, pref3)], start=1):
|
| 127 |
if r and p:
|
| 128 |
-
if r == "Por":
|
| 129 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
pref = "Por"
|
| 131 |
xb90_val = get_xb90_value(r, p)
|
| 132 |
if xb90_val == "":
|
|
@@ -289,13 +302,17 @@ with gr.Blocks(theme=gr.themes.Soft(), css="""
|
|
| 289 |
xb90_3 = gr.Textbox(label="xB90 per Giocatore 3", interactive=False)
|
| 290 |
pref3 = gr.Dropdown(label="Ruolo Preferito per Proposta (3)", choices=[], interactive=True)
|
| 291 |
|
| 292 |
-
# Add slider for configurable multiplier.
|
| 293 |
multiplier_slider = gr.Slider(minimum=0.5, maximum=1.5, value=1.05, step=0.01, label="Moltiplicatore di Scambio", interactive=True)
|
| 294 |
|
| 295 |
file_input.change(fn=load_excel, inputs=file_input, outputs=[role1, role2, role3, pref1, pref2, pref3])
|
| 296 |
role1.change(fn=update_players, inputs=role1, outputs=player1)
|
| 297 |
role2.change(fn=update_players, inputs=role2, outputs=player2)
|
| 298 |
role3.change(fn=update_players, inputs=role3, outputs=player3)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 299 |
player1.change(fn=get_xb90_value, inputs=[role1, player1], outputs=xb90_1)
|
| 300 |
player2.change(fn=get_xb90_value, inputs=[role2, player2], outputs=xb90_2)
|
| 301 |
player3.change(fn=get_xb90_value, inputs=[role3, player3], outputs=xb90_3)
|
|
|
|
| 13 |
"""
|
| 14 |
Reads the Excel file and normalizes header names.
|
| 15 |
Expected headers (row 1): "Player", "Role 1", "Role 2", "Role 3", "xB90".
|
| 16 |
+
Returns six Dropdown components: three for selected roles and three for preferred proposal roles,
|
| 17 |
+
populated with the union of roles from all three columns (with a blank option prepended).
|
| 18 |
"""
|
| 19 |
global df
|
| 20 |
logging.debug("load_excel: Received file %s", file.name)
|
|
|
|
| 39 |
df["role2"] = df["role2"].astype(str).str.strip()
|
| 40 |
df["role3"] = df["role3"].astype(str).str.strip()
|
| 41 |
df["xb90"] = pd.to_numeric(df["xb90"], errors="coerce")
|
| 42 |
+
# Get union of roles.
|
| 43 |
roles = pd.concat([df["role1"], df["role2"], df["role3"]]).dropna().unique().tolist()
|
| 44 |
roles = sorted(roles)
|
| 45 |
roles = [""] + roles # Prepend blank.
|
|
|
|
| 73 |
logging.debug("Players for role %s: %s", selected_role, players)
|
| 74 |
return gr.Dropdown(choices=players, interactive=True)
|
| 75 |
|
| 76 |
+
def sync_pref(selected_role):
|
| 77 |
+
"""
|
| 78 |
+
If the selected role is "Por", returns "Por" to automatically set the preferred proposal role.
|
| 79 |
+
Otherwise, returns an empty string.
|
| 80 |
+
"""
|
| 81 |
+
if selected_role == "Por":
|
| 82 |
+
return "Por"
|
| 83 |
+
return ""
|
| 84 |
+
|
| 85 |
def get_xb90_value(role, player):
|
| 86 |
"""
|
| 87 |
+
Returns the xB90 value (as a string) for the given player where the selected role appears in any role column.
|
|
|
|
| 88 |
"""
|
| 89 |
global df
|
| 90 |
logging.debug("get_xb90_value: role=%s, player=%s", role, player)
|
|
|
|
| 119 |
Computes exchange proposals:
|
| 120 |
- Actual value: sum of selected players’ xB90.
|
| 121 |
- Target: actual * multiplier.
|
| 122 |
+
- For each selected player, gathers candidate replacements from rows where:
|
| 123 |
(a) the candidate has the selected role (in any column), and
|
| 124 |
(b) if a preferred proposal role is provided, candidate must have it.
|
| 125 |
+
If no candidate meets the preferred criterion, the preference constraint is relaxed.
|
| 126 |
- Excludes any candidate that is among the selected players.
|
| 127 |
- Generates candidate combinations and selects up to three proposals ensuring no candidate
|
| 128 |
is repeated across proposals.
|
| 129 |
+
- Enforces that if a player's role is "Por", then the preferred must be "Por".
|
| 130 |
+
- If a user somehow sets a different preferred value for a "Por" player, an error is returned.
|
| 131 |
"""
|
| 132 |
global df
|
| 133 |
logging.debug("compute_exchange: Starting computation")
|
| 134 |
selected = []
|
| 135 |
for i, (r, p, pref) in enumerate([(role1, player1, pref1), (role2, player2, pref2), (role3, player3, pref3)], start=1):
|
| 136 |
if r and p:
|
| 137 |
+
if r == "Por":
|
| 138 |
+
if pref != "Por":
|
| 139 |
+
msg = f"Puoi scambiare un portiere solo per un altro portiere. (Giocatore {i})"
|
| 140 |
+
logging.error(msg)
|
| 141 |
+
return msg
|
| 142 |
+
# Automatically force preferred to Por.
|
| 143 |
pref = "Por"
|
| 144 |
xb90_val = get_xb90_value(r, p)
|
| 145 |
if xb90_val == "":
|
|
|
|
| 302 |
xb90_3 = gr.Textbox(label="xB90 per Giocatore 3", interactive=False)
|
| 303 |
pref3 = gr.Dropdown(label="Ruolo Preferito per Proposta (3)", choices=[], interactive=True)
|
| 304 |
|
|
|
|
| 305 |
multiplier_slider = gr.Slider(minimum=0.5, maximum=1.5, value=1.05, step=0.01, label="Moltiplicatore di Scambio", interactive=True)
|
| 306 |
|
| 307 |
file_input.change(fn=load_excel, inputs=file_input, outputs=[role1, role2, role3, pref1, pref2, pref3])
|
| 308 |
role1.change(fn=update_players, inputs=role1, outputs=player1)
|
| 309 |
role2.change(fn=update_players, inputs=role2, outputs=player2)
|
| 310 |
role3.change(fn=update_players, inputs=role3, outputs=player3)
|
| 311 |
+
# Sync preferred role: if role is "Por", force preferred to "Por"
|
| 312 |
+
role1.change(fn=sync_pref, inputs=role1, outputs=pref1)
|
| 313 |
+
role2.change(fn=sync_pref, inputs=role2, outputs=pref2)
|
| 314 |
+
role3.change(fn=sync_pref, inputs=role3, outputs=pref3)
|
| 315 |
+
|
| 316 |
player1.change(fn=get_xb90_value, inputs=[role1, player1], outputs=xb90_1)
|
| 317 |
player2.change(fn=get_xb90_value, inputs=[role2, player2], outputs=xb90_2)
|
| 318 |
player3.change(fn=get_xb90_value, inputs=[role3, player3], outputs=xb90_3)
|