scmlewis commited on
Commit
0fdd881
·
verified ·
1 Parent(s): 51ba079

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +146 -69
app.py CHANGED
@@ -2,11 +2,38 @@ import os
2
  import gradio as gr
3
  import requests
4
  import json
 
5
 
6
  GROQ_API_KEY = os.getenv("GROQ_API_KEY")
7
  GROQ_COMPLETION_URL = "https://api.groq.com/openai/v1/chat/completions"
8
  GROQ_MODEL = "llama-3.1-8b-instant"
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  def groq_completion(prompt, sys_prompt=None):
11
  headers = {
12
  "Authorization": f"Bearer {GROQ_API_KEY}",
@@ -15,7 +42,7 @@ def groq_completion(prompt, sys_prompt=None):
15
  body = {
16
  "model": GROQ_MODEL,
17
  "messages": [
18
- {"role": "system", "content": sys_prompt or "You are a fast and reliable business email assistant."},
19
  {"role": "user", "content": prompt}
20
  ],
21
  "temperature": 0.3,
@@ -31,19 +58,21 @@ def groq_completion(prompt, sys_prompt=None):
31
  print("Groq API response:", response.text)
32
  return "Error"
33
 
34
- def email_classifier_router(raw_email):
 
 
 
 
35
  prompt = (
36
- "Return ONLY compact JSON for analysis and response.\n"
37
- "Given the business email below, extract:\n"
38
- "- Category (Support Request, Sales Inquiry, Finance/Billing, Urgent Incident, Spam/Marketing)\n"
39
- "- Priority (Low, Medium, High)\n"
40
- "- Suggested Recipient (department or address)\n"
41
- "- Professional draft reply\n"
42
- "- Summary (one sentence)\n"
43
- "- Action Items (numbered list)\n\n"
44
- "Format:\n"
45
- '{"Category":"...", "Priority":"...", "Suggested Recipient":"...", "Draft Response":"...", "Summary":"...", "Action Items":["...","..."]}\n\n'
46
- f"{raw_email}"
47
  )
48
  raw_result = groq_completion(prompt)
49
  try:
@@ -56,69 +85,117 @@ def email_classifier_router(raw_email):
56
  "Suggested Recipient": "Error",
57
  "Draft Response": raw_result,
58
  "Summary": "Error",
59
- "Action Items": ["Error"]
 
60
  }
61
- return output
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
  with gr.Blocks(theme=gr.themes.Monochrome()) as demo:
64
- gr.Markdown("## 📨 AI Email Classifier & Router\nEasily classify, route, and summarize business emails.")
65
-
66
- with gr.Row(equal_height=True):
67
- gr.Markdown("**Load an example:**")
68
- ex1 = "From: help@company.com\nSubject: Unable to Login\nHi, I can't access my dashboard. Can you help?"
69
- ex2 = "From: sales@prospect.com\nSubject: Inquiry about pricing\nHi, Can you send over your latest pricing for enterprise?"
70
- ex3 = "From: accounts@supplier.com\nSubject: Invoice #2024-00123 Due Date Reminder\nDear Valued Client, This is a reminder invoice #2024-00123 for $1,500.00 is due..."
71
- ex4 = "From: it@company.com\nSubject: Server Down Alert\nURGENT: Database server unreachable since 3AM. Needs escalation."
72
- ex5 = "From: spammer@promo.com\nSubject: BIG SALE!!!\nDon't miss our special offers!"
73
- support_button = gr.Button("Support Request")
74
- sales_button = gr.Button("Sales Inquiry")
75
- finance_button = gr.Button("Finance / Billing")
76
- urgent_button = gr.Button("Urgent Incident")
77
- spam_button = gr.Button("Spam / Marketing")
78
 
79
- email_box = gr.Textbox(lines=8, label="Paste the entire raw email (including lines like 'From:', 'Subject:', etc.)", elem_id='email_box')
80
- classify_btn = gr.Button("Classify Email", elem_id='classify_btn', variant="primary")
81
-
82
- with gr.Column():
83
- gr.Markdown("### Classification Results")
84
- category = gr.Textbox(label="Category", elem_id='category')
85
- priority = gr.Textbox(label="Priority", elem_id='priority')
86
- recipient = gr.Textbox(label="Suggested Recipient", elem_id='recipient')
87
-
88
- with gr.Column():
89
- gr.Markdown("### ✨ Generated Response Draft")
90
- draft_response = gr.Textbox(lines=8, label="Generated Draft", elem_id='draft_response')
91
-
92
- with gr.Column():
93
- gr.Markdown("#### Summary")
94
- summary = gr.Textbox(label="Summary", elem_id='summary')
95
-
96
- with gr.Column():
97
- gr.Markdown("#### 🟣 Extracted Action Items")
98
- action_items = gr.Textbox(lines=4, label="Extracted Action Items", elem_id='actions')
99
-
100
- support_button.click(lambda: ex1, None, email_box)
101
- sales_button.click(lambda: ex2, None, email_box)
102
- finance_button.click(lambda: ex3, None, email_box)
103
- urgent_button.click(lambda: ex4, None, email_box)
104
- spam_button.click(lambda: ex5, None, email_box)
105
-
106
- def classify_and_render(email_text):
107
- result = email_classifier_router(email_text)
108
- cat = result.get("Category", "")
109
- pri = result.get("Priority", "")
110
- rec = result.get("Suggested Recipient", "")
111
- dra = result.get("Draft Response", "")
112
- summ = result.get("Summary", "")
113
- acts = result.get("Action Items", [])
114
- acts = "\n".join(acts) if isinstance(acts, list) else acts
115
- return cat, pri, rec, dra, summ, acts
 
 
 
 
 
 
116
 
117
  classify_btn.click(
118
- classify_and_render,
119
- inputs=[email_box],
120
- outputs=[category, priority, recipient, draft_response, summary, action_items]
121
  )
 
 
122
 
123
  if __name__ == "__main__":
124
  demo.launch()
 
2
  import gradio as gr
3
  import requests
4
  import json
5
+ from datetime import datetime
6
 
7
  GROQ_API_KEY = os.getenv("GROQ_API_KEY")
8
  GROQ_COMPLETION_URL = "https://api.groq.com/openai/v1/chat/completions"
9
  GROQ_MODEL = "llama-3.1-8b-instant"
10
 
11
+ # Dummy sender risk DB
12
+ SENDER_REPUTATION = {
13
+ "it@company.com": "Trusted",
14
+ "accounts@supplier.com": "Trusted",
15
+ "spammer@promo.com": "Suspicious",
16
+ "unknown@phish.com": "Flagged"
17
+ }
18
+
19
+ # In-memory structures
20
+ classification_history = []
21
+ analytics_counter = {}
22
+
23
+ default_categories = ["Support Request", "Sales Inquiry", "Finance/Billing", "Urgent Incident", "Spam/Marketing"]
24
+
25
+ default_templates = [
26
+ "Thank you for your email. We are looking into your request and will reply shortly.",
27
+ "We have received your billing inquiry and will review your account information.",
28
+ "Your support request has been escalated to our technical team."
29
+ ]
30
+
31
+ def get_sender(email_txt):
32
+ for line in email_txt.splitlines():
33
+ if line.lower().startswith("from:"):
34
+ return line.split(":",1)[-1].strip()
35
+ return ""
36
+
37
  def groq_completion(prompt, sys_prompt=None):
38
  headers = {
39
  "Authorization": f"Bearer {GROQ_API_KEY}",
 
42
  body = {
43
  "model": GROQ_MODEL,
44
  "messages": [
45
+ {"role": "system", "content": sys_prompt or "You are a helpful business email assistant."},
46
  {"role": "user", "content": prompt}
47
  ],
48
  "temperature": 0.3,
 
58
  print("Groq API response:", response.text)
59
  return "Error"
60
 
61
+ def email_classifier_router(email_txt, categories, templates):
62
+ sender = get_sender(email_txt)
63
+ sender_score = SENDER_REPUTATION.get(sender,"Unknown")
64
+ category_prompt = f"Categories (choose one or suggest new): {', '.join(categories)}\n"
65
+ template_list = "\n".join([f"- {t}" for t in templates])
66
  prompt = (
67
+ f"{category_prompt}"
68
+ "Extract:\n"
69
+ "- Category\n- Priority\n- Suggested Recipient\n- Professional draft response\n"
70
+ "- Summary (one sentence)\n- Action Items (numbered list)\n- Entities: invoice numbers, dates, customer names if present.\n"
71
+ "Format as single compact JSON dictionary.\n"
72
+ '{"Category":"...", "Priority":"...", "Suggested Recipient":"...", "Draft Response":"...", "Summary":"...", "Action Items":["..."], "Entities":{"Invoice":"","Date":"","Customer":""}}\n\n'
73
+ f"{email_txt}\n"
74
+ "If reply, you may use these reply templates as inspiration:\n"
75
+ f"{template_list}"
 
 
76
  )
77
  raw_result = groq_completion(prompt)
78
  try:
 
85
  "Suggested Recipient": "Error",
86
  "Draft Response": raw_result,
87
  "Summary": "Error",
88
+ "Action Items": ["Error"],
89
+ "Entities": {"Invoice":"", "Date":"", "Customer":""}
90
  }
91
+ # Store in history & update analytics
92
+ now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
93
+ entry = {
94
+ "datetime": now,
95
+ "email": email_txt,
96
+ "category": output.get("Category",""),
97
+ "priority": output.get("Priority",""),
98
+ "summary": output.get("Summary",""),
99
+ "draft": output.get("Draft Response",""),
100
+ "recipient": output.get("Suggested Recipient",""),
101
+ "entities": output.get("Entities",{}),
102
+ "actions": output.get("Action Items",[]),
103
+ "sender": sender,
104
+ "risk": sender_score
105
+ }
106
+ classification_history.append(entry)
107
+ analytics_counter[output.get("Category","Other")] = analytics_counter.get(output.get("Category","Other"),0)+1
108
+ return entry
109
+
110
+ def show_history():
111
+ res = []
112
+ for entry in reversed(classification_history):
113
+ block = gr.Group()
114
+ summary = entry['summary']
115
+ txt = f"**Category:** {entry['category']} \n**Priority:** {entry['priority']} \n{summary}"
116
+ btns = gr.Row()
117
+ block.append(gr.Markdown(txt))
118
+ block.append(btns)
119
+ res.append(block)
120
+ return res
121
+
122
+ def copy_email(entry_idx):
123
+ if 0 <= entry_idx < len(classification_history):
124
+ return classification_history[entry_idx]['email']
125
+ return ""
126
+
127
+ def load_email(entry_idx):
128
+ if 0 <= entry_idx < len(classification_history):
129
+ return classification_history[entry_idx]['email']
130
+ return ""
131
+
132
+ def clear_history():
133
+ classification_history.clear()
134
+ analytics_counter.clear()
135
+ return gr.update(visible=True)
136
 
137
  with gr.Blocks(theme=gr.themes.Monochrome()) as demo:
138
+ # Editable categories and template management
139
+ with gr.Row():
140
+ gr.Markdown("📝 **Manage Categories and Reply Templates**")
141
+ categories_box = gr.Textbox(label="Categories (comma separated)", value=", ".join(default_categories))
142
+ templates_box = gr.Textbox(label="Reply Templates (one per line)", value="\n".join(default_templates), lines=3)
143
+
144
+ gr.Markdown("## 📨 Classify & Reply to Emails")
145
+ email_box = gr.Textbox(lines=8, label="Paste the entire raw email")
146
+ classify_btn = gr.Button("Classify Email", variant="primary")
 
 
 
 
 
147
 
148
+ results = gr.JSON(label="Classification + Extraction Results")
149
+ sender_risk = gr.Textbox(label="Sender Risk Score", interactive=False)
150
+ entities = gr.JSON(label="Extracted Entities")
151
+
152
+ # Template suggester
153
+ template_select = gr.Dropdown(choices=default_templates, label="Insert Reply Template")
154
+ insert_btn = gr.Button("Insert Template into Draft")
155
+
156
+ # History display
157
+ gr.Markdown("### 🕒 Classification History")
158
+ history_output = gr.Markdown()
159
+ clear_btn = gr.Button("Clear History")
160
+
161
+ # Basic Analytics
162
+ analytics = gr.Markdown(label="Simple Analytics")
163
+
164
+ def classify(email, cats, tmps):
165
+ cat_list = [c.strip() for c in cats.split(",")]
166
+ tmpl_list = [t.strip() for t in tmps.split("\n") if t.strip()]
167
+ entry = email_classifier_router(email, cat_list, tmpl_list)
168
+ return (entry, entry["risk"], entry["entities"], render_history(classification_history), render_analytics(analytics_counter))
169
+
170
+ def render_history(history):
171
+ # Render HTML for cards
172
+ res = ""
173
+ for idx, h in enumerate(reversed(history)):
174
+ summary = h['summary']
175
+ res += f"""<div style="border:1px solid #333;margin:5px;padding:8px;">
176
+ <b>{h['datetime']}</b> <br>
177
+ <b>Category:</b> <span style='background:#448; color:white; border-radius:4px; padding:2px 8px;'>{h['category']}</span>
178
+ <b>Priority:</b> <span style='background:#aa4; color:black; border-radius:4px; padding:2px 8px;'>{h['priority']}</span>
179
+ <br>{summary[:120]}
180
+ <br>
181
+ <button onclick="navigator.clipboard.writeText({json.dumps(h['draft'])})">Copy Email</button>
182
+ <button onclick="navigator.clipboard.writeText({json.dumps(h['email'])})">Load</button>
183
+ </div>"""
184
+ return res
185
+
186
+ def render_analytics(counter):
187
+ res = "**Category Counts:**<br>"
188
+ for k, v in counter.items():
189
+ res += f"{k}: <b>{v}</b><br>"
190
+ return res
191
 
192
  classify_btn.click(
193
+ classify,
194
+ inputs=[email_box, categories_box, templates_box],
195
+ outputs=[results, sender_risk, entities, history_output, analytics]
196
  )
197
+ clear_btn.click(clear_history, None, history_output)
198
+ insert_btn.click(lambda t, d: d + "\n" + t, [template_select, email_box], email_box)
199
 
200
  if __name__ == "__main__":
201
  demo.launch()