PurchaseAgent / src /streamlit_app.py
PD03's picture
Update src/streamlit_app.py
af1c55a verified
raw
history blame
33.8 kB
import streamlit as st
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from streamlit_option_menu import option_menu
import time
from faker import Faker
from datetime import datetime, timedelta
import random
import json
from typing import Dict, List, Any
import os
# Page configuration
st.set_page_config(
page_title="SAP S/4HANA Agentic AI Procurement Analytics",
page_icon="πŸ€–",
layout="wide",
initial_sidebar_state="expanded"
)
# Custom CSS
st.markdown("""
<style>
/* Main theme colors */
:root {
--primary-color: #0066cc;
--secondary-color: #f0f8ff;
--accent-color: #ff6b35;
--success-color: #28a745;
--warning-color: #ffc107;
--danger-color: #dc3545;
}
/* Hide Streamlit branding */
#MainMenu {visibility: hidden;}
footer {visibility: hidden;}
header {visibility: hidden;}
/* Custom header styling */
.main-header {
background: linear-gradient(90deg, #0066cc, #004c99);
padding: 1rem;
border-radius: 10px;
margin-bottom: 2rem;
color: white;
text-align: center;
}
/* Metric cards styling */
.metric-card {
background: white;
padding: 1.5rem;
border-radius: 10px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
border-left: 4px solid var(--primary-color);
margin-bottom: 1rem;
}
/* AI insights styling */
.ai-insight {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 1rem;
border-radius: 10px;
margin: 1rem 0;
}
/* Alert styling */
.alert {
padding: 1rem;
border-radius: 8px;
margin: 1rem 0;
border-left: 4px solid;
}
.alert-success {
background-color: #d4edda;
border-color: var(--success-color);
color: #155724;
}
.alert-warning {
background-color: #fff3cd;
border-color: var(--warning-color);
color: #856404;
}
.alert-info {
background-color: #d1ecf1;
border-color: #17a2b8;
color: #0c5460;
}
/* Button styling */
.stButton > button {
background: linear-gradient(90deg, #0066cc, #004c99);
color: white;
border: none;
border-radius: 8px;
padding: 0.5rem 1rem;
font-weight: 600;
transition: all 0.3s ease;
}
.stButton > button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
</style>
""", unsafe_allow_html=True)
# Function to safely get OpenAI API key
def get_openai_api_key():
"""Safely retrieve OpenAI API key from various sources"""
api_key = None
# Method 1: Try from Streamlit secrets
try:
if hasattr(st, 'secrets') and 'OPENAI_API_KEY' in st.secrets:
api_key = st.secrets["OPENAI_API_KEY"]
except Exception:
pass
# Method 2: Try from environment variables
if not api_key:
api_key = os.getenv('OPENAI_API_KEY')
# Method 3: Try from Hugging Face Spaces environment
if not api_key:
api_key = os.getenv('OPENAI_API_TOKEN') # Sometimes HF uses this
return api_key
# Data generation function
@st.cache_data
def generate_synthetic_procurement_data():
"""Generate synthetic SAP S/4HANA procurement data"""
fake = Faker()
np.random.seed(42) # For reproducible data
random.seed(42)
# Vendors data
vendors = [
"Siemens AG", "BASF SE", "BMW Group", "Mercedes-Benz", "Bosch GmbH",
"ThyssenKrupp", "Bayer AG", "Continental AG", "Henkel AG", "SAP SE"
]
# Material categories
material_categories = [
"Raw Materials", "Components", "Packaging", "Services",
"IT Equipment", "Office Supplies", "Machinery", "Chemicals"
]
# Generate purchase orders
purchase_orders = []
for i in range(500):
order_date = fake.date_between(start_date='-2y', end_date='today')
delivery_date = order_date + timedelta(days=random.randint(1, 30))
po = {
'po_number': f"PO{str(i+1).zfill(6)}",
'vendor': random.choice(vendors),
'material_category': random.choice(material_categories),
'order_date': order_date,
'delivery_date': delivery_date,
'order_value': round(random.uniform(1000, 100000), 2),
'quantity': random.randint(1, 1000),
'unit_price': round(random.uniform(10, 500), 2),
'status': random.choice(['Open', 'Delivered', 'Invoiced', 'Paid']),
'plant': random.choice(['Plant_001', 'Plant_002', 'Plant_003']),
'buyer': fake.name(),
'currency': 'EUR',
'payment_terms': random.choice(['30 Days', '60 Days', '90 Days']),
'on_time_delivery': random.choice([True, False]),
'quality_score': round(random.uniform(7, 10), 1)
}
purchase_orders.append(po)
# Generate spend analytics data
spend_data = []
for vendor in vendors:
for category in material_categories:
spend = {
'vendor': vendor,
'category': category,
'total_spend': round(random.uniform(10000, 500000), 2),
'contract_compliance': round(random.uniform(80, 100), 1),
'risk_score': round(random.uniform(1, 10), 1),
'savings_potential': round(random.uniform(5, 25), 1)
}
spend_data.append(spend)
return pd.DataFrame(purchase_orders), pd.DataFrame(spend_data)
# AI Agent Classes
class LLMPoweredProcurementAgent:
"""AI Agent powered by OpenAI GPT for intelligent procurement analysis"""
def __init__(self, po_data: pd.DataFrame, spend_data: pd.DataFrame):
self.po_data = po_data
self.spend_data = spend_data
# Safely get OpenAI API key
self.api_key = get_openai_api_key()
self.llm_available = bool(self.api_key)
if self.llm_available:
try:
import openai
self.client = openai.OpenAI(api_key=self.api_key)
except ImportError:
self.llm_available = False
self.client = None
else:
self.client = None
def generate_executive_summary(self) -> str:
"""Generate an executive summary using GPT or fallback"""
if not self.llm_available:
# Enhanced rule-based summary if no API key
total_spend = self.po_data['order_value'].sum()
total_orders = len(self.po_data)
on_time_rate = self.po_data['on_time_delivery'].mean() * 100
quality_avg = self.po_data['quality_score'].mean()
top_category = self.po_data.groupby('material_category')['order_value'].sum().idxmax()
top_vendor = self.po_data.groupby('vendor')['order_value'].sum().idxmax()
return f"""**🎯 Executive Summary - Procurement Performance Dashboard**
πŸ“Š **Current Portfolio Overview**
β€’ Total procurement spend: €{total_spend:,.0f} across {total_orders:,} purchase orders
β€’ Active vendor network: {len(self.po_data['vendor'].unique())} strategic suppliers
β€’ Average order value: €{self.po_data['order_value'].mean():,.0f}
πŸ† **Performance Highlights**
β€’ On-time delivery performance: {on_time_rate:.1f}% (Industry benchmark: 85%)
β€’ Average supplier quality score: {quality_avg:.1f}/10
β€’ Leading spend category: {top_category}
β€’ Top strategic partner: {top_vendor}
⚑ **Strategic Opportunities**
β€’ Vendor consolidation potential identified in {len(self.po_data['vendor'].unique())} supplier base
β€’ Contract optimization opportunities with top-tier vendors
β€’ Digital procurement automation possibilities for routine purchases
πŸ’‘ **AI-Powered Recommendations**
β€’ Implement strategic sourcing for {top_category} category
β€’ Develop performance-based contracts with high-performing suppliers
β€’ Establish automated approval workflows for orders under €10,000
*πŸ”§ Note: Connect OpenAI API for advanced AI insights and natural language analysis*"""
# Prepare data summary for LLM
data_summary = {
"total_spend": float(self.po_data['order_value'].sum()),
"total_orders": len(self.po_data),
"unique_vendors": len(self.po_data['vendor'].unique()),
"avg_order_value": float(self.po_data['order_value'].mean()),
"on_time_delivery_rate": float(self.po_data['on_time_delivery'].mean()),
"top_vendors": self.po_data.groupby('vendor')['order_value'].sum().nlargest(3).to_dict(),
"top_categories": self.po_data.groupby('material_category')['order_value'].sum().nlargest(3).to_dict(),
"quality_score_avg": float(self.po_data['quality_score'].mean())
}
prompt = f"""
As a senior procurement analyst with expertise in SAP S/4HANA systems, provide an executive summary of procurement performance:
Data: {json.dumps(data_summary, indent=2)}
Provide:
1. Executive overview (2-3 sentences)
2. Key performance highlights with specific metrics
3. Critical areas needing attention
4. Strategic recommendations (3-4 actionable items)
Keep it professional, metrics-focused, and actionable for C-level executives.
"""
try:
response = self.client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "You are a senior procurement analyst with 15+ years of SAP S/4HANA experience."},
{"role": "user", "content": prompt}
],
max_tokens=600,
temperature=0.7
)
return response.choices[0].message.content
except Exception as e:
return f"πŸ€– AI Analysis temporarily unavailable. Using rule-based insights instead.\n\n{self.generate_executive_summary()}"
def chat_with_data(self, user_question: str) -> str:
"""Natural language interface to query procurement data"""
if not self.llm_available:
# Enhanced rule-based responses
question_lower = user_question.lower()
if any(word in question_lower for word in ["spend", "cost", "money", "budget"]):
total_spend = self.po_data['order_value'].sum()
top_category = self.po_data.groupby('material_category')['order_value'].sum().idxmax()
monthly_avg = total_spend / 24 # Assuming 2 years of data
return f"""πŸ’° **Spend Analysis:**
β€’ **Total procurement spend**: €{total_spend:,.0f}
β€’ **Monthly average**: €{monthly_avg:,.0f}
β€’ **Largest spend category**: {top_category}
β€’ **Average order size**: €{self.po_data['order_value'].mean():,.0f}
The spending is distributed across {len(self.po_data['material_category'].unique())} categories with {top_category} representing the highest investment area.
*πŸ’‘ Connect OpenAI API for detailed spend optimization strategies!*"""
elif any(word in question_lower for word in ["vendor", "supplier", "partner"]):
top_vendor = self.po_data.groupby('vendor')['order_value'].sum().idxmax()
vendor_count = len(self.po_data['vendor'].unique())
top_vendor_performance = self.po_data[self.po_data['vendor'] == top_vendor]['on_time_delivery'].mean() * 100
return f"""🀝 **Vendor Analysis:**
β€’ **Total active vendors**: {vendor_count}
β€’ **Top strategic partner**: {top_vendor}
β€’ **{top_vendor} performance**: {top_vendor_performance:.1f}% on-time delivery
β€’ **Vendor diversity**: Well-distributed across multiple suppliers
Your vendor portfolio shows good diversification with {top_vendor} as the leading partner.
*πŸ’‘ Connect OpenAI API for detailed vendor relationship strategies!*"""
elif any(word in question_lower for word in ["risk", "compliance", "quality"]):
avg_quality = self.po_data['quality_score'].mean()
on_time_rate = self.po_data['on_time_delivery'].mean() * 100
return f"""⚠️ **Risk & Quality Analysis:**
β€’ **Average quality score**: {avg_quality:.1f}/10
β€’ **On-time delivery rate**: {on_time_rate:.1f}%
β€’ **Performance status**: {'Excellent' if avg_quality > 8.5 else 'Good' if avg_quality > 7.5 else 'Needs Improvement'}
Overall risk profile appears {'low' if on_time_rate > 85 else 'moderate'} based on delivery performance metrics.
*πŸ’‘ Connect OpenAI API for comprehensive risk assessment!*"""
elif any(word in question_lower for word in ["trend", "pattern", "analysis"]):
return f"""πŸ“ˆ **Trend Analysis:**
β€’ **Data period**: {self.po_data['order_date'].min()} to {self.po_data['order_date'].max()}
β€’ **Total orders processed**: {len(self.po_data):,}
β€’ **Peak category**: {self.po_data.groupby('material_category')['order_value'].sum().idxmax()}
β€’ **Seasonal patterns**: Data shows consistent procurement activity
Historical data indicates stable procurement operations with opportunities for optimization.
*πŸ’‘ Connect OpenAI API for advanced trend forecasting!*"""
else:
return f"""πŸ€– **Procurement Assistant Ready!**
I can help you analyze:
β€’ πŸ’° **Spending patterns** and budget optimization
β€’ 🀝 **Vendor performance** and relationship management
β€’ ⚠️ **Risk assessment** and quality metrics
β€’ πŸ“ˆ **Trends and forecasting** for strategic planning
**Current data scope**: {len(self.po_data):,} orders across {len(self.po_data['vendor'].unique())} vendors
Try asking: "What are my biggest spending areas?" or "How are my vendors performing?"
*πŸ’‘ Connect OpenAI API for natural language conversations and advanced insights!*"""
# LLM-powered response
data_context = {
"procurement_summary": {
"total_spend": float(self.po_data['order_value'].sum()),
"order_count": len(self.po_data),
"vendor_count": len(self.po_data['vendor'].unique()),
"date_range": f"{self.po_data['order_date'].min()} to {self.po_data['order_date'].max()}",
"categories": self.po_data['material_category'].unique().tolist(),
"vendors": self.po_data['vendor'].unique().tolist()
},
"performance_metrics": {
"avg_quality_score": float(self.po_data['quality_score'].mean()),
"on_time_delivery_rate": float(self.po_data['on_time_delivery'].mean()),
"avg_order_value": float(self.po_data['order_value'].mean())
}
}
prompt = f"""
User Question: {user_question}
Procurement Data Context:
{json.dumps(data_context, indent=2)}
Answer the user's question based on the procurement data. Be conversational yet professional.
Include specific metrics when relevant and relate findings to business impact.
If you need additional data not available in the context, suggest what analysis would be helpful.
"""
try:
response = self.client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "You are an expert procurement analyst assistant. Provide helpful, professional responses about procurement data and strategy."},
{"role": "user", "content": prompt}
],
max_tokens=500,
temperature=0.7
)
return response.choices[0].message.content
except Exception as e:
return f"I'm having trouble accessing advanced AI right now. Here's what I can tell you based on the data:\n\n{self.chat_with_data(user_question)}"
def analyze_spend_patterns(self) -> Dict[str, Any]:
"""Analyze spending patterns and generate insights"""
total_spend = self.po_data['order_value'].sum()
avg_order_value = self.po_data['order_value'].mean()
# Top spending categories
category_spend = self.po_data.groupby('material_category')['order_value'].sum().sort_values(ascending=False)
# Vendor performance analysis
vendor_performance = self.po_data.groupby('vendor').agg({
'order_value': 'sum',
'on_time_delivery': 'mean',
'quality_score': 'mean'
}).round(2)
return {
'total_spend': total_spend,
'avg_order_value': avg_order_value,
'top_categories': category_spend.to_dict(),
'vendor_performance': vendor_performance.to_dict('index')
}
# Initialize session state and data
if 'data_loaded' not in st.session_state:
with st.spinner('πŸ”„ Generating synthetic SAP S/4HANA procurement data...'):
st.session_state.po_df, st.session_state.spend_df = generate_synthetic_procurement_data()
st.session_state.data_loaded = True
# Initialize AI agents
@st.cache_resource
def initialize_agents():
analytics_agent = LLMPoweredProcurementAgent(st.session_state.po_df, st.session_state.spend_df)
return analytics_agent
analytics_agent = initialize_agents()
# API Key status check
api_key = get_openai_api_key()
api_key_status = "🟒 Connected" if api_key else "πŸ”΄ Not Connected"
# Main header
st.markdown(f"""
<div class="main-header">
<h1>πŸ€– SAP S/4HANA Agentic AI Procurement Analytics</h1>
<p>Autonomous Intelligence for Procurement Excellence</p>
<small>OpenAI Status: {api_key_status} | Data: {len(st.session_state.po_df):,} Purchase Orders</small>
</div>
""", unsafe_allow_html=True)
# Sidebar navigation
with st.sidebar:
st.markdown("### πŸ€– AI-Powered Analytics")
st.markdown(f"**OpenAI Status:** {api_key_status}")
if not api_key:
st.markdown("""
<div class="alert alert-info">
<small><strong>πŸ’‘ Enhanced AI Features</strong><br>
Add OpenAI API key as OPENAI_API_KEY in your Hugging Face Space settings for advanced AI conversations and insights!</small>
</div>
""", unsafe_allow_html=True)
st.markdown("---")
selected = option_menu(
"Navigation",
["🏠 Dashboard", "πŸ’¬ AI Chat", "πŸ“Š Analytics", "🎯 Recommendations"],
icons=['house', 'chat', 'graph-up', 'target'],
menu_icon="cast",
default_index=0,
styles={
"container": {"padding": "0!important", "background-color": "#fafafa"},
"icon": {"color": "#0066cc", "font-size": "18px"},
"nav-link": {"font-size": "16px", "text-align": "left", "margin": "0px", "--hover-color": "#eee"},
"nav-link-selected": {"background-color": "#0066cc"},
}
)
st.markdown("---")
st.markdown("### πŸ“Š Quick Stats")
st.metric("Total Orders", f"{len(st.session_state.po_df):,}")
st.metric("Active Vendors", f"{len(st.session_state.po_df['vendor'].unique())}")
st.metric("Categories", f"{len(st.session_state.po_df['material_category'].unique())}")
if selected == "🏠 Dashboard":
# AI-generated insights at the top
st.markdown("### 🧠 AI Executive Summary")
with st.spinner('πŸ€– AI analyzing procurement data...'):
executive_summary = analytics_agent.generate_executive_summary()
st.markdown(f"""
<div class="ai-insight">
<h4>πŸ“Š Intelligent Analysis</h4>
<div style="white-space: pre-line; line-height: 1.6;">{executive_summary}</div>
</div>
""", unsafe_allow_html=True)
# Key metrics
insights = analytics_agent.analyze_spend_patterns()
col1, col2, col3, col4 = st.columns(4)
with col1:
st.markdown("""
<div class="metric-card">
<h3 style="color: var(--primary-color); margin: 0;">Total Spend</h3>
<h2 style="margin: 0.5rem 0;">€{:,.0f}</h2>
<p style="color: #28a745; margin: 0;">πŸ“ˆ Active Portfolio</p>
</div>
""".format(insights['total_spend']), unsafe_allow_html=True)
with col2:
st.markdown("""
<div class="metric-card">
<h3 style="color: var(--primary-color); margin: 0;">Avg Order Value</h3>
<h2 style="margin: 0.5rem 0;">€{:,.0f}</h2>
<p style="color: #17a2b8; margin: 0;">πŸ“Š Order Efficiency</p>
</div>
""".format(insights['avg_order_value']), unsafe_allow_html=True)
with col3:
active_vendors = len(st.session_state.po_df['vendor'].unique())
st.markdown("""
<div class="metric-card">
<h3 style="color: var(--primary-color); margin: 0;">Active Vendors</h3>
<h2 style="margin: 0.5rem 0;">{}</h2>
<p style="color: #6f42c1; margin: 0;">🀝 Strategic Partners</p>
</div>
""".format(active_vendors), unsafe_allow_html=True)
with col4:
on_time_delivery = st.session_state.po_df['on_time_delivery'].mean() * 100
st.markdown("""
<div class="metric-card">
<h3 style="color: var(--primary-color); margin: 0;">On-Time Delivery</h3>
<h2 style="margin: 0.5rem 0;">{:.1f}%</h2>
<p style="color: #28a745; margin: 0;">⏰ Performance</p>
</div>
""".format(on_time_delivery), unsafe_allow_html=True)
# Charts
st.markdown("### πŸ“Š Executive Dashboard")
col1, col2 = st.columns(2)
with col1:
# Spend by category
category_spend = st.session_state.po_df.groupby('material_category')['order_value'].sum().reset_index()
fig_pie = px.pie(
category_spend,
values='order_value',
names='material_category',
title='Spend Distribution by Category',
color_discrete_sequence=px.colors.qualitative.Set3
)
fig_pie.update_layout(
title_font_size=16,
title_x=0.5,
showlegend=True,
height=400
)
st.plotly_chart(fig_pie, use_container_width=True)
with col2:
# Top vendors
vendor_spend = st.session_state.po_df.groupby('vendor')['order_value'].sum().reset_index()
vendor_spend = vendor_spend.nlargest(8, 'order_value')
fig_bar = px.bar(
vendor_spend,
x='vendor',
y='order_value',
title='Top Vendors by Spend',
color='order_value',
color_continuous_scale='Blues'
)
fig_bar.update_layout(
title_font_size=16,
title_x=0.5,
xaxis_tickangle=45,
height=400
)
st.plotly_chart(fig_bar, use_container_width=True)
elif selected == "πŸ’¬ AI Chat":
st.markdown("### πŸ’¬ Chat with Your Procurement Data")
st.markdown(f"""
<div class="ai-insight">
<h4>πŸ€– Intelligent Procurement Assistant</h4>
<p>Ask me anything about your procurement data! I can analyze trends, vendor performance, spending patterns, and provide strategic recommendations.</p>
<p><small>Status: {api_key_status}</small></p>
</div>
""", unsafe_allow_html=True)
# Chat interface
if "messages" not in st.session_state:
st.session_state.messages = [
{"role": "assistant", "content": "Hello! I'm your AI procurement analyst. I've analyzed your procurement portfolio and I'm ready to help! What would you like to explore?"}
]
# Display chat messages
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
# Chat input
if prompt := st.chat_input("Ask about your procurement data..."):
# Add user message to chat history
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("user"):
st.markdown(prompt)
# Generate AI response
with st.chat_message("assistant"):
with st.spinner("πŸ€– Analyzing your question..."):
response = analytics_agent.chat_with_data(prompt)
st.markdown(response)
# Add assistant response to chat history
st.session_state.messages.append({"role": "assistant", "content": response})
# Suggested questions
st.markdown("#### πŸ’‘ Try these sample questions:")
col1, col2, col3 = st.columns(3)
sample_questions = [
"What are my biggest spending areas?",
"How are my vendors performing?",
"What risks should I be concerned about?"
]
for i, (col, question) in enumerate(zip([col1, col2, col3], sample_questions)):
with col:
if st.button(f"πŸ’­ {question}", key=f"q_{i}"):
# Add the question to chat
st.session_state.messages.append({"role": "user", "content": question})
with st.spinner("πŸ€– Analyzing..."):
response = analytics_agent.chat_with_data(question)
st.session_state.messages.append({"role": "assistant", "content": response})
st.rerun()
# Clear chat button
if st.button("πŸ—‘οΈ Clear Chat History"):
st.session_state.messages = [
{"role": "assistant", "content": "Chat cleared! What would you like to know about your procurement data?"}
]
st.rerun()
elif selected == "πŸ“Š Analytics":
st.markdown("### πŸ“ˆ Advanced Analytics Dashboard")
# Vendor performance analysis
st.markdown("#### πŸ† Vendor Performance Scorecard")
vendor_performance = st.session_state.po_df.groupby('vendor').agg({
'order_value': 'sum',
'on_time_delivery': 'mean',
'quality_score': 'mean',
'po_number': 'count'
}).round(2)
vendor_performance.columns = ['Total Spend (€)', 'On-Time Delivery (%)', 'Quality Score', 'Order Count']
vendor_performance['On-Time Delivery (%)'] = (vendor_performance['On-Time Delivery (%)'] * 100).round(1)
vendor_performance = vendor_performance.sort_values('Total Spend (€)', ascending=False)
st.dataframe(
vendor_performance.head(10),
use_container_width=True,
column_config={
"Total Spend (€)": st.column_config.NumberColumn(
"Total Spend (€)",
help="Total procurement spend with vendor",
format="€%.0f",
),
"On-Time Delivery (%)": st.column_config.NumberColumn(
"On-Time Delivery (%)",
help="Percentage of on-time deliveries",
format="%.1f%%",
),
"Quality Score": st.column_config.NumberColumn(
"Quality Score",
help="Average quality rating (1-10)",
format="%.1f/10",
)
}
)
# Performance charts
col1, col2 = st.columns(2)
with col1:
# Performance scatter plot
fig_scatter = px.scatter(
st.session_state.po_df,
x='on_time_delivery',
y='quality_score',
size='order_value',
color='vendor',
title='Vendor Performance Matrix',
labels={'on_time_delivery': 'On-Time Delivery Rate', 'quality_score': 'Quality Score (1-10)'},
hover_data=['vendor', 'order_value']
)
fig_scatter.update_layout(height=500, showlegend=False)
st.plotly_chart(fig_scatter, use_container_width=True)
with col2:
# Monthly trend
st.session_state.po_df['order_month'] = pd.to_datetime(st.session_state.po_df['order_date']).dt.to_period('M')
monthly_trend = st.session_state.po_df.groupby('order_month')['order_value'].sum().reset_index()
monthly_trend['order_month'] = monthly_trend['order_month'].astype(str)
fig_trend = px.line(
monthly_trend,
x='order_month',
y='order_value',
title='Monthly Procurement Spend Trend',
markers=True
)
fig_trend.update_layout(
height=500,
xaxis_tickangle=45
)
fig_trend.update_traces(line_color='#0066cc', line_width=3, marker_size=8)
st.plotly_chart(fig_trend, use_container_width=True)
elif selected == "🎯 Recommendations":
st.markdown("### πŸš€ Strategic Procurement Recommendations")
st.markdown("""
<div class="ai-insight">
<h3>🎯 AI-Powered Strategic Optimization</h3>
<p>Based on comprehensive data analysis, here are prioritized recommendations to enhance your procurement strategy and drive business value.</p>
</div>
""", unsafe_allow_html=True)
# Calculate some metrics for recommendations
vendor_count = len(st.session_state.po_df['vendor'].unique())
avg_order_value = st.session_state.po_df['order_value'].mean()
low_value_orders = len(st.session_state.po_df[st.session_state.po_df['order_value'] < 5000])
total_orders = len(st.session_state.po_df)
recommendations = [
{
"priority": "πŸ”₯ High Priority",
"title": "Vendor Consolidation Strategy",
"description": f"With {vendor_count} active vendors, consolidating to 5-7 strategic partners could reduce costs by 12-18% and improve relationship management.",
"impact": "πŸ’° Cost Reduction: €50K-75K annually",
"timeline": "3-6 months"
},
{
"priority": "⚑ Quick Win",
"title": "Procurement Process Automation",
"description": f"{low_value_orders}/{total_orders} orders ({low_value_orders/total_orders*100:.1f}%) are under €5,000. Implementing automated approval workflows could save 40+ hours weekly.",
"impact": "⏱️ Efficiency Gain: 160 hours/month",
"timeline": "4-8 weeks"
},
{
"priority": "πŸ“ˆ Strategic",
"title": "Performance-Based Contracts",
"description": "Implement KPI-driven contracts with top 5 vendors focusing on quality scores >8.5 and delivery performance >90%.",
"impact": "πŸ“Š Performance Improvement: 15-25%",
"timeline": "6-9 months"
},
{
"priority": "πŸ›‘οΈ Risk Management",
"title": "Supplier Risk Monitoring",
"description": "Deploy real-time risk assessment tools to monitor supplier financial health, compliance, and performance metrics.",
"impact": "⚠️ Risk Reduction: 30-40%",
"timeline": "2-4 months"
},
{
"priority": "🎯 Innovation",
"title": "Digital Procurement Platform",
"description": "Upgrade to AI-powered procurement platform with predictive analytics, spend optimization, and automated sourcing capabilities.",
"impact": "πŸš€ Digital Transformation: 25-35% efficiency",
"timeline": "9-12 months"
}
]
for i, rec in enumerate(recommendations, 1):
priority_color = {"πŸ”₯ High Priority": "#dc3545", "⚑ Quick Win": "#28a745", "πŸ“ˆ Strategic": "#0066cc", "πŸ›‘οΈ Risk Management": "#ffc107", "🎯 Innovation": "#6f42c1"}
st.markdown(f"""
<div class="alert alert-success">
<h4 style="color: {priority_color[rec['priority']]};">{rec['priority']}</h4>
<h3>{rec['title']}</h3>
<p style="margin-bottom: 1rem;">{rec['description']}</p>
<div style="display: flex; justify-content: space-between; font-size: 0.9rem;">
<span><strong>{rec['impact']}</strong></span>
<span><strong>⏱️ Timeline: {rec['timeline']}</strong></span>
</div>
</div>
""", unsafe_allow_html=True)
# Implementation roadmap
st.markdown("#### πŸ—ΊοΈ Implementation Roadmap")
roadmap_data = {
"Phase": ["Phase 1 (0-3 months)", "Phase 2 (3-6 months)", "Phase 3 (6-12 months)"],
"Focus Areas": [
"Process Automation, Quick Wins",
"Vendor Consolidation, Risk Management",
"Strategic Contracts, Digital Platform"
],
"Expected ROI": ["15-20%", "20-30%", "30-40%"],
"Key Deliverables": [
"Automated workflows, Spend visibility",
"Strategic partnerships, Risk framework",
"AI-powered platform, Performance management"
]
}
roadmap_df = pd.DataFrame(roadmap_data)
st.dataframe(roadmap_df, use_container_width=True, hide_index=True)
# Footer
st.markdown("---")
st.markdown(f"""
<div style="text-align: center; padding: 1rem; color: #666;">
<p>πŸ€– <strong>Agentic AI Procurement Analytics</strong> | Built with Streamlit & Python | SAP S/4HANA Integration Demo</p>
<p><em>Synthetic data demonstration β€’ {len(st.session_state.po_df):,} orders β€’ {len(st.session_state.po_df['vendor'].unique())} vendors β€’ OpenAI {api_key_status}</em></p>
<p><small>πŸ’‘ Add your OpenAI API key as 'OPENAI_API_KEY' in Hugging Face Space settings for enhanced AI features</small></p>
</div>
""", unsafe_allow_html=True)