Spaces:
Sleeping
Sleeping
| import pandas as pd | |
| import numpy as np | |
| from typing import Dict, List, Any | |
| import streamlit as st | |
| class ProcurementAgent: | |
| def __init__(self): | |
| self.insights = [] | |
| def analyze_spend_trends(self, df: pd.DataFrame) -> Dict[str, Any]: | |
| """Analyze spending trends and patterns""" | |
| try: | |
| # Monthly spend analysis | |
| df['PO_Date'] = pd.to_datetime(df['PO_Date']) | |
| monthly_spend = df.groupby(df['PO_Date'].dt.to_period('M'))['Total_Value'].sum() | |
| # Calculate trend | |
| if len(monthly_spend) > 1: | |
| trend = "increasing" if monthly_spend.iloc[-1] > monthly_spend.iloc[-2] else "decreasing" | |
| else: | |
| trend = "stable" | |
| # Top categories | |
| category_spend = df.groupby('Category')['Total_Value'].sum().sort_values(ascending=False) | |
| insights = { | |
| 'total_spend': df['Total_Value'].sum(), | |
| 'monthly_trend': trend, | |
| 'top_category': category_spend.index[0], | |
| 'top_category_spend': category_spend.iloc[0], | |
| 'avg_po_value': df['Total_Value'].mean(), | |
| 'recommendations': self._generate_spend_recommendations(df) | |
| } | |
| return insights | |
| except Exception as e: | |
| st.error(f"Error in spend analysis: {str(e)}") | |
| return {} | |
| def analyze_supplier_performance(self, df: pd.DataFrame) -> Dict[str, Any]: | |
| """Analyze supplier performance metrics""" | |
| try: | |
| supplier_metrics = df.groupby('Supplier').agg({ | |
| 'Total_Value': 'sum', | |
| 'Delivery_Performance': 'mean', | |
| 'PO_Number': 'count' | |
| }).round(2) | |
| # Best and worst performers | |
| best_supplier = supplier_metrics.loc[supplier_metrics['Delivery_Performance'].idxmax()] | |
| worst_supplier = supplier_metrics.loc[supplier_metrics['Delivery_Performance'].idxmin()] | |
| insights = { | |
| 'best_performer': { | |
| 'name': best_supplier.name, | |
| 'performance': best_supplier['Delivery_Performance'] | |
| }, | |
| 'worst_performer': { | |
| 'name': worst_supplier.name, | |
| 'performance': worst_supplier['Delivery_Performance'] | |
| }, | |
| 'recommendations': self._generate_supplier_recommendations(supplier_metrics) | |
| } | |
| return insights | |
| except Exception as e: | |
| st.error(f"Error in supplier analysis: {str(e)}") | |
| return {} | |
| def detect_anomalies(self, df: pd.DataFrame) -> List[Dict[str, Any]]: | |
| """Detect procurement anomalies""" | |
| anomalies = [] | |
| try: | |
| # High value orders | |
| threshold = df['Total_Value'].quantile(0.95) | |
| high_value_orders = df[df['Total_Value'] > threshold] | |
| for _, order in high_value_orders.iterrows(): | |
| anomalies.append({ | |
| 'type': 'High Value Order', | |
| 'po_number': order['PO_Number'], | |
| 'value': order['Total_Value'], | |
| 'supplier': order['Supplier'], | |
| 'risk_level': 'Medium' if order['Total_Value'] < threshold * 1.5 else 'High' | |
| }) | |
| # Overdue deliveries | |
| df['PO_Date'] = pd.to_datetime(df['PO_Date']) | |
| df['Delivery_Date'] = pd.to_datetime(df['Delivery_Date']) | |
| overdue = df[ | |
| (df['Delivery_Date'] < pd.Timestamp.now()) & | |
| (df['Status'] == 'Open') | |
| ] | |
| for _, order in overdue.iterrows(): | |
| days_overdue = (pd.Timestamp.now() - order['Delivery_Date']).days | |
| anomalies.append({ | |
| 'type': 'Overdue Delivery', | |
| 'po_number': order['PO_Number'], | |
| 'days_overdue': days_overdue, | |
| 'supplier': order['Supplier'], | |
| 'risk_level': 'High' if days_overdue > 30 else 'Medium' | |
| }) | |
| except Exception as e: | |
| st.error(f"Error in anomaly detection: {str(e)}") | |
| return anomalies[:10] # Return top 10 anomalies | |
| def _generate_spend_recommendations(self, df: pd.DataFrame) -> List[str]: | |
| """Generate AI-powered spending recommendations""" | |
| recommendations = [] | |
| # Category concentration analysis | |
| category_spend = df.groupby('Category')['Total_Value'].sum() | |
| total_spend = category_spend.sum() | |
| for category, spend in category_spend.items(): | |
| percentage = (spend / total_spend) * 100 | |
| if percentage > 30: | |
| recommendations.append(f"π― Consider diversifying suppliers in {category} (represents {percentage:.1f}% of total spend)") | |
| # Supplier dependency | |
| supplier_spend = df.groupby('Supplier')['Total_Value'].sum() | |
| for supplier, spend in supplier_spend.items(): | |
| percentage = (spend / total_spend) * 100 | |
| if percentage > 25: | |
| recommendations.append(f"β οΈ High dependency on {supplier} ({percentage:.1f}% of spend) - consider risk mitigation") | |
| # Price optimization | |
| avg_unit_prices = df.groupby('Category')['Unit_Price'].mean() | |
| recommendations.append("π‘ Implement category-specific negotiation strategies for cost optimization") | |
| return recommendations[:5] | |
| def _generate_supplier_recommendations(self, supplier_metrics: pd.DataFrame) -> List[str]: | |
| """Generate supplier performance recommendations""" | |
| recommendations = [] | |
| # Performance-based recommendations | |
| poor_performers = supplier_metrics[supplier_metrics['Delivery_Performance'] < 90] | |
| if not poor_performers.empty: | |
| recommendations.append(f"π Develop improvement plans for {len(poor_performers)} underperforming suppliers") | |
| # Volume-based recommendations | |
| high_volume_suppliers = supplier_metrics[supplier_metrics['PO_Number'] > supplier_metrics['PO_Number'].quantile(0.8)] | |
| recommendations.append(f"π€ Consider strategic partnerships with top {len(high_volume_suppliers)} high-volume suppliers") | |
| recommendations.append("π Implement regular supplier audits and performance reviews") | |
| recommendations.append("π Set up automated alerts for delivery performance degradation") | |
| return recommendations[:4] | |
| def generate_insights(self, po_data: pd.DataFrame, supplier_data: pd.DataFrame) -> Dict[str, Any]: | |
| """Generate comprehensive procurement insights""" | |
| spend_insights = self.analyze_spend_trends(po_data) | |
| supplier_insights = self.analyze_supplier_performance(po_data) | |
| anomalies = self.detect_anomalies(po_data) | |
| return { | |
| 'spend_analysis': spend_insights, | |
| 'supplier_analysis': supplier_insights, | |
| 'anomalies': anomalies, | |
| 'summary': self._generate_executive_summary(spend_insights, supplier_insights, anomalies) | |
| } | |
| def _generate_executive_summary(self, spend_insights: Dict, supplier_insights: Dict, anomalies: List) -> str: | |
| """Generate executive summary""" | |
| try: | |
| total_spend = spend_insights.get('total_spend', 0) | |
| trend = spend_insights.get('monthly_trend', 'stable') | |
| best_supplier = supplier_insights.get('best_performer', {}).get('name', 'N/A') | |
| anomaly_count = len(anomalies) | |
| summary = f""" | |
| π **Procurement Analytics Summary** | |
| β’ Total Spend: ${total_spend:,.2f} | |
| β’ Spending Trend: {trend.title()} | |
| β’ Best Performing Supplier: {best_supplier} | |
| β’ Critical Issues Detected: {anomaly_count} | |
| β’ Overall Health: {'Good' if anomaly_count < 5 else 'Needs Attention'} | |
| """ | |
| return summary | |
| except: | |
| return "π **Procurement Analytics Summary**\n\nData processing in progress..." | |