scmlewis commited on
Commit
84dad0c
·
verified ·
1 Parent(s): 0dab4fb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +61 -97
app.py CHANGED
@@ -44,15 +44,12 @@ def email_classifier_router(raw_email):
44
  "- Draft professional reply\n"
45
  "- Summary (one sentence)\n"
46
  "- Action Items (numbered list)\n\n"
47
- "Format:\n"
48
- '{"Category":"...", "Priority":"...", "Suggested Recipient":"...", "Draft Response":"...", "Summary":"...", "Action Items":["...","..."]}\n\n'
49
  f"{raw_email}"
50
  )
51
  raw_result = groq_completion(prompt)
52
  try:
53
  output = json.loads(raw_result)
54
  except Exception as e:
55
- print(f"JSON parse error: {e}\nRAW: {raw_result}")
56
  output = {
57
  "Category": "Error",
58
  "Priority": "Error",
@@ -73,91 +70,56 @@ def add_to_history(email, cat, pri, summ):
73
  }
74
  classification_history.append(entry)
75
 
76
- css = """
77
  body { background: linear-gradient(120deg, #10193a 0%, #175ad7 120%) !important; font-family: 'Inter', 'Segoe UI', Arial, sans-serif;}
78
  .gradio-container { background: transparent !important; }
79
- .card-block {
80
- background: rgba(27,36,68,0.96);
81
- border-radius: 30px;
82
- box-shadow: 0 6px 42px #0b2269bb, 0 1.5px 0 #186fc055 inset;
83
- padding: 38px 28px 29px 28px;
84
- margin: 32px 0;
85
- color: #fafeff;
86
- border: 2px solid #2847a46c;
87
- backdrop-filter: blur(8px);
88
- }
89
- input, textarea, .wrap.svelte-psy7la, .wrap.svelte-1ybjah6 {
90
- background: rgba(21,28,56,0.91)!important; border:1.5px solid #345ca3e3!important; color:#def1ff!important;
91
- border-radius: 14px !important; box-shadow: none !important;
92
- }
93
  label, .label.svelte-1ybjah6 { color: #70acf8!important; font-size: 1em !important; font-weight: 400;}
94
- .glass-btn {
95
- border-radius: 18px !important;
96
- box-shadow: 0 4px 18px #287bef25 !important;
97
- background: linear-gradient(90deg,#336bc0 60%,#1ae6ff 140%)!important;
98
- color: #fff !important;
99
- letter-spacing: .04em;
100
- border: none !important;
101
- font-size: 1.11em !important;
102
- font-weight: 600;
103
- padding: 12px 0 10px 0 !important;
104
- }
105
- .card-header {
106
- font-size: 1.32em;
107
- font-weight: 800;
108
- letter-spacing: 0.01em;
109
- margin: 0 0 15px 0;
110
- color: #ffffff;
111
- text-shadow: 0 3px 24px #175ad799;
112
- display: flex; align-items: center;
113
- }
114
- .badge {
115
- display:inline-block;
116
- border-radius:999px;
117
- padding:4px 16px;
118
- font-weight:600;
119
- background:linear-gradient(90deg,#2870ee 70%,#13e4fc 140%);
120
- box-shadow:0 1px 12px #0663fd29;
121
- color:#fff;
122
- margin-right:12px;
123
- font-size:1.05em;
124
- vertical-align:middle;
125
- }
126
  .priority-high { background:linear-gradient(90deg,#ed4864 60%,#fa4764 150%)!important; color:#fff;}
127
  .priority-medium { background:linear-gradient(90deg,#f3aa36 70%,#f6ea48 120%)!important;color:#222;}
128
  .priority-low { background:linear-gradient(90deg,#18cd67 60%,#27f8ac 150%)!important;color:#fff;}
129
- .history-record {
130
- background: rgba(35, 54, 90, 0.92);
131
- color: #e2f5ff;
132
- margin: 0 0 13px 0;
133
- border-radius: 14px;
134
- border-left: 5px solid #10baff;
135
- padding: 13px 22px 12px 22px;
136
- box-shadow: 0 2px 12px #08526733;
137
- transition: box-shadow .2s;
138
- font-size: 1.01em;
139
- }
140
- .history-record.selected { border-left:7px solid #22eef8; background: rgba(44,86,166,1);}
141
- .history-record .small { color:#a6c5e7; font-size: .92em;}
142
  """
143
 
144
  with gr.Blocks(css=css) as demo:
145
- gr.Markdown("<div style='text-align:center; margin:10px 0 16px 0; font-size:2em; letter-spacing:.01em; font-weight:900;color:#fff;'><span style='margin-right:10px;'>📧</span>AI Email Classifier & Router</div>")
 
 
 
 
 
 
 
 
146
  with gr.Row():
147
- with gr.Column(scale=5, min_width=410):
148
  with gr.Group(elem_id="input-card", elem_classes=["card-block"]):
149
  gr.Markdown("<div class='card-header'>✉️ Paste Your Email</div>")
150
- gr.Markdown("<span style='font-size:.95em; color:#a6c5e7;'>Choose Example:</span>")
151
  with gr.Row():
152
  support_button = gr.Button("Support Request")
153
  sales_button = gr.Button("Sales Inquiry")
154
  finance_button = gr.Button("Finance / Billing")
155
  urgent_button = gr.Button("Urgent Incident")
156
  spam_button = gr.Button("Spam / Marketing")
 
 
 
157
  email_box = gr.Textbox(lines=8, label="", placeholder="From: ...\nSubject: ...")
158
- classify_btn = gr.Button("Classify Email", elem_classes=["glass-btn"])
159
 
160
- with gr.Column(scale=7, min_width=430):
161
  with gr.Group(elem_id="output-card", elem_classes=["card-block"]):
162
  gr.Markdown("""<div class='card-header'>🧮 Classification Results</div>""")
163
  result_labels = gr.Markdown("")
@@ -167,20 +129,21 @@ with gr.Blocks(css=css) as demo:
167
  action_items = gr.Textbox(lines=3, label="Extracted Action Items")
168
 
169
  with gr.Group(elem_id="history-card", elem_classes=["card-block"]):
170
- gr.Markdown("""<div class='card-header'>🕒 Classification History</div>""")
171
- history_radio = gr.Radio([], label="", type="index")
172
- load_btn = gr.Button("Load Selected", elem_classes=["glass-btn"])
173
-
174
- ex1 = "From: help@company.com\nSubject: Unable to Login\nHi, I can't access my dashboard. Can you help?"
175
- ex2 = "From: sales@prospect.com\nSubject: Inquiry about pricing\nHi, Can you send over your latest pricing for enterprise?"
176
- 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..."
177
- ex4 = "From: it@company.com\nSubject: Server Down Alert\nURGENT: Database server unreachable since 3AM. Needs escalation."
178
- ex5 = "From: spammer@promo.com\nSubject: BIG SALE!!!\nDon't miss our special offers!"
179
- support_button.click(lambda: ex1, None, email_box)
180
- sales_button.click(lambda: ex2, None, email_box)
181
- finance_button.click(lambda: ex3, None, email_box)
182
- urgent_button.click(lambda: ex4, None, email_box)
183
- spam_button.click(lambda: ex5, None, email_box)
 
184
 
185
  def classify_and_render(email_text):
186
  result = email_classifier_router(email_text)
@@ -193,26 +156,27 @@ with gr.Blocks(css=css) as demo:
193
  acts = "\n".join(acts) if isinstance(acts, list) else acts
194
  add_to_history(email_text, cat, pri, summ)
195
  badge = f"<b>Category:</b> <span class='badge'>{cat}</span> <b>Priority:</b> <span class='badge priority-{pri.lower()}'>{pri}</span>"
196
- display = [
197
- f"**{h['datetime']}**\n"
198
- f"**Category:** <span class='badge'>{h['category']}</span> \n"
199
- f"**Priority:** <span class='badge priority-{h['priority'].lower()}'>{h['priority']}</span> \n"
200
- f"<span class='small'>{h['summary']}</span>"
201
- for h in classification_history
202
- ]
203
- return badge, rec, dra, summ, acts, gr.update(choices=display, value=len(display)-1)
204
-
205
- def load_history(idx):
206
- if idx is not None and 0 <= idx < len(classification_history):
207
- return classification_history[idx]["email"]
208
- return ""
 
 
209
 
210
  classify_btn.click(
211
  classify_and_render,
212
  inputs=[email_box],
213
- outputs=[result_labels, recipient, draft_response, summary, action_items, history_radio]
214
  )
215
- load_btn.click(load_history, inputs=[history_radio], outputs=email_box)
216
 
217
  if __name__ == "__main__":
218
  demo.launch()
 
44
  "- Draft professional reply\n"
45
  "- Summary (one sentence)\n"
46
  "- Action Items (numbered list)\n\n"
 
 
47
  f"{raw_email}"
48
  )
49
  raw_result = groq_completion(prompt)
50
  try:
51
  output = json.loads(raw_result)
52
  except Exception as e:
 
53
  output = {
54
  "Category": "Error",
55
  "Priority": "Error",
 
70
  }
71
  classification_history.append(entry)
72
 
73
+ css="""
74
  body { background: linear-gradient(120deg, #10193a 0%, #175ad7 120%) !important; font-family: 'Inter', 'Segoe UI', Arial, sans-serif;}
75
  .gradio-container { background: transparent !important; }
76
+ .card-block { background: rgba(27,36,68,0.96); border-radius: 30px; box-shadow: 0 6px 42px #0b2269bb, 0 1.5px 0 #186fc055 inset; padding: 38px 28px 29px 28px; margin: 32px 0; color: #fafeff; border: 2px solid #2847a46c; backdrop-filter: blur(8px);}
77
+ input, textarea, .wrap.svelte-psy7la, .wrap.svelte-1ybjah6 { background: rgba(21,28,56,0.91)!important; border:1.5px solid #345ca3e3!important; color:#def1ff!important; border-radius: 14px !important; box-shadow: none !important;}
 
 
 
 
 
 
 
 
 
 
 
 
78
  label, .label.svelte-1ybjah6 { color: #70acf8!important; font-size: 1em !important; font-weight: 400;}
79
+ .glass-btn { border-radius: 18px !important; box-shadow: 0 4px 18px #287bef25 !important; background: linear-gradient(90deg,#336bc0 60%,#1ae6ff 140%)!important; color: #fff !important; letter-spacing: .04em; border: none !important; font-size: 1.11em !important; font-weight: 600; padding: 12px 0 10px 0 !important;}
80
+ .card-header { font-size: 2.1em;font-weight:900;letter-spacing:0.01em; margin:0 0 28px 0; color: #fff; text-shadow: 0 5px 36px #175ad799;}
81
+ .badge { display:inline-block; border-radius:999px; padding:4px 16px; font-weight:600; background:linear-gradient(90deg,#2870ee 70%,#13e4fc 140%); box-shadow:0 1px 12px #0663fd29; color:#fff; margin-right:12px; font-size:1.12em; vertical-align:middle;}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  .priority-high { background:linear-gradient(90deg,#ed4864 60%,#fa4764 150%)!important; color:#fff;}
83
  .priority-medium { background:linear-gradient(90deg,#f3aa36 70%,#f6ea48 120%)!important;color:#222;}
84
  .priority-low { background:linear-gradient(90deg,#18cd67 60%,#27f8ac 150%)!important;color:#fff;}
85
+ .history-cardbox {display:flex;gap:28px;flex-wrap:wrap;}
86
+ .history-record {background: rgba(35, 54, 90, 0.92);color: #e2f5ff;margin:0 0 13px 0; border-radius: 16px;border-left: 5px solid #10baff; box-shadow: 0 2px 12px #08526733;padding:20px 26px 16px 26px;min-width:340px;max-width:370px;box-sizing:border-box;}
87
+ .history-ts { color:#a7b7ce;font-size:0.96em; }
88
+ .history-catlab { font-size:1.1em;font-weight:600; }
89
+ .history-summ { font-style:italic;font-size:1.08em;margin-top:7px;color:#eaf7ff;}
90
+ .history-btnrow { display:flex; gap:12px; margin-top:14px;}
91
+ .btn-md {padding:10px 22px;border-radius:14px; border:none;font-size:1.03em;font-weight:700;background:#3246b8; color:#fff;}
92
+ .btn-md:hover { background:#2284cc;}
93
+ .card-header svg {width:1.5em;height:1.5em;vertical-align:middle; margin-right:8px;}
 
 
 
 
94
  """
95
 
96
  with gr.Blocks(css=css) as demo:
97
+ gr.Markdown("""
98
+ <div style='text-align:center; margin:10px 0 22px 0; font-size:2.5em; font-weight:900; letter-spacing:.01em; color:#fff;'>
99
+ <svg width="36" height="36" fill="none" stroke="#26e2ec" stroke-width="3" style="vertical-align:middle;margin-right:9px;">
100
+ <circle cx="18" cy="18" r="16" fill="#0133a0" stroke-width="0"/>
101
+ <text x="50%" y="55%" text-anchor="middle" dominant-baseline="middle" font-family="Segoe UI" font-size="19" fill="#fff">✉️</text>
102
+ </svg>
103
+ AI Email Classifier & Router
104
+ </div>
105
+ """)
106
  with gr.Row():
107
+ with gr.Column(scale=6, min_width=420):
108
  with gr.Group(elem_id="input-card", elem_classes=["card-block"]):
109
  gr.Markdown("<div class='card-header'>✉️ Paste Your Email</div>")
110
+ gr.Markdown("<span style='font-size:1.05em; color:#a6c5e7;'>Choose Example:</span>")
111
  with gr.Row():
112
  support_button = gr.Button("Support Request")
113
  sales_button = gr.Button("Sales Inquiry")
114
  finance_button = gr.Button("Finance / Billing")
115
  urgent_button = gr.Button("Urgent Incident")
116
  spam_button = gr.Button("Spam / Marketing")
117
+ gr.Button("Account issue")
118
+ gr.Button("Legal inquiry")
119
+ gr.Button("Meeting scheduling")
120
  email_box = gr.Textbox(lines=8, label="", placeholder="From: ...\nSubject: ...")
 
121
 
122
+ with gr.Column(scale=8, min_width=430):
123
  with gr.Group(elem_id="output-card", elem_classes=["card-block"]):
124
  gr.Markdown("""<div class='card-header'>🧮 Classification Results</div>""")
125
  result_labels = gr.Markdown("")
 
129
  action_items = gr.Textbox(lines=3, label="Extracted Action Items")
130
 
131
  with gr.Group(elem_id="history-card", elem_classes=["card-block"]):
132
+ gr.Markdown("""<div class='card-header' style="margin-bottom:20px;">🕒 Classification History</div>""")
133
+ history_cardbox = gr.HTML(elem_id="history-cardbox")
134
+
135
+ exs = [
136
+ "From: support@mycrm.com\nSubject: Cannot login to dashboard\nBody: I've been unable to sign into my account for 3 days even after password reset.",
137
+ "From: prospect@b2bsales.com\nSubject: Inquiry about pricing\nHi, Can you send over your enterprise pricing and product details for Q1?",
138
+ "From: accounts@acmecorp.com\nSubject: Invoice #00456 Payment Reminder\nBody: This is a reminder that your invoice #00456 for $4,200.00 is due next week.",
139
+ "From: jane.doe@company.org\nSubject: Meeting request\nCould you schedule a call with the marketing team for Friday 3pm?",
140
+ "From: admin@infra.com\nSubject: URGENT Server Down\nThe production DB went down at 11:22 UTC, please escalate to engineering immediately.",
141
+ "From: legal@mycrm.com\nSubject: Contract question\nCan your team confirm paragraph 7.4 in the service agreement?",
142
+ "From: billing@b2bsales.com\nSubject: Account update\nPlease update billing address for account #AC10239.",
143
+ "From: teamlead@company.org\nSubject: Follow-up on project\nHi, just wanted a final status update on our July roadmap deliverables.",
144
+ ]
145
+ for idx, ex in enumerate(exs):
146
+ demo.children[0].children[0].children[1].children[idx].click(lambda ex=ex: ex, None, email_box)
147
 
148
  def classify_and_render(email_text):
149
  result = email_classifier_router(email_text)
 
156
  acts = "\n".join(acts) if isinstance(acts, list) else acts
157
  add_to_history(email_text, cat, pri, summ)
158
  badge = f"<b>Category:</b> <span class='badge'>{cat}</span> <b>Priority:</b> <span class='badge priority-{pri.lower()}'>{pri}</span>"
159
+ # Native HTML styled history cards
160
+ history_html = ""
161
+ for idx, h in enumerate(classification_history[::-1]):
162
+ history_html += f"""
163
+ <div class='history-record'>
164
+ <div class='history-ts'>{h['datetime']}</div>
165
+ <div class='history-catlab'>Category: <span class='badge'>{h['category']}</span> Priority: <span class='badge priority-{h['priority'].lower()}'>{h['priority']}</span></div>
166
+ <div class='history-summ'>{h['summary']}</div>
167
+ <div class='history-btnrow'>
168
+ <button class='btn-md' onclick="navigator.clipboard.writeText({json.dumps(h['email'])});">Copy Email</button>
169
+ <button class='btn-md' onclick="window.parent.postMessage({json.dumps(h['email'])}, '*');">Load</button>
170
+ </div>
171
+ </div>
172
+ """
173
+ return badge, rec, dra, summ, acts, history_html
174
 
175
  classify_btn.click(
176
  classify_and_render,
177
  inputs=[email_box],
178
+ outputs=[result_labels, recipient, draft_response, summary, action_items, history_cardbox]
179
  )
 
180
 
181
  if __name__ == "__main__":
182
  demo.launch()