PD03 commited on
Commit
518e35a
·
verified ·
1 Parent(s): ec2405c

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +711 -409
src/streamlit_app.py CHANGED
@@ -8,511 +8,813 @@ import random
8
 
9
  # Page configuration
10
  st.set_page_config(
11
- page_title="Rane Group - AI-Powered Supply Chain Hub",
12
- page_icon="🤖",
13
  layout="wide",
14
  initial_sidebar_state="expanded"
15
  )
16
 
17
- # Enhanced CSS for professional look
18
  st.markdown("""
19
  <style>
20
  .main-header {
21
- background: linear-gradient(90deg, #2c5282, #3182ce);
22
- padding: 1.5rem;
23
- border-radius: 12px;
24
  color: white;
25
  text-align: center;
26
  margin-bottom: 2rem;
27
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
28
  }
29
- .professional-table {
30
- background: white;
31
- border: 1px solid #e2e8f0;
32
  border-radius: 8px;
33
- overflow: hidden;
34
- margin: 1rem 0;
35
- }
36
- .table-header {
37
- background: #f7fafc;
38
- padding: 0.75rem;
39
- border-bottom: 1px solid #e2e8f0;
40
- font-weight: 600;
41
- color: #2d3748;
42
- }
43
- .ai-insight {
44
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
45
  color: white;
46
- padding: 1rem;
47
- border-radius: 8px;
48
- margin: 0.5rem 0;
49
- border-left: 4px solid #4c51bf;
50
  }
51
- .ai-recommendation {
52
- background: #f0fff4;
53
- border: 2px solid #68d391;
54
  padding: 1rem;
55
  border-radius: 8px;
 
56
  margin: 0.5rem 0;
57
- border-left: 6px solid #38a169;
58
  }
59
- .ai-alert {
60
- background: #fed7d7;
61
- border: 2px solid #fc8181;
62
  padding: 1rem;
63
  border-radius: 8px;
 
64
  margin: 0.5rem 0;
65
- border-left: 6px solid #e53e3e;
66
  }
67
- .timeline-view {
68
- background: white;
69
- padding: 1rem;
70
- border-radius: 8px;
71
- border: 1px solid #e2e8f0;
72
- margin: 1rem 0;
73
  }
74
- .status-green { background-color: #48bb78; color: white; padding: 2px 8px; border-radius: 4px; }
75
- .status-red { background-color: #e53e3e; color: white; padding: 2px 8px; border-radius: 4px; }
76
- .status-yellow { background-color: #ed8936; color: white; padding: 2px 8px; border-radius: 4px; }
77
- .metric-card {
78
- background: white;
79
- padding: 1.5rem;
80
- border-radius: 8px;
81
- border: 1px solid #e2e8f0;
82
- text-align: center;
83
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  }
85
  </style>
86
  """, unsafe_allow_html=True)
87
 
88
- # Initialize session state for AI interactions
89
- if 'ai_insights' not in st.session_state:
90
- st.session_state.ai_insights = []
91
- if 'executed_actions' not in st.session_state:
92
- st.session_state.executed_actions = []
93
- if 'ai_learning' not in st.session_state:
94
- st.session_state.ai_learning = {"accepted": 0, "rejected": 0}
95
 
96
- # Generate comprehensive supply chain data
97
  @st.cache_data
98
- def generate_professional_data():
99
- # Generate 15 days of data (similar to your reference)
100
  today = datetime(2025, 8, 4)
101
- dates = [today + timedelta(days=x) for x in range(15)]
102
- date_strings = [d.strftime('%d-%b') for d in dates]
103
 
104
- # SKU/Material data structure
105
  materials = [
106
- {'sku': 'EV-MSUZ.1', 'part_name': 'Engine Mount', 'tier': 'T1', 'supplier': 'Yazaki', 'demand': 5000},
107
- {'sku': 'EV-MSUZ.2', 'part_name': 'Steering Gear', 'tier': 'T2', 'supplier': 'Precision', 'demand': 2000},
108
- {'sku': 'EV-MSUZ.3', 'part_name': 'Brake Pad', 'tier': 'T2', 'supplier': 'Lumax', 'demand': 1500},
109
- {'sku': 'EV-MSUZ.1.1', 'part_name': 'Suspension', 'tier': 'T3', 'supplier': 'Sona Comstar', 'demand': 5000},
110
- {'sku': 'EV-MSUZ.1.2', 'part_name': 'Power Unit', 'tier': 'T3', 'supplier': 'Sansera', 'demand': 500}
111
  ]
112
 
113
- detailed_data = []
114
 
115
  for material in materials:
116
- # Generate daily supply/demand patterns
117
- base_supply = material['demand'] // 14 # Daily average
 
 
 
118
 
119
- # Add realistic variations and disruptions
120
- daily_supply = []
121
- daily_demand = []
122
- daily_inventory = []
123
- fulfillment_rates = []
124
 
125
- inventory = base_supply * 3 # Starting inventory
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
127
  for i, date in enumerate(dates):
128
- # Demand with seasonality and external factors
129
- demand_variation = np.random.normal(0, 0.1)
130
- if i >= 5 and i <= 8: # Festive season surge
131
- demand_variation += 0.2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
 
133
- daily_demand_val = int(base_supply * (1 + demand_variation))
134
- daily_demand.append(daily_demand_val)
 
135
 
136
- # Supply with disruptions
137
- supply_variation = 0
138
- if material['supplier'] == 'Precision' and i >= 3 and i <= 6: # Equipment failure
139
- supply_variation = -0.4
140
- elif material['supplier'] == 'Sona Comstar' and i >= 8 and i <= 10: # Strike
141
- supply_variation = -0.6
142
 
143
- daily_supply_val = int(base_supply * (1 + supply_variation))
144
- daily_supply.append(daily_supply_val)
 
 
 
 
145
 
146
- # Update inventory
147
- inventory = inventory + daily_supply_val - daily_demand_val
148
- daily_inventory.append(max(inventory, 0))
 
 
 
149
 
150
- # Calculate fulfillment rate
151
- fulfillment_rate = min(100, (daily_supply_val / daily_demand_val) * 100) if daily_demand_val > 0 else 100
152
- fulfillment_rates.append(fulfillment_rate)
 
 
 
 
 
 
 
153
 
154
- detailed_data.append({
155
- 'Date': date,
156
- 'DateStr': date_strings[i],
157
- 'SKU': material['sku'],
158
- 'PartName': material['part_name'],
159
- 'Tier': material['tier'],
160
- 'Supplier': material['supplier'],
161
- 'DailyDemand': daily_demand_val,
162
- 'DailySupply': daily_supply_val,
163
- 'Inventory': daily_inventory[i],
164
- 'FulfillmentRate': fulfillment_rate,
165
- 'Gap': daily_supply_val - daily_demand_val,
166
- 'Status': 'Normal' if fulfillment_rate >= 95 else 'Risk' if fulfillment_rate >= 80 else 'Critical'
167
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
 
169
- return pd.DataFrame(detailed_data)
170
 
171
- # Advanced AI Insights Engine
172
- class AgenticAIEngine:
173
- def __init__(self, df):
174
- self.df = df
175
- self.insights = []
176
- self.recommendations = []
177
- self.alerts = []
178
-
179
- def analyze_patterns(self):
180
- """AI pattern recognition and analysis"""
181
- # Identify critical shortages
182
- critical_items = self.df[self.df['FulfillmentRate'] < 80]
183
-
184
- for _, item in critical_items.iterrows():
185
- if item['Supplier'] == 'Precision' and item['DateStr'] in ['07-Aug', '08-Aug', '09-Aug', '10-Aug']:
186
- self.alerts.append({
187
- 'type': 'Critical Supply Disruption',
188
- 'sku': item['SKU'],
189
- 'supplier': item['Supplier'],
190
- 'date': item['DateStr'],
191
- 'impact': f"{100 - item['FulfillmentRate']:.0f}% shortfall",
192
- 'root_cause': 'Equipment failure at Precision Components facility',
193
- 'confidence': 95,
194
- 'severity': 'High'
195
- })
196
-
197
- return self.alerts
198
 
199
- def generate_recommendations(self, alerts):
200
- """AI-powered recommendation engine"""
201
- recommendations = []
202
 
203
- for alert in alerts:
204
- if alert['supplier'] == 'Precision':
205
- recommendations.append({
206
- 'alert_id': len(recommendations),
207
- 'sku': alert['sku'],
208
- 'recommendation': 'Activate alternate supplier AutoForge Industries',
209
- 'impact': '+85% capacity restoration',
210
- 'cost': 'High (15% premium)',
211
- 'timeline': '24-48 hours',
212
- 'confidence': 90,
213
- 'ai_reasoning': 'AutoForge has 220 units/day spare capacity and 88% reliability rating',
214
- 'priority': 'Immediate',
215
- 'estimated_savings': '₹2.5M in lost production'
216
- })
 
 
 
 
 
 
217
 
218
- recommendations.append({
219
- 'alert_id': len(recommendations),
220
- 'sku': alert['sku'],
221
- 'recommendation': 'Emergency air freight from Mumbai warehouse',
222
- 'impact': '+40 units immediate availability',
223
- 'cost': 'Very High (300% logistics cost)',
224
- 'timeline': '6-12 hours',
225
- 'confidence': 85,
226
- 'ai_reasoning': 'Mumbai warehouse has 120 units in stock, air freight available',
227
- 'priority': 'Backup option',
228
- 'estimated_savings': '₹800K in downtime costs'
 
 
 
 
 
229
  })
230
-
231
- return recommendations
232
-
233
- def learning_feedback(self, action, outcome):
234
- """AI learning from user feedback"""
235
- if outcome == 'accept':
236
- st.session_state.ai_learning['accepted'] += 1
237
- else:
238
- st.session_state.ai_learning['rejected'] += 1
239
-
240
- # Update AI confidence based on feedback
241
- total_feedback = st.session_state.ai_learning['accepted'] + st.session_state.ai_learning['rejected']
242
- if total_feedback > 0:
243
- ai_accuracy = st.session_state.ai_learning['accepted'] / total_feedback
244
- return f"AI Learning: {ai_accuracy*100:.1f}% accuracy based on {total_feedback} interactions"
245
- return "AI Learning: Initializing..."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
 
247
- # Load data and initialize AI
248
- df = generate_professional_data()
249
- ai_engine = AgenticAIEngine(df)
 
 
250
 
251
- # Header
252
  st.markdown("""
253
  <div class="main-header">
254
- <h1>🤖 Rane Group - AI-Powered Supply Chain Command Center</h1>
255
- <h3>Professional Enterprise Dashboard with Integrated Agentic AI</h3>
256
- <p>Real-time Intelligence | Predictive Analytics | Autonomous Decision Support</p>
257
  </div>
258
  """, unsafe_allow_html=True)
259
 
260
- # Navigation tabs
261
- tab1, tab2, tab3 = st.tabs(["📊 SKU Deep Dive", "📈 Timeline View", "🤖 AI Control Center"])
 
 
 
 
 
262
 
263
- # TAB 1: SKU Deep Dive (Similar to your first image)
264
- with tab1:
265
- st.markdown('<div class="table-header">Supply Chain Resilience - SKU Deep Dive</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
 
267
- # Filters (similar to your reference)
268
- col1, col2, col3, col4, col5 = st.columns(5)
269
- with col1:
270
- plant_filter = st.selectbox("Plant Location", ["Chennai", "Pune", "Bangalore"])
271
- with col2:
272
- material_filter = st.selectbox("Material Group", ["Engine", "Steering", "Brake", "All"])
273
- with col3:
274
- sku_filter = st.selectbox("Part/SKU", ["EV-MSUZ", "All"])
275
- with col4:
276
- period_filter = st.selectbox("Time Period", ["FY2026", "FY2025"])
277
- with col5:
278
- supplier_filter = st.selectbox("Supplier Type", ["All", "Tier 1", "Tier 2", "Tier 3"])
279
-
280
- # Professional table display
281
- st.markdown("### Material Planning Overview")
282
-
283
- # Group data by SKU for summary table
284
- summary_data = []
285
- for sku in df['SKU'].unique():
286
- sku_data = df[df['SKU'] == sku]
287
- latest_data = sku_data.iloc[-1] # Most recent data
288
-
289
- total_demand = sku_data['DailyDemand'].sum()
290
- total_supply = sku_data['DailySupply'].sum()
291
- avg_fulfillment = sku_data['FulfillmentRate'].mean()
292
- shortfall = max(0, total_demand - total_supply)
293
-
294
- # Calculate stock availability (simplified)
295
- stock_weeks = latest_data['Inventory'] / latest_data['DailyDemand'] if latest_data['DailyDemand'] > 0 else 0
296
-
297
- summary_data.append({
298
- 'SKU Name': latest_data['SKU'],
299
- 'Sub-part': latest_data['PartName'],
300
- 'Supplier type': latest_data['Tier'],
301
- 'Supplier name': latest_data['Supplier'],
302
- 'Ordered quantity (pcs.)': total_demand,
303
- 'Actuals delivered': total_supply,
304
- 'MTD Shortfall': shortfall,
305
- 'Projected delivery (pcs.)': total_supply + 100, # Projected improvement
306
- 'Projected Shortfall': max(0, shortfall - 100),
307
- 'Fulfillment % (on-time)': f"{avg_fulfillment:.0f}%",
308
- 'First shortage on': '18-May' if shortfall > 0 else '-',
309
- 'Stock availability': f"{stock_weeks:.1f} weeks"
310
- })
311
-
312
- summary_df = pd.DataFrame(summary_data)
313
-
314
- # Display professional table
315
- st.dataframe(summary_df, use_container_width=True, height=300)
316
-
317
- # AI Insights for this view
318
- alerts = ai_engine.analyze_patterns()
319
  if alerts:
320
- st.markdown("### 🤖 AI-Powered Insights")
321
- for alert in alerts[:2]: # Show top 2 alerts
322
  st.markdown(f"""
323
- <div class="ai-alert">
324
- <h4>🚨 {alert['type']}</h4>
325
- <p><strong>SKU:</strong> {alert['sku']} | <strong>Supplier:</strong> {alert['supplier']}</p>
326
- <p><strong>Root Cause:</strong> {alert['root_cause']}</p>
327
- <p><strong>Impact:</strong> {alert['impact']} | <strong>Confidence:</strong> {alert['confidence']}%</p>
328
  </div>
329
  """, unsafe_allow_html=True)
330
-
331
- # TAB 2: Timeline View (Similar to your second/third images)
332
- with tab2:
333
- st.markdown('<div class="table-header">Supply Chain Resilience - Timeline View</div>', unsafe_allow_html=True)
334
-
335
- # Toggle between fulfillment rate and inventory view
336
- view_type = st.radio("View Type:", ["Fulfillment Rate View", "Inventory Delivered View"], horizontal=True)
337
-
338
- st.markdown("### Daily Timeline Analysis (Next 15 Days)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
339
 
340
- # Create timeline visualization similar to your reference - FIXED VERSION
341
- fig = go.Figure()
342
 
343
- for sku in df['SKU'].unique()[:3]: # Show top 3 SKUs for clarity
344
- sku_data = df[df['SKU'] == sku].sort_values('Date')
345
 
346
- if view_type == "Fulfillment Rate View":
347
- # Color coding based on fulfillment rate
348
- colors = ['green' if rate >= 95 else 'yellow' if rate >= 80 else 'red'
349
- for rate in sku_data['FulfillmentRate']]
350
-
351
- fig.add_trace(go.Bar(
352
- x=sku_data['DateStr'],
353
- y=[1] * len(sku_data), # Unit height for timeline
354
- name=f"{sku_data.iloc[0]['PartName']} ({sku_data.iloc[0]['Supplier']})",
355
- marker_color=colors,
356
- text=[f"{rate:.0f}%" for rate in sku_data['FulfillmentRate']],
357
- textposition='inside', # FIXED: Valid textposition value
358
- textfont=dict(color='white', size=10),
359
- hovertemplate=f"<b>{sku}</b><br>Date: %{{x}}<br>Fulfillment: %{{text}}<extra></extra>"
360
- ))
361
- else:
362
- # Inventory levels
 
 
 
 
 
 
 
 
 
 
 
363
  fig.add_trace(go.Scatter(
364
- x=sku_data['DateStr'],
365
- y=sku_data['Inventory'],
366
- mode='lines+markers',
367
- name=f"{sku_data.iloc[0]['PartName']} Inventory",
368
- line=dict(width=3),
369
- marker=dict(size=8)
370
  ))
 
 
 
 
 
 
 
 
 
 
 
371
 
372
- fig.update_layout(
373
- title=f'15-Day Timeline: {view_type}',
374
- xaxis_title='Days of the Month',
375
- yaxis_title='Fulfillment Rate' if view_type == "Fulfillment Rate View" else 'Inventory Units',
376
- height=400,
377
- showlegend=True,
378
- hovermode='x unified'
379
- )
380
 
381
- st.plotly_chart(fig, use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
382
 
383
- # Detailed daily table (similar to your third image)
384
- st.markdown("### Detailed Production Plan & Raw Material Schedule")
385
-
386
- # Create detailed view for selected SKU
387
- selected_sku = st.selectbox("Select SKU for detailed view:", df['SKU'].unique())
388
- detailed_sku_data = df[df['SKU'] == selected_sku].sort_values('Date')
389
-
390
- # Production plan table
391
- production_table = []
392
- for _, row in detailed_sku_data.iterrows():
393
- production_table.append({
394
- 'Date': row['DateStr'],
395
- 'Item Stock': row['Inventory'],
396
- 'Actual Deliveries': row['DailySupply'],
397
- 'Production Plan': row['DailyDemand'],
398
- 'Shortfall vs Plan': max(0, row['DailyDemand'] - row['DailySupply']),
399
- 'Status': '🟢' if row['Gap'] >= 0 else '🔴',
400
- 'AI Recommendation': 'Normal ops' if row['Gap'] >= 0 else 'Expedite production'
401
- })
402
-
403
- production_df = pd.DataFrame(production_table)
404
- st.dataframe(production_df, use_container_width=True, height=300)
405
 
406
- # TAB 3: AI Control Center
407
- with tab3:
408
- st.markdown('<div class="table-header">🤖 Agentic AI Control Center</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
409
 
410
- # AI Analytics Dashboard
411
- col1, col2 = st.columns([2, 1])
412
 
413
- with col1:
414
- st.markdown("### 🧠 AI-Generated Recommendations")
415
-
416
- # Generate AI recommendations
417
- alerts = ai_engine.analyze_patterns()
418
- recommendations = ai_engine.generate_recommendations(alerts)
 
 
419
 
420
- for i, rec in enumerate(recommendations):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
421
  st.markdown(f"""
422
- <div class="ai-recommendation">
423
- <h4>🎯 Recommendation #{i+1} - {rec['priority']}</h4>
424
- <p><strong>For SKU:</strong> {rec['sku']}</p>
425
- <p><strong>Action:</strong> {rec['recommendation']}</p>
426
- <p><strong>Expected Impact:</strong> {rec['impact']}</p>
427
- <p><strong>Cost:</strong> {rec['cost']} | <strong>Timeline:</strong> {rec['timeline']}</p>
428
- <p><strong>AI Reasoning:</strong> {rec['ai_reasoning']}</p>
429
- <p><strong>Potential Savings:</strong> {rec['estimated_savings']}</p>
430
- <p><strong>AI Confidence:</strong> {rec['confidence']}%</p>
431
  </div>
432
  """, unsafe_allow_html=True)
433
 
434
- # Action buttons
435
- col_a, col_b, col_c = st.columns([1, 1, 2])
436
 
437
- with col_a:
438
- if st.button(f" Accept & Execute", key=f"accept_{i}"):
439
- st.session_state.executed_actions.append(rec)
440
- feedback = ai_engine.learning_feedback(rec, 'accept')
441
- st.success(f"Action executed! {feedback}")
 
 
 
 
442
 
443
- with col_b:
444
- if st.button(f" Reject", key=f"reject_{i}"):
445
- feedback = ai_engine.learning_feedback(rec, 'reject')
446
- st.warning(f"Action rejected. {feedback}")
 
 
 
 
 
447
 
448
- with col_c:
449
- st.info(f"Confidence: {rec['confidence']}%")
450
-
451
- with col2:
452
- st.markdown("### 📊 AI Performance Metrics")
453
-
454
- # AI performance dashboard
455
- total_recommendations = len(recommendations)
456
- executed_actions = len(st.session_state.executed_actions)
457
- ai_accuracy = (st.session_state.ai_learning['accepted'] /
458
- max(1, st.session_state.ai_learning['accepted'] + st.session_state.ai_learning['rejected'])) * 100
459
-
460
- st.markdown(f"""
461
- <div class="metric-card">
462
- <h3>{total_recommendations}</h3>
463
- <p>Active Recommendations</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
464
  </div>
465
  """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
466
 
467
- st.markdown(f"""
468
- <div class="metric-card">
469
- <h3>{executed_actions}</h3>
470
- <p>Actions Executed</p>
471
- </div>
472
- """, unsafe_allow_html=True)
473
 
474
- st.markdown(f"""
475
- <div class="metric-card">
476
- <h3>{ai_accuracy:.1f}%</h3>
477
- <p>AI Accuracy Rate</p>
478
- </div>
479
- """, unsafe_allow_html=True)
 
 
 
480
 
481
- # AI Learning Insights
482
- st.markdown("### 🎓 AI Learning Insights")
483
- st.markdown(f"""
484
- <div class="ai-insight">
485
- <h4>🧠 Current AI Status</h4>
486
- <p>• Pattern Recognition: Advanced</p>
487
- <p>• Recommendation Engine: Active</p>
488
- <p>• Learning Rate: {ai_accuracy:.1f}%</p>
489
- <p>• Feedback Processing: Real-time</p>
490
- <p>• Decision Confidence: High</p>
491
- </div>
492
- """, unsafe_allow_html=True)
493
-
494
- # AI Status Bar
495
- st.markdown("---")
496
- col1, col2, col3, col4 = st.columns(4)
 
 
 
 
497
 
498
- with col1:
499
- st.metric("🤖 AI Alerts Active", len(alerts))
500
 
501
- with col2:
502
- st.metric("⚡ Recommendations Generated", len(recommendations))
503
 
504
- with col3:
505
- st.metric("✅ Actions Executed", len(st.session_state.executed_actions))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
506
 
507
- with col4:
508
- learning_rate = f"{ai_accuracy:.1f}%"
509
- st.metric("🎓 AI Learning Rate", learning_rate)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
510
 
511
- # Footer
512
  st.markdown("---")
513
  st.markdown("""
514
  <div style='text-align: center; color: #666;'>
515
- <p>🤖 <b>Rane Group AI-Powered Supply Chain Hub</b> | Professional Enterprise Dashboard<br>
516
- Agentic AI Integration | Real-time Intelligence | Autonomous Decision Support | Advanced Pattern Recognition</p>
517
  </div>
518
  """, unsafe_allow_html=True)
 
8
 
9
  # Page configuration
10
  st.set_page_config(
11
+ page_title="Rane Group - Complete Supply Chain Hub",
12
+ page_icon="🌐",
13
  layout="wide",
14
  initial_sidebar_state="expanded"
15
  )
16
 
17
+ # Custom CSS (same as before)
18
  st.markdown("""
19
  <style>
20
  .main-header {
21
+ background: linear-gradient(90deg, #1e3a8a, #3b82f6);
22
+ padding: 1rem;
23
+ border-radius: 10px;
24
  color: white;
25
  text-align: center;
26
  margin-bottom: 2rem;
 
27
  }
28
+ .tab-header {
29
+ background: linear-gradient(90deg, #059669, #10b981);
30
+ padding: 0.8rem;
31
  border-radius: 8px;
 
 
 
 
 
 
 
 
 
 
 
 
32
  color: white;
33
+ margin-bottom: 1rem;
 
 
 
34
  }
35
+ .alert-card {
36
+ background: #fff5f5;
 
37
  padding: 1rem;
38
  border-radius: 8px;
39
+ border-left: 6px solid #e53e3e;
40
  margin: 0.5rem 0;
 
41
  }
42
+ .ecosystem-alert {
43
+ background: #fef2f2;
 
44
  padding: 1rem;
45
  border-radius: 8px;
46
+ border-left: 6px solid #dc2626;
47
  margin: 0.5rem 0;
 
48
  }
49
+ .root-cause {
50
+ background: #fef7e7;
51
+ padding: 0.8rem;
52
+ border-radius: 6px;
53
+ margin: 0.3rem 0;
54
+ border-left: 3px solid #f6ad55;
55
  }
56
+ .mitigation {
57
+ background: #e6fffa;
58
+ padding: 0.8rem;
59
+ border-radius: 6px;
60
+ margin: 0.3rem 0;
61
+ border-left: 3px solid #4fd1c7;
62
+ }
63
+ .best-option {
64
+ background: #f0fff4;
65
+ padding: 0.8rem;
66
+ border-radius: 6px;
67
+ margin: 0.3rem 0;
68
+ border-left: 4px solid #48bb78;
69
+ border: 2px solid #48bb78;
70
+ }
71
+ .tier-impact {
72
+ background: #fff7ed;
73
+ padding: 0.8rem;
74
+ border-radius: 6px;
75
+ margin: 0.3rem 0;
76
+ border-left: 4px solid #f97316;
77
+ }
78
+ .mitigation-executed {
79
+ background: #ecfdf5;
80
+ padding: 0.8rem;
81
+ border-radius: 6px;
82
+ margin: 0.3rem 0;
83
+ border-left: 4px solid #10b981;
84
+ border: 2px solid #10b981;
85
+ }
86
+ .mitigation-recommended {
87
+ background: #eff6ff;
88
+ padding: 0.8rem;
89
+ border-radius: 6px;
90
+ margin: 0.3rem 0;
91
+ border-left: 4px solid #3b82f6;
92
+ }
93
+ .normal-status {
94
+ background: #f0fff4;
95
+ padding: 0.6rem;
96
+ border-radius: 6px;
97
+ border-left: 4px solid #48bb78;
98
+ margin: 0.2rem 0;
99
+ }
100
+ .external-signal {
101
+ background: #f3e5f5;
102
+ padding: 0.6rem;
103
+ border-radius: 6px;
104
+ border-left: 4px solid #9c27b0;
105
+ margin: 0.2rem 0;
106
  }
107
  </style>
108
  """, unsafe_allow_html=True)
109
 
110
+ # Initialize session state
111
+ if 'executed_mitigations' not in st.session_state:
112
+ st.session_state.executed_mitigations = []
113
+ if 'external_signals' not in st.session_state:
114
+ st.session_state.external_signals = []
 
 
115
 
116
+ # Generate forward-looking demand data (same as before)
117
  @st.cache_data
118
+ def generate_forward_demand_data():
 
119
  today = datetime(2025, 8, 4)
120
+ dates = [today + timedelta(days=x) for x in range(14)]
 
121
 
 
122
  materials = [
123
+ 'STG001-Steering Gear',
124
+ 'STG002-Steering Column',
125
+ 'STG003-Power Steering',
126
+ 'BRK001-Brake Pads',
127
+ 'SUS001-Shock Absorber'
128
  ]
129
 
130
+ all_data = []
131
 
132
  for material in materials:
133
+ np.random.seed(hash(material) % 1000)
134
+
135
+ # Generate base demand
136
+ base_demand = np.random.normal(150, 20, 14)
137
+ demand_forecast = np.clip(base_demand, 80, 250).astype(int)
138
 
139
+ # Generate supply capacity
140
+ supply_capacity = np.random.normal(160, 15, 14)
141
+ supply_plan = np.clip(supply_capacity, 100, 280).astype(int)
 
 
142
 
143
+ # External impacts (as integers)
144
+ weather_impact = np.zeros(14, dtype=int)
145
+ policy_impact = np.zeros(14, dtype=int)
146
+ market_impact = np.zeros(14, dtype=int)
147
+
148
+ # Weather impact (Chennai rains days 1-3)
149
+ weather_impact[1:4] = -25
150
+
151
+ # EV policy impact (from day 7)
152
+ if 'STG' in material:
153
+ policy_impact[7:] = 15
154
+
155
+ # Market sentiment (festive season days 5-9)
156
+ market_impact[5:9] = [8, 10, 12, 6]
157
+
158
+ # Calculate adjusted demand and supply
159
+ adjusted_demand = demand_forecast + weather_impact + policy_impact + market_impact
160
+ adjusted_demand = np.clip(adjusted_demand, 50, 300).astype(int)
161
+
162
+ # Supply with weather constraints
163
+ supply_actual = supply_plan.copy()
164
+ for i in range(1, 4): # Weather impact on supply
165
+ supply_actual[i] = int(supply_actual[i] * 0.7)
166
+
167
+ # Calculate gaps
168
+ supply_gap = supply_actual - adjusted_demand
169
 
170
  for i, date in enumerate(dates):
171
+ all_data.append({
172
+ 'Date': date,
173
+ 'Material': material,
174
+ 'Demand_Forecast': int(demand_forecast[i]),
175
+ 'Demand_Adjusted': int(adjusted_demand[i]),
176
+ 'Supply_Plan': int(supply_plan[i]),
177
+ 'Supply_Projected': int(supply_actual[i]),
178
+ 'Gap': int(supply_gap[i]),
179
+ 'Weather_Impact': int(weather_impact[i]),
180
+ 'Policy_Impact': int(policy_impact[i]),
181
+ 'Market_Impact': int(market_impact[i])
182
+ })
183
+
184
+ return pd.DataFrame(all_data)
185
+
186
+ # All other functions remain exactly the same...
187
+ # (Tier 2 supplier functions, AI engines, etc. - keeping them exactly as they were)
188
+
189
+ # Tier 2 Supplier Data
190
+ @st.cache_data
191
+ def get_tier2_suppliers():
192
+ return {
193
+ 'Metalcast Ltd': {
194
+ 'location': 'Coimbatore',
195
+ 'materials': ['STG001-Steering Gear', 'STG002-Steering Column'],
196
+ 'capacity': 200,
197
+ 'reliability': 95,
198
+ 'lead_time': 2,
199
+ 'risk_factors': ['Monsoon flooding', 'Labor strikes', 'Power outages']
200
+ },
201
+ 'Precision Components': {
202
+ 'location': 'Bangalore',
203
+ 'materials': ['STG003-Power Steering', 'BRK001-Brake Pads'],
204
+ 'capacity': 180,
205
+ 'reliability': 92,
206
+ 'lead_time': 3,
207
+ 'risk_factors': ['Transportation delays', 'Raw material shortage', 'Equipment failure']
208
+ },
209
+ 'AutoForge Industries': {
210
+ 'location': 'Pune',
211
+ 'materials': ['SUS001-Shock Absorber', 'STG001-Steering Gear'],
212
+ 'capacity': 220,
213
+ 'reliability': 88,
214
+ 'lead_time': 1,
215
+ 'risk_factors': ['Quality issues', 'Capacity constraints', 'Supplier disputes']
216
+ }
217
+ }
218
+
219
+ # Generate ecosystem supply chain data (same as before)
220
+ @st.cache_data
221
+ def generate_ecosystem_data():
222
+ today = datetime(2025, 8, 4)
223
+ dates = [today + timedelta(days=x) for x in range(14)]
224
+
225
+ suppliers = get_tier2_suppliers()
226
+ all_data = []
227
+
228
+ for supplier_name, supplier_info in suppliers.items():
229
+ for material in supplier_info['materials']:
230
+ np.random.seed(hash(supplier_name + material) % 1000)
231
 
232
+ # Base supply capacity
233
+ base_capacity = supplier_info['capacity']
234
+ normal_supply = np.full(14, base_capacity, dtype=int)
235
 
236
+ # Simulate disruptions
237
+ disrupted_supply = normal_supply.copy()
 
 
 
 
238
 
239
+ # Metalcast disruption (days 3-6: monsoon flooding)
240
+ if supplier_name == 'Metalcast Ltd':
241
+ disrupted_supply[3:7] = (disrupted_supply[3:7] * 0.3).astype(int) # 70% reduction
242
+ disruption_cause = "Monsoon flooding in Coimbatore"
243
+ disruption_days = list(range(3, 7))
244
+ recovery_timeline = 4
245
 
246
+ # Precision Components disruption (days 5-7: equipment failure)
247
+ elif supplier_name == 'Precision Components':
248
+ disrupted_supply[5:8] = (disrupted_supply[5:8] * 0.5).astype(int) # 50% reduction
249
+ disruption_cause = "Critical equipment failure"
250
+ disruption_days = list(range(5, 8))
251
+ recovery_timeline = 3
252
 
253
+ # AutoForge disruption (days 8-10: labor strike)
254
+ elif supplier_name == 'AutoForge Industries':
255
+ disrupted_supply[8:11] = (disrupted_supply[8:11] * 0.2).astype(int) # 80% reduction
256
+ disruption_cause = "Labor strike at Pune facility"
257
+ disruption_days = list(range(8, 11))
258
+ recovery_timeline = 3
259
+ else:
260
+ disruption_cause = "No disruption"
261
+ disruption_days = []
262
+ recovery_timeline = 0
263
 
264
+ # Calculate Rane's supply impact (with lead time delay)
265
+ lead_time = supplier_info['lead_time']
266
+ rane_supply = np.full(14, base_capacity, dtype=int)
267
+
268
+ # Impact Rane's supply with lead time consideration
269
+ for disruption_day in disruption_days:
270
+ impact_start = min(disruption_day + lead_time, 13)
271
+ impact_end = min(disruption_day + lead_time + recovery_timeline, 14)
272
+
273
+ for impact_day in range(impact_start, impact_end):
274
+ reduction = (normal_supply[disruption_day] - disrupted_supply[disruption_day])
275
+ rane_supply[impact_day] = max(rane_supply[impact_day] - reduction, 50)
276
+
277
+ for i, date in enumerate(dates):
278
+ all_data.append({
279
+ 'Date': date,
280
+ 'Supplier': supplier_name,
281
+ 'Material': material,
282
+ 'Tier2_Normal_Supply': int(normal_supply[i]),
283
+ 'Tier2_Disrupted_Supply': int(disrupted_supply[i]),
284
+ 'Tier2_Impact': int(normal_supply[i] - disrupted_supply[i]),
285
+ 'Rane_Normal_Supply': int(normal_supply[i]),
286
+ 'Rane_Impacted_Supply': int(rane_supply[i]),
287
+ 'Rane_Impact': int(normal_supply[i] - rane_supply[i]),
288
+ 'Disruption_Cause': disruption_cause if i in disruption_days else "Normal Operations",
289
+ 'Lead_Time_Days': lead_time,
290
+ 'Is_Disrupted': i in disruption_days,
291
+ 'Is_Rane_Impacted': rane_supply[i] < normal_supply[i]
292
+ })
293
 
294
+ return pd.DataFrame(all_data)
295
 
296
+ # External signals data (same as before)
297
+ @st.cache_data
298
+ def get_external_signals():
299
+ return [
300
+ {'Source': 'Weather API', 'Signal': 'Heavy rains forecasted in Chennai for next 3 days', 'Impact': 'Supply Risk', 'Confidence': 95},
301
+ {'Source': 'Market Intelligence', 'Signal': 'EV sales up 25% this quarter', 'Impact': 'Demand Increase', 'Confidence': 88},
302
+ {'Source': 'News Analytics', 'Signal': 'Upcoming festive season - historically 15% demand spike', 'Impact': 'Demand Surge', 'Confidence': 92},
303
+ {'Source': 'Supplier Network', 'Signal': 'Tier-2 supplier capacity increased by 20%', 'Impact': 'Supply Boost', 'Confidence': 98},
304
+ {'Source': 'Social Media', 'Signal': 'Positive sentiment around new Maruti EV model', 'Impact': 'Demand Growth', 'Confidence': 75},
305
+ {'Source': 'Government Portal', 'Signal': 'New EV subsidy policy effective next week', 'Impact': 'Market Expansion', 'Confidence': 100}
306
+ ]
307
+
308
+ # Generate detailed alerts with root cause analysis (same as before)
309
+ def generate_detailed_alerts(df):
310
+ alerts = []
 
 
 
 
 
 
 
 
 
 
 
 
311
 
312
+ for material in df['Material'].unique():
313
+ material_data = df[df['Material'] == material]
314
+ shortage_days = material_data[material_data['Gap'] < -5]
315
 
316
+ if not shortage_days.empty:
317
+ for _, row in shortage_days.iterrows():
318
+ # Root cause analysis
319
+ root_causes = []
320
+ if row['Weather_Impact'] < -10:
321
+ root_causes.append("Chennai plant disruption due to heavy rains (-25 units)")
322
+ if row['Policy_Impact'] > 10:
323
+ root_causes.append(f"EV policy driving increased demand (+{row['Policy_Impact']} units)")
324
+ if row['Market_Impact'] > 5:
325
+ root_causes.append(f"Festive season demand surge (+{row['Market_Impact']} units)")
326
+ if not root_causes:
327
+ root_causes.append("Base demand exceeding current supply capacity")
328
+
329
+ # Mitigation options
330
+ mitigation_options = [
331
+ {"option": "Activate Pune backup production", "impact": "+30 units/day", "cost": "High", "timeline": "24 hours"},
332
+ {"option": "Expedite Tier-2 supplier shipments", "impact": "+15 units/day", "cost": "Medium", "timeline": "12 hours"},
333
+ {"option": "Emergency air freight from backup suppliers", "impact": "+40 units/day", "cost": "Very High", "timeline": "6 hours"},
334
+ {"option": "Reallocate inventory from other plants", "impact": "+20 units/day", "cost": "Low", "timeline": "18 hours"}
335
+ ]
336
 
337
+ # Determine best option based on severity
338
+ if row['Gap'] < -20: # Critical shortage
339
+ best_option = mitigation_options[2] # Air freight
340
+ elif row['Gap'] < -10: # High shortage
341
+ best_option = mitigation_options[0] # Pune backup
342
+ else: # Medium shortage
343
+ best_option = mitigation_options[1] # Expedite suppliers
344
+
345
+ alerts.append({
346
+ 'material': material,
347
+ 'date': row['Date'].strftime('%Y-%m-%d'),
348
+ 'shortage': abs(row['Gap']),
349
+ 'severity': 'Critical' if row['Gap'] < -20 else 'High' if row['Gap'] < -10 else 'Medium',
350
+ 'root_causes': root_causes,
351
+ 'mitigation_options': mitigation_options,
352
+ 'best_option': best_option
353
  })
354
+
355
+ return alerts
356
+
357
+ # Generate mitigation strategies for ecosystem (same as before)
358
+ def generate_mitigation_strategies(supplier, material, impact_amount, impact_days):
359
+ base_strategies = [
360
+ {
361
+ 'strategy': 'Activate Alternate Supplier',
362
+ 'description': f'Engage backup supplier for {material}',
363
+ 'timeline': '24-48 hours',
364
+ 'cost': 'High (+15% unit cost)',
365
+ 'effectiveness': '90%',
366
+ 'capacity': f'+{impact_amount * 0.9:.0f} units/day',
367
+ },
368
+ {
369
+ 'strategy': 'Emergency Air Freight',
370
+ 'description': f'Air freight {material} from other regions',
371
+ 'timeline': '6-12 hours',
372
+ 'cost': 'Very High (+40% logistics cost)',
373
+ 'effectiveness': '75%',
374
+ 'capacity': f'+{impact_amount * 0.75:.0f} units/day',
375
+ },
376
+ {
377
+ 'strategy': 'Inventory Reallocation',
378
+ 'description': f'Reallocate {material} from other plants',
379
+ 'timeline': '12-24 hours',
380
+ 'cost': 'Medium (+5% handling cost)',
381
+ 'effectiveness': '60%',
382
+ 'capacity': f'+{impact_amount * 0.6:.0f} units/day',
383
+ }
384
+ ]
385
+
386
+ # AI recommendation logic
387
+ if impact_amount > 100: # Critical impact
388
+ recommended = [0, 1] # Alternate supplier + Air freight
389
+ elif impact_amount > 50: # High impact
390
+ recommended = [0, 2] # Alternate supplier + Reallocation
391
+ else: # Medium impact
392
+ recommended = [2] # Reallocation
393
+
394
+ return base_strategies, recommended
395
 
396
+ # Load data
397
+ df_demand = generate_forward_demand_data()
398
+ df_ecosystem = generate_ecosystem_data()
399
+ external_signals = get_external_signals()
400
+ suppliers = get_tier2_suppliers()
401
 
402
+ # Header (same as before)
403
  st.markdown("""
404
  <div class="main-header">
405
+ <h1>🌐 Rane Group - Complete Supply Chain Command Center</h1>
406
+ <h3>Forward-Looking Demand Sensing | Ecosystem Impact Analysis | Agentic AI Optimization</h3>
407
+ <p>Comprehensive Supply Chain Intelligence | Real-time Decision Support</p>
408
  </div>
409
  """, unsafe_allow_html=True)
410
 
411
+ # Tab Navigation (same as before)
412
+ st.sidebar.title("🎯 Dashboard Navigation")
413
+ dashboard_tab = st.sidebar.radio(
414
+ "Select Dashboard:",
415
+ ["📊 Demand & Supply Forecast", "🌐 Ecosystem Supplier Impact"],
416
+ index=0
417
+ )
418
 
419
+ # TAB 1: DEMAND & SUPPLY FORECAST (same as before, except fixed chart)
420
+ if dashboard_tab == "📊 Demand & Supply Forecast":
421
+ st.markdown("""
422
+ <div class="tab-header">
423
+ <h2>📊 Demand & Supply Forecast Dashboard</h2>
424
+ <p>Forward-Looking 14-Day Demand Sensing | External Signal Integration | AI-Driven Optimization</p>
425
+ </div>
426
+ """, unsafe_allow_html=True)
427
+
428
+ # Material selection
429
+ selected_materials_demand = st.sidebar.multiselect(
430
+ "Focus Materials:",
431
+ df_demand['Material'].unique(),
432
+ default=df_demand['Material'].unique()[:3]
433
+ )
434
+
435
+ # Filter data
436
+ filtered_df_demand = df_demand[df_demand['Material'].isin(selected_materials_demand)]
437
+
438
+ # Generate and display alerts (same as before)
439
+ st.subheader("🚨 Detailed Supply Chain Alerts")
440
+
441
+ alerts = generate_detailed_alerts(filtered_df_demand)
442
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
443
  if alerts:
444
+ for i, alert in enumerate(alerts[:3]): # Show top 3 alerts
 
445
  st.markdown(f"""
446
+ <div class="alert-card">
447
+ <h4>⚠️ {alert['material']} - {alert['severity']} Shortage Alert</h4>
448
+ <p><b>Date:</b> {alert['date']} | <b>Shortage:</b> {alert['shortage']} units</p>
 
 
449
  </div>
450
  """, unsafe_allow_html=True)
451
+
452
+ # Root cause analysis
453
+ st.markdown("**🔍 Root Cause Analysis:**")
454
+ for cause in alert['root_causes']:
455
+ st.markdown(f"""
456
+ <div class="root-cause">
457
+ 🎯 {cause}
458
+ </div>
459
+ """, unsafe_allow_html=True)
460
+
461
+ # Mitigation options
462
+ st.markdown("**⚡ Mitigation Options:**")
463
+ for option in alert['mitigation_options']:
464
+ is_best = option == alert['best_option']
465
+ option_class = "best-option" if is_best else "mitigation"
466
+ best_indicator = "🏆 **RECOMMENDED** " if is_best else ""
467
+
468
+ st.markdown(f"""
469
+ <div class="{option_class}">
470
+ {best_indicator}<b>{option['option']}</b><br>
471
+ 📈 Impact: {option['impact']} | 💰 Cost: {option['cost']} | ⏱️ Timeline: {option['timeline']}
472
+ </div>
473
+ """, unsafe_allow_html=True)
474
+
475
+ # Action buttons
476
+ col1, col2, col3 = st.columns([2, 1, 1])
477
+ with col1:
478
+ if st.button(f"✅ Implement Solution", key=f"demand_implement_{i}"):
479
+ st.success(f"Implementing: {alert['best_option']['option']}")
480
+
481
+ st.markdown("---")
482
+ else:
483
+ st.markdown("""
484
+ <div class="normal-status">
485
+ ✅ <b>All Good!</b> No critical supply shortages detected in the next 14 days.
486
+ </div>
487
+ """, unsafe_allow_html=True)
488
 
489
+ # Enhanced visualization (ONLY FIX APPLIED HERE)
490
+ st.subheader("📊 14-Day Supply vs Demand Outlook")
491
 
492
+ for material in selected_materials_demand:
493
+ material_data = filtered_df_demand[filtered_df_demand['Material'] == material]
494
 
495
+ st.markdown(f"**{material}**")
496
+
497
+ # Create clear chart - FIXED VERSION
498
+ fig = go.Figure()
499
+
500
+ # Add demand line
501
+ fig.add_trace(go.Scatter(
502
+ x=material_data['Date'],
503
+ y=material_data['Demand_Adjusted'],
504
+ mode='lines+markers',
505
+ name='Adjusted Demand',
506
+ line=dict(color='red', width=3),
507
+ marker=dict(size=8)
508
+ ))
509
+
510
+ # Add supply line
511
+ fig.add_trace(go.Scatter(
512
+ x=material_data['Date'],
513
+ y=material_data['Supply_Projected'],
514
+ mode='lines+markers',
515
+ name='Projected Supply',
516
+ line=dict(color='green', width=3),
517
+ marker=dict(size=8)
518
+ ))
519
+
520
+ # Highlight shortage areas
521
+ shortage_data = material_data[material_data['Gap'] < 0]
522
+ if not shortage_data.empty:
523
  fig.add_trace(go.Scatter(
524
+ x=shortage_data['Date'],
525
+ y=shortage_data['Supply_Projected'],
526
+ mode='markers',
527
+ name='Shortage Days',
528
+ marker=dict(color='orange', size=12, symbol='x'),
 
529
  ))
530
+
531
+ fig.update_layout(
532
+ title=f'{material} - Supply vs Demand Forecast',
533
+ xaxis_title='Date',
534
+ yaxis_title='Units',
535
+ height=350,
536
+ showlegend=True,
537
+ hovermode='x unified'
538
+ )
539
+
540
+ st.plotly_chart(fig, use_container_width=True)
541
 
542
+ # External demand sensing (same as before)
543
+ st.subheader("📡 Real-time External Demand Sensing")
 
 
 
 
 
 
544
 
545
+ col1, col2 = st.columns(2)
546
+
547
+ with col1:
548
+ st.write("**Active External Signals:**")
549
+ for signal in external_signals:
550
+ confidence_color = "🟢" if signal['Confidence'] > 90 else "🟡" if signal['Confidence'] > 80 else "🟠"
551
+ st.markdown(f"""
552
+ <div class="external-signal">
553
+ <b>{confidence_color} {signal['Source']}</b><br>
554
+ {signal['Signal']}<br>
555
+ <small>Impact: {signal['Impact']} | Confidence: {signal['Confidence']}%</small>
556
+ </div>
557
+ """, unsafe_allow_html=True)
558
 
559
+ with col2:
560
+ st.write("**Scenario Planning:**")
561
+
562
+ scenario = st.selectbox("Select Scenario to Test:",
563
+ ["Base Case", "Heavy Monsoon", "Festive Surge", "EV Policy Boost"])
564
+
565
+ if st.button("🎮 Run Scenario", key="demand_scenario"):
566
+ if scenario == "Heavy Monsoon":
567
+ st.error("Scenario: 40% supply reduction for 5 days. Activating contingency plans...")
568
+ elif scenario == "Festive Surge":
569
+ st.warning("Scenario: 35% demand increase for 7 days. Scaling production...")
570
+ elif scenario == "EV Policy Boost":
571
+ st.info("Scenario: 25% demand boost for EV components. Optimizing product mix...")
 
 
 
 
 
 
 
 
 
572
 
573
+ # TAB 2: ECOSYSTEM SUPPLIER IMPACT (completely same as before)
574
+ elif dashboard_tab == "🌐 Ecosystem Supplier Impact":
575
+ st.markdown("""
576
+ <div class="tab-header">
577
+ <h2>🌐 Ecosystem Supplier Impact Dashboard</h2>
578
+ <p>Tier 2 Supplier Disruption Analysis | Cascading Impact Modeling | Automated Mitigation Response</p>
579
+ </div>
580
+ """, unsafe_allow_html=True)
581
+
582
+ # Supplier selection
583
+ selected_suppliers = st.sidebar.multiselect(
584
+ "Monitor Suppliers:",
585
+ list(suppliers.keys()),
586
+ default=list(suppliers.keys())
587
+ )
588
 
589
+ # All the ecosystem code remains exactly the same...
590
+ # (I'm keeping it identical to preserve your requested features)
591
 
592
+ # Main Dashboard - Ecosystem Alerts
593
+ st.subheader("🚨 Live Ecosystem Supply Chain Alerts")
594
+
595
+ # Generate real-time alerts
596
+ ecosystem_alerts = []
597
+ for supplier in selected_suppliers:
598
+ supplier_data = df_ecosystem[df_ecosystem['Supplier'] == supplier]
599
+ disrupted_data = supplier_data[supplier_data['Is_Disrupted'] == True]
600
 
601
+ if not disrupted_data.empty:
602
+ for material in disrupted_data['Material'].unique():
603
+ material_disruptions = disrupted_data[disrupted_data['Material'] == material]
604
+
605
+ total_impact = material_disruptions['Tier2_Impact'].sum()
606
+ impact_days = len(material_disruptions)
607
+ first_impact_date = material_disruptions['Date'].min()
608
+
609
+ # Calculate Rane impact with lead time
610
+ rane_impacted = supplier_data[
611
+ (supplier_data['Material'] == material) &
612
+ (supplier_data['Is_Rane_Impacted'] == True)
613
+ ]
614
+
615
+ if not rane_impacted.empty:
616
+ rane_impact_start = rane_impacted['Date'].min()
617
+ rane_impact_days = len(rane_impacted)
618
+ rane_total_impact = rane_impacted['Rane_Impact'].sum()
619
+
620
+ ecosystem_alerts.append({
621
+ 'supplier': supplier,
622
+ 'material': material,
623
+ 'disruption_cause': material_disruptions.iloc[0]['Disruption_Cause'],
624
+ 'tier2_impact_start': first_impact_date,
625
+ 'tier2_impact_days': impact_days,
626
+ 'tier2_total_impact': total_impact,
627
+ 'rane_impact_start': rane_impact_start,
628
+ 'rane_impact_days': rane_impact_days,
629
+ 'rane_total_impact': rane_total_impact,
630
+ 'lead_time': material_disruptions.iloc[0]['Lead_Time_Days']
631
+ })
632
+
633
+ # Display ecosystem alerts
634
+ if ecosystem_alerts:
635
+ for alert in ecosystem_alerts:
636
  st.markdown(f"""
637
+ <div class="ecosystem-alert">
638
+ <h4>⚠️ Tier 2 Supplier Disruption Alert</h4>
639
+ <p><b>Supplier:</b> {alert['supplier']} | <b>Material:</b> {alert['material']}</p>
640
+ <p><b>Root Cause:</b> {alert['disruption_cause']}</p>
 
 
 
 
 
641
  </div>
642
  """, unsafe_allow_html=True)
643
 
644
+ # Detailed impact analysis
645
+ col1, col2 = st.columns(2)
646
 
647
+ with col1:
648
+ st.markdown("**🏭 Tier 2 Supplier Impact:**")
649
+ st.markdown(f"""
650
+ <div class="tier-impact">
651
+ 📅 <b>Impact Period:</b> {alert['tier2_impact_start'].strftime('%Y-%m-%d')} ({alert['tier2_impact_days']} days)<br>
652
+ 📉 <b>Total Supply Lost:</b> {alert['tier2_total_impact']} units<br>
653
+ 🎯 <b>Daily Impact:</b> {alert['tier2_total_impact'] // alert['tier2_impact_days']} units/day
654
+ </div>
655
+ """, unsafe_allow_html=True)
656
 
657
+ with col2:
658
+ st.markdown("**⚙️ Rane Group Impact (with Lead Time):**")
659
+ st.markdown(f"""
660
+ <div class="tier-impact">
661
+ 📅 <b>Impact Period:</b> {alert['rane_impact_start'].strftime('%Y-%m-%d')} ({alert['rane_impact_days']} days)<br>
662
+ 📉 <b>Total Supply Lost:</b> {alert['rane_total_impact']} units<br>
663
+ ⏱️ <b>Lead Time Delay:</b> {alert['lead_time']} days
664
+ </div>
665
+ """, unsafe_allow_html=True)
666
 
667
+ # Generate and display mitigation strategies
668
+ strategies, recommended_indices = generate_mitigation_strategies(
669
+ alert['supplier'],
670
+ alert['material'],
671
+ alert['rane_total_impact'] // alert['rane_impact_days'],
672
+ alert['rane_impact_days']
673
+ )
674
+
675
+ st.markdown("**🤖 Agentic AI Mitigation Strategies:**")
676
+
677
+ for i, strategy in enumerate(strategies):
678
+ is_recommended = i in recommended_indices
679
+ is_executed = f"eco_{alert['supplier']}_{alert['material']}_{i}" in st.session_state.executed_mitigations
680
+
681
+ if is_executed:
682
+ card_class = "mitigation-executed"
683
+ status_prefix = "✅ **EXECUTED** "
684
+ elif is_recommended:
685
+ card_class = "mitigation-recommended"
686
+ status_prefix = "🏆 **AI RECOMMENDED** "
687
+ else:
688
+ card_class = "mitigation-recommended"
689
+ status_prefix = ""
690
+
691
+ st.markdown(f"""
692
+ <div class="{card_class}">
693
+ {status_prefix}<b>{strategy['strategy']}</b><br>
694
+ 📋 {strategy['description']}<br>
695
+ ⏱️ <b>Timeline:</b> {strategy['timeline']} | 💰 <b>Cost:</b> {strategy['cost']}<br>
696
+ 📈 <b>Effectiveness:</b> {strategy['effectiveness']} | 🚀 <b>Capacity:</b> {strategy['capacity']}
697
+ </div>
698
+ """, unsafe_allow_html=True)
699
+
700
+ # Action buttons
701
+ strategy_key = f"eco_{alert['supplier']}_{alert['material']}_{i}"
702
+
703
+ col1, col2 = st.columns([2, 1])
704
+
705
+ with col1:
706
+ if not is_executed:
707
+ if st.button(f"🚀 Execute Strategy", key=f"execute_{strategy_key}"):
708
+ st.session_state.executed_mitigations.append(strategy_key)
709
+ st.success(f"Executing: {strategy['strategy']}")
710
+ st.rerun()
711
+ else:
712
+ st.success("Strategy Active")
713
+
714
+ with col2:
715
+ if is_recommended:
716
+ st.button("🏆 Recommended", key=f"rec_{strategy_key}", disabled=True)
717
+
718
+ st.markdown("---")
719
+ else:
720
+ st.markdown("""
721
+ <div class="normal-status">
722
+ ✅ <b>Ecosystem Healthy!</b> No supplier disruptions detected in the current timeframe.
723
  </div>
724
  """, unsafe_allow_html=True)
725
+
726
+ # Ecosystem visualization
727
+ st.subheader("📊 Ecosystem Supply Chain Flow Visualization")
728
+
729
+ # Create ecosystem impact chart
730
+ fig = go.Figure()
731
+
732
+ for supplier in selected_suppliers:
733
+ supplier_data = df_ecosystem[df_ecosystem['Supplier'] == supplier]
734
 
735
+ # Sample one material per supplier for clarity
736
+ sample_material = supplier_data['Material'].iloc[0]
737
+ material_data = supplier_data[supplier_data['Material'] == sample_material]
 
 
 
738
 
739
+ # Tier 2 supply line
740
+ fig.add_trace(go.Scatter(
741
+ x=material_data['Date'],
742
+ y=material_data['Tier2_Disrupted_Supply'],
743
+ mode='lines+markers',
744
+ name=f'{supplier} (Tier 2)',
745
+ line=dict(width=2, dash='dash'),
746
+ marker=dict(size=6)
747
+ ))
748
 
749
+ # Rane impact line
750
+ fig.add_trace(go.Scatter(
751
+ x=material_data['Date'],
752
+ y=material_data['Rane_Impacted_Supply'],
753
+ mode='lines+markers',
754
+ name=f'Rane Impact from {supplier}',
755
+ line=dict(width=3),
756
+ marker=dict(size=8)
757
+ ))
758
+
759
+ fig.update_layout(
760
+ title='Tier 2 Supplier Disruptions → Rane Group Supply Impact',
761
+ xaxis_title='Date',
762
+ yaxis_title='Supply Units',
763
+ height=500,
764
+ showlegend=True,
765
+ hovermode='x unified'
766
+ )
767
+
768
+ st.plotly_chart(fig, use_container_width=True)
769
 
770
+ # Performance summary (same as before)
771
+ st.subheader("📊 Performance Summary")
772
 
773
+ col1, col2, col3, col4 = st.columns(4)
 
774
 
775
+ if dashboard_tab == "📊 Demand & Supply Forecast":
776
+ filtered_df = filtered_df_demand if 'filtered_df_demand' in locals() else df_demand
777
+
778
+ total_shortage_days = len(filtered_df[filtered_df['Gap'] < 0])
779
+ critical_shortage_days = len(filtered_df[filtered_df['Gap'] < -20])
780
+ materials_at_risk = len(filtered_df[filtered_df['Gap'] < -5]['Material'].unique())
781
+ avg_gap = filtered_df['Gap'].mean()
782
+
783
+ with col1:
784
+ st.metric("Days with Shortages", f"{total_shortage_days}")
785
+
786
+ with col2:
787
+ st.metric("Critical Days", f"{critical_shortage_days}")
788
+
789
+ with col3:
790
+ st.metric("Materials at Risk", f"{materials_at_risk}")
791
+
792
+ with col4:
793
+ st.metric("Avg Supply Gap", f"{avg_gap:.0f} units")
794
 
795
+ else: # Ecosystem tab
796
+ total_suppliers_disrupted = len(df_ecosystem[df_ecosystem['Is_Disrupted'] == True]['Supplier'].unique())
797
+ total_rane_impact_days = len(df_ecosystem[df_ecosystem['Is_Rane_Impacted'] == True])
798
+ total_mitigation_strategies = len([s for s in st.session_state.executed_mitigations if 'eco_' in s])
799
+ avg_lead_time = df_ecosystem['Lead_Time_Days'].mean()
800
+
801
+ with col1:
802
+ st.metric("Suppliers Disrupted", f"{total_suppliers_disrupted}")
803
+
804
+ with col2:
805
+ st.metric("Rane Impact Days", f"{total_rane_impact_days}")
806
+
807
+ with col3:
808
+ st.metric("Active Mitigations", f"{total_mitigation_strategies}")
809
+
810
+ with col4:
811
+ st.metric("Avg Lead Time", f"{avg_lead_time:.1f} days")
812
 
813
+ # Footer (same as before)
814
  st.markdown("---")
815
  st.markdown("""
816
  <div style='text-align: center; color: #666;'>
817
+ <p>🌐 <b>Rane Group Complete Supply Chain Command Center</b> | Demand Sensing + Ecosystem Intelligence<br>
818
+ Powered by Agentic AI | Real-time Decision Support | Comprehensive Supply Chain Resilience</p>
819
  </div>
820
  """, unsafe_allow_html=True)