PD03 commited on
Commit
f94228c
·
verified ·
1 Parent(s): 781a2f6

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +373 -1489
src/streamlit_app.py CHANGED
@@ -1,4 +1,4 @@
1
- #Complete Yazaki India Ltd version - Full Feature Set
2
  import streamlit as st
3
  import pandas as pd
4
  import numpy as np
@@ -15,7 +15,7 @@ st.set_page_config(
15
  initial_sidebar_state="expanded"
16
  )
17
 
18
- # Complete Custom CSS
19
  st.markdown("""
20
  <style>
21
  .main-header {
@@ -60,38 +60,6 @@ st.markdown("""
60
  border-radius: 8px;
61
  margin: 0.5rem 0;
62
  }
63
-
64
- .supplier-card {
65
- background: white;
66
- border: 1px solid #e0e0e0;
67
- border-radius: 10px;
68
- padding: 1rem;
69
- margin: 0.5rem 0;
70
- box-shadow: 0 2px 4px rgba(0,0,0,0.05);
71
- }
72
-
73
- .mitigation-card {
74
- background: #f0f8ff;
75
- border: 1px solid #2196f3;
76
- border-radius: 8px;
77
- padding: 1rem;
78
- margin: 0.5rem 0;
79
- }
80
-
81
- .external-signal {
82
- background: white;
83
- border-radius: 8px;
84
- padding: 0.8rem;
85
- margin: 0.5rem 0;
86
- box-shadow: 0 1px 3px rgba(0,0,0,0.1);
87
- }
88
-
89
- .stMetric {
90
- background: white;
91
- padding: 1rem;
92
- border-radius: 8px;
93
- border: 1px solid #e0e0e0;
94
- }
95
  </style>
96
  """, unsafe_allow_html=True)
97
 
@@ -100,12 +68,8 @@ if 'executed_mitigations' not in st.session_state:
100
  st.session_state.executed_mitigations = []
101
  if 'external_signals' not in st.session_state:
102
  st.session_state.external_signals = []
103
- if 'buffer_settings' not in st.session_state:
104
- st.session_state.buffer_settings = {}
105
- if 'alert_history' not in st.session_state:
106
- st.session_state.alert_history = []
107
 
108
- # COMPLETE: Generate 8-week forward-looking demand data for Yazaki
109
  @st.cache_data
110
  def generate_8week_demand_data():
111
  today = datetime(2025, 8, 4)
@@ -114,75 +78,47 @@ def generate_8week_demand_data():
114
  # Yazaki-specific materials (wire harnesses, connectors, electrical components)
115
  materials = [
116
  'WH001-Engine Wire Harness',
117
- 'WH002-Dashboard Wire Harness',
118
- 'WH003-Door Wire Harness',
119
  'CON001-Electrical Connector',
120
- 'CON002-Multi-Pin Connector',
121
  'TER001-Wire Terminal',
122
- 'TER002-Crimp Terminal',
123
- 'FUS001-Fuse Box Assembly',
124
- 'REL001-Relay Module',
125
- 'SWI001-Switch Assembly'
126
  ]
127
 
128
  all_data = []
129
  for material in materials:
130
  np.random.seed(hash(material) % 1000)
131
 
132
- # Generate sophisticated demand patterns
133
  base_demand = np.random.normal(150, 15, 56)
134
 
135
- # First 14 days: FIRM DEMAND with customer confirmed orders
136
  firm_demand = np.clip(base_demand[:14], 100, 200).astype(int)
137
 
138
- # Days 15-56: Customer shared demand (tentative forecasts)
139
  customer_shared = np.clip(base_demand[14:] * (1 + 0.05 * np.sin(np.linspace(0, 3.14, 42))), 80, 220).astype(int)
140
 
141
- # Days 15-56: AI-corrected demand (with external signals and market intelligence)
142
  external_factors = np.zeros(42)
143
-
144
- # Weather impact (weeks 3-4) - affects logistics and supplier operations
145
  external_factors[0:14] += np.random.normal(0, 5, 14)
146
-
147
- # EV policy impact (weeks 5-8) - higher for wire harnesses due to EV complexity
148
  if 'WH' in material:
149
- external_factors[14:] += 15 # Higher impact for wire harnesses in EVs
150
  elif 'CON' in material or 'TER' in material:
151
- external_factors[14:] += 10 # Moderate impact for connectors/terminals
152
- elif 'REL' in material or 'SWI' in material:
153
- external_factors[14:] += 8 # Lower impact for relays/switches
154
-
155
- # Festive season automotive demand boost (weeks 6-7)
156
- external_factors[28:42] += np.random.normal(12, 3, 14)
157
-
158
- # Supply chain disruption factors (global chip shortage impact)
159
- if 'FUS' in material or 'REL' in material:
160
- external_factors[21:35] += 6 # Electronic components more affected
161
-
162
- # Market sentiment and new model launches
163
- external_factors[35:42] += np.random.normal(5, 2, 7)
164
 
165
- corrected_demand = np.clip(customer_shared + external_factors, 60, 280).astype(int)
166
 
167
- # Generate comprehensive supply plan for 56 days
168
- base_supply_capacity = 155 + (hash(material) % 40) - 20 # Vary by material
169
- supply_capacity = np.random.normal(base_supply_capacity, 12, 56)
170
- supply_plan = np.clip(supply_capacity, 120, 250).astype(int)
171
 
172
- # Apply realistic disruptions to supply
173
  supply_actual = supply_plan.copy()
 
174
 
175
- # Weather-related supply disruption (Chennai monsoons, days 15-18)
176
- supply_actual[15:19] = (supply_actual[15:19] * 0.75).astype(int)
177
-
178
- # Tier-2 supplier quality issue (days 25-27)
179
- if 'CON' in material:
180
- supply_actual[25:28] = (supply_actual[25:28] * 0.6).astype(int)
181
-
182
- # Transportation strike impact (days 35-37)
183
- supply_actual[35:38] = (supply_actual[35:38] * 0.8).astype(int)
184
-
185
- # Generate additional metrics
186
  for i, date in enumerate(dates):
187
  # Determine which demand to use
188
  if i < 14:
@@ -198,29 +134,14 @@ def generate_8week_demand_data():
198
  corrected_val = corrected_demand[i-14]
199
  demand_type = "AI-Corrected"
200
 
201
- # Calculate comprehensive metrics
202
  shortfall = max(0, demand_used - supply_actual[i])
203
- excess = max(0, supply_actual[i] - demand_used)
204
- fill_rate = min(100, (supply_actual[i] / demand_used) * 100) if demand_used > 0 else 100
205
-
206
- # Risk scoring
207
- risk_score = 0
208
- if shortfall > 0:
209
- risk_score += (shortfall / demand_used) * 40 if demand_used > 0 else 20
210
- if i >= 15 and i <= 18: # Weather disruption period
211
- risk_score += 15
212
- if demand_type == "AI-Corrected" and corrected_val and customer_val:
213
- if corrected_val > customer_val * 1.2: # High demand correction
214
- risk_score += 10
215
-
216
- risk_level = "Critical" if risk_score >= 50 else "High" if risk_score >= 30 else "Medium" if risk_score >= 15 else "Low"
217
 
218
  all_data.append({
219
  'Date': date,
220
  'Week': f"Week {(i//7)+1}",
221
  'Day': i + 1,
222
  'Material': material,
223
- 'Material_Category': material.split('-')[0],
224
  'Firm_Demand': firm_val,
225
  'Customer_Demand': customer_val,
226
  'Corrected_Demand': corrected_val,
@@ -228,80 +149,43 @@ def generate_8week_demand_data():
228
  'Supply_Plan': supply_plan[i],
229
  'Supply_Projected': supply_actual[i],
230
  'Shortfall': shortfall,
231
- 'Excess': excess,
232
- 'Fill_Rate': round(fill_rate, 1),
233
  'Demand_Type': demand_type,
234
- 'Gap': supply_actual[i] - demand_used,
235
- 'Risk_Score': round(risk_score, 1),
236
- 'Risk_Level': risk_level,
237
- 'Week_Number': (i//7)+1
238
  })
239
 
240
  return pd.DataFrame(all_data)
241
 
242
- # COMPLETE Yazaki-specific Tier-2 suppliers with detailed information
243
  @st.cache_data
244
  def get_tier2_suppliers():
245
  return {
246
- 'Furukawa Electric India Pvt Ltd': {
247
- 'location': 'Chennai, Tamil Nadu',
248
- 'materials': ['WH001-Engine Wire Harness', 'WH002-Dashboard Wire Harness', 'WH003-Door Wire Harness'],
249
- 'capacity': 220,
250
- 'reliability': 96,
251
  'lead_time': 2,
252
- 'risk_factors': ['Monsoon flooding', 'Port congestion Chennai', 'Copper price volatility', 'Power grid instability'],
253
- 'tier_level': 'Tier-2',
254
- 'certifications': ['ISO 9001', 'TS 16949', 'ISO 14001'],
255
- 'financial_health': 'Strong',
256
- 'backup_available': True,
257
- 'contract_type': 'Long-term',
258
- 'performance_rating': 4.8
259
  },
260
- 'Sumitomo Wiring Systems India': {
261
- 'location': 'Bangalore, Karnataka',
262
- 'materials': ['CON001-Electrical Connector', 'CON002-Multi-Pin Connector', 'TER001-Wire Terminal', 'TER002-Crimp Terminal'],
263
- 'capacity': 200,
264
- 'reliability': 94,
265
  'lead_time': 3,
266
- 'risk_factors': ['Transportation delays NH4', 'Raw material shortage', 'Equipment aging', 'Skilled labor shortage'],
267
- 'tier_level': 'Tier-2',
268
- 'certifications': ['ISO 9001', 'TS 16949'],
269
- 'financial_health': 'Stable',
270
- 'backup_available': True,
271
- 'contract_type': 'Medium-term',
272
- 'performance_rating': 4.6
273
  },
274
  'JST India Private Limited': {
275
- 'location': 'Pune, Maharashtra',
276
- 'materials': ['FUS001-Fuse Box Assembly', 'CON001-Electrical Connector', 'REL001-Relay Module'],
277
- 'capacity': 180,
278
- 'reliability': 91,
279
  'lead_time': 1,
280
- 'risk_factors': ['Quality consistency issues', 'Capacity constraints', 'Supplier payment disputes', 'Mumbai port dependency'],
281
- 'tier_level': 'Tier-2',
282
- 'certifications': ['ISO 9001', 'TS 16949', 'UL Listed'],
283
- 'financial_health': 'Moderate',
284
- 'backup_available': False,
285
- 'contract_type': 'Short-term',
286
- 'performance_rating': 4.2
287
- },
288
- 'Motherson Sumi Infotech & Designs': {
289
- 'location': 'Noida, Uttar Pradesh',
290
- 'materials': ['SWI001-Switch Assembly', 'REL001-Relay Module', 'FUS001-Fuse Box Assembly'],
291
- 'capacity': 160,
292
- 'reliability': 89,
293
- 'lead_time': 4,
294
- 'risk_factors': ['Delhi NCR pollution restrictions', 'Highway congestion', 'Seasonal workforce fluctuation'],
295
- 'tier_level': 'Tier-2',
296
- 'certifications': ['ISO 9001', 'TS 16949'],
297
- 'financial_health': 'Stable',
298
- 'backup_available': True,
299
- 'contract_type': 'Long-term',
300
- 'performance_rating': 4.4
301
  }
302
  }
303
 
304
- # COMPLETE ecosystem generation with advanced modeling
305
  @st.cache_data
306
  def generate_ecosystem_data():
307
  today = datetime(2025, 8, 4)
@@ -314,1496 +198,496 @@ def generate_ecosystem_data():
314
  np.random.seed(hash(supplier_name + material) % 1000)
315
 
316
  base_capacity = supplier_info['capacity']
317
- reliability_factor = supplier_info['reliability'] / 100
318
-
319
- # Generate normal supply with reliability variation
320
- normal_supply = np.random.normal(base_capacity * reliability_factor, base_capacity * 0.05, 14).astype(int)
321
- normal_supply = np.clip(normal_supply, base_capacity * 0.8, base_capacity * 1.1).astype(int)
322
-
323
  disrupted_supply = normal_supply.copy()
324
 
325
- # Apply realistic disruptions based on supplier profiles
326
- if supplier_name == 'Furukawa Electric India Pvt Ltd':
327
- # Chennai monsoon disruption days 3-6
328
- disrupted_supply[3:7] = (disrupted_supply[3:7] * 0.25).astype(int)
329
- disruption_cause = "Severe monsoon flooding in Chennai affecting production and logistics"
330
  disruption_days = list(range(3, 7))
331
- disruption_severity = "Critical"
332
- elif supplier_name == 'Sumitomo Wiring Systems India':
333
- # Equipment failure days 5-7
334
- disrupted_supply[5:8] = (disrupted_supply[5:8] * 0.45).astype(int)
335
- disruption_cause = "Critical injection molding equipment failure - spare parts delayed"
336
  disruption_days = list(range(5, 8))
337
- disruption_severity = "High"
338
  elif supplier_name == 'JST India Private Limited':
339
- # Labor strike days 8-10
340
- disrupted_supply[8:11] = (disrupted_supply[8:11] * 0.15).astype(int)
341
- disruption_cause = "Unplanned labor strike at Pune facility over wage negotiations"
342
  disruption_days = list(range(8, 11))
343
- disruption_severity = "Critical"
344
- elif supplier_name == 'Motherson Sumi Infotech & Designs':
345
- # Transportation delays days 6-8
346
- disrupted_supply[6:9] = (disrupted_supply[6:9] * 0.7).astype(int)
347
- disruption_cause = "Highway blockage on Delhi-Noida route due to farmer protests"
348
- disruption_days = list(range(6, 9))
349
- disruption_severity = "Medium"
350
  else:
351
- disruption_cause = "Normal Operations"
352
  disruption_days = []
353
- disruption_severity = "None"
354
 
355
  lead_time = supplier_info['lead_time']
356
- yazaki_supply = normal_supply.copy()
357
 
358
- # Calculate cascading impact on Yazaki with lead time consideration
359
  for disruption_day in disruption_days:
360
  arrival_day = disruption_day + lead_time
361
  if arrival_day < 14:
362
  reduction = normal_supply[disruption_day] - disrupted_supply[disruption_day]
363
  yazaki_supply[arrival_day] = max(yazaki_supply[arrival_day] - reduction, 0)
364
 
365
- # Calculate financial impact
366
- unit_cost = 100 + (hash(material) % 200) # Simulate unit costs
367
-
368
  for i, date in enumerate(dates):
369
- tier2_impact = int(normal_supply[i] - disrupted_supply[i])
370
- yazaki_impact = int(normal_supply[i] - yazaki_supply[i])
371
- financial_impact = yazaki_impact * unit_cost
372
-
373
- # Recovery timeline estimation
374
- if i in disruption_days:
375
- days_to_recover = len(disruption_days) + lead_time
376
- else:
377
- days_to_recover = 0
378
-
379
  all_data.append({
380
  'Date': date,
381
  'Supplier': supplier_name,
382
  'Material': material,
383
- 'Supplier_Location': supplier_info['location'],
384
  'Tier2_Normal_Supply': int(normal_supply[i]),
385
  'Tier2_Disrupted_Supply': int(disrupted_supply[i]),
386
- 'Tier2_Impact': tier2_impact,
387
  'Yazaki_Normal_Supply': int(normal_supply[i]),
388
  'Yazaki_Impacted_Supply': int(yazaki_supply[i]),
389
- 'Yazaki_Impact': yazaki_impact,
390
- 'Financial_Impact_INR': financial_impact,
391
  'Disruption_Cause': disruption_cause if i in disruption_days else "Normal Operations",
392
- 'Disruption_Severity': disruption_severity if i in disruption_days else "None",
393
  'Lead_Time_Days': lead_time,
394
  'Is_Disrupted': i in disruption_days,
395
- 'Is_Yazaki_Impacted': yazaki_supply[i] < normal_supply[i],
396
- 'Recovery_Timeline_Days': days_to_recover if i in disruption_days else 0,
397
- 'Supplier_Reliability': supplier_info['reliability'],
398
- 'Backup_Available': supplier_info['backup_available'],
399
- 'Performance_Rating': supplier_info['performance_rating']
400
  })
401
 
402
  return pd.DataFrame(all_data)
403
 
404
- # COMPLETE external signals with advanced market intelligence
405
  @st.cache_data
406
  def get_external_signals():
407
  return [
408
- {
409
- 'Source': 'Weather API (IMD)',
410
- 'Signal': 'Heavy to very heavy rainfall forecasted in Chennai and surrounding areas for next 72 hours',
411
- 'Impact': 'Supply Chain Risk',
412
- 'Confidence': 97,
413
- 'Urgency': 'Immediate',
414
- 'Affected_Materials': ['WH001', 'WH002', 'WH003'],
415
- 'Estimated_Impact': '60-80% production reduction',
416
- 'Timeline': '3-5 days',
417
- 'Mitigation_Available': True
418
- },
419
- {
420
- 'Source': 'Market Intelligence (Automotive)',
421
- 'Signal': 'EV sales in India increased by 32% this quarter - Tata Motors, Mahindra leading growth',
422
- 'Impact': 'Demand Surge',
423
- 'Confidence': 91,
424
- 'Urgency': 'High',
425
- 'Affected_Materials': ['WH001', 'WH002', 'CON001', 'REL001'],
426
- 'Estimated_Impact': '25-30% demand increase',
427
- 'Timeline': '4-6 weeks',
428
- 'Mitigation_Available': True
429
- },
430
- {
431
- 'Source': 'News Analytics (Economic)',
432
- 'Signal': 'Upcoming festive season (Diwali, Dussehra) - historical data shows 18% automotive demand spike',
433
- 'Impact': 'Seasonal Demand Peak',
434
- 'Confidence': 94,
435
- 'Urgency': 'Medium',
436
- 'Affected_Materials': ['All'],
437
- 'Estimated_Impact': '15-20% demand increase',
438
- 'Timeline': '6-8 weeks',
439
- 'Mitigation_Available': True
440
- },
441
- {
442
- 'Source': 'Supplier Network (Tier-1)',
443
- 'Signal': 'Sumitomo expanding connector manufacturing capacity by 25% at Bangalore facility',
444
- 'Impact': 'Supply Capacity Boost',
445
- 'Confidence': 99,
446
- 'Urgency': 'Low',
447
- 'Affected_Materials': ['CON001', 'CON002', 'TER001', 'TER002'],
448
- 'Estimated_Impact': '+25% supply capacity',
449
- 'Timeline': '2-3 weeks',
450
- 'Mitigation_Available': False
451
- },
452
- {
453
- 'Source': 'Social Media Analytics',
454
- 'Signal': 'Highly positive consumer sentiment for new Maruti Suzuki and Hyundai EV models on social platforms',
455
- 'Impact': 'Potential Demand Growth',
456
- 'Confidence': 78,
457
- 'Urgency': 'Medium',
458
- 'Affected_Materials': ['WH001', 'WH002', 'CON001'],
459
- 'Estimated_Impact': '8-12% demand growth',
460
- 'Timeline': '3-4 weeks',
461
- 'Mitigation_Available': True
462
- },
463
- {
464
- 'Source': 'Government Portal (MoRTH)',
465
- 'Signal': 'New EV subsidy scheme (FAME III) approved - ₹15,000 additional subsidy per vehicle',
466
- 'Impact': 'Market Expansion',
467
- 'Confidence': 100,
468
- 'Urgency': 'High',
469
- 'Affected_Materials': ['All EV-related components'],
470
- 'Estimated_Impact': '40-50% EV segment growth',
471
- 'Timeline': '1-2 weeks implementation',
472
- 'Mitigation_Available': True
473
- },
474
- {
475
- 'Source': 'Logistics Intelligence',
476
- 'Signal': 'NH4 highway construction causing 2-hour average delays for Bangalore-Chennai route',
477
- 'Impact': 'Transportation Delays',
478
- 'Confidence': 88,
479
- 'Urgency': 'Medium',
480
- 'Affected_Materials': ['CON001', 'CON002', 'TER001', 'TER002'],
481
- 'Estimated_Impact': '1-2 days delivery delays',
482
- 'Timeline': '4-6 weeks (construction period)',
483
- 'Mitigation_Available': True
484
- },
485
- {
486
- 'Source': 'Financial Markets',
487
- 'Signal': 'Copper prices increased 8% this week due to global supply concerns',
488
- 'Impact': 'Cost Inflation',
489
- 'Confidence': 95,
490
- 'Urgency': 'High',
491
- 'Affected_Materials': ['WH001', 'WH002', 'WH003'],
492
- 'Estimated_Impact': '5-8% material cost increase',
493
- 'Timeline': 'Immediate',
494
- 'Mitigation_Available': False
495
- }
496
  ]
497
 
498
- # COMPLETE alert generation with sophisticated logic
499
  def generate_detailed_alerts(df):
500
  alerts = []
501
  for material in df['Material'].unique():
502
  material_data = df[df['Material'] == material]
503
-
504
- # Identify various types of alerts
505
  shortage_days = material_data[material_data['Shortfall'] > 5]
506
- high_risk_days = material_data[material_data['Risk_Score'] >= 30]
507
- low_fill_rate_days = material_data[material_data['Fill_Rate'] < 85]
508
 
509
- # Process shortage alerts
510
- for _, row in shortage_days.iterrows():
511
- root_causes = []
512
-
513
- if row['Day'] > 14:
514
- if row['Corrected_Demand'] and row['Customer_Demand']:
515
- diff = row['Corrected_Demand'] - row['Customer_Demand']
516
- if diff > 10:
517
- root_causes.append(f"AI detected {diff} units additional demand from market signals")
518
- root_causes.append("External factors: EV policy impact, festive season, market sentiment")
519
 
520
- if row['Day'] >= 15 and row['Day'] <= 18:
521
- root_causes.append("Chennai monsoon disruption affecting Furukawa Electric supply chain")
522
- elif row['Day'] >= 25 and row['Day'] <= 27:
523
- root_causes.append("Quality issues at Tier-2 connector supplier affecting production")
524
- elif row['Day'] >= 35 and row['Day'] <= 37:
525
- root_causes.append("Transportation strike impact on material deliveries")
526
- else:
527
- root_causes.append("Firm customer demand exceeding current supply capacity")
528
- root_causes.append("Insufficient safety stock buffer for confirmed orders")
529
-
530
- if not root_causes:
531
- root_causes.append("Base demand variability exceeding supply flexibility")
532
-
533
- # Advanced mitigation options with detailed impact analysis
534
- mitigation_options = [
535
- {
536
- "option": "Activate Aurangabad backup production facility",
537
- "impact": f"+{int(row['Shortfall'] * 0.8)} units/day",
538
- "cost": "High (₹2.5L/day operational cost)",
539
- "timeline": "18-24 hours",
540
- "success_probability": "90%",
541
- "resource_requirements": "15 additional staff, equipment setup"
542
- },
543
- {
544
- "option": "Emergency air freight from Yazaki Philippines plant",
545
- "impact": f"+{int(row['Shortfall'] * 1.2)} units/day",
546
- "cost": "Very High (₹8-12/unit logistics premium)",
547
- "timeline": "4-6 hours",
548
- "success_probability": "95%",
549
- "resource_requirements": "Customs clearance, quality verification"
550
- },
551
- {
552
- "option": "Expedite Tier-2 supplier overtime production",
553
- "impact": f"+{int(row['Shortfall'] * 0.6)} units/day",
554
- "cost": "Medium (25% overtime premium)",
555
- "timeline": "8-12 hours",
556
- "success_probability": "85%",
557
- "resource_requirements": "Supplier capacity confirmation, quality assurance"
558
- },
559
- {
560
- "option": "Reallocate inventory from Chennai/Bangalore Yazaki plants",
561
- "impact": f"+{int(row['Shortfall'] * 0.5)} units/day",
562
- "cost": "Low (₹500/unit transfer cost)",
563
- "timeline": "12-18 hours",
564
- "success_probability": "75%",
565
- "resource_requirements": "Inter-plant coordination, transportation"
566
- },
567
- {
568
- "option": "Activate alternate supplier (backup vendor network)",
569
- "impact": f"+{int(row['Shortfall'] * 0.7)} units/day",
570
- "cost": "High (15-20% unit cost premium)",
571
- "timeline": "24-36 hours",
572
- "success_probability": "80%",
573
- "resource_requirements": "Quality qualification, contract negotiation"
574
- }
575
- ]
576
-
577
- # Intelligent best option selection
578
- if row['Shortfall'] > 40:
579
- best_option = mitigation_options[1] # Emergency air freight
580
- secondary_option = mitigation_options[0] # Backup production
581
- elif row['Shortfall'] > 25:
582
- best_option = mitigation_options[0] # Backup production
583
- secondary_option = mitigation_options[4] # Alternate supplier
584
- elif row['Shortfall'] > 15:
585
- best_option = mitigation_options[2] # Overtime production
586
- secondary_option = mitigation_options[3] # Inventory reallocation
587
- else:
588
- best_option = mitigation_options[3] # Inventory reallocation
589
- secondary_option = mitigation_options[2] # Overtime production
590
-
591
- # Calculate business impact
592
- revenue_at_risk = row['Shortfall'] * 250 # Assume ₹250 revenue per unit
593
- customer_impact = "High" if row['Shortfall'] > 30 else "Medium" if row['Shortfall'] > 15 else "Low"
594
-
595
- alerts.append({
596
- 'alert_id': f"ALERT-{material.split('-')[0]}-{row['Day']:02d}",
597
- 'material': material,
598
- 'date': row['Date'].strftime('%Y-%m-%d'),
599
- 'week': row['Week'],
600
- 'shortage': int(row['Shortfall']),
601
- 'demand_type': row['Demand_Type'],
602
- 'severity': row['Risk_Level'],
603
- 'fill_rate': row['Fill_Rate'],
604
- 'risk_score': row['Risk_Score'],
605
- 'root_causes': root_causes,
606
- 'mitigation_options': mitigation_options,
607
- 'best_option': best_option,
608
- 'secondary_option': secondary_option,
609
- 'revenue_at_risk': revenue_at_risk,
610
- 'customer_impact': customer_impact,
611
- 'generated_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
612
- })
613
-
614
- # Sort alerts by severity and shortage amount
615
- severity_order = {'Critical': 4, 'High': 3, 'Medium': 2, 'Low': 1}
616
- alerts.sort(key=lambda x: (severity_order.get(x['severity'], 0), x['shortage']), reverse=True)
617
 
618
  return alerts
619
 
620
- # COMPLETE mitigation strategies with advanced modeling
621
  def generate_mitigation_strategies(supplier, material, impact_amount, impact_days):
622
  base_strategies = [
623
  {
624
- 'strategy': 'Activate Primary Alternate Supplier',
625
- 'description': f'Engage pre-qualified backup supplier for {material}',
626
- 'timeline': '18-24 hours',
627
- 'cost': 'High (+18% unit cost, ₹50K setup)',
628
- 'effectiveness': '92%',
629
- 'capacity': f'+{impact_amount * 0.92:.0f} units/day',
630
- 'risks': ['Quality variation risk', 'Initial delivery delays'],
631
- 'prerequisites': ['Supplier audit completion', 'Quality agreement'],
632
- 'resource_allocation': 'Supply chain team: 3 FTE for 48 hours'
633
- },
634
- {
635
- 'strategy': 'Emergency Air Freight from Global Network',
636
- 'description': f'Air freight {material} from Yazaki Philippines/Thailand facilities',
637
- 'timeline': '4-8 hours',
638
- 'cost': 'Very High (+45% logistics cost, ₹15/unit)',
639
- 'effectiveness': '88%',
640
- 'capacity': f'+{impact_amount * 0.88:.0f} units/day',
641
- 'risks': ['Customs delays', 'Weather disruptions'],
642
- 'prerequisites': ['Export/import licenses', 'Quality certificates'],
643
- 'resource_allocation': 'Logistics team: 2 FTE, Customs agent'
644
  },
645
  {
646
- 'strategy': 'Inter-Plant Inventory Reallocation',
647
- 'description': f'Reallocate {material} inventory from Chennai/Bangalore plants',
648
- 'timeline': '8-16 hours',
649
- 'cost': 'Medium (+8% handling cost, ₹5K transport)',
650
  'effectiveness': '75%',
651
  'capacity': f'+{impact_amount * 0.75:.0f} units/day',
652
- 'risks': ['Inter-plant stock availability', 'Transportation delays'],
653
- 'prerequisites': ['Stock verification', 'Transport arrangement'],
654
- 'resource_allocation': 'Warehouse team: 2 FTE for coordination'
655
- },
656
- {
657
- 'strategy': 'Overtime Production Acceleration',
658
- 'description': f'Implement 16-hour shifts to accelerate {material} production',
659
- 'timeline': '4-6 hours',
660
- 'cost': 'High (+35% labor cost, ₹80K/day)',
661
- 'effectiveness': '65%',
662
- 'capacity': f'+{impact_amount * 0.65:.0f} units/day',
663
- 'risks': ['Quality control challenges', 'Worker fatigue'],
664
- 'prerequisites': ['Worker availability', 'Equipment readiness'],
665
- 'resource_allocation': '24 additional workers across 2 shifts'
666
  },
667
  {
668
- 'strategy': 'Customer Demand Reshuffling',
669
- 'description': f'Negotiate delivery timeline adjustments with lower priority customers',
670
- 'timeline': '2-4 hours',
671
- 'cost': 'Low (relationship management cost only)',
672
  'effectiveness': '60%',
673
- 'capacity': f'+{impact_amount * 0.60:.0f} units effective',
674
- 'risks': ['Customer relationship impact', 'Future order risks'],
675
- 'prerequisites': ['Customer communication', 'Management approval'],
676
- 'resource_allocation': 'Account management team: 2 FTE'
677
  }
678
  ]
679
 
680
- # Intelligent strategy recommendation based on multiple factors
681
- if impact_amount > 150:
682
- recommended = [0, 1, 3] # Multiple strategies for high impact
683
- elif impact_amount > 80:
684
- recommended = [0, 2] # Primary alternate + reallocation
685
- elif impact_amount > 40:
686
- recommended = [2, 3] # Reallocation + overtime
687
  else:
688
- recommended = [4, 2] # Demand management + reallocation
689
 
690
  return base_strategies, recommended
691
 
692
- # COMPLETE buffer optimization with advanced algorithms
693
- def calculate_optimal_buffers(df_demand, df_ecosystem):
694
- """Calculate optimal safety stock using advanced statistical methods"""
695
- buffer_recommendations = {}
696
-
697
- for material in df_demand['Material'].unique():
698
- material_data = df_demand[df_demand['Material'] == material]
699
-
700
- # Statistical analysis
701
- avg_demand = material_data['Demand_Used'].mean()
702
- demand_std = material_data['Demand_Used'].std()
703
- max_demand = material_data['Demand_Used'].max()
704
- demand_cv = demand_std / avg_demand if avg_demand > 0 else 0
705
-
706
- # Supply variability analysis
707
- supply_std = material_data['Supply_Projected'].std()
708
- supply_reliability = (material_data['Supply_Projected'] >= material_data['Demand_Used']).mean()
709
-
710
- # Risk-based buffer calculation
711
- service_level = 0.95 # Target 95% service level
712
- safety_factor = 1.65 # Z-score for 95% service level
713
-
714
- # Base safety stock (demand variability)
715
- demand_buffer = safety_factor * demand_std
716
-
717
- # Supply risk buffer
718
- supply_risk_multiplier = 1 + (1 - supply_reliability)
719
- supply_buffer = demand_buffer * supply_risk_multiplier
720
-
721
- # Lead time buffer (considering ecosystem disruptions)
722
- ecosystem_data = df_ecosystem[df_ecosystem['Material'] == material]
723
- avg_lead_time = ecosystem_data['Lead_Time_Days'].mean() if not ecosystem_data.empty else 2
724
- disruption_frequency = ecosystem_data['Is_Disrupted'].mean() if not ecosystem_data.empty else 0.1
725
-
726
- lead_time_buffer = avg_demand * avg_lead_time * (1 + disruption_frequency)
727
-
728
- # Advanced buffer calculation
729
- base_buffer = max(demand_buffer, supply_buffer)
730
- total_recommended_buffer = base_buffer + (lead_time_buffer * 0.3)
731
-
732
- # Current buffer estimation (assume 10% of average demand)
733
- current_buffer = avg_demand * 0.10
734
-
735
- # Cost-benefit analysis
736
- unit_holding_cost = 50 + (hash(material) % 100) # Simulated holding cost
737
- shortage_cost = 300 + (hash(material) % 200) # Simulated shortage cost
738
-
739
- buffer_gap = total_recommended_buffer - current_buffer
740
- holding_cost_increase = buffer_gap * unit_holding_cost
741
- risk_reduction = min(95, buffer_gap / avg_demand * 100)
742
-
743
- buffer_recommendations[material] = {
744
- 'current_buffer': int(current_buffer),
745
- 'recommended_buffer': int(total_recommended_buffer),
746
- 'buffer_gap': int(buffer_gap),
747
- 'avg_demand': round(avg_demand, 1),
748
- 'demand_variability': round(demand_cv, 2),
749
- 'supply_reliability': round(supply_reliability * 100, 1),
750
- 'service_level_target': 95,
751
- 'holding_cost_increase': int(holding_cost_increase),
752
- 'risk_reduction_percent': round(risk_reduction, 1),
753
- 'roi_months': round(shortage_cost / (holding_cost_increase / 12), 1) if holding_cost_increase > 0 else 0,
754
- 'priority': 'High' if buffer_gap > avg_demand * 0.2 else 'Medium' if buffer_gap > avg_demand * 0.1 else 'Low'
755
- }
756
-
757
- return buffer_recommendations
758
-
759
- # Load comprehensive data
760
  df_demand = generate_8week_demand_data()
761
  df_ecosystem = generate_ecosystem_data()
762
  external_signals = get_external_signals()
763
  suppliers = get_tier2_suppliers()
764
 
765
- # COMPLETE main header with advanced styling
766
- st.markdown("""
767
- <div class="main-header">
768
- <h1>🔌 Yazaki India Ltd - Advanced Supply Chain Command Center</h1>
769
- <p style="font-size: 1.2em; margin-top: 10px;">
770
- <strong>AI-Powered Supply Chain Intelligence | 8-Week Demand Planning | Real-time Risk Monitoring</strong>
771
- </p>
772
- <p style="font-size: 1em; margin-top: 5px; opacity: 0.9;">
773
- Electrical Components & Wire Harness Manufacturing | Comprehensive Ecosystem Analysis
774
- </p>
775
- </div>
776
- """, unsafe_allow_html=True)
777
-
778
- # Enhanced sidebar navigation
779
- st.sidebar.markdown("""
780
- <div style="background: linear-gradient(135deg, #1f4e79, #2d5aa0); padding: 1rem; border-radius: 10px; margin-bottom: 1rem;">
781
- <h2 style="color: white; margin: 0; text-align: center;">🎯 Command Center</h2>
782
- </div>
783
- """, unsafe_allow_html=True)
784
 
 
 
785
  dashboard_tab = st.sidebar.radio(
786
- "Select Dashboard Module:",
787
- [
788
- "📊 Advanced Demand & Supply Forecast",
789
- "🌐 Ecosystem Risk & Impact Analysis",
790
- "🛡️ Intelligent Buffer Optimization",
791
- "⚡ Real-time Alert Management",
792
- "📈 Performance Analytics Dashboard"
793
- ],
794
  index=0
795
  )
796
 
797
- # TAB 1: ADVANCED DEMAND & SUPPLY FORECAST
798
- if dashboard_tab == "📊 Advanced Demand & Supply Forecast":
799
  st.markdown("""
800
  <div style="background: linear-gradient(135deg, #1f4e79, #2d5aa0); padding: 20px; border-radius: 15px; margin-bottom: 20px;">
801
  <h2 style="color: white; margin: 0; text-align: center;">
802
- 📊 8-Week Advanced Planning Horizon
803
  </h2>
804
- <p style="color: white; text-align: center; margin: 10px 0 0 0;">
805
- Firm Orders (Days 1-14) | AI-Enhanced Forecasts (Days 15-56) | Multi-Signal Intelligence Integration
806
- </p>
807
  </div>
808
  """, unsafe_allow_html=True)
809
 
810
- # Enhanced control panel
811
- col1, col2, col3 = st.columns([2, 1, 1])
812
-
813
- with col1:
814
- selected_material = st.selectbox(
815
- "🔍 Select Material for Deep Analysis:",
816
- df_demand['Material'].unique(),
817
- key="forecast_material",
818
- format_func=lambda x: f"{x.split('-')[0]} - {x.split('-')[1]}"
819
- )
820
-
821
- with col2:
822
- view_mode = st.selectbox(
823
- "📈 View Mode:",
824
- ["Demand vs Supply", "Risk Analysis", "Fill Rate Analysis"],
825
- key="view_mode"
826
- )
827
-
828
- with col3:
829
- time_filter = st.selectbox(
830
- "⏰ Time Filter:",
831
- ["All 8 Weeks", "Firm Period (1-2 weeks)", "Forecast Period (3-8 weeks)"],
832
- key="time_filter"
833
- )
834
 
835
- # Filter data based on selections
836
  material_df = df_demand[df_demand['Material'] == selected_material].copy()
837
 
838
- if time_filter == "Firm Period (1-2 weeks)":
839
- material_df = material_df[material_df['Day'] <= 14]
840
- elif time_filter == "Forecast Period (3-8 weeks)":
841
- material_df = material_df[material_df['Day'] > 14]
842
 
843
- # Create comprehensive visualization
844
- if view_mode == "Demand vs Supply":
845
- fig = go.Figure()
846
-
847
- # Firm demand
848
- firm_data = material_df[material_df['Demand_Type'] == 'Firm']
849
- if not firm_data.empty:
850
- fig.add_trace(go.Scatter(
851
- x=firm_data['Date'],
852
- y=firm_data['Demand_Used'],
853
- mode='lines+markers',
854
- name='Firm Demand (Confirmed Orders)',
855
- line=dict(color='#1f77b4', width=4),
856
- marker=dict(size=10, symbol='circle'),
857
- hovertemplate='<b>Firm Demand</b><br>Date: %{x}<br>Units: %{y}<extra></extra>'
858
- ))
859
-
860
- # AI-corrected demand
861
- corrected_data = material_df[material_df['Demand_Type'] == 'AI-Corrected']
862
- if not corrected_data.empty:
863
- fig.add_trace(go.Scatter(
864
- x=corrected_data['Date'],
865
- y=corrected_data['Customer_Demand'],
866
- mode='lines',
867
- name='Customer Forecast',
868
- line=dict(color='#ff7f0e', width=2, dash='dot'),
869
- opacity=0.7,
870
- hovertemplate='<b>Customer Forecast</b><br>Date: %{x}<br>Units: %{y}<extra></extra>'
871
- ))
872
-
873
- fig.add_trace(go.Scatter(
874
- x=corrected_data['Date'],
875
- y=corrected_data['Corrected_Demand'],
876
- mode='lines+markers',
877
- name='AI-Corrected Demand (Market Intelligence)',
878
- line=dict(color='#d62728', width=3, dash='solid'),
879
- marker=dict(size=8, symbol='diamond'),
880
- hovertemplate='<b>AI-Corrected Demand</b><br>Date: %{x}<br>Units: %{y}<extra></extra>'
881
- ))
882
-
883
- # Supply projection
884
- fig.add_trace(go.Scatter(
885
- x=material_df['Date'],
886
- y=material_df['Supply_Projected'],
887
- mode='lines+markers',
888
- name='Supply Projection (with disruptions)',
889
- line=dict(color='#2ca02c', width=3),
890
- marker=dict(size=6),
891
- hovertemplate='<b>Supply Projection</b><br>Date: %{x}<br>Units: %{y}<extra></extra>'
892
- ))
893
-
894
- # Highlight critical shortage areas
895
- shortage_data = material_df[material_df['Shortfall'] > 10]
896
- if not shortage_data.empty:
897
- fig.add_trace(go.Scatter(
898
- x=shortage_data['Date'],
899
- y=shortage_data['Demand_Used'],
900
- mode='markers',
901
- name='Critical Shortage Alert',
902
- marker=dict(color='red', size=15, symbol='triangle-up'),
903
- hovertemplate='<b>SHORTAGE ALERT</b><br>Date: %{x}<br>Demand: %{y}<br>Shortage: ' +
904
- shortage_data['Shortfall'].astype(str) + '<extra></extra>'
905
- ))
906
 
907
- elif view_mode == "Risk Analysis":
908
- fig = go.Figure()
909
-
910
- # Risk score over time
911
- fig.add_trace(go.Scatter(
912
- x=material_df['Date'],
913
- y=material_df['Risk_Score'],
914
- mode='lines+markers',
915
- name='Risk Score',
916
- line=dict(color='#ff4444', width=3),
917
- marker=dict(size=8),
918
- yaxis='y',
919
- hovertemplate='<b>Risk Score</b><br>Date: %{x}<br>Score: %{y}<extra></extra>'
920
- ))
921
-
922
- # Fill rate
923
- fig.add_trace(go.Scatter(
924
- x=material_df['Date'],
925
- y=material_df['Fill_Rate'],
926
- mode='lines+markers',
927
- name='Fill Rate (%)',
928
- line=dict(color='#2ca02c', width=2),
929
- marker=dict(size=6),
930
- yaxis='y2',
931
- hovertemplate='<b>Fill Rate</b><br>Date: %{x}<br>Rate: %{y}%<extra></extra>'
932
- ))
933
-
934
- # Add risk level zones
935
- fig.add_hline(y=50, line_dash="dash", line_color="red",
936
- annotation_text="Critical Risk Threshold")
937
- fig.add_hline(y=30, line_dash="dash", line_color="orange",
938
- annotation_text="High Risk Threshold")
939
-
940
- fig.update_layout(
941
- yaxis=dict(title="Risk Score", side="left"),
942
- yaxis2=dict(title="Fill Rate (%)", side="right", overlaying="y")
943
- )
944
 
945
- elif view_mode == "Fill Rate Analysis":
946
- fig = go.Figure()
947
-
 
 
 
 
 
 
 
 
 
 
948
  fig.add_trace(go.Scatter(
949
- x=material_df['Date'],
950
- y=material_df['Fill_Rate'],
951
- mode='lines+markers',
952
- name='Fill Rate (%)',
953
- line=dict(color='#2ca02c', width=3),
954
- marker=dict(size=8),
955
- fill='tonexty',
956
- hovertemplate='<b>Fill Rate</b><br>Date: %{x}<br>Rate: %{y}%<extra></extra>'
957
  ))
958
-
959
- # Add SLA threshold
960
- fig.add_hline(y=95, line_dash="dash", line_color="blue",
961
- annotation_text="SLA Target (95%)")
962
-
963
- # Color zones
964
- fig.add_hrect(y0=95, y1=100, fillcolor="green", opacity=0.1, annotation_text="Excellent")
965
- fig.add_hrect(y0=85, y1=95, fillcolor="yellow", opacity=0.1, annotation_text="Acceptable")
966
- fig.add_hrect(y0=0, y1=85, fillcolor="red", opacity=0.1, annotation_text="Critical")
967
 
968
  fig.update_layout(
969
- title=f"Advanced Analysis: {selected_material} ({view_mode})",
970
  xaxis_title="Date",
971
- yaxis_title="Units" if view_mode == "Demand vs Supply" else ("Risk Score" if view_mode == "Risk Analysis" else "Fill Rate (%)"),
 
972
  height=600,
973
  showlegend=True,
974
- hovermode='x unified',
975
- template='plotly_white'
976
  )
977
 
978
  st.plotly_chart(fig, use_container_width=True)
979
 
980
- # Advanced metrics dashboard
981
- col1, col2, col3, col4 = st.columns(4)
982
-
983
- with col1:
984
- avg_fill_rate = material_df['Fill_Rate'].mean()
985
- st.metric(
986
- "Average Fill Rate",
987
- f"{avg_fill_rate:.1f}%",
988
- delta=f"{avg_fill_rate - 95:.1f}% vs Target",
989
- delta_color="inverse"
990
- )
991
-
992
- with col2:
993
- total_shortage = material_df['Shortfall'].sum()
994
- st.metric(
995
- "Total Shortage Risk",
996
- f"{total_shortage} units",
997
- delta=f"{material_df[material_df['Shortfall'] > 0].shape[0]} days affected"
998
- )
999
-
1000
- with col3:
1001
- avg_risk = material_df['Risk_Score'].mean()
1002
- risk_trend = "↗" if material_df['Risk_Score'].iloc[-1] > material_df['Risk_Score'].iloc[0] else "↘"
1003
- st.metric(
1004
- "Average Risk Score",
1005
- f"{avg_risk:.1f}",
1006
- delta=f"{risk_trend} Trending"
1007
- )
1008
 
1009
- with col4:
1010
- demand_variability = material_df['Demand_Used'].std() / material_df['Demand_Used'].mean()
1011
- st.metric(
1012
- "Demand Variability",
1013
- f"{demand_variability:.2f} CV",
1014
- delta="Higher = More Volatile"
1015
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1016
 
1017
- elif dashboard_tab == "🌐 Ecosystem Risk & Impact Analysis":
 
1018
  st.markdown("""
1019
  <div style="background: linear-gradient(135deg, #1f4e79, #2d5aa0); padding: 20px; border-radius: 15px; margin-bottom: 20px;">
1020
  <h2 style="color: white; margin: 0; text-align: center;">
1021
- 🌐 Comprehensive Ecosystem Impact Analysis
1022
  </h2>
1023
- <p style="color: white; text-align: center; margin: 10px 0 0 0;">
1024
- Tier-2 Supplier Intelligence | Cascading Risk Modeling | Automated Response Systems
1025
- </p>
1026
  </div>
1027
  """, unsafe_allow_html=True)
1028
 
1029
- # Supplier selection with enhanced information
1030
- supplier_names = list(suppliers.keys())
1031
  selected_supplier = st.selectbox(
1032
- "🏭 Select Tier-2 Supplier for Deep Dive Analysis:",
1033
- supplier_names,
1034
- key="ecosystem_supplier",
1035
- format_func=lambda x: f"{x} ({suppliers[x]['location']} - {suppliers[x]['performance_rating']}⭐)"
1036
  )
1037
 
1038
- # Supplier profile card
1039
- supplier_info = suppliers[selected_supplier]
1040
-
1041
- st.markdown(f"""
1042
- <div class="supplier-card">
1043
- <h3>🏭 {selected_supplier}</h3>
1044
- <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin-top: 15px;">
1045
- <div><strong>📍 Location:</strong> {supplier_info['location']}</div>
1046
- <div><strong>⚡ Capacity:</strong> {supplier_info['capacity']} units/day</div>
1047
- <div><strong>🎯 Reliability:</strong> {supplier_info['reliability']}%</div>
1048
- <div><strong>⏱️ Lead Time:</strong> {supplier_info['lead_time']} days</div>
1049
- <div><strong>⭐ Performance:</strong> {supplier_info['performance_rating']}/5.0</div>
1050
- <div><strong>💼 Financial Health:</strong> {supplier_info['financial_health']}</div>
1051
- </div>
1052
- <div style="margin-top: 10px;">
1053
- <strong>🎯 Materials Supplied:</strong>
1054
- <ul style="margin: 5px 0;">
1055
- {''.join([f"<li>{material}</li>" for material in supplier_info['materials']])}
1056
- </ul>
1057
- </div>
1058
- <div style="margin-top: 10px;">
1059
- <strong>⚠️ Key Risk Factors:</strong>
1060
- <ul style="margin: 5px 0;">
1061
- {''.join([f"<li>{risk}</li>" for risk in supplier_info['risk_factors']])}
1062
- </ul>
1063
- </div>
1064
- </div>
1065
- """, unsafe_allow_html=True)
1066
-
1067
- # Filter ecosystem data
1068
  supplier_df = df_ecosystem[df_ecosystem['Supplier'] == selected_supplier]
1069
 
1070
- # Advanced visualization
1071
- tab1, tab2, tab3 = st.tabs(["📊 Impact Analysis", "📈 Financial Impact", "🔄 Recovery Timeline"])
1072
 
1073
- with tab1:
1074
- col1, col2 = st.columns(2)
 
1075
 
1076
- with col1:
1077
- # Tier-2 supplier disruption chart
1078
- fig1 = go.Figure()
1079
 
1080
- for material in supplier_df['Material'].unique():
1081
- material_data = supplier_df[supplier_df['Material'] == material]
1082
-
1083
- fig1.add_trace(go.Scatter(
1084
- x=material_data['Date'],
1085
- y=material_data['Tier2_Normal_Supply'],
1086
- mode='lines',
1087
- name=f'{material.split("-")[1]} - Normal',
1088
- line=dict(width=3),
1089
- opacity=0.8
1090
- ))
1091
-
1092
- fig1.add_trace(go.Scatter(
1093
- x=material_data['Date'],
1094
- y=material_data['Tier2_Disrupted_Supply'],
1095
- mode='lines+markers',
1096
- name=f'{material.split("-")[1]} - Disrupted',
1097
- line=dict(dash='dot', width=3),
1098
- marker=dict(size=6)
1099
- ))
1100
-
1101
- fig1.update_layout(
1102
- title=f"Tier-2 Supply Impact: {selected_supplier.split()[0]}...",
1103
- xaxis_title="Date",
1104
- yaxis_title="Supply Units/Day",
1105
- height=400,
1106
- template='plotly_white'
1107
- )
1108
 
1109
- st.plotly_chart(fig1, use_container_width=True)
 
 
 
 
 
 
1110
 
1111
- with col2:
1112
- # Yazaki cascading impact chart
1113
- fig2 = go.Figure()
1114
-
1115
- for material in supplier_df['Material'].unique():
1116
- material_data = supplier_df[supplier_df['Material'] == material]
1117
-
1118
- fig2.add_trace(go.Scatter(
1119
- x=material_data['Date'],
1120
- y=material_data['Yazaki_Normal_Supply'],
1121
- mode='lines',
1122
- name=f'{material.split("-")[1]} - Normal',
1123
- line=dict(width=3),
1124
- opacity=0.8
1125
- ))
1126
-
1127
- fig2.add_trace(go.Scatter(
1128
- x=material_data['Date'],
1129
- y=material_data['Yazaki_Impacted_Supply'],
1130
- mode='lines+markers',
1131
- name=f'{material.split("-")[1]} - Impacted',
1132
- line=dict(dash='solid', width=3),
1133
- marker=dict(size=8, symbol='triangle-down')
1134
- ))
1135
-
1136
- fig2.update_layout(
1137
- title="Cascading Impact on Yazaki Production",
1138
- xaxis_title="Date",
1139
- yaxis_title="Available Supply Units/Day",
1140
- height=400,
1141
- template='plotly_white'
1142
- )
1143
-
1144
- st.plotly_chart(fig2, use_container_width=True)
1145
 
1146
- with tab2:
1147
- # Financial impact analysis
1148
- total_financial_impact = supplier_df['Financial_Impact_INR'].sum()
1149
 
1150
- col1, col2, col3 = st.columns(3)
1151
- with col1:
1152
- st.metric("Total Financial Impact", f"₹{total_financial_impact:,}", delta="14-day period")
1153
- with col2:
1154
- peak_impact = supplier_df['Financial_Impact_INR'].max()
1155
- st.metric("Peak Daily Impact", f"₹{peak_impact:,}", delta="Maximum single day")
1156
- with col3:
1157
- avg_impact = supplier_df[supplier_df['Financial_Impact_INR'] > 0]['Financial_Impact_INR'].mean()
1158
- st.metric("Average Daily Impact", f"₹{avg_impact:,.0f}", delta="When disrupted")
 
 
 
 
 
 
 
 
 
1159
 
1160
- # Financial impact chart
1161
- fig3 = px.bar(
1162
- supplier_df,
1163
- x='Date',
1164
- y='Financial_Impact_INR',
1165
- color='Material',
1166
- title=f"Daily Financial Impact from {selected_supplier} Disruptions",
1167
- labels={'Financial_Impact_INR': 'Financial Impact (₹)'}
1168
  )
1169
- fig3.update_layout(height=400, template='plotly_white')
1170
- st.plotly_chart(fig3, use_container_width=True)
1171
-
1172
- with tab3:
1173
- # Recovery timeline analysis
1174
- disrupted_days = supplier_df[supplier_df['Is_Disrupted'] == True]
1175
 
1176
- if not disrupted_days.empty:
1177
- st.markdown("### 🔄 Recovery Timeline Analysis")
1178
-
1179
- for _, day_data in disrupted_days.head(3).iterrows(): # Show first 3 disruptions
 
 
 
 
 
 
 
 
 
 
 
1180
  st.markdown(f"""
1181
- <div class="alert-high">
1182
- <h4>📅 {day_data['Date'].strftime('%Y-%m-%d')} - {day_data['Material']}</h4>
1183
- <p><strong>Disruption:</strong> {day_data['Disruption_Cause']}</p>
1184
- <p><strong>Severity:</strong> {day_data['Disruption_Severity']}</p>
1185
- <p><strong>Impact:</strong> -{day_data['Tier2_Impact']} units → Yazaki impact: -{day_data['Yazaki_Impact']} units (after {day_data['Lead_Time_Days']} days)</p>
1186
- <p><strong>Recovery Time:</strong> {day_data['Recovery_Timeline_Days']} days</p>
 
 
 
 
 
 
 
 
 
1187
  </div>
1188
  """, unsafe_allow_html=True)
 
 
1189
 
1190
- elif dashboard_tab == "🛡️ Intelligent Buffer Optimization":
 
1191
  st.markdown("""
1192
  <div style="background: linear-gradient(135deg, #1f4e79, #2d5aa0); padding: 20px; border-radius: 15px; margin-bottom: 20px;">
1193
  <h2 style="color: white; margin: 0; text-align: center;">
1194
- 🛡️ AI-Driven Intelligent Buffer Optimization
1195
  </h2>
1196
- <p style="color: white; text-align: center; margin: 10px 0 0 0;">
1197
- Statistical Analysis | Risk-Based Safety Stock | Cost-Benefit Optimization
1198
- </p>
1199
  </div>
1200
  """, unsafe_allow_html=True)
1201
 
1202
- # Calculate optimal buffers
1203
- buffer_recommendations = calculate_optimal_buffers(df_demand, df_ecosystem)
1204
-
1205
- # Overview metrics
1206
- col1, col2, col3, col4 = st.columns(4)
1207
-
1208
- with col1:
1209
- total_current = sum([rec['current_buffer'] for rec in buffer_recommendations.values()])
1210
- st.metric("Current Total Buffer", f"{total_current:,} units")
1211
-
1212
- with col2:
1213
- total_recommended = sum([rec['recommended_buffer'] for rec in buffer_recommendations.values()])
1214
- st.metric("Recommended Total", f"{total_recommended:,} units")
1215
-
1216
- with col3:
1217
- total_gap = sum([rec['buffer_gap'] for rec in buffer_recommendations.values()])
1218
- st.metric("Total Buffer Gap", f"{total_gap:,} units", delta=f"+{((total_gap/total_current)*100):.1f}%")
 
 
 
 
 
 
 
1219
 
1220
- with col4:
1221
- total_cost = sum([rec['holding_cost_increase'] for rec in buffer_recommendations.values()])
1222
- st.metric("Investment Required", f"₹{total_cost:,}")
1223
 
1224
- # Buffer analysis visualization
1225
- materials = list(buffer_recommendations.keys())
1226
- current_buffers = [buffer_recommendations[mat]['current_buffer'] for mat in materials]
1227
- recommended_buffers = [buffer_recommendations[mat]['recommended_buffer'] for mat in materials]
1228
 
1229
  fig = go.Figure()
1230
 
1231
  fig.add_trace(go.Bar(
1232
- name='Current Safety Stock',
1233
- x=[mat.split('-')[1] for mat in materials],
1234
- y=current_buffers,
1235
- marker_color='lightblue',
1236
- text=current_buffers,
1237
- textposition='auto'
1238
  ))
1239
 
1240
  fig.add_trace(go.Bar(
1241
- name='Recommended Safety Stock',
1242
- x=[mat.split('-')[1] for mat in materials],
1243
- y=recommended_buffers,
1244
- marker_color='orange',
1245
- text=recommended_buffers,
1246
- textposition='auto'
1247
  ))
1248
 
1249
  fig.update_layout(
1250
- title="Current vs Optimal Safety Stock Levels by Material",
1251
  xaxis_title="Materials",
1252
- yaxis_title="Safety Stock Units",
1253
  barmode='group',
1254
- height=500,
1255
- template='plotly_white'
1256
  )
1257
 
1258
  st.plotly_chart(fig, use_container_width=True)
1259
 
1260
- # Detailed recommendations table
1261
- st.subheader("📋 Detailed Buffer Optimization Recommendations")
1262
-
1263
- buffer_df_display = pd.DataFrame([
1264
- {
1265
- 'Material': mat.split('-')[1],
1266
- 'Current Buffer': rec['current_buffer'],
1267
- 'Recommended Buffer': rec['recommended_buffer'],
1268
- 'Gap (Units)': rec['buffer_gap'],
1269
- 'Investment (₹)': f"₹{rec['holding_cost_increase']:,}",
1270
- 'Risk Reduction': f"{rec['risk_reduction_percent']}%",
1271
- 'ROI (Months)': rec['roi_months'],
1272
- 'Priority': rec['priority'],
1273
- 'Demand Variability': rec['demand_variability'],
1274
- 'Supply Reliability': f"{rec['supply_reliability']}%"
1275
- }
1276
- for mat, rec in buffer_recommendations.items()
1277
- ])
1278
-
1279
- # Color-code priority
1280
- def color_priority(val):
1281
- if val == 'High':
1282
- return 'background-color: #ffebee'
1283
- elif val == 'Medium':
1284
- return 'background-color: #fff3e0'
1285
- else:
1286
- return 'background-color: #e8f5e8'
1287
-
1288
- styled_df = buffer_df_display.style.applymap(
1289
- color_priority, subset=['Priority']
1290
- ).format({
1291
- 'Demand Variability': '{:.2f}',
1292
- 'ROI (Months)': '{:.1f}'
1293
- })
1294
-
1295
- st.dataframe(styled_df, use_container_width=True, height=400)
1296
-
1297
- elif dashboard_tab == "⚡ Real-time Alert Management":
1298
- st.markdown("""
1299
- <div style="background: linear-gradient(135deg, #1f4e79, #2d5aa0); padding: 20px; border-radius: 15px; margin-bottom: 20px;">
1300
- <h2 style="color: white; margin: 0; text-align: center;">
1301
- ⚡ Real-time Supply Chain Alert Management System
1302
- </h2>
1303
- <p style="color: white; text-align: center; margin: 10px 0 0 0;">
1304
- Advanced Alert Generation | Intelligent Prioritization | Automated Response Recommendations
1305
- </p>
1306
- </div>
1307
- """, unsafe_allow_html=True)
1308
-
1309
- # Generate comprehensive alerts
1310
- alerts = generate_detailed_alerts(df_demand)
1311
-
1312
- # Alert summary dashboard
1313
- col1, col2, col3, col4 = st.columns(4)
1314
-
1315
- with col1:
1316
- critical_alerts = len([a for a in alerts if a['severity'] == 'Critical'])
1317
- st.metric("Critical Alerts", critical_alerts, delta="Immediate Action Required")
1318
-
1319
- with col2:
1320
- high_alerts = len([a for a in alerts if a['severity'] == 'High'])
1321
- st.metric("High Priority", high_alerts, delta="24hr Response Time")
1322
-
1323
- with col3:
1324
- total_revenue_risk = sum([a['revenue_at_risk'] for a in alerts])
1325
- st.metric("Revenue at Risk", f"₹{total_revenue_risk:,}", delta="8-week period")
1326
-
1327
- with col4:
1328
- avg_shortage = np.mean([a['shortage'] for a in alerts]) if alerts else 0
1329
- st.metric("Avg Shortage", f"{avg_shortage:.0f} units", delta="Per incident")
1330
-
1331
- # Alert filtering
1332
- col1, col2, col3 = st.columns(3)
1333
-
1334
- with col1:
1335
- severity_filter = st.multiselect(
1336
- "Filter by Severity:",
1337
- ["Critical", "High", "Medium", "Low"],
1338
- default=["Critical", "High"],
1339
- key="severity_filter"
1340
- )
1341
-
1342
- with col2:
1343
- material_filter = st.multiselect(
1344
- "Filter by Material Category:",
1345
- df_demand['Material_Category'].unique(),
1346
- key="material_filter"
1347
- )
1348
-
1349
- with col3:
1350
- show_resolved = st.checkbox("Show Resolved Alerts", key="show_resolved")
1351
-
1352
- # Filter alerts
1353
- filtered_alerts = [
1354
- alert for alert in alerts
1355
- if alert['severity'] in severity_filter and
1356
- (not material_filter or any(cat in alert['material'] for cat in material_filter))
1357
- ]
1358
-
1359
- # Display alerts with advanced formatting
1360
- st.subheader(f"🚨 Active Alerts ({len(filtered_alerts)} items)")
1361
-
1362
- for i, alert in enumerate(filtered_alerts[:10]): # Show top 10
1363
- severity_colors = {
1364
- 'Critical': '#ff4444',
1365
- 'High': '#ff8800',
1366
- 'Medium': '#ffcc00',
1367
- 'Low': '#4CAF50'
1368
- }
1369
-
1370
- severity_color = severity_colors.get(alert['severity'], '#gray')
1371
-
1372
- with st.expander(
1373
- f"🚨 {alert['severity']} Alert: {alert['material'].split('-')[1]} | "
1374
- f"Shortage: {alert['shortage']} units | Revenue Risk: ₹{alert['revenue_at_risk']:,}",
1375
- expanded=(i < 3) # Auto-expand first 3 alerts
1376
- ):
1377
- col1, col2 = st.columns([2, 1])
1378
-
1379
- with col1:
1380
- st.markdown(f"""
1381
- <div style="border-left: 5px solid {severity_color}; padding-left: 15px;">
1382
- <h4 style="color: {severity_color}; margin: 0;">Alert Details</h4>
1383
- <p><strong>Alert ID:</strong> {alert['alert_id']}</p>
1384
- <p><strong>Material:</strong> {alert['material']}</p>
1385
- <p><strong>Date:</strong> {alert['date']} ({alert['week']})</p>
1386
- <p><strong>Demand Type:</strong> {alert['demand_type']}</p>
1387
- <p><strong>Fill Rate:</strong> {alert['fill_rate']}%</p>
1388
- <p><strong>Risk Score:</strong> {alert['risk_score']}/100</p>
1389
- <p><strong>Customer Impact:</strong> {alert['customer_impact']}</p>
1390
- </div>
1391
- """, unsafe_allow_html=True)
1392
-
1393
- st.markdown("**Root Cause Analysis:**")
1394
- for cause in alert['root_causes']:
1395
- st.markdown(f"• {cause}")
1396
-
1397
- with col2:
1398
- st.markdown("**🎯 Recommended Action**")
1399
- best_option = alert['best_option']
1400
-
1401
- st.markdown(f"""
1402
- <div class="mitigation-card">
1403
- <h5>{best_option['option']}</h5>
1404
- <p><strong>Impact:</strong> {best_option['impact']}</p>
1405
- <p><strong>Timeline:</strong> {best_option['timeline']}</p>
1406
- <p><strong>Cost:</strong> {best_option['cost']}</p>
1407
- <p><strong>Success Rate:</strong> {best_option['success_probability']}</p>
1408
- <p><strong>Resources:</strong> {best_option['resource_requirements']}</p>
1409
- </div>
1410
- """, unsafe_allow_html=True)
1411
-
1412
- if st.button(f"Execute Action {i+1}", key=f"execute_{i}"):
1413
- st.success(f"✅ Mitigation action initiated: {best_option['option']}")
1414
- st.session_state.executed_mitigations.append({
1415
- 'alert_id': alert['alert_id'],
1416
- 'action': best_option['option'],
1417
- 'timestamp': datetime.now()
1418
- })
1419
 
1420
- elif dashboard_tab == "📈 Performance Analytics Dashboard":
1421
- st.markdown("""
1422
- <div style="background: linear-gradient(135deg, #1f4e79, #2d5aa0); padding: 20px; border-radius: 15px; margin-bottom: 20px;">
1423
- <h2 style="color: white; margin: 0; text-align: center;">
1424
- 📈 Advanced Performance Analytics Dashboard
1425
- </h2>
1426
- <p style="color: white; text-align: center; margin: 10px 0 0 0;">
1427
- KPI Monitoring | Trend Analysis | Predictive Insights | Supplier Scorecards
1428
- </p>
1429
- </div>
1430
- """, unsafe_allow_html=True)
1431
-
1432
- # KPI Summary Cards
1433
- col1, col2, col3, col4, col5 = st.columns(5)
1434
-
1435
- with col1:
1436
- overall_fill_rate = df_demand['Fill_Rate'].mean()
1437
- st.metric(
1438
- "Overall Fill Rate",
1439
- f"{overall_fill_rate:.1f}%",
1440
- delta=f"{overall_fill_rate - 95:.1f}% vs SLA"
1441
- )
1442
-
1443
- with col2:
1444
- total_demand = df_demand['Demand_Used'].sum()
1445
- st.metric("Total 8-Week Demand", f"{total_demand:,} units")
1446
-
1447
- with col3:
1448
- supply_efficiency = (df_demand['Supply_Projected'].sum() / df_demand['Supply_Plan'].sum()) * 100
1449
- st.metric(
1450
- "Supply Efficiency",
1451
- f"{supply_efficiency:.1f}%",
1452
- delta="Actual vs Plan"
1453
- )
1454
-
1455
- with col4:
1456
- risk_incidents = len(df_demand[df_demand['Risk_Score'] >= 30])
1457
- st.metric("Risk Incidents", f"{risk_incidents}", delta="High+ Risk Days")
1458
-
1459
- with col5:
1460
- supplier_reliability = df_ecosystem.groupby('Supplier')['Supplier_Reliability'].first().mean()
1461
- st.metric(
1462
- "Avg Supplier Reliability",
1463
- f"{supplier_reliability:.1f}%",
1464
- delta="Network Average"
1465
- )
1466
-
1467
- # Advanced analytics tabs
1468
- tab1, tab2, tab3, tab4 = st.tabs(["📊 Trend Analysis", "🎯 Supplier Scorecard", "🔮 Predictive Insights", "💰 Cost Analysis"])
1469
-
1470
- with tab1:
1471
- st.subheader("📈 Weekly Performance Trends")
1472
-
1473
- # Weekly aggregation
1474
- weekly_performance = df_demand.groupby('Week_Number').agg({
1475
- 'Fill_Rate': 'mean',
1476
- 'Risk_Score': 'mean',
1477
- 'Shortfall': 'sum',
1478
- 'Demand_Used': 'sum',
1479
- 'Supply_Projected': 'sum'
1480
- }).reset_index()
1481
-
1482
- fig = make_subplots(
1483
- rows=2, cols=2,
1484
- subplot_titles=('Fill Rate Trend', 'Risk Score Trend', 'Weekly Demand vs Supply', 'Shortage Incidents'),
1485
- specs=[[{"secondary_y": False}, {"secondary_y": False}],
1486
- [{"secondary_y": True}, {"secondary_y": False}]]
1487
- )
1488
-
1489
- # Fill rate trend
1490
- fig.add_trace(
1491
- go.Scatter(x=weekly_performance['Week_Number'], y=weekly_performance['Fill_Rate'],
1492
- mode='lines+markers', name='Fill Rate', line=dict(color='green', width=3)),
1493
- row=1, col=1
1494
- )
1495
-
1496
- # Risk score trend
1497
- fig.add_trace(
1498
- go.Scatter(x=weekly_performance['Week_Number'], y=weekly_performance['Risk_Score'],
1499
- mode='lines+markers', name='Risk Score', line=dict(color='red', width=3)),
1500
- row=1, col=2
1501
- )
1502
-
1503
- # Demand vs Supply
1504
- fig.add_trace(
1505
- go.Bar(x=weekly_performance['Week_Number'], y=weekly_performance['Demand_Used'],
1506
- name='Weekly Demand', marker_color='blue', opacity=0.7),
1507
- row=2, col=1
1508
- )
1509
- fig.add_trace(
1510
- go.Scatter(x=weekly_performance['Week_Number'], y=weekly_performance['Supply_Projected'],
1511
- mode='lines+markers', name='Weekly Supply', line=dict(color='orange', width=3)),
1512
- row=2, col=1, secondary_y=True
1513
- )
1514
-
1515
- # Shortage incidents
1516
- fig.add_trace(
1517
- go.Bar(x=weekly_performance['Week_Number'], y=weekly_performance['Shortfall'],
1518
- name='Weekly Shortage', marker_color='red', opacity=0.8),
1519
- row=2, col=2
1520
- )
1521
-
1522
- fig.update_layout(height=600, showlegend=True, template='plotly_white')
1523
- st.plotly_chart(fig, use_container_width=True)
1524
-
1525
- with tab2:
1526
- st.subheader("🎯 Comprehensive Supplier Scorecard")
1527
-
1528
- # Calculate supplier metrics
1529
- supplier_metrics = []
1530
- for supplier_name, supplier_info in suppliers.items():
1531
- supplier_ecosystem = df_ecosystem[df_ecosystem['Supplier'] == supplier_name]
1532
-
1533
- if not supplier_ecosystem.empty:
1534
- reliability_score = (1 - supplier_ecosystem['Is_Disrupted'].mean()) * 100
1535
- avg_impact = supplier_ecosystem['Yazaki_Impact'].mean()
1536
- financial_impact = supplier_ecosystem['Financial_Impact_INR'].sum()
1537
- recovery_time = supplier_ecosystem['Recovery_Timeline_Days'].max()
1538
-
1539
- # Overall score calculation (weighted average)
1540
- overall_score = (
1541
- reliability_score * 0.3 +
1542
- supplier_info['performance_rating'] * 20 * 0.25 +
1543
- (100 - min(avg_impact * 2, 100)) * 0.25 +
1544
- (100 - min(recovery_time * 10, 100)) * 0.2
1545
- )
1546
-
1547
- supplier_metrics.append({
1548
- 'Supplier': supplier_name.split()[0] + '...', # Shortened name
1549
- 'Overall Score': round(overall_score, 1),
1550
- 'Reliability %': round(reliability_score, 1),
1551
- 'Performance Rating': supplier_info['performance_rating'],
1552
- 'Avg Impact': round(avg_impact, 0),
1553
- 'Financial Impact (₹)': f"₹{financial_impact:,}",
1554
- 'Max Recovery Time': f"{recovery_time} days",
1555
- 'Location': supplier_info['location'].split(',')[0], # City only
1556
- 'Backup Available': '✅' if supplier_info['backup_available'] else '❌'
1557
- })
1558
-
1559
- supplier_scorecard_df = pd.DataFrame(supplier_metrics)
1560
-
1561
- # Display scorecard with conditional formatting
1562
- def score_color(val):
1563
- if val >= 80:
1564
- return 'background-color: #d4edda' # Green
1565
- elif val >= 60:
1566
- return 'background-color: #fff3cd' # Yellow
1567
- else:
1568
- return 'background-color: #f8d7da' # Red
1569
-
1570
- styled_scorecard = supplier_scorecard_df.style.applymap(
1571
- score_color, subset=['Overall Score']
1572
- ).applymap(
1573
- score_color, subset=['Reliability %']
1574
- )
1575
-
1576
- st.dataframe(styled_scorecard, use_container_width=True)
1577
-
1578
- # Supplier comparison radar chart
1579
- fig_radar = go.Figure()
1580
-
1581
- categories = ['Reliability', 'Performance', 'Recovery Speed', 'Cost Impact', 'Risk Level']
1582
-
1583
- for supplier_metric in supplier_metrics:
1584
- reliability = supplier_metric['Reliability %']
1585
- performance = supplier_metric['Performance Rating'] * 20
1586
- recovery = 100 - (int(supplier_metric['Max Recovery Time'].split()[0]) * 10)
1587
- cost_impact = 100 - min(50, 100) # Simplified
1588
- risk_level = 100 - supplier_metric['Avg Impact']
1589
-
1590
- values = [reliability, performance, recovery, cost_impact, risk_level]
1591
-
1592
- fig_radar.add_trace(go.Scatterpolar(
1593
- r=values + [values[0]], # Close the polygon
1594
- theta=categories + [categories[0]],
1595
- fill='toself',
1596
- name=supplier_metric['Supplier'],
1597
- opacity=0.6
1598
- ))
1599
-
1600
- fig_radar.update_layout(
1601
- polar=dict(
1602
- radialaxis=dict(visible=True, range=[0, 100])
1603
- ),
1604
- showlegend=True,
1605
- title="Supplier Performance Radar Comparison",
1606
- height=500
1607
- )
1608
-
1609
- st.plotly_chart(fig_radar, use_container_width=True)
1610
-
1611
- with tab3:
1612
- st.subheader("🔮 Predictive Insights & Future Projections")
1613
-
1614
- # Simple trend predictions (using linear regression concepts)
1615
- st.markdown("**Key Predictive Insights:**")
1616
-
1617
- # Demand trend prediction
1618
- demand_trend = np.polyfit(range(len(df_demand)), df_demand.groupby('Day')['Demand_Used'].sum().values, 1)
1619
- demand_direction = "increasing" if demand_trend[0] > 0 else "decreasing"
1620
-
1621
- st.markdown(f"""
1622
- <div class="metric-card">
1623
- <h4>📈 Demand Trend Forecast</h4>
1624
- <p>Overall demand is <strong>{demand_direction}</strong> at a rate of <strong>{abs(demand_trend[0]):.1f} units/day</strong></p>
1625
- <p>Expected total demand for next 4 weeks: <strong>{int(df_demand['Demand_Used'].sum() * 0.5 + demand_trend[0] * 28):,} units</strong></p>
1626
- </div>
1627
- """, unsafe_allow_html=True)
1628
-
1629
- # Risk prediction
1630
- high_risk_materials = df_demand.groupby('Material')['Risk_Score'].mean().sort_values(ascending=False).head(3)
1631
-
1632
- st.markdown(f"""
1633
- <div class="metric-card">
1634
- <h4>⚠️ High-Risk Material Forecast</h4>
1635
- <p>Top 3 materials with highest predicted risk:</p>
1636
- <ul>
1637
- {''.join([f'<li><strong>{mat.split("-")[1]}:</strong> {score:.1f} risk score</li>' for mat, score in high_risk_materials.items()])}
1638
- </ul>
1639
- </div>
1640
- """, unsafe_allow_html=True)
1641
-
1642
- # Supplier risk prediction
1643
- supplier_risk = df_ecosystem.groupby('Supplier').agg({
1644
- 'Is_Disrupted': 'sum',
1645
- 'Yazaki_Impact': 'sum',
1646
- 'Financial_Impact_INR': 'sum'
1647
- }).sort_values('Financial_Impact_INR', ascending=False)
1648
-
1649
- st.markdown("**🏭 Supplier Risk Prediction:**")
1650
- for supplier in supplier_risk.head(2).index:
1651
- risk_data = supplier_risk.loc[supplier]
1652
- st.markdown(f"""
1653
- <div class="alert-medium">
1654
- <strong>{supplier.split()[0]}:</strong>
1655
- {int(risk_data['Is_Disrupted'])} disruption days,
1656
- ₹{int(risk_data['Financial_Impact_INR']):,} total impact
1657
- </div>
1658
- """, unsafe_allow_html=True)
1659
-
1660
- with tab4:
1661
- st.subheader("💰 Comprehensive Cost Analysis")
1662
-
1663
- # Cost breakdown analysis
1664
- col1, col2 = st.columns(2)
1665
-
1666
- with col1:
1667
- st.markdown("**Supply Chain Cost Breakdown:**")
1668
-
1669
- # Simulated cost analysis
1670
- total_material_cost = df_demand['Demand_Used'].sum() * 150 # ₹150 average per unit
1671
- disruption_cost = df_ecosystem['Financial_Impact_INR'].sum()
1672
- buffer_cost = sum([rec['holding_cost_increase'] for rec in buffer_recommendations.values()])
1673
- mitigation_cost = len(alerts) * 50000 # ₹50K average per mitigation
1674
-
1675
- cost_data = {
1676
- 'Category': ['Material Costs', 'Disruption Impact', 'Buffer Investment', 'Mitigation Costs'],
1677
- 'Amount (₹)': [total_material_cost, disruption_cost, buffer_cost, mitigation_cost]
1678
- }
1679
-
1680
- cost_df = pd.DataFrame(cost_data)
1681
-
1682
- fig_pie = px.pie(
1683
- cost_df,
1684
- values='Amount (₹)',
1685
- names='Category',
1686
- title="Cost Distribution Analysis"
1687
- )
1688
- st.plotly_chart(fig_pie, use_container_width=True)
1689
-
1690
- with col2:
1691
- st.markdown("**Cost Impact by Material Category:**")
1692
-
1693
- material_costs = df_demand.groupby('Material_Category').agg({
1694
- 'Demand_Used': 'sum',
1695
- 'Shortfall': 'sum'
1696
- })
1697
-
1698
- material_costs['Material_Cost'] = material_costs['Demand_Used'] * 150
1699
- material_costs['Shortage_Cost'] = material_costs['Shortfall'] * 300
1700
- material_costs['Total_Cost'] = material_costs['Material_Cost'] + material_costs['Shortage_Cost']
1701
-
1702
- fig_bar = px.bar(
1703
- material_costs.reset_index(),
1704
- x='Material_Category',
1705
- y=['Material_Cost', 'Shortage_Cost'],
1706
- title="Cost Analysis by Material Category",
1707
- labels={'value': 'Cost (₹)', 'variable': 'Cost Type'}
1708
- )
1709
- st.plotly_chart(fig_bar, use_container_width=True)
1710
-
1711
- # Cost optimization recommendations
1712
- st.markdown("**💡 Cost Optimization Recommendations:**")
1713
-
1714
- cost_savings_potential = disruption_cost * 0.6 + mitigation_cost * 0.4
1715
- st.markdown(f"""
1716
- <div class="metric-card">
1717
- <h4>Potential Annual Savings: ₹{cost_savings_potential:,.0f}</h4>
1718
- <ul>
1719
- <li><strong>Proactive Buffer Optimization:</strong> Reduce emergency costs by 40%</li>
1720
- <li><strong>Supplier Diversification:</strong> Lower disruption risk by 35%</li>
1721
- <li><strong>Predictive Analytics:</strong> Improve demand accuracy by 25%</li>
1722
- <li><strong>Automated Response:</strong> Reduce mitigation response time by 60%</li>
1723
- </ul>
1724
- </div>
1725
- """, unsafe_allow_html=True)
1726
-
1727
- # COMPLETE Enhanced External Signals Sidebar
1728
  st.sidebar.markdown("---")
1729
- st.sidebar.markdown("""
1730
- <div style="background: linear-gradient(135deg, #1f4e79, #2d5aa0); padding: 1rem; border-radius: 10px; margin-bottom: 1rem;">
1731
- <h3 style="color: white; margin: 0; text-align: center;">🌍 Market Intelligence Hub</h3>
1732
- </div>
1733
- """, unsafe_allow_html=True)
1734
-
1735
- # Enhanced external signals display
1736
- for i, signal in enumerate(external_signals[:4]): # Show top 4 signals
1737
- confidence_color = "#4CAF50" if signal['Confidence'] > 90 else "#FF9800" if signal['Confidence'] > 80 else "#F44336"
1738
- urgency_color = "#FF5722" if signal['Urgency'] == 'Immediate' else "#FF9800" if signal['Urgency'] == 'High' else "#4CAF50"
1739
-
1740
  st.sidebar.markdown(f"""
1741
- <div class="external-signal" style="border-left: 3px solid {confidence_color};">
1742
- <div style="display: flex; justify-content: space-between; align-items: center;">
1743
- <strong style="color: {confidence_color};">{signal['Source']}</strong>
1744
- <span style="background: {urgency_color}; color: white; padding: 2px 6px; border-radius: 10px; font-size: 0.7em;">
1745
- {signal['Urgency']}
1746
- </span>
1747
- </div>
1748
- <p style="font-size: 0.85em; margin: 5px 0;">{signal['Signal']}</p>
1749
- <div style="font-size: 0.75em; color: #666;">
1750
- <strong>Impact:</strong> {signal['Impact']}<br>
1751
- <strong>Confidence:</strong> {signal['Confidence']}%<br>
1752
- <strong>Timeline:</strong> {signal['Timeline']}<br>
1753
- <strong>Estimated Impact:</strong> {signal['Estimated_Impact']}
1754
- </div>
1755
  </div>
1756
  """, unsafe_allow_html=True)
1757
 
1758
- # Advanced system status
1759
- st.sidebar.markdown("---")
1760
- st.sidebar.markdown("### 🔧 System Status")
1761
-
1762
- system_status = {
1763
- "Data Pipeline": "🟢 Operational",
1764
- "AI Models": "🟢 Active",
1765
- "External APIs": "🟡 Partial",
1766
- "Alert System": "🟢 Running"
1767
- }
1768
-
1769
- for system, status in system_status.items():
1770
- st.sidebar.markdown(f"**{system}:** {status}")
1771
-
1772
- st.sidebar.markdown(f"**Last Updated:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
1773
-
1774
- # COMPLETE Footer with advanced branding
1775
  st.markdown("---")
1776
  st.markdown("""
1777
- <div style="text-align: center; padding: 30px; background: linear-gradient(135deg, #1f4e79, #2d5aa0); border-radius: 15px; color: white; margin-top: 30px;">
1778
- <h2 style="margin: 0;">🔌 Yazaki India Ltd</h2>
1779
- <h3 style="margin: 10px 0;">Advanced Supply Chain Command Center</h3>
1780
- <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin: 20px 0;">
1781
- <div>
1782
- <h4 style="margin: 5px 0; color: #FFD700;">Planning Horizon</h4>
1783
- <p style="margin: 0;">8-Week Forward Visibility</p>
1784
- </div>
1785
- <div>
1786
- <h4 style="margin: 5px 0; color: #FFD700;">Intelligence</h4>
1787
- <p style="margin: 0;">AI-Enhanced Forecasting</p>
1788
- </div>
1789
- <div>
1790
- <h4 style="margin: 5px 0; color: #FFD700;">Coverage</h4>
1791
- <p style="margin: 0;">End-to-End Ecosystem</p>
1792
- </div>
1793
- <div>
1794
- <h4 style="margin: 5px 0; color: #FFD700;">Response</h4>
1795
- <p style="margin: 0;">Automated Mitigation</p>
1796
- </div>
1797
- </div>
1798
- <hr style="border: 1px solid rgba(255,255,255,0.3); margin: 20px 0;">
1799
- <p style="margin: 5px 0; font-style: italic;">
1800
- Electrical Components & Wire Harness Manufacturing Excellence
1801
- </p>
1802
- <p style="margin: 5px 0; font-size: 0.9em;">
1803
- <strong>Powered by Advanced Analytics | Machine Learning | Real-time Intelligence</strong>
1804
- </p>
1805
- <p style="margin: 5px 0; font-size: 0.8em; opacity: 0.8;">
1806
- Comprehensive Supply Chain Resilience Platform v3.0 | 2025
1807
- </p>
1808
  </div>
1809
  """, unsafe_allow_html=True)
 
1
+ #Stable version for Yazaki India Ltd - Same structure as Rane demo
2
  import streamlit as st
3
  import pandas as pd
4
  import numpy as np
 
15
  initial_sidebar_state="expanded"
16
  )
17
 
18
+ # Custom CSS (same as original)
19
  st.markdown("""
20
  <style>
21
  .main-header {
 
60
  border-radius: 8px;
61
  margin: 0.5rem 0;
62
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  </style>
64
  """, unsafe_allow_html=True)
65
 
 
68
  st.session_state.executed_mitigations = []
69
  if 'external_signals' not in st.session_state:
70
  st.session_state.external_signals = []
 
 
 
 
71
 
72
+ # Generate 8-week forward-looking demand data for Yazaki
73
  @st.cache_data
74
  def generate_8week_demand_data():
75
  today = datetime(2025, 8, 4)
 
78
  # Yazaki-specific materials (wire harnesses, connectors, electrical components)
79
  materials = [
80
  'WH001-Engine Wire Harness',
81
+ 'WH002-Dashboard Wire Harness',
 
82
  'CON001-Electrical Connector',
 
83
  'TER001-Wire Terminal',
84
+ 'FUS001-Fuse Box Assembly'
 
 
 
85
  ]
86
 
87
  all_data = []
88
  for material in materials:
89
  np.random.seed(hash(material) % 1000)
90
 
91
+ # Generate base demand patterns
92
  base_demand = np.random.normal(150, 15, 56)
93
 
94
+ # First 14 days: FIRM DEMAND
95
  firm_demand = np.clip(base_demand[:14], 100, 200).astype(int)
96
 
97
+ # Days 15-56: Customer shared demand (tentative)
98
  customer_shared = np.clip(base_demand[14:] * (1 + 0.05 * np.sin(np.linspace(0, 3.14, 42))), 80, 220).astype(int)
99
 
100
+ # Days 15-56: AI-corrected demand (with external signals)
101
  external_factors = np.zeros(42)
102
+ # Weather impact (weeks 3-4)
 
103
  external_factors[0:14] += np.random.normal(0, 5, 14)
104
+ # EV policy impact (weeks 5-8) - higher for wire harnesses
 
105
  if 'WH' in material:
106
+ external_factors[14:] += 12 # Higher impact for wire harnesses in EVs
107
  elif 'CON' in material or 'TER' in material:
108
+ external_factors[14:] += 8 # Moderate impact for connectors/terminals
109
+ # Festive season boost (weeks 6-7)
110
+ external_factors[28:42] += 8
 
 
 
 
 
 
 
 
 
 
111
 
112
+ corrected_demand = np.clip(customer_shared + external_factors, 60, 250).astype(int)
113
 
114
+ # Generate supply plan for 56 days
115
+ supply_capacity = np.random.normal(155, 12, 56)
116
+ supply_plan = np.clip(supply_capacity, 120, 220).astype(int)
 
117
 
118
+ # Apply disruptions to supply (weather impact on days 15-18)
119
  supply_actual = supply_plan.copy()
120
+ supply_actual[15:19] = (supply_actual[15:19] * 0.8).astype(int)
121
 
 
 
 
 
 
 
 
 
 
 
 
122
  for i, date in enumerate(dates):
123
  # Determine which demand to use
124
  if i < 14:
 
134
  corrected_val = corrected_demand[i-14]
135
  demand_type = "AI-Corrected"
136
 
137
+ # Calculate shortfall
138
  shortfall = max(0, demand_used - supply_actual[i])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
 
140
  all_data.append({
141
  'Date': date,
142
  'Week': f"Week {(i//7)+1}",
143
  'Day': i + 1,
144
  'Material': material,
 
145
  'Firm_Demand': firm_val,
146
  'Customer_Demand': customer_val,
147
  'Corrected_Demand': corrected_val,
 
149
  'Supply_Plan': supply_plan[i],
150
  'Supply_Projected': supply_actual[i],
151
  'Shortfall': shortfall,
 
 
152
  'Demand_Type': demand_type,
153
+ 'Gap': supply_actual[i] - demand_used
 
 
 
154
  })
155
 
156
  return pd.DataFrame(all_data)
157
 
158
+ # Yazaki-specific Tier-2 suppliers
159
  @st.cache_data
160
  def get_tier2_suppliers():
161
  return {
162
+ 'Furukawa Electric India': {
163
+ 'location': 'Chennai',
164
+ 'materials': ['WH001-Engine Wire Harness', 'WH002-Dashboard Wire Harness'],
165
+ 'capacity': 200,
166
+ 'reliability': 95,
167
  'lead_time': 2,
168
+ 'risk_factors': ['Monsoon flooding', 'Port congestion', 'Copper price volatility']
 
 
 
 
 
 
169
  },
170
+ 'Sumitomo Wiring Systems': {
171
+ 'location': 'Bangalore',
172
+ 'materials': ['CON001-Electrical Connector', 'TER001-Wire Terminal'],
173
+ 'capacity': 180,
174
+ 'reliability': 92,
175
  'lead_time': 3,
176
+ 'risk_factors': ['Transportation delays', 'Raw material shortage', 'Equipment failure']
 
 
 
 
 
 
177
  },
178
  'JST India Private Limited': {
179
+ 'location': 'Pune',
180
+ 'materials': ['FUS001-Fuse Box Assembly', 'CON001-Electrical Connector'],
181
+ 'capacity': 220,
182
+ 'reliability': 88,
183
  'lead_time': 1,
184
+ 'risk_factors': ['Quality issues', 'Capacity constraints', 'Supplier disputes']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  }
186
  }
187
 
188
+ # Generate ecosystem data
189
  @st.cache_data
190
  def generate_ecosystem_data():
191
  today = datetime(2025, 8, 4)
 
198
  np.random.seed(hash(supplier_name + material) % 1000)
199
 
200
  base_capacity = supplier_info['capacity']
201
+ normal_supply = np.full(14, base_capacity, dtype=int)
 
 
 
 
 
202
  disrupted_supply = normal_supply.copy()
203
 
204
+ if supplier_name == 'Furukawa Electric India':
205
+ disrupted_supply[3:7] = (disrupted_supply[3:7] * 0.3).astype(int)
206
+ disruption_cause = "Monsoon flooding in Chennai"
 
 
207
  disruption_days = list(range(3, 7))
208
+ elif supplier_name == 'Sumitomo Wiring Systems':
209
+ disrupted_supply[5:8] = (disrupted_supply[5:8] * 0.5).astype(int)
210
+ disruption_cause = "Critical equipment failure"
 
 
211
  disruption_days = list(range(5, 8))
 
212
  elif supplier_name == 'JST India Private Limited':
213
+ disrupted_supply[8:11] = (disrupted_supply[8:11] * 0.2).astype(int)
214
+ disruption_cause = "Labor strike at Pune facility"
 
215
  disruption_days = list(range(8, 11))
 
 
 
 
 
 
 
216
  else:
217
+ disruption_cause = "No disruption"
218
  disruption_days = []
 
219
 
220
  lead_time = supplier_info['lead_time']
221
+ yazaki_supply = np.full(14, base_capacity, dtype=int)
222
 
 
223
  for disruption_day in disruption_days:
224
  arrival_day = disruption_day + lead_time
225
  if arrival_day < 14:
226
  reduction = normal_supply[disruption_day] - disrupted_supply[disruption_day]
227
  yazaki_supply[arrival_day] = max(yazaki_supply[arrival_day] - reduction, 0)
228
 
 
 
 
229
  for i, date in enumerate(dates):
 
 
 
 
 
 
 
 
 
 
230
  all_data.append({
231
  'Date': date,
232
  'Supplier': supplier_name,
233
  'Material': material,
 
234
  'Tier2_Normal_Supply': int(normal_supply[i]),
235
  'Tier2_Disrupted_Supply': int(disrupted_supply[i]),
236
+ 'Tier2_Impact': int(normal_supply[i] - disrupted_supply[i]),
237
  'Yazaki_Normal_Supply': int(normal_supply[i]),
238
  'Yazaki_Impacted_Supply': int(yazaki_supply[i]),
239
+ 'Yazaki_Impact': int(normal_supply[i] - yazaki_supply[i]),
 
240
  'Disruption_Cause': disruption_cause if i in disruption_days else "Normal Operations",
 
241
  'Lead_Time_Days': lead_time,
242
  'Is_Disrupted': i in disruption_days,
243
+ 'Is_Yazaki_Impacted': yazaki_supply[i] < normal_supply[i]
 
 
 
 
244
  })
245
 
246
  return pd.DataFrame(all_data)
247
 
248
+ # Updated external signals for Yazaki
249
  @st.cache_data
250
  def get_external_signals():
251
  return [
252
+ {'Source': 'Weather API', 'Signal': 'Heavy rains forecasted in Chennai for next 3 days', 'Impact': 'Supply Risk', 'Confidence': 95},
253
+ {'Source': 'Market Intelligence', 'Signal': 'EV sales up 25% this quarter - increased wire harness demand', 'Impact': 'Demand Increase', 'Confidence': 88},
254
+ {'Source': 'News Analytics', 'Signal': 'Upcoming festive season - historically 15% automotive demand spike', 'Impact': 'Demand Surge', 'Confidence': 92},
255
+ {'Source': 'Supplier Network', 'Signal': 'Tier-2 connector supplier capacity increased by 20%', 'Impact': 'Supply Boost', 'Confidence': 98},
256
+ {'Source': 'Social Media', 'Signal': 'Positive sentiment around new Tata EV models', 'Impact': 'Demand Growth', 'Confidence': 75},
257
+ {'Source': 'Government Portal', 'Signal': 'New EV subsidy policy effective next week', 'Impact': 'Market Expansion', 'Confidence': 100}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258
  ]
259
 
260
+ # Generate alerts for 8-week data
261
  def generate_detailed_alerts(df):
262
  alerts = []
263
  for material in df['Material'].unique():
264
  material_data = df[df['Material'] == material]
 
 
265
  shortage_days = material_data[material_data['Shortfall'] > 5]
 
 
266
 
267
+ if not shortage_days.empty:
268
+ for _, row in shortage_days.iterrows():
269
+ root_causes = []
 
 
 
 
 
 
 
270
 
271
+ if row['Day'] > 14:
272
+ if row['Corrected_Demand'] and row['Customer_Demand']:
273
+ diff = row['Corrected_Demand'] - row['Customer_Demand']
274
+ if diff > 10:
275
+ root_causes.append(f"AI detected {diff} units additional demand from external signals")
276
+
277
+ if row['Day'] >= 15 and row['Day'] <= 18:
278
+ root_causes.append("Chennai plant weather disruption reducing supply")
279
+ else:
280
+ root_causes.append("Firm demand exceeding supply capacity")
281
+
282
+ if not root_causes:
283
+ root_causes.append("Base demand exceeding current supply capacity")
284
+
285
+ mitigation_options = [
286
+ {"option": "Activate Aurangabad backup production", "impact": "+30 units/day", "cost": "High", "timeline": "24 hours"},
287
+ {"option": "Expedite Tier-2 supplier shipments", "impact": "+15 units/day", "cost": "Medium", "timeline": "12 hours"},
288
+ {"option": "Emergency air freight from Yazaki Philippines", "impact": "+40 units/day", "cost": "Very High", "timeline": "6 hours"},
289
+ {"option": "Reallocate inventory from other Yazaki plants", "impact": "+20 units/day", "cost": "Low", "timeline": "18 hours"}
290
+ ]
291
+
292
+ if row['Shortfall'] > 30:
293
+ best_option = mitigation_options[2]
294
+ elif row['Shortfall'] > 15:
295
+ best_option = mitigation_options[0]
296
+ else:
297
+ best_option = mitigation_options[1]
298
+
299
+ alerts.append({
300
+ 'material': material,
301
+ 'date': row['Date'].strftime('%Y-%m-%d'),
302
+ 'week': row['Week'],
303
+ 'shortage': int(row['Shortfall']),
304
+ 'demand_type': row['Demand_Type'],
305
+ 'severity': 'Critical' if row['Shortfall'] > 30 else 'High' if row['Shortfall'] > 15 else 'Medium',
306
+ 'root_causes': root_causes,
307
+ 'mitigation_options': mitigation_options,
308
+ 'best_option': best_option
309
+ })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
 
311
  return alerts
312
 
313
+ # Mitigation strategies with Yazaki-specific updates
314
  def generate_mitigation_strategies(supplier, material, impact_amount, impact_days):
315
  base_strategies = [
316
  {
317
+ 'strategy': 'Activate Alternate Supplier',
318
+ 'description': f'Engage backup supplier for {material}',
319
+ 'timeline': '24-48 hours',
320
+ 'cost': 'High (+15% unit cost)',
321
+ 'effectiveness': '90%',
322
+ 'capacity': f'+{impact_amount * 0.9:.0f} units/day',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
323
  },
324
  {
325
+ 'strategy': 'Emergency Air Freight',
326
+ 'description': f'Air freight {material} from Yazaki global network',
327
+ 'timeline': '6-12 hours',
328
+ 'cost': 'Very High (+40% logistics cost)',
329
  'effectiveness': '75%',
330
  'capacity': f'+{impact_amount * 0.75:.0f} units/day',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
331
  },
332
  {
333
+ 'strategy': 'Inventory Reallocation',
334
+ 'description': f'Reallocate {material} from other Yazaki plants',
335
+ 'timeline': '12-24 hours',
336
+ 'cost': 'Medium (+5% handling cost)',
337
  'effectiveness': '60%',
338
+ 'capacity': f'+{impact_amount * 0.6:.0f} units/day',
 
 
 
339
  }
340
  ]
341
 
342
+ if impact_amount > 100:
343
+ recommended = [0, 1]
344
+ elif impact_amount > 50:
345
+ recommended = [0, 2]
 
 
 
346
  else:
347
+ recommended = [2]
348
 
349
  return base_strategies, recommended
350
 
351
+ # Load data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
  df_demand = generate_8week_demand_data()
353
  df_ecosystem = generate_ecosystem_data()
354
  external_signals = get_external_signals()
355
  suppliers = get_tier2_suppliers()
356
 
357
+ # MAIN TITLE (same style as original)
358
+ st.title("Yazaki India Ltd - Supply Chain Command Center")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
359
 
360
+ # Tab Navigation (EXACTLY same as original)
361
+ st.sidebar.title("🎯 Dashboard Navigation")
362
  dashboard_tab = st.sidebar.radio(
363
+ "Select Dashboard:",
364
+ ["📊 Demand & Supply Forecast", "🌐 Ecosystem Supplier Impact", "🛡️ Buffer Optimizer"],
 
 
 
 
 
 
365
  index=0
366
  )
367
 
368
+ # TAB 1: DEMAND & SUPPLY FORECAST (same structure as original)
369
+ if dashboard_tab == "📊 Demand & Supply Forecast":
370
  st.markdown("""
371
  <div style="background: linear-gradient(135deg, #1f4e79, #2d5aa0); padding: 20px; border-radius: 15px; margin-bottom: 20px;">
372
  <h2 style="color: white; margin: 0; text-align: center;">
373
+ 🔌 8-Week Planning Horizon | Firm Demand (Days 1-14) | AI-Corrected Demand (Days 15-56)
374
  </h2>
 
 
 
375
  </div>
376
  """, unsafe_allow_html=True)
377
 
378
+ # Material selection
379
+ selected_material = st.selectbox(
380
+ "Select Material for Analysis:",
381
+ df_demand['Material'].unique(),
382
+ key="forecast_material"
383
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
384
 
385
+ # Filter data
386
  material_df = df_demand[df_demand['Material'] == selected_material].copy()
387
 
388
+ # Create visualization (same structure as original)
389
+ fig = go.Figure()
 
 
390
 
391
+ # Add firm demand (days 1-14)
392
+ firm_data = material_df[material_df['Demand_Type'] == 'Firm']
393
+ fig.add_trace(go.Scatter(
394
+ x=firm_data['Date'],
395
+ y=firm_data['Demand_Used'],
396
+ mode='lines+markers',
397
+ name='Firm Demand (Days 1-14)',
398
+ line=dict(color='#2E86AB', width=3),
399
+ marker=dict(size=8)
400
+ ))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
401
 
402
+ # Add AI-corrected demand (days 15-56)
403
+ corrected_data = material_df[material_df['Demand_Type'] == 'AI-Corrected']
404
+ fig.add_trace(go.Scatter(
405
+ x=corrected_data['Date'],
406
+ y=corrected_data['Demand_Used'],
407
+ mode='lines+markers',
408
+ name='AI-Corrected Demand (Days 15-56)',
409
+ line=dict(color='#A23B72', width=3, dash='dot'),
410
+ marker=dict(size=6)
411
+ ))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
412
 
413
+ # Add supply projection
414
+ fig.add_trace(go.Scatter(
415
+ x=material_df['Date'],
416
+ y=material_df['Supply_Projected'],
417
+ mode='lines+markers',
418
+ name='Supply Projection',
419
+ line=dict(color='#F18F01', width=2),
420
+ marker=dict(size=6)
421
+ ))
422
+
423
+ # Highlight shortage areas
424
+ shortage_data = material_df[material_df['Shortfall'] > 0]
425
+ if not shortage_data.empty:
426
  fig.add_trace(go.Scatter(
427
+ x=shortage_data['Date'],
428
+ y=shortage_data['Shortfall'],
429
+ mode='markers',
430
+ name='Shortage Alert',
431
+ marker=dict(color='red', size=10, symbol='triangle-up'),
432
+ yaxis='y2'
 
 
433
  ))
 
 
 
 
 
 
 
 
 
434
 
435
  fig.update_layout(
436
+ title=f"8-Week Demand & Supply Forecast - {selected_material}",
437
  xaxis_title="Date",
438
+ yaxis_title="Units",
439
+ yaxis2=dict(title="Shortage", overlaying='y', side='right'),
440
  height=600,
441
  showlegend=True,
442
+ hovermode='x unified'
 
443
  )
444
 
445
  st.plotly_chart(fig, use_container_width=True)
446
 
447
+ # Generate and display alerts (same structure as original)
448
+ alerts = generate_detailed_alerts(df_demand)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
449
 
450
+ if alerts:
451
+ st.markdown("""
452
+ <div style="background: #ffe6e6; padding: 15px; border-radius: 10px; border-left: 5px solid #ff4444; margin: 20px 0;">
453
+ <h3 style="color: #cc0000; margin-top: 0;">⚠️ Critical Supply Chain Alerts</h3>
454
+ </div>
455
+ """, unsafe_allow_html=True)
456
+
457
+ for alert in alerts[:3]: # Show top 3 alerts
458
+ severity_color = {'Critical': '#ff4444', 'High': '#ff8800', 'Medium': '#ffcc00'}[alert['severity']]
459
+
460
+ st.markdown(f"""
461
+ <div style="background: white; padding: 15px; border-radius: 10px; border-left: 5px solid {severity_color}; margin: 10px 0; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
462
+ <h4 style="color: {severity_color}; margin: 0 0 10px 0;">
463
+ 🚨 {alert['severity']} Alert: {alert['material']}
464
+ </h4>
465
+ <p style="margin: 5px 0;">
466
+ <strong>Date:</strong> {alert['date']} ({alert['week']}) |
467
+ <strong>Shortage:</strong> {alert['shortage']} units |
468
+ <strong>Type:</strong> {alert['demand_type']}
469
+ </p>
470
+ <p style="margin: 5px 0;"><strong>Root Causes:</strong></p>
471
+ <ul style="margin: 5px 0;">
472
+ {''.join([f"<li>{cause}</li>" for cause in alert['root_causes']])}
473
+ </ul>
474
+ <p style="margin: 10px 0 5px 0;"><strong>🎯 Recommended Action:</strong></p>
475
+ <div style="background: #f0f8ff; padding: 10px; border-radius: 5px;">
476
+ <strong>{alert['best_option']['option']}</strong><br>
477
+ Impact: {alert['best_option']['impact']} | Cost: {alert['best_option']['cost']} | Timeline: {alert['best_option']['timeline']}
478
+ </div>
479
+ </div>
480
+ """, unsafe_allow_html=True)
481
 
482
+ # TAB 2: ECOSYSTEM SUPPLIER IMPACT (same structure as original)
483
+ elif dashboard_tab == "🌐 Ecosystem Supplier Impact":
484
  st.markdown("""
485
  <div style="background: linear-gradient(135deg, #1f4e79, #2d5aa0); padding: 20px; border-radius: 15px; margin-bottom: 20px;">
486
  <h2 style="color: white; margin: 0; text-align: center;">
487
+ 🌐 Tier 2 Supplier Disruption Analysis | Cascading Impact Modeling | Automated Mitigation Response
488
  </h2>
 
 
 
489
  </div>
490
  """, unsafe_allow_html=True)
491
 
492
+ # Supplier selection
 
493
  selected_supplier = st.selectbox(
494
+ "Select Tier-2 Supplier for Analysis:",
495
+ df_ecosystem['Supplier'].unique(),
496
+ key="ecosystem_supplier"
 
497
  )
498
 
499
+ # Filter and analyze
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
500
  supplier_df = df_ecosystem[df_ecosystem['Supplier'] == selected_supplier]
501
 
502
+ col1, col2 = st.columns(2)
 
503
 
504
+ with col1:
505
+ # Supplier disruption chart
506
+ fig1 = go.Figure()
507
 
508
+ for material in supplier_df['Material'].unique():
509
+ material_data = supplier_df[supplier_df['Material'] == material]
 
510
 
511
+ fig1.add_trace(go.Scatter(
512
+ x=material_data['Date'],
513
+ y=material_data['Tier2_Normal_Supply'],
514
+ mode='lines',
515
+ name=f'{material} - Normal',
516
+ line=dict(width=2)
517
+ ))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
518
 
519
+ fig1.add_trace(go.Scatter(
520
+ x=material_data['Date'],
521
+ y=material_data['Tier2_Disrupted_Supply'],
522
+ mode='lines',
523
+ name=f'{material} - Disrupted',
524
+ line=dict(dash='dot', width=2)
525
+ ))
526
 
527
+ fig1.update_layout(
528
+ title=f"Tier-2 Supplier Impact: {selected_supplier}",
529
+ xaxis_title="Date",
530
+ yaxis_title="Supply Units",
531
+ height=400
532
+ )
533
+
534
+ st.plotly_chart(fig1, use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
535
 
536
+ with col2:
537
+ # Yazaki impact chart
538
+ fig2 = go.Figure()
539
 
540
+ for material in supplier_df['Material'].unique():
541
+ material_data = supplier_df[supplier_df['Material'] == material]
542
+
543
+ fig2.add_trace(go.Scatter(
544
+ x=material_data['Date'],
545
+ y=material_data['Yazaki_Normal_Supply'],
546
+ mode='lines',
547
+ name=f'{material} - Normal',
548
+ line=dict(width=2)
549
+ ))
550
+
551
+ fig2.add_trace(go.Scatter(
552
+ x=material_data['Date'],
553
+ y=material_data['Yazaki_Impacted_Supply'],
554
+ mode='lines',
555
+ name=f'{material} - Impacted',
556
+ line=dict(dash='dot', width=2)
557
+ ))
558
 
559
+ fig2.update_layout(
560
+ title=f"Cascading Impact on Yazaki Production",
561
+ xaxis_title="Date",
562
+ yaxis_title="Supply Units",
563
+ height=400
 
 
 
564
  )
 
 
 
 
 
 
565
 
566
+ st.plotly_chart(fig2, use_container_width=True)
567
+
568
+ # Disruption alerts (same structure as original)
569
+ disrupted_days = supplier_df[supplier_df['Is_Disrupted'] == True]
570
+
571
+ if not disrupted_days.empty:
572
+ for _, alert_day in disrupted_days.iterrows():
573
+ if alert_day['Tier2_Impact'] > 0:
574
+ strategies, recommended = generate_mitigation_strategies(
575
+ alert_day['Supplier'],
576
+ alert_day['Material'],
577
+ alert_day['Tier2_Impact'],
578
+ 1
579
+ )
580
+
581
  st.markdown(f"""
582
+ <div style="background: white; padding: 15px; border-radius: 10px; border-left: 5px solid #ff8800; margin: 10px 0; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
583
+ <h4 style="color: #ff8800; margin: 0 0 10px 0;">
584
+ 🏭 Supplier Disruption Alert
585
+ </h4>
586
+ <p style="margin: 5px 0;">
587
+ <strong>Supplier:</strong> {alert_day['Supplier']} |
588
+ <strong>Material:</strong> {alert_day['Material']}
589
+ </p>
590
+ <p style="margin: 5px 0;">
591
+ <strong>Root Cause:</strong> {alert_day['Disruption_Cause']}
592
+ </p>
593
+ <p style="margin: 5px 0;">
594
+ <strong>Impact:</strong> -{alert_day['Tier2_Impact']} units |
595
+ <strong>Yazaki Impact:</strong> -{alert_day['Yazaki_Impact']} units (after {alert_day['Lead_Time_Days']} days)
596
+ </p>
597
  </div>
598
  """, unsafe_allow_html=True)
599
+
600
+ break # Show only first alert to avoid repetition
601
 
602
+ # TAB 3: BUFFER OPTIMIZER (same structure as original)
603
+ elif dashboard_tab == "🛡️ Buffer Optimizer":
604
  st.markdown("""
605
  <div style="background: linear-gradient(135deg, #1f4e79, #2d5aa0); padding: 20px; border-radius: 15px; margin-bottom: 20px;">
606
  <h2 style="color: white; margin: 0; text-align: center;">
607
+ 🛡️ AI-driven safety-stock recommendations across the full network
608
  </h2>
 
 
 
609
  </div>
610
  """, unsafe_allow_html=True)
611
 
612
+ # Buffer optimization logic (same as original)
613
+ buffer_data = []
614
+ for material in df_demand['Material'].unique():
615
+ material_data = df_demand[df_demand['Material'] == material]
616
+ avg_demand = material_data['Demand_Used'].mean()
617
+ demand_volatility = material_data['Demand_Used'].std()
618
+ max_shortfall = material_data['Shortfall'].max()
619
+
620
+ # Calculate recommended buffer
621
+ base_buffer = avg_demand * 0.15 # 15% base buffer
622
+ volatility_buffer = demand_volatility * 1.5
623
+ risk_buffer = max_shortfall * 0.8
624
+
625
+ recommended_buffer = int(base_buffer + volatility_buffer + risk_buffer)
626
+ current_buffer = int(avg_demand * 0.10) # Assume current is 10%
627
+
628
+ buffer_data.append({
629
+ 'Material': material,
630
+ 'Current_Buffer': current_buffer,
631
+ 'Recommended_Buffer': recommended_buffer,
632
+ 'Gap': recommended_buffer - current_buffer,
633
+ 'Cost_Impact': f"₹{(recommended_buffer - current_buffer) * 150:,}", # Assuming ₹150 per unit
634
+ 'Risk_Reduction': f"{min(90, max_shortfall * 2):.0f}%"
635
+ })
636
 
637
+ buffer_df = pd.DataFrame(buffer_data)
 
 
638
 
639
+ # Display buffer recommendations
640
+ st.subheader("📊 Safety Stock Recommendations")
 
 
641
 
642
  fig = go.Figure()
643
 
644
  fig.add_trace(go.Bar(
645
+ name='Current Buffer',
646
+ x=buffer_df['Material'],
647
+ y=buffer_df['Current_Buffer'],
648
+ marker_color='lightblue'
 
 
649
  ))
650
 
651
  fig.add_trace(go.Bar(
652
+ name='Recommended Buffer',
653
+ x=buffer_df['Material'],
654
+ y=buffer_df['Recommended_Buffer'],
655
+ marker_color='orange'
 
 
656
  ))
657
 
658
  fig.update_layout(
659
+ title="Current vs Recommended Safety Stock Levels",
660
  xaxis_title="Materials",
661
+ yaxis_title="Buffer Stock Units",
662
  barmode='group',
663
+ height=400
 
664
  )
665
 
666
  st.plotly_chart(fig, use_container_width=True)
667
 
668
+ # Buffer recommendations table
669
+ st.subheader("📋 Detailed Buffer Analysis")
670
+ st.dataframe(buffer_df, use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
671
 
672
+ # External Signals Panel (same structure as original)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
673
  st.sidebar.markdown("---")
674
+ st.sidebar.subheader("🌍 External Market Signals")
675
+ for signal in external_signals[:3]:
676
+ confidence_color = "green" if signal['Confidence'] > 90 else "orange" if signal['Confidence'] > 80 else "red"
 
 
 
 
 
 
 
 
677
  st.sidebar.markdown(f"""
678
+ <div style="background: white; padding: 8px; border-radius: 8px; margin: 8px 0; border-left: 3px solid {confidence_color};">
679
+ <strong style="color: {confidence_color};">{signal['Source']}</strong><br>
680
+ <small>{signal['Signal']}</small><br>
681
+ <small><strong>Impact:</strong> {signal['Impact']} ({signal['Confidence']}%)</small>
 
 
 
 
 
 
 
 
 
 
682
  </div>
683
  """, unsafe_allow_html=True)
684
 
685
+ # Footer (same style as original)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
686
  st.markdown("---")
687
  st.markdown("""
688
+ <div style="text-align: center; padding: 20px; background: linear-gradient(135deg, #1f4e79, #2d5aa0); border-radius: 15px; color: white;">
689
+ <h3>🔌 Yazaki India Ltd 8-Week Supply Chain Command Center</h3>
690
+ <p><strong>Firm + AI-Corrected Demand | Ecosystem Intelligence + Buffer Optimization</strong></p>
691
+ <p><em>Powered by Agentic AI | 8-Week Planning Horizon | Comprehensive Supply Chain Resilience</em></p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
692
  </div>
693
  """, unsafe_allow_html=True)