MBG0903 commited on
Commit
defccd4
Β·
verified Β·
1 Parent(s): 8f8e94f

Update agents/reasoner.py

Browse files
Files changed (1) hide show
  1. agents/reasoner.py +130 -2
agents/reasoner.py CHANGED
@@ -84,7 +84,7 @@ def run_picking_optimization(message, picking_df):
84
 
85
 
86
  # ============================================================
87
- # DEMAND FORECASTING β€” PHASE 3 MODULE 1
88
  # ============================================================
89
 
90
  def run_demand_forecast(message, slotting_df):
@@ -114,6 +114,7 @@ def run_demand_forecast(message, slotting_df):
114
 
115
  reasoning_steps.append("Generated 7-day demand projection.")
116
 
 
117
  plt.figure(figsize=(6, 4))
118
  plt.plot(forecast_df["Day"], forecast_df["Forecasted_Demand"], marker="o")
119
  plt.title("7-Day Demand Forecast")
@@ -135,7 +136,7 @@ def run_demand_forecast(message, slotting_df):
135
 
136
 
137
  # ============================================================
138
- # REPLENISHMENT OPTIMIZATION β€” PHASE 3 MODULE 2
139
  # ============================================================
140
 
141
  def run_replenishment_analysis(message, slotting_df):
@@ -170,3 +171,130 @@ def run_replenishment_analysis(message, slotting_df):
170
  )
171
 
172
  return explanation, df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
 
86
  # ============================================================
87
+ # DEMAND FORECASTING β€” MODULE 1
88
  # ============================================================
89
 
90
  def run_demand_forecast(message, slotting_df):
 
114
 
115
  reasoning_steps.append("Generated 7-day demand projection.")
116
 
117
+ # Plot forecast
118
  plt.figure(figsize=(6, 4))
119
  plt.plot(forecast_df["Day"], forecast_df["Forecasted_Demand"], marker="o")
120
  plt.title("7-Day Demand Forecast")
 
136
 
137
 
138
  # ============================================================
139
+ # REPLENISHMENT OPTIMIZATION β€” MODULE 2
140
  # ============================================================
141
 
142
  def run_replenishment_analysis(message, slotting_df):
 
171
  )
172
 
173
  return explanation, df
174
+
175
+
176
+ # ============================================================
177
+ # INVENTORY REBALANCING β€” MODULE 3
178
+ # ============================================================
179
+
180
+ def run_rebalancing_analysis(message, slotting_df):
181
+ reasoning = []
182
+ df = slotting_df.copy()
183
+
184
+ if "Frequency" not in df.columns:
185
+ return "Frequency missing β€” cannot rebalance.", None
186
+
187
+ if "Aisle" not in df.columns:
188
+ df["Aisle"] = np.arange(1, len(df) + 1)
189
+ reasoning.append("Aisle data missing β€” assigned aisles automatically.")
190
+
191
+ velocity_map = {"fast": 3, "medium": 2, "slow": 1}
192
+ df["VelScore"] = df["Velocity"].str.lower().map(velocity_map)
193
+ df["LoadScore"] = df["VelScore"] * 0.6 + df["Frequency"] * 0.4
194
+ reasoning.append("Calculated SKU load score (velocity + frequency).")
195
+
196
+ aisle_load = df.groupby("Aisle")["LoadScore"].sum().reset_index()
197
+ avg_load = aisle_load["LoadScore"].mean()
198
+
199
+ aisle_load["Congestion"] = aisle_load["LoadScore"].apply(
200
+ lambda x: "πŸ”΄ High" if x > avg_load * 1.25
201
+ else ("🟑 Medium" if x > avg_load * 0.75 else "🟒 Low")
202
+ )
203
+
204
+ df = df.merge(aisle_load[["Aisle", "Congestion"]], on="Aisle", how="left")
205
+ reasoning.append("Assigned congestion levels to aisles.")
206
+
207
+ high_aisles = aisle_load[aisle_load["Congestion"] == "πŸ”΄ High"]["Aisle"].tolist()
208
+ low_aisles = aisle_load[aisle_load["Congestion"] == "🟒 Low"]["Aisle"].tolist()
209
+
210
+ move_plan = []
211
+
212
+ if high_aisles and low_aisles:
213
+ for aisle in high_aisles:
214
+ congested_skus = df[df["Aisle"] == aisle].sort_values("LoadScore", ascending=False)
215
+ top_to_move = congested_skus.head(2)
216
+
217
+ for i, row in top_to_move.iterrows():
218
+ target_aisle = low_aisles[i % len(low_aisles)]
219
+ move_plan.append({
220
+ "SKU": row["SKU"],
221
+ "FromAisle": row["Aisle"],
222
+ "ToAisle": target_aisle,
223
+ "LoadScore": round(row["LoadScore"], 2),
224
+ "Reason": "Reduce congestion"
225
+ })
226
+
227
+ reasoning.append("Generated SKU redistribution plan.")
228
+ else:
229
+ reasoning.append("No congestion found β€” no rebalancing needed.")
230
+
231
+ move_df = pd.DataFrame(move_plan)
232
+
233
+ explanation = (
234
+ "### πŸ”„ Inventory Rebalancing\n"
235
+ "SKU redistribution plan to reduce aisle congestion.\n\n"
236
+ "#### πŸ” Reasoning\n" + "\n".join([f"- {r}" for r in reasoning])
237
+ )
238
+
239
+ return explanation, move_df
240
+
241
+
242
+ # ============================================================
243
+ # WORKFORCE OPTIMIZATION β€” MODULE 4
244
+ # ============================================================
245
+
246
+ def run_workforce_optimization(message, slotting_df):
247
+ """
248
+ Estimate workforce needed based on SKU demand load.
249
+ """
250
+ reasoning = []
251
+ df = slotting_df.copy()
252
+
253
+ if "Frequency" not in df.columns:
254
+ return "Cannot calculate workforce β€” missing Frequency column.", None
255
+
256
+ df["Workload"] = df["Frequency"] * 1.2 # weight multiplier
257
+ total_workload = df["Workload"].sum()
258
+ workers_needed = max(1, int(total_workload // 150))
259
+
260
+ reasoning.append(f"Total workload: {total_workload:.2f}")
261
+ reasoning.append(f"Workers required (estimated): {workers_needed}")
262
+
263
+ result = pd.DataFrame({
264
+ "Metric": ["Total Workload", "Estimated Workers Needed"],
265
+ "Value": [total_workload, workers_needed]
266
+ })
267
+
268
+ explanation = (
269
+ "### πŸ‘· Workforce Optimization\n"
270
+ "Estimated staffing requirement based on SKU workload.\n\n"
271
+ "#### πŸ” Reasoning\n" + "\n".join([f"- {r}" for r in reasoning])
272
+ )
273
+
274
+ return explanation, result
275
+
276
+
277
+ # ============================================================
278
+ # DOCK SCHEDULING OPTIMIZATION β€” MODULE 5
279
+ # ============================================================
280
+
281
+ def run_dock_scheduling(message, slotting_df):
282
+ """
283
+ Simple dock scheduling:
284
+ - Assigns SKUs to docks based on demand priority
285
+ """
286
+ reasoning = []
287
+ df = slotting_df.copy()
288
+
289
+ df["Priority"] = df["Frequency"].rank(ascending=False)
290
+ df["AssignedDock"] = df["Priority"].apply(lambda x: int((x - 1) % 3) + 1)
291
+
292
+ reasoning.append("Assigned SKUs to 3 docks based on priority rank.")
293
+
294
+ explanation = (
295
+ "### πŸš› Dock Scheduling Optimization\n"
296
+ "SKUs allocated to dock doors based on priority.\n\n"
297
+ "#### πŸ” Reasoning\n" + "\n".join([f"- {r}" for r in reasoning])
298
+ )
299
+
300
+ return explanation, df[["SKU", "Frequency", "Priority", "AssignedDock"]]