|
|
import streamlit as st |
|
|
import os |
|
|
from smolagents import CodeAgent, LiteLLMModel, tool |
|
|
import json |
|
|
from datetime import datetime |
|
|
import random |
|
|
|
|
|
|
|
|
st.set_page_config( |
|
|
page_title="AI Procurement Agent", |
|
|
page_icon="π€", |
|
|
layout="wide" |
|
|
) |
|
|
|
|
|
|
|
|
@st.cache_resource |
|
|
def get_model(): |
|
|
api_key = os.environ.get("OPENAI_API_KEY") |
|
|
if not api_key: |
|
|
st.error("β οΈ OpenAI API Key not found in Spaces secrets!") |
|
|
st.info("Add OPENAI_API_KEY to your Spaces secrets in Settings.") |
|
|
st.stop() |
|
|
|
|
|
return LiteLLMModel( |
|
|
model_id="gpt-3.5-turbo", |
|
|
api_key=api_key, |
|
|
temperature=0.2 |
|
|
) |
|
|
|
|
|
|
|
|
@tool |
|
|
def query_sap_pr(pr_number: str) -> str: |
|
|
""" |
|
|
Query SAP purchase requisition details |
|
|
|
|
|
Args: |
|
|
pr_number: The purchase requisition number to query |
|
|
""" |
|
|
materials = ["Steel Pipes", "Cement", "Electrical Cables", "Safety Equipment"] |
|
|
mock_data = { |
|
|
"pr_number": pr_number, |
|
|
"materials": f"{random.choice(materials)} - {random.randint(50, 200)} units", |
|
|
"total_value": random.randint(30000, 80000), |
|
|
"requestor": random.choice(["John Doe", "Jane Smith", "Mike Johnson"]), |
|
|
"department": random.choice(["Construction", "Manufacturing", "Maintenance"]), |
|
|
"urgency": random.choice(["High", "Medium", "Low"]), |
|
|
"delivery_date": "2025-10-15", |
|
|
"status": "Approved" |
|
|
} |
|
|
return json.dumps(mock_data, indent=2) |
|
|
|
|
|
@tool |
|
|
def check_vendor_solvency(vendor_name: str) -> str: |
|
|
""" |
|
|
Check vendor financial solvency from external sources |
|
|
|
|
|
Args: |
|
|
vendor_name: Name of the vendor to check financial solvency for |
|
|
""" |
|
|
scores = ["A+", "A", "A-", "B+", "B"] |
|
|
risk_levels = ["Low", "Medium", "High"] |
|
|
mock_data = { |
|
|
"vendor_name": vendor_name, |
|
|
"credit_rating": random.choice(scores), |
|
|
"financial_stability": "Stable", |
|
|
"solvency_score": random.randint(65, 95), |
|
|
"debt_ratio": round(random.uniform(0.2, 0.6), 2), |
|
|
"risk_level": random.choice(risk_levels[:2]), |
|
|
"recommendation": "Approved for business" |
|
|
} |
|
|
return json.dumps(mock_data, indent=2) |
|
|
|
|
|
@tool |
|
|
def get_vendor_performance(vendor_name: str) -> str: |
|
|
""" |
|
|
Get historical vendor performance metrics |
|
|
|
|
|
Args: |
|
|
vendor_name: Name of the vendor to get performance history for |
|
|
""" |
|
|
mock_data = { |
|
|
"vendor_name": vendor_name, |
|
|
"evaluation_period": "12 months", |
|
|
"total_orders": random.randint(15, 80), |
|
|
"on_time_delivery": f"{random.randint(85, 98)}%", |
|
|
"quality_score": round(random.uniform(3.5, 5.0), 1), |
|
|
"order_accuracy": f"{random.randint(92, 99)}%", |
|
|
"avg_lead_time": f"{random.randint(7, 21)} days", |
|
|
"overall_rating": round(random.uniform(3.5, 4.8), 1), |
|
|
"issues_resolved": random.randint(0, 3) |
|
|
} |
|
|
return json.dumps(mock_data, indent=2) |
|
|
|
|
|
@tool |
|
|
def compare_material_rates(material: str) -> str: |
|
|
""" |
|
|
Compare current market rates for materials |
|
|
|
|
|
Args: |
|
|
material: Type of material to compare rates for |
|
|
""" |
|
|
vendors = ["Alpha Corp", "Beta Supplies", "Gamma Materials", "Delta Industries"] |
|
|
base_price = random.randint(80, 250) |
|
|
|
|
|
quotes = [] |
|
|
for vendor in random.sample(vendors, 3): |
|
|
quotes.append({ |
|
|
"vendor": vendor, |
|
|
"price_per_unit": base_price + random.randint(-25, 30), |
|
|
"lead_time": f"{random.randint(5, 20)} days", |
|
|
"min_order": random.randint(10, 50) |
|
|
}) |
|
|
|
|
|
mock_data = { |
|
|
"material": material, |
|
|
"market_average": base_price, |
|
|
"vendor_quotes": quotes, |
|
|
"best_value_vendor": min(quotes, key=lambda x: x["price_per_unit"])["vendor"], |
|
|
"price_trend": random.choice(["Stable", "Increasing", "Decreasing"]) |
|
|
} |
|
|
return json.dumps(mock_data, indent=2) |
|
|
|
|
|
@tool |
|
|
def optimize_vendor_selection(requirements: str) -> str: |
|
|
""" |
|
|
Run optimization to find best vendor combination |
|
|
|
|
|
Args: |
|
|
requirements: Procurement requirements and constraints to optimize for |
|
|
""" |
|
|
vendors = ["ABC Supplies", "XYZ Materials", "DEF Corp", "GHI Industries"] |
|
|
selected_vendor = random.choice(vendors) |
|
|
|
|
|
mock_data = { |
|
|
"requirements_analyzed": requirements, |
|
|
"recommended_vendor": selected_vendor, |
|
|
"optimization_score": round(random.uniform(7.5, 9.5), 1), |
|
|
"total_estimated_cost": random.randint(40000, 70000), |
|
|
"potential_savings": f"{random.randint(8, 18)}%", |
|
|
"risk_assessment": "Low to Medium", |
|
|
"confidence_level": f"{random.randint(85, 96)}%", |
|
|
"key_factors": ["Cost efficiency", "Quality track record", "Delivery reliability"] |
|
|
} |
|
|
return json.dumps(mock_data, indent=2) |
|
|
|
|
|
@tool |
|
|
def create_purchase_order(vendor: str, amount: str) -> str: |
|
|
""" |
|
|
Create purchase order in SAP system |
|
|
|
|
|
Args: |
|
|
vendor: Name of the vendor to create purchase order for |
|
|
amount: Total amount for the purchase order |
|
|
""" |
|
|
po_number = f"PO{datetime.now().strftime('%Y%m%d%H%M%S')[-8:]}" |
|
|
|
|
|
mock_data = { |
|
|
"po_number": po_number, |
|
|
"vendor": vendor, |
|
|
"total_amount": amount, |
|
|
"currency": "USD", |
|
|
"status": "Created Successfully", |
|
|
"payment_terms": "NET 30", |
|
|
"delivery_terms": "FOB Destination", |
|
|
"created_by": "AI_Procurement_Agent", |
|
|
"created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), |
|
|
"approval_required": random.choice([True, False]) |
|
|
} |
|
|
return json.dumps(mock_data, indent=2) |
|
|
|
|
|
|
|
|
@st.cache_resource |
|
|
def get_agent(): |
|
|
tools = [ |
|
|
query_sap_pr, |
|
|
check_vendor_solvency, |
|
|
get_vendor_performance, |
|
|
compare_material_rates, |
|
|
optimize_vendor_selection, |
|
|
create_purchase_order |
|
|
] |
|
|
|
|
|
return CodeAgent( |
|
|
tools=tools, |
|
|
model=get_model() |
|
|
) |
|
|
|
|
|
def main(): |
|
|
st.title("π€ AI Procurement Agent") |
|
|
st.markdown("*Demo powered by Hugging Face SmolAgents + OpenAI GPT-4*") |
|
|
|
|
|
with st.expander("βΉοΈ About this Demo"): |
|
|
st.markdown(""" |
|
|
This AI agent can help automate procurement workflows by: |
|
|
- Querying purchase requisitions |
|
|
- Evaluating vendor financial health |
|
|
- Analyzing vendor performance history |
|
|
- Comparing material market rates |
|
|
- Optimizing vendor selection |
|
|
- Creating purchase orders |
|
|
|
|
|
**Note:** This uses mock data for demonstration purposes. |
|
|
""") |
|
|
|
|
|
|
|
|
with st.sidebar: |
|
|
st.header("π― Demo Scenarios") |
|
|
scenario = st.selectbox( |
|
|
"Choose a workflow:", |
|
|
[ |
|
|
"π Full Procurement Workflow", |
|
|
"π Vendor Evaluation", |
|
|
"π° Price Analysis", |
|
|
"π€ Custom AI Query" |
|
|
] |
|
|
) |
|
|
|
|
|
st.markdown("---") |
|
|
st.markdown("**π Using OpenAI GPT-4**") |
|
|
|
|
|
|
|
|
col1, col2 = st.columns([1, 1]) |
|
|
|
|
|
with col1: |
|
|
st.header("π Input") |
|
|
|
|
|
if scenario == "π Full Procurement Workflow": |
|
|
pr_number = st.text_input("Enter PR Number:", value="PR-2025-001") |
|
|
|
|
|
if st.button("π Start Full Workflow", type="primary", use_container_width=True): |
|
|
process_full_workflow(pr_number) |
|
|
|
|
|
elif scenario == "π Vendor Evaluation": |
|
|
vendor_name = st.text_input("Enter Vendor Name:", value="ABC Supplies") |
|
|
|
|
|
if st.button("π Evaluate This Vendor", use_container_width=True): |
|
|
evaluate_vendor(vendor_name) |
|
|
|
|
|
elif scenario == "π° Price Analysis": |
|
|
material = st.text_input("Enter Material Type:", value="Steel Pipes") |
|
|
|
|
|
if st.button("π° Analyze Market Prices", use_container_width=True): |
|
|
analyze_prices(material) |
|
|
|
|
|
else: |
|
|
custom_query = st.text_area( |
|
|
"Enter your procurement query:", |
|
|
value="Evaluate vendor XYZ Corp and check if they're suitable for a 50K USD steel pipes order", |
|
|
height=80 |
|
|
) |
|
|
|
|
|
if st.button("π€ Ask AI Agent", use_container_width=True): |
|
|
run_custom_query(custom_query) |
|
|
|
|
|
with col2: |
|
|
st.header("π€ AI Agent Response") |
|
|
|
|
|
if 'agent_response' not in st.session_state: |
|
|
st.info("π Select a scenario and click a button to see the AI agent in action!") |
|
|
else: |
|
|
with st.container(): |
|
|
st.success("β
Agent completed successfully!") |
|
|
|
|
|
with st.expander("π Full Agent Response", expanded=True): |
|
|
st.markdown(st.session_state['agent_response']) |
|
|
|
|
|
|
|
|
def process_full_workflow(pr_number): |
|
|
with st.spinner("π€ AI Agent is working on your procurement request..."): |
|
|
prompt = f""" |
|
|
Execute a complete procurement workflow for PR {pr_number}: |
|
|
|
|
|
1. Query the SAP purchase requisition details |
|
|
2. For any vendors found, check their financial solvency |
|
|
3. Review their historical performance |
|
|
4. Compare current market rates for the materials |
|
|
5. Run optimization to select the best vendor option |
|
|
6. Create a purchase order for the recommended vendor |
|
|
|
|
|
Provide a clear summary with your final recommendation and reasoning. |
|
|
""" |
|
|
|
|
|
try: |
|
|
agent = get_agent() |
|
|
result = agent.run(prompt) |
|
|
st.session_state['agent_response'] = result |
|
|
st.rerun() |
|
|
except Exception as e: |
|
|
st.error(f"Error: {str(e)}") |
|
|
|
|
|
def evaluate_vendor(vendor_name): |
|
|
with st.spinner(f"π€ Evaluating {vendor_name}..."): |
|
|
prompt = f""" |
|
|
Conduct a comprehensive evaluation of vendor '{vendor_name}': |
|
|
|
|
|
1. Check their financial solvency and credit rating |
|
|
2. Analyze their historical performance metrics |
|
|
3. Provide a clear recommendation on working with them |
|
|
4. Highlight any risks or benefits |
|
|
""" |
|
|
|
|
|
try: |
|
|
agent = get_agent() |
|
|
result = agent.run(prompt) |
|
|
st.session_state['agent_response'] = result |
|
|
st.rerun() |
|
|
except Exception as e: |
|
|
st.error(f"Error: {str(e)}") |
|
|
|
|
|
def analyze_prices(material): |
|
|
with st.spinner(f"π€ Analyzing prices for {material}..."): |
|
|
prompt = f""" |
|
|
Perform price analysis for '{material}': |
|
|
|
|
|
1. Get current market rates from multiple vendors |
|
|
2. Compare pricing and identify the best value option |
|
|
3. Consider factors like lead time and minimum orders |
|
|
4. Provide pricing recommendations |
|
|
""" |
|
|
|
|
|
try: |
|
|
agent = get_agent() |
|
|
result = agent.run(prompt) |
|
|
st.session_state['agent_response'] = result |
|
|
st.rerun() |
|
|
except Exception as e: |
|
|
st.error(f"Error: {str(e)}") |
|
|
|
|
|
def run_custom_query(query): |
|
|
with st.spinner("π€ Processing your custom query..."): |
|
|
try: |
|
|
agent = get_agent() |
|
|
result = agent.run(query) |
|
|
st.session_state['agent_response'] = result |
|
|
st.rerun() |
|
|
except Exception as e: |
|
|
st.error(f"Error: {str(e)}") |
|
|
|
|
|
if __name__ == "__main__": |
|
|
main() |
|
|
|