MBG0903 commited on
Commit
5d377bc
Β·
verified Β·
1 Parent(s): ca16a57

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +137 -41
src/streamlit_app.py CHANGED
@@ -2,20 +2,11 @@ import os
2
  import streamlit as st
3
  from openai import OpenAI
4
 
5
- # ------------------------------
6
- # CONFIG
7
- # ------------------------------
8
- # Hugging Face: Settings -> Variables -> add OPENAI_API_KEY
9
  OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") or st.secrets.get("OPENAI_API_KEY", None)
10
 
11
- st.set_page_config(
12
- page_title="Procelevate AI Agent",
13
- page_icon="πŸ€–",
14
- layout="wide"
15
- )
16
-
17
  st.title("πŸ€– Procelevate Agent Suite")
18
- st.write("PO Automation + Email Responder (Streamlit, HF Docker)")
19
 
20
  if not OPENAI_API_KEY:
21
  st.warning("⚠️ OPENAI_API_KEY not found. Set it in the Space secrets.")
@@ -23,7 +14,6 @@ client = OpenAI(api_key=OPENAI_API_KEY) if OPENAI_API_KEY else None
23
 
24
 
25
  def call_llm(system_prompt: str, user_prompt: str) -> str:
26
- """Small helper to call OpenAI."""
27
  if client is None:
28
  return "❗OPENAI_API_KEY not set."
29
  resp = client.chat.completions.create(
@@ -32,22 +22,16 @@ def call_llm(system_prompt: str, user_prompt: str) -> str:
32
  {"role": "system", "content": system_prompt},
33
  {"role": "user", "content": user_prompt},
34
  ],
35
- temperature=0.3,
36
  )
37
  return resp.choices[0].message.content
38
 
39
 
40
- # ------------------------------
41
- # PO GENERATOR
42
- # ------------------------------
43
  def generate_po(buyer_name, buyer_address, supplier_name, supplier_email, items_text, payment_terms, notes):
44
  system_prompt = """You are a Purchase Order (PO) generation assistant for Procelevate.
45
- You will take supplier details, buyer details, item list, and payment terms, and output a clean, well-structured PO.
46
- Output in markdown with clear headings, table for line items, and totals.
47
- If any field is missing, make reasonable placeholders."""
48
  user_prompt = f"""
49
- Create a Purchase Order with the following details:
50
-
51
  Buyer:
52
  - Name: {buyer_name}
53
  - Address: {buyer_address}
@@ -56,45 +40,114 @@ Supplier:
56
  - Name: {supplier_name}
57
  - Email: {supplier_email}
58
 
59
- Line Items (parse this and make a table with Item, Qty, Unit Price, Line Total):
60
  {items_text}
61
 
62
  Payment Terms: {payment_terms}
63
- Additional Notes: {notes}
64
-
65
- At the end, show Subtotal, Taxes (assume 18% if not given), and Grand Total.
66
  """
67
  return call_llm(system_prompt, user_prompt)
68
 
69
 
70
- # ------------------------------
71
- # EMAIL RESPONDER
72
- # ------------------------------
73
  def generate_email_reply(incoming_email, reply_goal, tone):
74
  system_prompt = """You are an AI email responder for Procelevate Consulting & Academy.
75
- You will read an incoming email and write a professional, concise reply matching the selected tone.
76
- Always add a polite closing with 'Regards, Procelevate Team' unless user says otherwise."""
77
  user_prompt = f"""
78
  Incoming email:
79
  \"\"\"{incoming_email}\"\"\"
80
-
81
- Goal of reply: {reply_goal}
82
  Tone: {tone}
 
 
 
83
 
84
- Write the reply email body only.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  """
86
  return call_llm(system_prompt, user_prompt)
87
 
88
 
89
- # ------------------------------
90
- # UI
91
- # ------------------------------
92
- tab1, tab2 = st.tabs(["πŸ“„ PO Automation", "πŸ“§ Email Responder"])
 
 
 
 
 
 
 
 
 
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  with tab1:
95
  st.subheader("πŸ“„ Generate Purchase Order")
96
  col1, col2 = st.columns(2)
97
-
98
  with col1:
99
  buyer_name = st.text_input("Buyer Name", value="Procelevate Consulting")
100
  buyer_address = st.text_area("Buyer Address", value="Bengaluru, Karnataka, India", height=80)
@@ -110,7 +163,7 @@ with tab1:
110
  height=120
111
  )
112
 
113
- if st.button("Generate PO"):
114
  po_md = generate_po(
115
  buyer_name,
116
  buyer_address,
@@ -124,6 +177,7 @@ with tab1:
124
  st.markdown("### βœ… Generated PO")
125
  st.markdown(po_md)
126
 
 
127
  with tab2:
128
  st.subheader("πŸ“§ Generate Email Reply")
129
  incoming_email = st.text_area(
@@ -141,9 +195,51 @@ with tab2:
141
  index=0
142
  )
143
 
144
- if st.button("Generate Reply"):
145
  reply_text = generate_email_reply(incoming_email, reply_goal, tone)
146
  st.markdown("---")
147
  st.markdown("### βœ… Reply Email")
148
  st.markdown(reply_text)
149
- st.info("You can copy-paste this into Gmail / Outlook.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  import streamlit as st
3
  from openai import OpenAI
4
 
5
+ # ===== CONFIG =====
 
 
 
6
  OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") or st.secrets.get("OPENAI_API_KEY", None)
7
 
8
+ st.set_page_config(page_title="Procelevate AI Agent", page_icon="πŸ€–", layout="wide")
 
 
 
 
 
9
  st.title("πŸ€– Procelevate Agent Suite")
 
10
 
11
  if not OPENAI_API_KEY:
12
  st.warning("⚠️ OPENAI_API_KEY not found. Set it in the Space secrets.")
 
14
 
15
 
16
  def call_llm(system_prompt: str, user_prompt: str) -> str:
 
17
  if client is None:
18
  return "❗OPENAI_API_KEY not set."
19
  resp = client.chat.completions.create(
 
22
  {"role": "system", "content": system_prompt},
23
  {"role": "user", "content": user_prompt},
24
  ],
25
+ temperature=0.25,
26
  )
27
  return resp.choices[0].message.content
28
 
29
 
30
+ # ===== EXISTING FUNCTIONS =====
 
 
31
  def generate_po(buyer_name, buyer_address, supplier_name, supplier_email, items_text, payment_terms, notes):
32
  system_prompt = """You are a Purchase Order (PO) generation assistant for Procelevate.
33
+ Output in markdown with headings, line-item table, and totals. Assume 18% tax if missing."""
 
 
34
  user_prompt = f"""
 
 
35
  Buyer:
36
  - Name: {buyer_name}
37
  - Address: {buyer_address}
 
40
  - Name: {supplier_name}
41
  - Email: {supplier_email}
42
 
43
+ Line Items:
44
  {items_text}
45
 
46
  Payment Terms: {payment_terms}
47
+ Notes: {notes}
 
 
48
  """
49
  return call_llm(system_prompt, user_prompt)
50
 
51
 
 
 
 
52
  def generate_email_reply(incoming_email, reply_goal, tone):
53
  system_prompt = """You are an AI email responder for Procelevate Consulting & Academy.
54
+ Write a concise reply in the requested tone. End with 'Regards, Procelevate Team'."""
 
55
  user_prompt = f"""
56
  Incoming email:
57
  \"\"\"{incoming_email}\"\"\"
58
+ Goal: {reply_goal}
 
59
  Tone: {tone}
60
+ """
61
+ return call_llm(system_prompt, user_prompt)
62
+
63
 
64
+ # ===== NEW: QUOTATION β†’ PR β†’ PO PIPELINE =====
65
+
66
+ def extract_text_from_upload(uploaded_file):
67
+ # simplest path: handle text files directly
68
+ if uploaded_file is None:
69
+ return ""
70
+ if uploaded_file.type == "text/plain":
71
+ return uploaded_file.read().decode("utf-8")
72
+
73
+ # for PDFs we need a parser; if pdfplumber not installed, just say so
74
+ if uploaded_file.type == "application/pdf":
75
+ try:
76
+ import pdfplumber
77
+ text_parts = []
78
+ with pdfplumber.open(uploaded_file) as pdf:
79
+ for page in pdf.pages:
80
+ text_parts.append(page.extract_text() or "")
81
+ return "\n".join(text_parts)
82
+ except Exception as e:
83
+ return f"PDF uploaded but could not parse: {e}"
84
+
85
+ # fallback
86
+ return uploaded_file.read().decode("utf-8", errors="ignore")
87
+
88
+
89
+ def create_pr_from_quotation(quotation_text, buyer_org):
90
+ system_prompt = """You are a purchasing assistant. Given a supplier quotation text, extract:
91
+ - supplier_name
92
+ - line_items (description, qty, unit_price if present)
93
+ - currency (guess if missing)
94
+ Return a clean JSON-like structure representing a Purchase Requisition (PR) for internal approval."""
95
+ user_prompt = f"""
96
+ Organisation: {buyer_org}
97
+ Quotation text:
98
+ \"\"\"{quotation_text}\"\"\"
99
+
100
+ Return PR as JSON with keys:
101
+ pr_title, supplier_name, currency, line_items, total_if_available.
102
  """
103
  return call_llm(system_prompt, user_prompt)
104
 
105
 
106
+ def create_approval_email(pr_json_text, approver_email="approver@example.com"):
107
+ system_prompt = """You are an approval workflow assistant. Write an approval request email for a PR.
108
+ Email must include: PR title, supplier, amount, and a clear approve/reject instruction.
109
+ Don't actually send it, just draft."""
110
+ user_prompt = f"""
111
+ PR details (JSON):
112
+ {pr_json_text}
113
+
114
+ Approver email: {approver_email}
115
+ Write the approval email.
116
+ """
117
+ return call_llm(system_prompt, user_prompt)
118
+
119
 
120
+ def create_po_from_pr(pr_json_text, buyer_name, buyer_address, supplier_email):
121
+ system_prompt = """You are a PO generator. Convert the approved PR (JSON) into a Purchase Order in markdown.
122
+ Include buyer, supplier, line items table, totals, and payment terms (assume Net 30)."""
123
+ user_prompt = f"""
124
+ Buyer name: {buyer_name}
125
+ Buyer address: {buyer_address}
126
+ Supplier email: {supplier_email}
127
+ PR JSON:
128
+ {pr_json_text}
129
+ """
130
+ return call_llm(system_prompt, user_prompt)
131
+
132
+
133
+ def create_supplier_email(po_markdown, supplier_email):
134
+ system_prompt = """You are a business email writer. Write an email to supplier attaching/sending PO details.
135
+ Keep it formal, short. Mention PO number if present."""
136
+ user_prompt = f"""
137
+ Supplier: {supplier_email}
138
+ PO content:
139
+ {po_markdown}
140
+ """
141
+ return call_llm(system_prompt, user_prompt)
142
+
143
+
144
+ # ===== UI TABS =====
145
+ tab1, tab2, tab3 = st.tabs(["πŸ“„ PO Automation", "πŸ“§ Email Responder", "πŸ“¦ Quotation β†’ PR β†’ PO"])
146
+
147
+ # --- TAB 1: Existing PO form ---
148
  with tab1:
149
  st.subheader("πŸ“„ Generate Purchase Order")
150
  col1, col2 = st.columns(2)
 
151
  with col1:
152
  buyer_name = st.text_input("Buyer Name", value="Procelevate Consulting")
153
  buyer_address = st.text_area("Buyer Address", value="Bengaluru, Karnataka, India", height=80)
 
163
  height=120
164
  )
165
 
166
+ if st.button("Generate PO", key="gen_po_basic"):
167
  po_md = generate_po(
168
  buyer_name,
169
  buyer_address,
 
177
  st.markdown("### βœ… Generated PO")
178
  st.markdown(po_md)
179
 
180
+ # --- TAB 2: Email responder ---
181
  with tab2:
182
  st.subheader("πŸ“§ Generate Email Reply")
183
  incoming_email = st.text_area(
 
195
  index=0
196
  )
197
 
198
+ if st.button("Generate Reply", key="gen_reply"):
199
  reply_text = generate_email_reply(incoming_email, reply_goal, tone)
200
  st.markdown("---")
201
  st.markdown("### βœ… Reply Email")
202
  st.markdown(reply_text)
203
+
204
+ # --- TAB 3: Quotation β†’ PR β†’ PO ---
205
+ with tab3:
206
+ st.subheader("πŸ“¦ Quotation β†’ PR β†’ PO")
207
+ st.write("Upload supplier quotation, let the model draft PR, generate approval mail, and convert to PO after approval.")
208
+
209
+ quotation_file = st.file_uploader("Upload quotation (PDF or .txt)", type=["pdf", "txt"])
210
+ buyer_org = st.text_input("Buyer Org / Company", value="Procelevate Consulting")
211
+ supplier_email_q = st.text_input("Supplier Email (for final PO)", value="supplier@example.com")
212
+ buyer_address_q = st.text_input("Buyer Address", value="Bengaluru, Karnataka, India")
213
+
214
+ if st.button("1️⃣ Extract β†’ Create PR"):
215
+ quotation_text = extract_text_from_upload(quotation_file)
216
+ st.markdown("**Extracted text (preview):**")
217
+ st.code(quotation_text[:800] or "No text extracted.", language="text")
218
+
219
+ pr_json_text = create_pr_from_quotation(quotation_text, buyer_org)
220
+ st.markdown("### βœ… Draft PR (JSON-like)")
221
+ st.code(pr_json_text, language="json")
222
+
223
+ st.session_state["latest_pr"] = pr_json_text
224
+ st.success("PR drafted. Now generate approval email below.")
225
+
226
+ if "latest_pr" in st.session_state:
227
+ if st.button("2️⃣ Generate Approval Email"):
228
+ approval_email = create_approval_email(st.session_state["latest_pr"])
229
+ st.markdown("### βœ… Approval Email (send this via Outlook/Gmail/n8n):")
230
+ st.markdown(approval_email)
231
+ st.session_state["approval_email"] = approval_email
232
+
233
+ if "latest_pr" in st.session_state:
234
+ if st.button("3️⃣ Simulate Approval β†’ Generate PO"):
235
+ po_md = create_po_from_pr(st.session_state["latest_pr"], buyer_org, buyer_address_q, supplier_email_q)
236
+ st.markdown("### βœ… Generated PO (from approved PR)")
237
+ st.markdown(po_md)
238
+ st.session_state["po_md"] = po_md
239
+
240
+ if "po_md" in st.session_state:
241
+ if st.button("4️⃣ Prepare Supplier Email"):
242
+ supplier_mail = create_supplier_email(st.session_state["po_md"], supplier_email_q)
243
+ st.markdown("### βœ… Supplier Email (copy & send)")
244
+ st.markdown(supplier_mail)
245
+ st.info("To auto-send this, connect SMTP or n8n webhook.")