#Stable version for Yazaki India Ltd import streamlit as st import pandas as pd import numpy as np import plotly.express as px import plotly.graph_objects as go from datetime import datetime, timedelta import random # Page configuration st.set_page_config( page_title="Yazaki India Ltd - Complete Supply Chain Hub", page_icon="🌐", layout="wide", initial_sidebar_state="expanded" ) # Custom CSS (same as before) st.markdown(""" """, unsafe_allow_html=True) # Initialize session state if 'executed_mitigations' not in st.session_state: st.session_state.executed_mitigations = [] if 'external_signals' not in st.session_state: st.session_state.external_signals = [] # UPDATED: Generate 8-week forward-looking demand data @st.cache_data def generate_8week_demand_data(): today = datetime(2025, 8, 4) dates = [today + timedelta(days=x) for x in range(56)] # 8 weeks = 56 days materials = [ 'YAZ001-Wiring Harness', 'YAZ002-Connectors', 'YAZ003-Terminals', 'YAZ004-Sensors', 'YAZ005-Cable Assemblies' ] all_data = [] for material in materials: np.random.seed(hash(material) % 1000) # Generate base demand patterns base_demand = np.random.normal(150, 15, 56) # First 14 days: FIRM DEMAND firm_demand = np.clip(base_demand[:14], 100, 200).astype(int) # Days 15-56: Customer shared demand (tentative) customer_shared = np.clip(base_demand[14:] * (1 + 0.05 * np.sin(np.linspace(0, 3.14, 42))), 80, 220).astype(int) # Days 15-56: AI-corrected demand (with external signals) external_factors = np.zeros(42) # Weather impact (weeks 3-4) external_factors[0:14] += np.random.normal(0, 5, 14) # EV policy impact (weeks 5-8) if 'YAZ' in material: external_factors[14:] += 10 # Festive season boost (weeks 6-7) external_factors[28:42] += 8 corrected_demand = np.clip(customer_shared + external_factors, 60, 250).astype(int) # Generate supply plan for 56 days supply_capacity = np.random.normal(155, 12, 56) supply_plan = np.clip(supply_capacity, 120, 220).astype(int) # Apply disruptions to supply (weather impact on days 15-18) supply_actual = supply_plan.copy() supply_actual[15:19] = (supply_actual[15:19] * 0.8).astype(int) for i, date in enumerate(dates): # Determine which demand to use if i < 14: demand_used = firm_demand[i] firm_val = firm_demand[i] customer_val = None corrected_val = None demand_type = "Firm" else: demand_used = corrected_demand[i-14] firm_val = None customer_val = customer_shared[i-14] corrected_val = corrected_demand[i-14] demand_type = "AI-Corrected" # Calculate shortfall shortfall = max(0, demand_used - supply_actual[i]) all_data.append({ 'Date': date, 'Week': f"Week {(i//7)+1}", 'Day': i + 1, 'Material': material, 'Firm_Demand': firm_val, 'Customer_Demand': customer_val, 'Corrected_Demand': corrected_val, 'Demand_Used': demand_used, 'Supply_Plan': supply_plan[i], 'Supply_Projected': supply_actual[i], 'Shortfall': shortfall, 'Demand_Type': demand_type, 'Gap': supply_actual[i] - demand_used }) return pd.DataFrame(all_data) # UPDATED: Tier-2 suppliers for Yazaki India @st.cache_data def get_tier2_suppliers(): return { 'Electro Components Pvt Ltd': { 'location': 'Chennai', 'materials': ['YAZ001-Wiring Harness', 'YAZ002-Connectors'], 'capacity': 210, 'reliability': 93, 'lead_time': 3, 'risk_factors': ['Port delays', 'Power outages', 'Labor strikes'] }, 'Connectix Solutions': { 'location': 'Ahmedabad', 'materials': ['YAZ003-Terminals', 'YAZ004-Sensors'], 'capacity': 190, 'reliability': 90, 'lead_time': 2, 'risk_factors': ['Raw material shortage', 'Transportation issues', 'Equipment failure'] }, 'WireCraft Industries': { 'location': 'Pune', 'materials': ['YAZ005-Cable Assemblies', 'YAZ001-Wiring Harness'], 'capacity': 230, 'reliability': 87, 'lead_time': 1, 'risk_factors': ['Quality checks', 'Capacity limits', 'Supplier disputes'] } } # UPDATED: Ecosystem data with Yazaki-specific naming @st.cache_data def generate_ecosystem_data(): today = datetime(2025, 8, 4) dates = [today + timedelta(days=x) for x in range(14)] suppliers = get_tier2_suppliers() all_data = [] for supplier_name, supplier_info in suppliers.items(): for material in supplier_info['materials']: np.random.seed(hash(supplier_name + material) % 1000) base_capacity = supplier_info['capacity'] normal_supply = np.full(14, base_capacity, dtype=int) disrupted_supply = normal_supply.copy() if supplier_name == 'Electro Components Pvt Ltd': disrupted_supply[3:7] = (disrupted_supply[3:7] * 0.3).astype(int) disruption_cause = "Port delays in Chennai affecting imports" disruption_days = list(range(3, 7)) elif supplier_name == 'Connectix Solutions': disrupted_supply[5:8] = (disrupted_supply[5:8] * 0.5).astype(int) disruption_cause = "Critical equipment failure at Ahmedabad facility" disruption_days = list(range(5, 8)) elif supplier_name == 'WireCraft Industries': disrupted_supply[8:11] = (disrupted_supply[8:11] * 0.2).astype(int) disruption_cause = "Labor strike at Pune facility" disruption_days = list(range(8, 11)) else: disruption_cause = "No disruption" disruption_days = [] lead_time = supplier_info['lead_time'] yazaki_supply = np.full(14, base_capacity, dtype=int) for disruption_day in disruption_days: arrival_day = disruption_day + lead_time if arrival_day < 14: reduction = normal_supply[disruption_day] - disrupted_supply[disruption_day] yazaki_supply[arrival_day] = max(yazaki_supply[arrival_day] - reduction, 0) for i, date in enumerate(dates): all_data.append({ 'Date': date, 'Supplier': supplier_name, 'Material': material, 'Tier2_Normal_Supply': int(normal_supply[i]), 'Tier2_Disrupted_Supply': int(disrupted_supply[i]), 'Tier2_Impact': int(normal_supply[i] - disrupted_supply[i]), 'Yazaki_Normal_Supply': int(normal_supply[i]), 'Yazaki_Impacted_Supply': int(yazaki_supply[i]), 'Yazaki_Impact': int(normal_supply[i] - yazaki_supply[i]), 'Disruption_Cause': disruption_cause if i in disruption_days else "Normal Operations", 'Lead_Time_Days': lead_time, 'Is_Disrupted': i in disruption_days, 'Is_Yazaki_Impacted': yazaki_supply[i] < normal_supply[i] }) return pd.DataFrame(all_data) # External signals (unchanged) @st.cache_data def get_external_signals(): return [ {'Source': 'Weather API', 'Signal': 'Heavy rains forecasted in Chennai for next 3 days', 'Impact': 'Supply Risk', 'Confidence': 95}, {'Source': 'Market Intelligence', 'Signal': 'EV sales up 25% this quarter', 'Impact': 'Demand Increase', 'Confidence': 88}, {'Source': 'News Analytics', 'Signal': 'Upcoming festive season - historically 15% demand spike', 'Impact': 'Demand Surge', 'Confidence': 92}, {'Source': 'Supplier Network', 'Signal': 'Tier-2 supplier capacity increased by 20%', 'Impact': 'Supply Boost', 'Confidence': 98}, {'Source': 'Social Media', 'Signal': 'Positive sentiment around new Maruti EV model', 'Impact': 'Demand Growth', 'Confidence': 75}, {'Source': 'Government Portal', 'Signal': 'New EV subsidy policy effective next week', 'Impact': 'Market Expansion', 'Confidence': 100} ] # UPDATED: Generate alerts for 8-week data def generate_detailed_alerts(df): alerts = [] for material in df['Material'].unique(): material_data = df[df['Material'] == material] shortage_days = material_data[material_data['Shortfall'] > 5] if not shortage_days.empty: for _, row in shortage_days.iterrows(): root_causes = [] if row['Day'] > 14: if row['Corrected_Demand'] and row['Customer_Demand']: diff = row['Corrected_Demand'] - row['Customer_Demand'] if diff > 10: root_causes.append(f"AI detected {diff} units additional demand from external signals") if row['Day'] >= 15 and row['Day'] <= 18: root_causes.append("Chennai plant weather disruption reducing supply") else: root_causes.append("Firm demand exceeding supply capacity") if not root_causes: root_causes.append("Base demand exceeding current supply capacity") mitigation_options = [ {"option": "Activate Pune backup production", "impact": "+30 units/day", "cost": "High", "timeline": "24 hours"}, {"option": "Expedite Tier-2 supplier shipments", "impact": "+15 units/day", "cost": "Medium", "timeline": "12 hours"}, {"option": "Emergency air freight from backup suppliers", "impact": "+40 units/day", "cost": "Very High", "timeline": "6 hours"}, {"option": "Reallocate inventory from other plants", "impact": "+20 units/day", "cost": "Low", "timeline": "18 hours"} ] if row['Shortfall'] > 30: best_option = mitigation_options[2] elif row['Shortfall'] > 15: best_option = mitigation_options[0] else: best_option = mitigation_options[1] alerts.append({ 'material': material, 'date': row['Date'].strftime('%Y-%m-%d'), 'week': row['Week'], 'shortage': int(row['Shortfall']), 'demand_type': row['Demand_Type'], 'severity': 'Critical' if row['Shortfall'] > 30 else 'High' if row['Shortfall'] > 15 else 'Medium', 'root_causes': root_causes, 'mitigation_options': mitigation_options, 'best_option': best_option }) return alerts # Keep mitigation strategies unchanged def generate_mitigation_strategies(supplier, material, impact_amount, impact_days): base_strategies = [ { 'strategy': 'Activate Alternate Supplier', 'description': f'Engage backup supplier for {material}', 'timeline': '24-48 hours', 'cost': 'High (+15% unit cost)', 'effectiveness': '90%', 'capacity': f'+{impact_amount * 0.9:.0f} units/day', }, { 'strategy': 'Emergency Air Freight', 'description': f'Air freight {material} from other regions', 'timeline': '6-12 hours', 'cost': 'Very High (+40% logistics cost)', 'effectiveness': '75%', 'capacity': f'+{impact_amount * 0.75:.0f} units/day', }, { 'strategy': 'Inventory Reallocation', 'description': f'Reallocate {material} from other plants', 'timeline': '12-24 hours', 'cost': 'Medium (+5% handling cost)', 'effectiveness': '60%', 'capacity': f'+{impact_amount * 0.6:.0f} units/day', } ] if impact_amount > 100: recommended = [0, 1] elif impact_amount > 50: recommended = [0, 2] else: recommended = [2] return base_strategies, recommended # Load data df_demand = generate_8week_demand_data() df_ecosystem = generate_ecosystem_data() external_signals = get_external_signals() suppliers = get_tier2_suppliers() # Simple title (header removed as requested) st.title("Supply Chain Command Center") # Tab Navigation (same as before) st.sidebar.title("🎯 Dashboard Navigation") dashboard_tab = st.sidebar.radio( "Select Dashboard:", ["📊 Demand & Supply Forecast", "🌐 Ecosystem Supplier Impact", "🛡️ Buffer Optimizer"], index=0 ) # UPDATED TAB 1: 8-WEEK DEMAND & SUPPLY FORECAST if dashboard_tab == "📊 Demand & Supply Forecast": st.markdown("""

📊 8-Week Demand & Supply Forecast Dashboard

8-Week Planning Horizon | Firm Demand (Days 1-14) | AI-Corrected Demand (Days 15-56)

""", unsafe_allow_html=True) # Material selection selected_materials_demand = st.sidebar.multiselect( "Focus Materials:", df_demand['Material'].unique(), default=df_demand['Material'].unique()[:3] ) # Week filter week_filter = st.sidebar.selectbox( "Focus on Weeks:", ["All 8 Weeks", "Weeks 1-2 (Firm)", "Weeks 3-4", "Weeks 5-6", "Weeks 7-8"], index=0 ) # Filter data filtered_df_demand = df_demand[df_demand['Material'].isin(selected_materials_demand)] if week_filter != "All 8 Weeks": if week_filter == "Weeks 1-2 (Firm)": filtered_df_demand = filtered_df_demand[filtered_df_demand['Day'] <= 14] elif week_filter == "Weeks 3-4": filtered_df_demand = filtered_df_demand[(filtered_df_demand['Day'] > 14) & (filtered_df_demand['Day'] <= 28)] elif week_filter == "Weeks 5-6": filtered_df_demand = filtered_df_demand[(filtered_df_demand['Day'] > 28) & (filtered_df_demand['Day'] <= 42)] else: # Weeks 7-8 filtered_df_demand = filtered_df_demand[filtered_df_demand['Day'] > 42] # Generate and display alerts st.subheader("🚨 8-Week Supply Chain Alerts") alerts = generate_detailed_alerts(filtered_df_demand) if alerts: for i, alert in enumerate(alerts[:3]): st.markdown(f"""

⚠️ {alert['material']} - {alert['severity']} Shortage Alert

Date: {alert['date']} ({alert['week']}) | Shortage: {alert['shortage']} units | Type: {alert['demand_type']}

""", unsafe_allow_html=True) st.markdown("**🔍 Root Cause Analysis:**") for cause in alert['root_causes']: st.markdown(f"""
🎯 {cause}
""", unsafe_allow_html=True) st.markdown("**⚡ Mitigation Options:**") for option in alert['mitigation_options']: is_best = option == alert['best_option'] option_class = "best-option" if is_best else "mitigation" best_indicator = "🏆 **RECOMMENDED** " if is_best else "" st.markdown(f"""
{best_indicator}{option['option']}
📈 Impact: {option['impact']} | 💰 Cost: {option['cost']} | ⏱️ Timeline: {option['timeline']}
""", unsafe_allow_html=True) col1, col2, col3 = st.columns([2, 1, 1]) with col1: if st.button(f"✅ Implement Solution", key=f"demand_implement_{i}"): st.success(f"Implementing: {alert['best_option']['option']}") st.markdown("---") else: st.markdown("""
All Good! No critical supply shortages detected in the 8-week horizon.
""", unsafe_allow_html=True) # UPDATED: 8-Week Detailed Planning Table st.subheader("📋 8-Week Demand-Supply Planning Table") # Prepare display table display_df = filtered_df_demand.copy() display_df['Date_Display'] = display_df['Date'].dt.strftime('%m-%d') # Create styled table table_cols = ['Date_Display', 'Week', 'Material', 'Firm_Demand', 'Customer_Demand', 'Corrected_Demand', 'Supply_Projected', 'Shortfall'] table_data = display_df[table_cols].copy() table_data.columns = ['Date', 'Week', 'Material', 'Firm Demand', 'Customer Demand', 'Corrected Demand', 'Supply Plan', 'Shortfall'] # Color coding function def highlight_shortfall(val): if pd.isna(val): return '' return 'background-color: #ffcccc' if val > 0 else '' def highlight_firm_period(row): if pd.notna(row['Firm Demand']): return ['background-color: #e6f3ff'] * len(row) return [''] * len(row) # Apply styling styled_table = table_data.style.applymap(highlight_shortfall, subset=['Shortfall']) styled_table = styled_table.apply(highlight_firm_period, axis=1) st.dataframe(styled_table, use_container_width=True, height=500) # Weekly summary st.subheader("📊 Weekly Summary") weekly_summary = filtered_df_demand.groupby(['Week', 'Material']).agg({ 'Demand_Used': 'sum', 'Supply_Projected': 'sum', 'Shortfall': 'sum' }).reset_index() weekly_summary['Balance'] = weekly_summary['Supply_Projected'] - weekly_summary['Demand_Used'] st.dataframe(weekly_summary, use_container_width=True) # Enhanced visualization st.subheader("📈 8-Week Demand vs Supply Outlook") for material in selected_materials_demand: material_data = filtered_df_demand[filtered_df_demand['Material'] == material] st.markdown(f"**{material}**") fig = go.Figure() # Add demand used line fig.add_trace(go.Scatter( x=material_data['Date'], y=material_data['Demand_Used'], mode='lines+markers', name='Demand Used', line=dict(color='blue', width=3), marker=dict(size=6) )) # Add supply line fig.add_trace(go.Scatter( x=material_data['Date'], y=material_data['Supply_Projected'], mode='lines+markers', name='Supply Projected', line=dict(color='green', width=3), marker=dict(size=6) )) # Highlight shortfall areas shortage_data = material_data[material_data['Shortfall'] > 0] if not shortage_data.empty: fig.add_trace(go.Scatter( x=shortage_data['Date'], y=shortage_data['Supply_Projected'], mode='markers', name='Shortage Days', marker=dict(color='red', size=10, symbol='x'), )) # Mark firm demand period firm_data = material_data[material_data['Day'] <= 14] if not firm_data.empty: fig.add_vrect( x0=firm_data['Date'].min(), x1=firm_data['Date'].max(), fillcolor="lightblue", opacity=0.2, line_width=0, annotation_text="Firm Demand Period", annotation_position="top left" ) fig.update_layout( title=f'{material} - 8-Week Supply vs Demand Forecast', xaxis_title='Date', yaxis_title='Units', height=400, showlegend=True, hovermode='x unified' ) st.plotly_chart(fig, use_container_width=True) # External demand sensing (same as before) st.subheader("📡 Real-time External Demand Sensing") col1, col2 = st.columns(2) with col1: st.write("**Active External Signals:**") for signal in external_signals: confidence_color = "🟢" if signal['Confidence'] > 90 else "🟡" if signal['Confidence'] > 80 else "🟠" st.markdown(f"""
{confidence_color} {signal['Source']}
{signal['Signal']}
Impact: {signal['Impact']} | Confidence: {signal['Confidence']}%
""", unsafe_allow_html=True) with col2: st.write("**8-Week Scenario Planning:**") scenario = st.selectbox("Select Scenario to Test:", ["Base Case", "Extended Monsoon", "Sustained EV Boost", "Supply Chain Strike"]) if st.button("🎮 Run 8-Week Scenario", key="demand_scenario"): if scenario == "Extended Monsoon": st.error("Scenario: 30% supply reduction for 3 weeks. Activating multi-tier contingency plans...") elif scenario == "Sustained EV Boost": st.warning("Scenario: 25% demand increase for 6 weeks. Scaling ecosystem capacity...") elif scenario == "Supply Chain Strike": st.info("Scenario: Multi-supplier disruption. Implementing emergency protocols...") # Keep TAB 2 and TAB 3 unchanged from previous version, but replace Rane with Yazaki in variables and text elif dashboard_tab == "🌐 Ecosystem Supplier Impact": st.markdown("""

🌐 Ecosystem Supplier Impact Dashboard

Tier 2 Supplier Disruption Analysis | Cascading Impact Modeling | Automated Mitigation Response

""", unsafe_allow_html=True) selected_suppliers = st.sidebar.multiselect( "Monitor Suppliers:", list(suppliers.keys()), default=list(suppliers.keys()) ) st.subheader("🚨 Live Ecosystem Supply Chain Alerts") ecosystem_alerts = [] for supplier in selected_suppliers: supplier_data = df_ecosystem[df_ecosystem['Supplier'] == supplier] disrupted_data = supplier_data[supplier_data['Is_Disrupted'] == True] if not disrupted_data.empty: for material in disrupted_data['Material'].unique(): material_disruptions = disrupted_data[disrupted_data['Material'] == material] total_impact = material_disruptions['Tier2_Impact'].sum() impact_days = len(material_disruptions) first_impact_date = material_disruptions['Date'].min() yazaki_impacted = supplier_data[ (supplier_data['Material'] == material) & (supplier_data['Is_Yazaki_Impacted'] == True) ] if not yazaki_impacted.empty: yazaki_impact_start = yazaki_impacted['Date'].min() yazaki_impact_days = len(yazaki_impacted) yazaki_total_impact = yazaki_impacted['Yazaki_Impact'].sum() ecosystem_alerts.append({ 'supplier': supplier, 'material': material, 'disruption_cause': material_disruptions.iloc[0]['Disruption_Cause'], 'tier2_impact_start': first_impact_date, 'tier2_impact_days': impact_days, 'tier2_total_impact': total_impact, 'yazaki_impact_start': yazaki_impact_start, 'yazaki_impact_days': yazaki_impact_days, 'yazaki_total_impact': yazaki_total_impact, 'lead_time': material_disruptions.iloc[0]['Lead_Time_Days'] }) if ecosystem_alerts: for alert in ecosystem_alerts: st.markdown(f"""

⚠️ Tier 2 Supplier Disruption Alert

Supplier: {alert['supplier']} | Material: {alert['material']}

Root Cause: {alert['disruption_cause']}

""", unsafe_allow_html=True) col1, col2 = st.columns(2) with col1: st.markdown("**🏭 Tier 2 Supplier Impact:**") st.markdown(f"""
📅 Impact Period: {alert['tier2_impact_start'].strftime('%Y-%m-%d')} ({alert['tier2_impact_days']} days)
📉 Total Supply Lost: {alert['tier2_total_impact']} units
🎯 Daily Impact: {alert['tier2_total_impact'] // alert['tier2_impact_days']} units/day
""", unsafe_allow_html=True) with col2: st.markdown("**⚙️ Yazaki India Ltd Impact (with Lead Time):**") st.markdown(f"""
📅 Impact Period: {alert['yazaki_impact_start'].strftime('%Y-%m-%d')} ({alert['yazaki_impact_days']} days)
📉 Total Supply Lost: {alert['yazaki_total_impact']} units
⏱️ Lead Time Delay: {alert['lead_time']} days
""", unsafe_allow_html=True) strategies, recommended_indices = generate_mitigation_strategies( alert['supplier'], alert['material'], alert['yazaki_total_impact'] // alert['yazaki_impact_days'], alert['yazaki_impact_days'] ) st.markdown("**🤖 Agentic AI Mitigation Strategies:**") for i, strategy in enumerate(strategies): is_recommended = i in recommended_indices is_executed = f"eco_{alert['supplier']}_{alert['material']}_{i}" in st.session_state.executed_mitigations if is_executed: card_class = "mitigation-executed" status_prefix = "✅ **EXECUTED** " elif is_recommended: card_class = "mitigation-recommended" status_prefix = "🏆 **AI RECOMMENDED** " else: card_class = "mitigation-recommended" status_prefix = "" st.markdown(f"""
{status_prefix}{strategy['strategy']}
📋 {strategy['description']}
⏱️ Timeline: {strategy['timeline']} | 💰 Cost: {strategy['cost']}
📈 Effectiveness: {strategy['effectiveness']} | 🚀 Capacity: {strategy['capacity']}
""", unsafe_allow_html=True) strategy_key = f"eco_{alert['supplier']}_{alert['material']}_{i}" col1, col2 = st.columns([2, 1]) with col1: if not is_executed: if st.button(f"🚀 Execute Strategy", key=f"execute_{strategy_key}"): st.session_state.executed_mitigations.append(strategy_key) st.success(f"Executing: {strategy['strategy']}") st.rerun() else: st.success("Strategy Active") with col2: if is_recommended: st.button("🏆 Recommended", key=f"rec_{strategy_key}", disabled=True) st.markdown("---") else: st.markdown("""
Ecosystem Healthy! No supplier disruptions detected in the current timeframe.
""", unsafe_allow_html=True) st.subheader("📊 Ecosystem Supply Chain Flow Visualization") fig = go.Figure() for supplier in selected_suppliers: supplier_data = df_ecosystem[df_ecosystem['Supplier'] == supplier] sample_material = supplier_data['Material'].iloc[0] material_data = supplier_data[supplier_data['Material'] == sample_material] fig.add_trace(go.Scatter( x=material_data['Date'], y=material_data['Tier2_Disrupted_Supply'], mode='lines+markers', name=f'{supplier} (Tier 2)', line=dict(width=2, dash='dash'), marker=dict(size=6) )) fig.add_trace(go.Scatter( x=material_data['Date'], y=material_data['Yazaki_Impacted_Supply'], mode='lines+markers', name=f'Yazaki Impact from {supplier}', line=dict(width=3), marker=dict(size=8) )) fig.update_layout( title='Tier 2 Supplier Disruptions → Yazaki India Ltd Supply Impact', xaxis_title='Date', yaxis_title='Supply Units', height=500, showlegend=True, hovermode='x unified' ) st.plotly_chart(fig, use_container_width=True) # TAB 3: BUFFER OPTIMIZER (same as before) elif dashboard_tab == "🛡️ Buffer Optimizer": st.markdown("""

🛡️ Multi-Echelon Buffer Optimizer

AI-driven safety-stock recommendations across the full network

""", unsafe_allow_html=True) service_level = st.slider("Target Service Level (%)", 90, 99, 95) review_period = st.number_input("Inventory Review Period (days)", min_value=1, max_value=14, value=1) z_factor = {90: 1.28, 92: 1.41, 95: 1.64, 97: 1.88, 98: 2.05, 99: 2.33} Z = z_factor.get(service_level, 1.64) # Use 8-week demand data for buffer calculation demand_stats = (df_demand .groupby("Material") .agg(DailyMean=("Demand_Used", "mean"), Sigma=("Demand_Used", "std")) .reset_index()) lead_times = (df_ecosystem .groupby("Material") .agg(LeadTime=("Lead_Time_Days", "max")) .reset_index()) current_buffers = (df_demand[df_demand["Day"] == 1] .loc[:, ["Material", "Supply_Projected"]] .rename(columns={"Supply_Projected": "OnHand"})) buffer_df = (demand_stats.merge(lead_times, on="Material") .merge(current_buffers, on="Material", how="left")) buffer_df["RecommendedBuffer"] = ( Z * buffer_df["Sigma"] * np.sqrt(buffer_df["LeadTime"] + review_period) ).round() buffer_df["Delta"] = buffer_df["RecommendedBuffer"] - buffer_df["OnHand"] buffer_df["Action"] = np.where(buffer_df["Delta"] > 50, "Increase buffer", np.where(buffer_df["Delta"] < -50, "Reduce buffer", "OK")) st.subheader("📋 Buffer Recommendations") display_cols = ["Material", "OnHand", "RecommendedBuffer", "Delta", "Action"] st.dataframe(buffer_df[display_cols], use_container_width=True, height=300) st.subheader("💰 Cost Impact Analysis") carrying_cost = st.number_input("Annual Carrying Cost (% of unit cost)", min_value=0, max_value=50, value=20) unit_cost = 100 buffer_df["CostImpact(₹)"] = (buffer_df["Delta"] * unit_cost * (carrying_cost/100) / 12) cost_chart_data = buffer_df.set_index("Material")["CostImpact(₹)"] st.bar_chart(cost_chart_data) st.subheader("⚡ Execute AI Recommendations") for _, row in buffer_df.iterrows(): if row["Action"] != "OK": if st.button(f"🚀 {row['Action']} for {row['Material']}", key=row["Material"]): st.success(f"AI executed: {row['Action']} - Adjusting {int(row['Delta'])} units for {row['Material']}") # Performance summary st.subheader("📊 Performance Summary") col1, col2, col3, col4 = st.columns(4) if dashboard_tab == "📊 Demand & Supply Forecast": filtered_df = filtered_df_demand if 'filtered_df_demand' in locals() else df_demand total_shortage_days = len(filtered_df[filtered_df['Shortfall'] > 0]) critical_shortage_days = len(filtered_df[filtered_df['Shortfall'] > 30]) materials_at_risk = len(filtered_df[filtered_df['Shortfall'] > 5]['Material'].unique()) avg_shortfall = filtered_df['Shortfall'].mean() with col1: st.metric("Days with Shortages", f"{total_shortage_days}") with col2: st.metric("Critical Days", f"{critical_shortage_days}") with col3: st.metric("Materials at Risk", f"{materials_at_risk}") with col4: st.metric("Avg Daily Shortfall", f"{avg_shortfall:.1f} units") elif dashboard_tab == "🌐 Ecosystem Supplier Impact": total_suppliers_disrupted = len(df_ecosystem[df_ecosystem['Is_Disrupted'] == True]['Supplier'].unique()) total_yazaki_impact_days = len(df_ecosystem[df_ecosystem['Is_Yazaki_Impacted'] == True]) total_mitigation_strategies = len([s for s in st.session_state.executed_mitigations if 'eco_' in s]) avg_lead_time = df_ecosystem['Lead_Time_Days'].mean() with col1: st.metric("Suppliers Disrupted", f"{total_suppliers_disrupted}") with col2: st.metric("Yazaki Impact Days", f"{total_yazaki_impact_days}") with col3: st.metric("Active Mitigations", f"{total_mitigation_strategies}") with col4: st.metric("Avg Lead Time", f"{avg_lead_time:.1f} days") else: # Buffer Optimizer if 'buffer_df' in locals(): total_materials = len(buffer_df) materials_need_increase = len(buffer_df[buffer_df['Action'] == 'Increase buffer']) materials_need_decrease = len(buffer_df[buffer_df['Action'] == 'Reduce buffer']) total_cost_impact = buffer_df['CostImpact(₹)'].sum() with col1: st.metric("Total Materials", f"{total_materials}") with col2: st.metric("Need Buffer Increase", f"{materials_need_increase}") with col3: st.metric("Need Buffer Reduction", f"{materials_need_decrease}") with col4: st.metric("Monthly Cost Impact", f"₹{total_cost_impact:,.0f}") # Footer st.markdown("---") st.markdown("""

🌐 Yazaki India Ltd 8-Week Supply Chain Command Center | Firm + AI-Corrected Demand | Ecosystem Intelligence + Buffer Optimization
Powered by Agentic AI | 8-Week Planning Horizon | Comprehensive Supply Chain Resilience

""", unsafe_allow_html=True)