MBG0903 commited on
Commit
5e044ad
·
verified ·
1 Parent(s): 57b3801

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +153 -125
app.py CHANGED
@@ -1,145 +1,173 @@
1
  import gradio as gr
2
  import pandas as pd
3
- import numpy as np
4
-
5
- PRIMARY_COLOR = "#0f2c59"
6
-
7
- # ==============================
8
- # WAREHOUSE MODEL PARAMETERS
9
- # ==============================
10
- NUM_AISLES = 30
11
- NUM_RACKS = 20
12
-
13
- FAST_ZONE = range(1, 6) # aisles 1–5
14
- MID_ZONE = range(6, 16) # aisles 6–15
15
- SLOW_ZONE = range(16, 31) # aisles 16–30
16
-
17
-
18
- # ==============================
19
- # SLOT RECOMMENDATION ENGINE
20
- # ==============================
21
- def recommend_slot(velocity):
22
- """
23
- Assign aisle zone based on SKU velocity.
24
- """
25
- velocity = str(velocity).lower()
26
-
27
- if velocity in ["fast", "high", "f"]:
28
- aisle = np.random.choice(list(FAST_ZONE))
29
- reason = "Fast-moving SKU — Assigned close to dispatch to reduce pick time."
30
-
31
- elif velocity in ["medium", "mid", "m"]:
32
- aisle = np.random.choice(list(MID_ZONE))
33
- reason = "Medium-moving SKU — Assigned to middle zone to balance travel distance."
34
-
35
- else:
36
- aisle = np.random.choice(list(SLOW_ZONE))
37
- reason = "Slow-moving SKU — Assigned to back aisles to avoid congestion."
38
-
39
- rack = np.random.randint(1, NUM_RACKS + 1)
40
-
41
- return aisle, rack, reason
42
-
43
-
44
- # ==============================
45
- # MAIN OPTIMIZATION FUNCTION
46
- # ==============================
47
- def optimize_slotting(df):
48
- if df is None or len(df) == 0:
49
- return None, "⚠️ Please upload SKU data."
50
-
51
- results = []
52
-
53
- for _, row in df.iterrows():
54
- sku = row["SKU"]
55
- velocity = row["Velocity"]
56
- frequency = row.get("Frequency", "")
57
-
58
- aisle, rack, reason = recommend_slot(velocity)
59
-
60
- results.append({
61
- "SKU": sku,
62
- "Velocity": velocity,
63
- "Frequency": frequency,
64
- "Suggested Aisle": aisle,
65
- "Suggested Rack": rack,
66
- "Reason": reason
67
- })
68
-
69
- output_df = pd.DataFrame(results)
70
- return output_df, "✅ Optimization Completed"
71
-
72
-
73
- # ==============================
74
- # GRADIO UI
75
- # ==============================
76
- def build_interface():
77
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  with gr.Blocks() as demo:
79
- gr.HTML("<style>.gr-button{background-color:#FF6A00 !important;color:white !important;}</style>")
80
-
81
  gr.Markdown(
82
- "<h1 style='color:%s'>Procelevate Inventory Slotting Optimizer</h1>"
83
- "<h3>AI-powered SKU placement engine to reduce picking time & congestion.</h3>"
84
- % PRIMARY_COLOR
85
  )
86
 
87
- gr.Markdown("### 📦 Upload SKU File or Enter Data")
88
 
89
- template_df = pd.DataFrame({
90
- "SKU": ["A123", "B555", "C888"],
91
- "Velocity": ["Fast", "Medium", "Slow"],
92
- "Frequency": [120, 60, 5]
93
- })
94
-
95
- sku_table = gr.Dataframe(
96
- value=template_df,
97
  headers=["SKU", "Velocity", "Frequency"],
98
- row_count=5,
99
- col_count=3,
100
- wrap=True
101
- )
102
-
103
- optimize_btn = gr.Button("Optimize Slotting", size="lg")
104
-
105
- result_table = gr.Dataframe(
106
- headers=["SKU", "Velocity", "Frequency",
107
- "Suggested Aisle", "Suggested Rack", "Reason"],
108
- row_count=5
109
  )
110
 
111
- business_insight = gr.Markdown("")
112
 
113
- def run(df):
114
- result, status = optimize_slotting(df)
115
- if result is None:
116
- return None, status
 
 
 
117
 
118
- # Business insight summary
119
- fast = len(result[result["Velocity"].str.lower() == "fast"])
120
- medium = len(result[result["Velocity"].str.lower() == "medium"])
121
- slow = len(result[result["Velocity"].str.lower() == "slow"])
122
 
123
- insight = f"""
124
- ### 📊 Business Insight Summary
125
 
126
- - **Fast Movers:** {fast} SKUs moved closest to dispatch for quicker turnaround.
127
- - **Medium Movers:** {medium} SKUs distributed in central aisles to balance traffic.
128
- - **Slow Movers:** {slow} SKUs placed in far aisles to reduce congestion.
129
 
130
- This improves:
131
- - 🚶 **Walking distance reduction**
132
- - 🚚 **Faster order fulfillment**
133
- - 🎯 **Better space utilization**
134
- - 🔄 **Lower aisle congestion**
135
- """
136
-
137
- return result, insight
138
-
139
- optimize_btn.click(run, inputs=[sku_table], outputs=[result_table, business_insight])
140
 
141
  return demo
142
 
143
 
144
- demo = build_interface()
145
  demo.launch()
 
1
  import gradio as gr
2
  import pandas as pd
3
+ import matplotlib.pyplot as plt
4
+ import io
5
+ import base64
6
+
7
+ # ---------------------------------------------------
8
+ # Helper: Generate Heatmap Image (Aisle × Rack)
9
+ # ---------------------------------------------------
10
+ def generate_slotting_heatmap(df):
11
+ plt.figure(figsize=(8, 6))
12
+ plt.scatter(df["Suggested Aisle"], df["Suggested Rack"],
13
+ c='orange', s=120, edgecolor='black')
14
+
15
+ plt.title("SKU Slotting Heatmap (Aisle × Rack)")
16
+ plt.xlabel("Aisle Number")
17
+ plt.ylabel("Rack Number")
18
+ plt.grid(True, alpha=0.3)
19
+
20
+ # Add SKU labels near points
21
+ for i, sku in enumerate(df["SKU"]):
22
+ plt.text(df["Suggested Aisle"][i] + 0.3,
23
+ df["Suggested Rack"][i] + 0.3,
24
+ sku, fontsize=9)
25
+
26
+ buf = io.BytesIO()
27
+ plt.savefig(buf, format="png", bbox_inches='tight')
28
+ plt.close()
29
+ buf.seek(0)
30
+
31
+ encoded = base64.b64encode(buf.read()).decode()
32
+ return "data:image/png;base64," + encoded
33
+
34
+
35
+ # ---------------------------------------------------
36
+ # Helper: Generate Before vs After Distance Chart
37
+ # ---------------------------------------------------
38
+ def generate_distance_chart(before_dist, after_dist):
39
+ plt.figure(figsize=(7, 5))
40
+
41
+ plt.bar(["Before", "After"], [before_dist, after_dist],
42
+ color=["red", "green"])
43
+
44
+ plt.title("Walking Distance Comparison")
45
+ plt.ylabel("Distance (meters)")
46
+
47
+ buf = io.BytesIO()
48
+ plt.savefig(buf, format="png", bbox_inches='tight')
49
+ plt.close()
50
+ buf.seek(0)
51
+
52
+ encoded = base64.b64encode(buf.read()).decode()
53
+ return "data:image/png;base64," + encoded
54
+
55
+
56
+ # ---------------------------------------------------
57
+ # Core Slotting Engine
58
+ # ---------------------------------------------------
59
+ def optimize_slotting(sku_df):
60
+ if sku_df is None or len(sku_df) == 0:
61
+ return None, "No data provided.", None, None
62
+
63
+ df = sku_df.copy()
64
+
65
+ # Mapping velocities to warehouse zone logic
66
+ velocity_zone_map = {
67
+ "Fast": (3, 14), # near dispatch
68
+ "Medium": (6, 20), # middle aisles
69
+ "Slow": (20, 6) # far aisles
70
+ }
71
+
72
+ suggested_aisles = []
73
+ suggested_racks = []
74
+ reasons = []
75
+
76
+ for i in range(len(df)):
77
+ velocity = df.loc[i, "Velocity"]
78
+ freq = df.loc[i, "Frequency"]
79
+ sku = df.loc[i, "SKU"]
80
+
81
+ if velocity not in velocity_zone_map:
82
+ aisle, rack = (10, 10) # fallback
83
+ reason = "Default placement due to unknown velocity."
84
+ else:
85
+ aisle, rack = velocity_zone_map[velocity]
86
+ reason = f"{velocity}-moving SKU — placed strategically to reduce picker travel."
87
+
88
+ suggested_aisles.append(aisle)
89
+ suggested_racks.append(rack)
90
+ reasons.append(reason)
91
+
92
+ df["Suggested Aisle"] = suggested_aisles
93
+ df["Suggested Rack"] = suggested_racks
94
+ df["Reason"] = reasons
95
+
96
+ # Business insight summary
97
+ insight = (
98
+ "��� **Business Insight Summary**\n"
99
+ "- Fast movers placed closest to dispatch to minimize walking distance.\n"
100
+ "- Medium movers placed in central aisles to balance traffic.\n"
101
+ "- Slow movers placed in deep aisles to avoid congestion.\n\n"
102
+ "**Operational Impact:**\n"
103
+ "✔ Walking distance reduction\n"
104
+ "✔ Faster order fulfillment\n"
105
+ "✔ Better warehouse throughput\n"
106
+ "✔ Lower aisle congestion\n"
107
+ )
108
+
109
+ # Generate visuals
110
+ heatmap_img = generate_slotting_heatmap(df)
111
+
112
+ before_distance = 300 # static demo number
113
+ after_distance = 180 # static demo number
114
+ distance_img = generate_distance_chart(before_distance, after_distance)
115
+
116
+ return df, insight, heatmap_img, distance_img
117
+
118
+
119
+ # ---------------------------------------------------
120
+ # UI Layout
121
+ # ---------------------------------------------------
122
+ def build_ui():
123
  with gr.Blocks() as demo:
 
 
124
  gr.Markdown(
125
+ "<h1>Procelevate Inventory Slotting Optimizer</h1>"
126
+ "<p>AI-powered SKU placement engine to reduce picking time, congestion & improve throughput.</p>"
 
127
  )
128
 
129
+ gr.Markdown("📦 **Upload SKU File or Enter Data**")
130
 
131
+ # Input table
132
+ input_table = gr.Dataframe(
 
 
 
 
 
 
133
  headers=["SKU", "Velocity", "Frequency"],
134
+ datatype=["str", "str", "number"],
135
+ row_count=3,
136
+ value=[
137
+ ["A123", "Fast", 120],
138
+ ["B555", "Medium", 60],
139
+ ["C888", "Slow", 5]
140
+ ],
141
+ label="SKU Velocity Table"
 
 
 
142
  )
143
 
144
+ submit_btn = gr.Button("Optimize Slotting", variant="primary")
145
 
146
+ # Tabs for results
147
+ with gr.Tabs():
148
+ with gr.Tab("Optimized Slotting"):
149
+ output_table = gr.Dataframe(
150
+ headers=["SKU", "Velocity", "Frequency", "Suggested Aisle", "Suggested Rack", "Reason"],
151
+ label="Optimized Slotting Table"
152
+ )
153
 
154
+ with gr.Tab("Heatmap Visualization"):
155
+ heatmap_view = gr.Image(label="SKU Slotting Heatmap")
 
 
156
 
157
+ with gr.Tab("Walking Distance Savings"):
158
+ distance_view = gr.Image(label="Walking Distance Chart")
159
 
160
+ with gr.Tab("Business Insights"):
161
+ insight_box = gr.Markdown()
 
162
 
163
+ submit_btn.click(
164
+ optimize_slotting,
165
+ inputs=[input_table],
166
+ outputs=[output_table, insight_box, heatmap_view, distance_view]
167
+ )
 
 
 
 
 
168
 
169
  return demo
170
 
171
 
172
+ demo = build_ui()
173
  demo.launch()