Procelevate_PO_Automation / src /streamlit_app.py
MBG0903's picture
Update src/streamlit_app.py
5d377bc verified
import os
import streamlit as st
from openai import OpenAI
# ===== CONFIG =====
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") or st.secrets.get("OPENAI_API_KEY", None)
st.set_page_config(page_title="Procelevate AI Agent", page_icon="πŸ€–", layout="wide")
st.title("πŸ€– Procelevate Agent Suite")
if not OPENAI_API_KEY:
st.warning("⚠️ OPENAI_API_KEY not found. Set it in the Space secrets.")
client = OpenAI(api_key=OPENAI_API_KEY) if OPENAI_API_KEY else None
def call_llm(system_prompt: str, user_prompt: str) -> str:
if client is None:
return "❗OPENAI_API_KEY not set."
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
],
temperature=0.25,
)
return resp.choices[0].message.content
# ===== EXISTING FUNCTIONS =====
def generate_po(buyer_name, buyer_address, supplier_name, supplier_email, items_text, payment_terms, notes):
system_prompt = """You are a Purchase Order (PO) generation assistant for Procelevate.
Output in markdown with headings, line-item table, and totals. Assume 18% tax if missing."""
user_prompt = f"""
Buyer:
- Name: {buyer_name}
- Address: {buyer_address}
Supplier:
- Name: {supplier_name}
- Email: {supplier_email}
Line Items:
{items_text}
Payment Terms: {payment_terms}
Notes: {notes}
"""
return call_llm(system_prompt, user_prompt)
def generate_email_reply(incoming_email, reply_goal, tone):
system_prompt = """You are an AI email responder for Procelevate Consulting & Academy.
Write a concise reply in the requested tone. End with 'Regards, Procelevate Team'."""
user_prompt = f"""
Incoming email:
\"\"\"{incoming_email}\"\"\"
Goal: {reply_goal}
Tone: {tone}
"""
return call_llm(system_prompt, user_prompt)
# ===== NEW: QUOTATION β†’ PR β†’ PO PIPELINE =====
def extract_text_from_upload(uploaded_file):
# simplest path: handle text files directly
if uploaded_file is None:
return ""
if uploaded_file.type == "text/plain":
return uploaded_file.read().decode("utf-8")
# for PDFs we need a parser; if pdfplumber not installed, just say so
if uploaded_file.type == "application/pdf":
try:
import pdfplumber
text_parts = []
with pdfplumber.open(uploaded_file) as pdf:
for page in pdf.pages:
text_parts.append(page.extract_text() or "")
return "\n".join(text_parts)
except Exception as e:
return f"PDF uploaded but could not parse: {e}"
# fallback
return uploaded_file.read().decode("utf-8", errors="ignore")
def create_pr_from_quotation(quotation_text, buyer_org):
system_prompt = """You are a purchasing assistant. Given a supplier quotation text, extract:
- supplier_name
- line_items (description, qty, unit_price if present)
- currency (guess if missing)
Return a clean JSON-like structure representing a Purchase Requisition (PR) for internal approval."""
user_prompt = f"""
Organisation: {buyer_org}
Quotation text:
\"\"\"{quotation_text}\"\"\"
Return PR as JSON with keys:
pr_title, supplier_name, currency, line_items, total_if_available.
"""
return call_llm(system_prompt, user_prompt)
def create_approval_email(pr_json_text, approver_email="approver@example.com"):
system_prompt = """You are an approval workflow assistant. Write an approval request email for a PR.
Email must include: PR title, supplier, amount, and a clear approve/reject instruction.
Don't actually send it, just draft."""
user_prompt = f"""
PR details (JSON):
{pr_json_text}
Approver email: {approver_email}
Write the approval email.
"""
return call_llm(system_prompt, user_prompt)
def create_po_from_pr(pr_json_text, buyer_name, buyer_address, supplier_email):
system_prompt = """You are a PO generator. Convert the approved PR (JSON) into a Purchase Order in markdown.
Include buyer, supplier, line items table, totals, and payment terms (assume Net 30)."""
user_prompt = f"""
Buyer name: {buyer_name}
Buyer address: {buyer_address}
Supplier email: {supplier_email}
PR JSON:
{pr_json_text}
"""
return call_llm(system_prompt, user_prompt)
def create_supplier_email(po_markdown, supplier_email):
system_prompt = """You are a business email writer. Write an email to supplier attaching/sending PO details.
Keep it formal, short. Mention PO number if present."""
user_prompt = f"""
Supplier: {supplier_email}
PO content:
{po_markdown}
"""
return call_llm(system_prompt, user_prompt)
# ===== UI TABS =====
tab1, tab2, tab3 = st.tabs(["πŸ“„ PO Automation", "πŸ“§ Email Responder", "πŸ“¦ Quotation β†’ PR β†’ PO"])
# --- TAB 1: Existing PO form ---
with tab1:
st.subheader("πŸ“„ Generate Purchase Order")
col1, col2 = st.columns(2)
with col1:
buyer_name = st.text_input("Buyer Name", value="Procelevate Consulting")
buyer_address = st.text_area("Buyer Address", value="Bengaluru, Karnataka, India", height=80)
payment_terms = st.text_input("Payment Terms", value="Net 30 days")
with col2:
supplier_name = st.text_input("Supplier Name", value="")
supplier_email = st.text_input("Supplier Email", value="")
notes = st.text_area("Additional Notes", value="Please deliver services as per agreed SOW.", height=80)
items_text = st.text_area(
"Line Items (one per line)",
value="1. AI/ML Bootcamp Seats, Qty 10, Unit Price 2999\n2. Consulting Hours, Qty 5, Unit Price 1500",
height=120
)
if st.button("Generate PO", key="gen_po_basic"):
po_md = generate_po(
buyer_name,
buyer_address,
supplier_name,
supplier_email,
items_text,
payment_terms,
notes
)
st.markdown("---")
st.markdown("### βœ… Generated PO")
st.markdown(po_md)
# --- TAB 2: Email responder ---
with tab2:
st.subheader("πŸ“§ Generate Email Reply")
incoming_email = st.text_area(
"Incoming email",
value="Hi Mahesh, we are interested in your Smart Daycare Suite. Can you share pricing and a demo slot?",
height=140
)
reply_goal = st.text_input(
"What should the reply do?",
value="Acknowledge, share that we have multiple AI/ML modules, and propose 30-min demo."
)
tone = st.selectbox(
"Tone",
options=["Professional", "Friendly", "Formal-Client", "Follow-up/Reminder"],
index=0
)
if st.button("Generate Reply", key="gen_reply"):
reply_text = generate_email_reply(incoming_email, reply_goal, tone)
st.markdown("---")
st.markdown("### βœ… Reply Email")
st.markdown(reply_text)
# --- TAB 3: Quotation β†’ PR β†’ PO ---
with tab3:
st.subheader("πŸ“¦ Quotation β†’ PR β†’ PO")
st.write("Upload supplier quotation, let the model draft PR, generate approval mail, and convert to PO after approval.")
quotation_file = st.file_uploader("Upload quotation (PDF or .txt)", type=["pdf", "txt"])
buyer_org = st.text_input("Buyer Org / Company", value="Procelevate Consulting")
supplier_email_q = st.text_input("Supplier Email (for final PO)", value="supplier@example.com")
buyer_address_q = st.text_input("Buyer Address", value="Bengaluru, Karnataka, India")
if st.button("1️⃣ Extract β†’ Create PR"):
quotation_text = extract_text_from_upload(quotation_file)
st.markdown("**Extracted text (preview):**")
st.code(quotation_text[:800] or "No text extracted.", language="text")
pr_json_text = create_pr_from_quotation(quotation_text, buyer_org)
st.markdown("### βœ… Draft PR (JSON-like)")
st.code(pr_json_text, language="json")
st.session_state["latest_pr"] = pr_json_text
st.success("PR drafted. Now generate approval email below.")
if "latest_pr" in st.session_state:
if st.button("2️⃣ Generate Approval Email"):
approval_email = create_approval_email(st.session_state["latest_pr"])
st.markdown("### βœ… Approval Email (send this via Outlook/Gmail/n8n):")
st.markdown(approval_email)
st.session_state["approval_email"] = approval_email
if "latest_pr" in st.session_state:
if st.button("3️⃣ Simulate Approval β†’ Generate PO"):
po_md = create_po_from_pr(st.session_state["latest_pr"], buyer_org, buyer_address_q, supplier_email_q)
st.markdown("### βœ… Generated PO (from approved PR)")
st.markdown(po_md)
st.session_state["po_md"] = po_md
if "po_md" in st.session_state:
if st.button("4️⃣ Prepare Supplier Email"):
supplier_mail = create_supplier_email(st.session_state["po_md"], supplier_email_q)
st.markdown("### βœ… Supplier Email (copy & send)")
st.markdown(supplier_mail)
st.info("To auto-send this, connect SMTP or n8n webhook.")