Spaces:
Runtime error
Runtime error
| 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.") | |