amendolajine commited on
Commit
363ee67
·
verified ·
1 Parent(s): 414cb71

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +44 -18
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 selected roles and three for preferred proposal roles,
17
- populated from the union of roles in all role columns (with a blank option prepended).
18
  """
19
  global df
20
  logging.debug("load_excel: Received file %s", file.name)
@@ -42,7 +42,7 @@ def load_excel(file):
42
  # Get union of roles from all three columns.
43
  roles = pd.concat([df["role1"], df["role2"], df["role3"]]).dropna().unique().tolist()
44
  roles = sorted(roles)
45
- roles = [""] + roles # Prepend blank option.
46
  logging.debug("Roles found: %s", roles)
47
  return (
48
  gr.Dropdown(choices=roles, interactive=True),
@@ -89,23 +89,45 @@ def get_xb90_value(role, player):
89
  return value
90
  return ""
91
 
92
- def compute_exchange(role1, player1, pref1, role2, player2, pref2, role3, player3, pref3):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  """
94
  Computes exchange proposals:
95
  - Actual value: sum of selected players’ xB90.
96
- - Target: actual * 1.05.
97
- - For each selected player, gather candidate replacements from rows where the candidate
98
- has the selected role (in any column) and, if a preferred proposal role is provided,
99
- it must match. If no candidate meets the preferred criterion, the preference is relaxed.
 
100
  - Excludes any candidate that is among the selected players.
101
- - Generates candidate combinations and selects up to three proposals ensuring that no candidate
102
- appears in more than one proposal.
 
103
  """
104
  global df
105
  logging.debug("compute_exchange: Starting computation")
106
  selected = []
107
  for i, (r, p, pref) in enumerate([(role1, player1, pref1), (role2, player2, pref2), (role3, player3, pref3)], start=1):
108
  if r and p:
 
 
 
109
  xb90_val = get_xb90_value(r, p)
110
  if xb90_val == "":
111
  msg = f"Error: Could not find xB90 for Player {i}."
@@ -123,15 +145,15 @@ def compute_exchange(role1, player1, pref1, role2, player2, pref2, role3, player
123
  return "Please select at least one player."
124
 
125
  actual_value = sum(item["xb90"] for item in selected)
126
- target = actual_value * 1.05
127
- logging.debug("Actual value: %s, Target: %s", actual_value, target)
128
 
129
  selected_names = {sel["player"] for sel in selected}
130
  candidate_lists = []
131
  for sel in selected:
132
  r = sel["role"]
133
  pref = sel["pref"]
134
- logging.debug("Gathering candidates for selected role %s with preference %s", r, pref)
135
  if pref:
136
  candidates_df = df[
137
  (((df["role1"] == r) | (df["role2"] == r) | (df["role3"] == r))) &
@@ -154,7 +176,7 @@ def compute_exchange(role1, player1, pref1, role2, player2, pref2, role3, player
154
  candidates = candidates_df[["player", "xb90"]].dropna().to_dict(orient="records")
155
  logging.debug("Candidates for role %s: %s", r, candidates)
156
  if not candidates:
157
- return f"No alternative candidates found for role '{r}' (excluding selected players)."
158
  candidate_lists.append(candidates)
159
 
160
  all_combos = list(itertools.product(*candidate_lists))
@@ -175,7 +197,7 @@ def compute_exchange(role1, player1, pref1, role2, player2, pref2, role3, player
175
  combo_diffs.append((combo, combo_value, diff))
176
  combo_diffs.sort(key=lambda x: x[2])
177
 
178
- # Choose up to three proposals ensuring no candidate is repeated across proposals.
179
  selected_options = []
180
  used_candidates = set()
181
  for combo, combo_value, diff in combo_diffs:
@@ -198,9 +220,10 @@ def compute_exchange(role1, player1, pref1, role2, player2, pref2, role3, player
198
  for idx, (combo, combo_value, diff, _) in enumerate(selected_options, start=1):
199
  option_str = f"Option {idx} (Total xB90: {combo_value:.2f}, Diff: {diff:.2f}):\n"
200
  for i, candidate in enumerate(combo):
 
201
  option_str += (
202
  f" - Replacement for '{selected[i]['player']}' (Role: {selected[i]['role']}): "
203
- f"{candidate['player']} (xB90: {candidate['xb90']})\n"
204
  )
205
  output += option_str + "\n"
206
  logging.debug("Exchange proposals computed successfully.")
@@ -213,7 +236,7 @@ with gr.Blocks(theme=gr.themes.Soft(), css="""
213
  font-family: 'Montserrat', sans-serif;
214
  }
215
  .gradio-container {
216
- background: linear-gradient(rgba(0,0,0,0.6), rgba(0,0,0,0.6)), url('https://source.unsplash.com/1600x900/?football') no-repeat center center fixed;
217
  background-size: cover;
218
  }
219
  .gradio-interface {
@@ -266,6 +289,9 @@ with gr.Blocks(theme=gr.themes.Soft(), css="""
266
  xb90_3 = gr.Textbox(label="xB90 per Giocatore 3", interactive=False)
267
  pref3 = gr.Dropdown(label="Ruolo Preferito per Proposta (3)", choices=[], interactive=True)
268
 
 
 
 
269
  file_input.change(fn=load_excel, inputs=file_input, outputs=[role1, role2, role3, pref1, pref2, pref3])
270
  role1.change(fn=update_players, inputs=role1, outputs=player1)
271
  role2.change(fn=update_players, inputs=role2, outputs=player2)
@@ -279,7 +305,7 @@ with gr.Blocks(theme=gr.themes.Soft(), css="""
279
 
280
  exchange_button.click(
281
  fn=compute_exchange,
282
- inputs=[role1, player1, pref1, role2, player2, pref2, role3, player3, pref3],
283
  outputs=output_box,
284
  )
285
 
 
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 the selected roles and three for the corresponding preferred proposal roles,
17
+ populated with the union of roles from all three role columns (with a blank option prepended).
18
  """
19
  global df
20
  logging.debug("load_excel: Received file %s", file.name)
 
42
  # Get union of roles from all three columns.
43
  roles = pd.concat([df["role1"], df["role2"], df["role3"]]).dropna().unique().tolist()
44
  roles = sorted(roles)
45
+ roles = [""] + roles # Prepend blank.
46
  logging.debug("Roles found: %s", roles)
47
  return (
48
  gr.Dropdown(choices=roles, interactive=True),
 
89
  return value
90
  return ""
91
 
92
+ def get_candidate_roles(candidate_name):
93
+ """
94
+ Returns a comma-separated string of roles for the candidate.
95
+ """
96
+ global df
97
+ if df is None or not candidate_name:
98
+ return ""
99
+ row = df[df["player"] == candidate_name]
100
+ if not row.empty:
101
+ roles = set()
102
+ for col in ["role1", "role2", "role3"]:
103
+ val = row.iloc[0][col]
104
+ if pd.notna(val) and str(val).strip():
105
+ roles.add(str(val).strip())
106
+ return ", ".join(sorted(roles))
107
+ return ""
108
+
109
+ def compute_exchange(role1, player1, pref1, role2, player2, pref2, role3, player3, pref3, multiplier):
110
  """
111
  Computes exchange proposals:
112
  - Actual value: sum of selected players’ xB90.
113
+ - Target: actual * multiplier.
114
+ - For each selected player, gather candidate replacements from rows where:
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 preference, relax the constraint.
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
+ - Also enforces that if the selected role is "Por", then the preferred must be "Por".
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": # enforce rule: if role is Por, then preferred must be Por.
129
+ logging.debug("For player %d with role 'Por', forcing preferred to 'Por'", i)
130
+ pref = "Por"
131
  xb90_val = get_xb90_value(r, p)
132
  if xb90_val == "":
133
  msg = f"Error: Could not find xB90 for Player {i}."
 
145
  return "Please select at least one player."
146
 
147
  actual_value = sum(item["xb90"] for item in selected)
148
+ target = actual_value * multiplier
149
+ logging.debug("Actual value: %s, Target: %s (multiplier=%s)", actual_value, target, multiplier)
150
 
151
  selected_names = {sel["player"] for sel in selected}
152
  candidate_lists = []
153
  for sel in selected:
154
  r = sel["role"]
155
  pref = sel["pref"]
156
+ logging.debug("Gathering candidates for role %s with preference %s", r, pref)
157
  if pref:
158
  candidates_df = df[
159
  (((df["role1"] == r) | (df["role2"] == r) | (df["role3"] == r))) &
 
176
  candidates = candidates_df[["player", "xb90"]].dropna().to_dict(orient="records")
177
  logging.debug("Candidates for role %s: %s", r, candidates)
178
  if not candidates:
179
+ return f"No alternative candidates found for role '{r}' (excluding selected players) matching preference '{pref}'."
180
  candidate_lists.append(candidates)
181
 
182
  all_combos = list(itertools.product(*candidate_lists))
 
197
  combo_diffs.append((combo, combo_value, diff))
198
  combo_diffs.sort(key=lambda x: x[2])
199
 
200
+ # Choose up to three proposals ensuring disjoint candidate sets.
201
  selected_options = []
202
  used_candidates = set()
203
  for combo, combo_value, diff in combo_diffs:
 
220
  for idx, (combo, combo_value, diff, _) in enumerate(selected_options, start=1):
221
  option_str = f"Option {idx} (Total xB90: {combo_value:.2f}, Diff: {diff:.2f}):\n"
222
  for i, candidate in enumerate(combo):
223
+ cand_roles = get_candidate_roles(candidate["player"])
224
  option_str += (
225
  f" - Replacement for '{selected[i]['player']}' (Role: {selected[i]['role']}): "
226
+ f"{candidate['player']} (Role: {cand_roles}, xB90: {candidate['xb90']})\n"
227
  )
228
  output += option_str + "\n"
229
  logging.debug("Exchange proposals computed successfully.")
 
236
  font-family: 'Montserrat', sans-serif;
237
  }
238
  .gradio-container {
239
+ background: linear-gradient(rgba(0,0,0,0.6), rgba(0,0,0,0.6)), url('https://source.unsplash.com/1600x900/?football,stadium') no-repeat center center fixed;
240
  background-size: cover;
241
  }
242
  .gradio-interface {
 
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)
 
305
 
306
  exchange_button.click(
307
  fn=compute_exchange,
308
+ inputs=[role1, player1, pref1, role2, player2, pref2, role3, player3, pref3, multiplier_slider],
309
  outputs=output_box,
310
  )
311