Spaces:
Build error
Build error
Create ai_agents.py
Browse files- ai_agents.py +232 -0
ai_agents.py
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ai_agents.py
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import numpy as np
|
| 4 |
+
import openai
|
| 5 |
+
import json
|
| 6 |
+
from typing import Dict, List, Any
|
| 7 |
+
import streamlit as st
|
| 8 |
+
|
| 9 |
+
class LLMPoweredProcurementAgent:
|
| 10 |
+
"""AI Agent powered by OpenAI GPT for intelligent procurement analysis"""
|
| 11 |
+
|
| 12 |
+
def __init__(self, po_data: pd.DataFrame, spend_data: pd.DataFrame):
|
| 13 |
+
self.po_data = po_data
|
| 14 |
+
self.spend_data = spend_data
|
| 15 |
+
self.client = openai.OpenAI(api_key=st.secrets["OPENAI_API_KEY"])
|
| 16 |
+
|
| 17 |
+
def generate_executive_summary(self) -> str:
|
| 18 |
+
"""Generate an executive summary using GPT"""
|
| 19 |
+
|
| 20 |
+
# Prepare data summary for LLM
|
| 21 |
+
data_summary = {
|
| 22 |
+
"total_spend": float(self.po_data['order_value'].sum()),
|
| 23 |
+
"total_orders": len(self.po_data),
|
| 24 |
+
"unique_vendors": len(self.po_data['vendor'].unique()),
|
| 25 |
+
"avg_order_value": float(self.po_data['order_value'].mean()),
|
| 26 |
+
"on_time_delivery_rate": float(self.po_data['on_time_delivery'].mean()),
|
| 27 |
+
"top_vendors": self.po_data.groupby('vendor')['order_value'].sum().nlargest(3).to_dict(),
|
| 28 |
+
"top_categories": self.po_data.groupby('material_category')['order_value'].sum().nlargest(3).to_dict(),
|
| 29 |
+
"quality_score_avg": float(self.po_data['quality_score'].mean())
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
prompt = f"""
|
| 33 |
+
As a senior procurement analyst, provide an executive summary of the procurement performance based on this data:
|
| 34 |
+
|
| 35 |
+
{json.dumps(data_summary, indent=2)}
|
| 36 |
+
|
| 37 |
+
Please provide:
|
| 38 |
+
1. A concise executive overview (2-3 sentences)
|
| 39 |
+
2. Key performance highlights
|
| 40 |
+
3. Areas of concern (if any)
|
| 41 |
+
4. Strategic recommendations (2-3 bullet points)
|
| 42 |
+
|
| 43 |
+
Keep the tone professional and actionable. Focus on business impact.
|
| 44 |
+
"""
|
| 45 |
+
|
| 46 |
+
try:
|
| 47 |
+
response = self.client.chat.completions.create(
|
| 48 |
+
model="gpt-4",
|
| 49 |
+
messages=[
|
| 50 |
+
{"role": "system", "content": "You are an expert procurement analyst with 15+ years of experience in SAP S/4HANA systems."},
|
| 51 |
+
{"role": "user", "content": prompt}
|
| 52 |
+
],
|
| 53 |
+
max_tokens=500,
|
| 54 |
+
temperature=0.7
|
| 55 |
+
)
|
| 56 |
+
return response.choices[0].message.content
|
| 57 |
+
except Exception as e:
|
| 58 |
+
return f"AI Analysis temporarily unavailable: {str(e)}"
|
| 59 |
+
|
| 60 |
+
def analyze_vendor_performance(self, vendor_name: str) -> str:
|
| 61 |
+
"""Deep dive analysis of specific vendor using LLM"""
|
| 62 |
+
|
| 63 |
+
vendor_data = self.po_data[self.po_data['vendor'] == vendor_name]
|
| 64 |
+
|
| 65 |
+
if vendor_data.empty:
|
| 66 |
+
return f"No data found for vendor: {vendor_name}"
|
| 67 |
+
|
| 68 |
+
vendor_metrics = {
|
| 69 |
+
"total_orders": len(vendor_data),
|
| 70 |
+
"total_spend": float(vendor_data['order_value'].sum()),
|
| 71 |
+
"avg_order_value": float(vendor_data['order_value'].mean()),
|
| 72 |
+
"on_time_delivery": float(vendor_data['on_time_delivery'].mean()),
|
| 73 |
+
"quality_score": float(vendor_data['quality_score'].mean()),
|
| 74 |
+
"categories": vendor_data['material_category'].value_counts().to_dict(),
|
| 75 |
+
"recent_trends": vendor_data.tail(10)['order_value'].tolist()
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
prompt = f"""
|
| 79 |
+
Analyze the performance of vendor "{vendor_name}" based on this procurement data:
|
| 80 |
+
|
| 81 |
+
{json.dumps(vendor_metrics, indent=2)}
|
| 82 |
+
|
| 83 |
+
Provide:
|
| 84 |
+
1. Overall performance assessment
|
| 85 |
+
2. Strengths and weaknesses
|
| 86 |
+
3. Risk factors to monitor
|
| 87 |
+
4. Specific recommendations for relationship management
|
| 88 |
+
5. Contract negotiation talking points
|
| 89 |
+
|
| 90 |
+
Be specific and actionable in your recommendations.
|
| 91 |
+
"""
|
| 92 |
+
|
| 93 |
+
try:
|
| 94 |
+
response = self.client.chat.completions.create(
|
| 95 |
+
model="gpt-4",
|
| 96 |
+
messages=[
|
| 97 |
+
{"role": "system", "content": "You are a strategic sourcing expert specializing in vendor relationship management and contract negotiations."},
|
| 98 |
+
{"role": "user", "content": prompt}
|
| 99 |
+
],
|
| 100 |
+
max_tokens=600,
|
| 101 |
+
temperature=0.6
|
| 102 |
+
)
|
| 103 |
+
return response.choices[0].message.content
|
| 104 |
+
except Exception as e:
|
| 105 |
+
return f"Vendor analysis unavailable: {str(e)}"
|
| 106 |
+
|
| 107 |
+
def generate_anomaly_insights(self, anomalies: List[Dict]) -> str:
|
| 108 |
+
"""Generate natural language insights about detected anomalies"""
|
| 109 |
+
|
| 110 |
+
if not anomalies:
|
| 111 |
+
return "No significant anomalies detected in your procurement data. Your processes appear to be operating within normal parameters."
|
| 112 |
+
|
| 113 |
+
prompt = f"""
|
| 114 |
+
I've detected the following anomalies in procurement data:
|
| 115 |
+
|
| 116 |
+
{json.dumps(anomalies, indent=2)}
|
| 117 |
+
|
| 118 |
+
As a procurement risk specialist, please:
|
| 119 |
+
1. Explain what these anomalies might indicate
|
| 120 |
+
2. Assess the potential business impact
|
| 121 |
+
3. Provide immediate action steps
|
| 122 |
+
4. Suggest preventive measures for the future
|
| 123 |
+
|
| 124 |
+
Be specific about risks and prioritize the most critical issues.
|
| 125 |
+
"""
|
| 126 |
+
|
| 127 |
+
try:
|
| 128 |
+
response = self.client.chat.completions.create(
|
| 129 |
+
model="gpt-4",
|
| 130 |
+
messages=[
|
| 131 |
+
{"role": "system", "content": "You are a procurement risk management expert with deep knowledge of supply chain vulnerabilities and mitigation strategies."},
|
| 132 |
+
{"role": "user", "content": prompt}
|
| 133 |
+
],
|
| 134 |
+
max_tokens=500,
|
| 135 |
+
temperature=0.5
|
| 136 |
+
)
|
| 137 |
+
return response.choices[0].message.content
|
| 138 |
+
except Exception as e:
|
| 139 |
+
return f"Anomaly analysis unavailable: {str(e)}"
|
| 140 |
+
|
| 141 |
+
def chat_with_data(self, user_question: str) -> str:
|
| 142 |
+
"""Natural language interface to query procurement data"""
|
| 143 |
+
|
| 144 |
+
# Create a data context for the LLM
|
| 145 |
+
data_context = {
|
| 146 |
+
"procurement_summary": {
|
| 147 |
+
"total_spend": float(self.po_data['order_value'].sum()),
|
| 148 |
+
"order_count": len(self.po_data),
|
| 149 |
+
"vendor_count": len(self.po_data['vendor'].unique()),
|
| 150 |
+
"date_range": f"{self.po_data['order_date'].min()} to {self.po_data['order_date'].max()}",
|
| 151 |
+
"categories": self.po_data['material_category'].unique().tolist(),
|
| 152 |
+
"vendors": self.po_data['vendor'].unique().tolist()
|
| 153 |
+
},
|
| 154 |
+
"performance_metrics": {
|
| 155 |
+
"avg_quality_score": float(self.po_data['quality_score'].mean()),
|
| 156 |
+
"on_time_delivery_rate": float(self.po_data['on_time_delivery'].mean()),
|
| 157 |
+
"avg_order_value": float(self.po_data['order_value'].mean())
|
| 158 |
+
}
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
prompt = f"""
|
| 162 |
+
User Question: {user_question}
|
| 163 |
+
|
| 164 |
+
Procurement Data Context:
|
| 165 |
+
{json.dumps(data_context, indent=2)}
|
| 166 |
+
|
| 167 |
+
Please answer the user's question based on the procurement data provided. If you need specific calculations or data analysis that isn't available in the context, explain what additional analysis would be needed.
|
| 168 |
+
|
| 169 |
+
Keep your response conversational but professional, and always relate back to business impact where possible.
|
| 170 |
+
"""
|
| 171 |
+
|
| 172 |
+
try:
|
| 173 |
+
response = self.client.chat.completions.create(
|
| 174 |
+
model="gpt-4",
|
| 175 |
+
messages=[
|
| 176 |
+
{"role": "system", "content": "You are an AI procurement analyst assistant. Answer questions about procurement data in a helpful, conversational way while maintaining professional expertise."},
|
| 177 |
+
{"role": "user", "content": prompt}
|
| 178 |
+
],
|
| 179 |
+
max_tokens=400,
|
| 180 |
+
temperature=0.7
|
| 181 |
+
)
|
| 182 |
+
return response.choices[0].message.content
|
| 183 |
+
except Exception as e:
|
| 184 |
+
return f"I'm having trouble accessing the AI right now. Please try again later. Error: {str(e)}"
|
| 185 |
+
|
| 186 |
+
class IntelligentRiskAgent:
|
| 187 |
+
"""Risk assessment agent powered by OpenAI"""
|
| 188 |
+
|
| 189 |
+
def __init__(self, spend_data: pd.DataFrame):
|
| 190 |
+
self.spend_data = spend_data
|
| 191 |
+
self.client = openai.OpenAI(api_key=st.secrets["OPENAI_API_KEY"])
|
| 192 |
+
|
| 193 |
+
def generate_risk_report(self) -> str:
|
| 194 |
+
"""Generate comprehensive risk assessment using LLM"""
|
| 195 |
+
|
| 196 |
+
risk_data = {
|
| 197 |
+
"high_risk_suppliers": len(self.spend_data[self.spend_data['risk_score'] > 7]),
|
| 198 |
+
"total_suppliers": len(self.spend_data),
|
| 199 |
+
"avg_risk_score": float(self.spend_data['risk_score'].mean()),
|
| 200 |
+
"highest_risk_categories": self.spend_data.nlargest(5, 'risk_score')[['vendor', 'category', 'risk_score']].to_dict('records'),
|
| 201 |
+
"contract_compliance_avg": float(self.spend_data['contract_compliance'].mean()),
|
| 202 |
+
"low_compliance_count": len(self.spend_data[self.spend_data['contract_compliance'] < 85])
|
| 203 |
+
}
|
| 204 |
+
|
| 205 |
+
prompt = f"""
|
| 206 |
+
Generate a comprehensive supplier risk assessment report based on this data:
|
| 207 |
+
|
| 208 |
+
{json.dumps(risk_data, indent=2)}
|
| 209 |
+
|
| 210 |
+
Please provide:
|
| 211 |
+
1. Executive summary of risk landscape
|
| 212 |
+
2. Critical risk areas requiring immediate attention
|
| 213 |
+
3. Medium-term risk mitigation strategies
|
| 214 |
+
4. KPIs to monitor going forward
|
| 215 |
+
5. Recommended risk management framework improvements
|
| 216 |
+
|
| 217 |
+
Focus on actionable insights and business continuity.
|
| 218 |
+
"""
|
| 219 |
+
|
| 220 |
+
try:
|
| 221 |
+
response = self.client.chat.completions.create(
|
| 222 |
+
model="gpt-4",
|
| 223 |
+
messages=[
|
| 224 |
+
{"role": "system", "content": "You are a supply chain risk management consultant with expertise in enterprise risk frameworks and business continuity planning."},
|
| 225 |
+
{"role": "user", "content": prompt}
|
| 226 |
+
],
|
| 227 |
+
max_tokens=700,
|
| 228 |
+
temperature=0.6
|
| 229 |
+
)
|
| 230 |
+
return response.choices[0].message.content
|
| 231 |
+
except Exception as e:
|
| 232 |
+
return f"Risk analysis unavailable: {str(e)}"
|