DevNumb commited on
Commit
44c6a74
·
verified ·
1 Parent(s): 44de1a4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +217 -670
app.py CHANGED
@@ -2,706 +2,253 @@ import gradio as gr
2
  import requests
3
  import os
4
  import base64
5
- from PIL import Image
6
  import io
7
  import datetime
 
 
 
 
 
8
 
9
- # Configuration from environment variables
10
  OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY")
11
- DEFAULT_REPORT_EMAIL = os.getenv("REPORT_EMAIL")
12
  BREVO_API_KEY = os.getenv("BREVO_API_KEY")
13
- BREVO_FROM_EMAIL = os.getenv("BREVO_FROM_EMAIL", "noreply@yourdomain.com")
14
 
15
- # Store conversation history and settings
16
  conversation_history = []
17
- current_report_email = DEFAULT_REPORT_EMAIL
18
 
19
- # Department configurations
 
 
 
20
  departments = {
21
- "administration": {
22
- "name": "Administration",
23
- "email": os.getenv("ADMIN_EMAIL", ""),
24
- "responsibilities": "Overall management, decision making, and coordination"
25
- },
26
- "production": {
27
- "name": "Production",
28
- "email": os.getenv("PRODUCTION_EMAIL", ""),
29
- "responsibilities": "Manufacturing, quality control, and production planning"
30
- },
31
- "magazine": {
32
- "name": "Magazine Management",
33
- "email": os.getenv("MAGAZINE_EMAIL", ""),
34
- "responsibilities": "Content creation, publishing, and distribution"
35
- }
36
  }
37
 
38
- def update_report_email(new_email):
39
- """Update the report email address"""
40
- global current_report_email
41
- if new_email and "@" in new_email and "." in new_email:
42
- current_report_email = new_email.strip()
43
- return f"✅ Report email updated to: {current_report_email}"
44
- else:
45
- return "❌ Please enter a valid email address"
46
-
47
- def send_email_brevo_api(to_email, subject, html_content, from_name="AI Coordination System"):
48
- """Send email using Brevo API"""
49
- try:
50
- if not BREVO_API_KEY:
51
- return "❌ Email not configured - missing Brevo API key"
52
-
53
- response = requests.post(
54
- "https://api.brevo.com/v3/smtp/email",
55
- headers={
56
- "accept": "application/json",
57
- "content-type": "application/json",
58
- "api-key": BREVO_API_KEY
59
- },
60
- json={
61
- "sender": {
62
- "name": from_name,
63
- "email": BREVO_FROM_EMAIL
64
- },
65
- "to": [{"email": to_email}],
66
- "subject": subject,
67
- "htmlContent": html_content
68
- },
69
- timeout=10
70
- )
71
-
72
- if response.status_code == 201:
73
- return f"✅ Email sent to {to_email}"
74
- else:
75
- error_msg = response.json().get('message', 'Unknown error')
76
- return f"❌ Failed to send email: {error_msg}"
77
-
78
- except Exception as e:
79
- return f"❌ Email error: {str(e)}"
80
-
81
- def analyze_coordination_needs(user_message, department, user_name, image=None):
82
- """Use LLM to analyze coordination needs and suggest actions - with image support"""
83
-
84
- if image:
85
- # Convert image to base64 for vision model
86
- buffered = io.BytesIO()
87
- image.save(buffered, format="PNG")
88
- img_base64 = base64.b64encode(buffered.getvalue()).decode()
89
-
90
- prompt = f"""
91
- You are an Enterprise Operations Coordination AI.
92
-
93
- Analyze the request AND the attached image to determine responsibility and next actions.
94
-
95
- Write formally and professionally.
96
- No casual tone. No emojis.
97
-
98
- AVAILABLE DEPARTMENTS:
99
- - Administration: approvals, management, coordination
100
- - Production: equipment, facilities, manufacturing, maintenance
101
- - Magazine: design, content, publishing
102
-
103
- REQUEST:
104
- Requestor: {user_name}
105
- Origin Department: {department}
106
- Message: {user_message}
107
-
108
- Provide:
109
-
110
- === EXECUTIVE SUMMARY ===
111
- Short professional summary
112
-
113
- === IMAGE OBSERVATIONS ===
114
- Important findings from the image
115
-
116
- === RECOMMENDED TARGET DEPARTMENT ===
117
- Choose ONLY ONE: Administration | Production | Magazine
118
- Reason
119
 
120
- === ACTION PLAN ===
121
- Numbered steps
122
 
123
- === PRIORITY ===
124
- Low | Medium | High with reason
125
 
126
- === FOLLOW-UP ===
127
- Monitoring or escalation steps
 
 
 
 
 
 
 
 
 
128
  """
129
- try:
130
- response = requests.post(
131
- "https://openrouter.ai/api/v1/chat/completions",
132
- headers={
133
- "Authorization": f"Bearer {OPENROUTER_API_KEY}",
134
- "Content-Type": "application/json",
135
- },
136
- json={
137
- "model": "google/gemma-3-27b-it:free", # Vision model
138
- "messages": [
139
- {
140
- "role": "user",
141
- "content": [
142
- {
143
- "type": "text",
144
- "text": prompt
145
- },
146
- {
147
- "type": "image_url",
148
- "image_url": {
149
- "url": f"data:image/png;base64,{img_base64}"
150
- }
151
- }
152
- ]
153
- }
154
- ],
155
- "temperature": 0.3
156
- },
157
- timeout=60
158
- )
159
-
160
- if response.status_code == 200:
161
- data = response.json()
162
- return data["choices"][0]["message"]["content"]
163
- else:
164
- return "I'm having trouble analyzing the image right now. Please try again in a moment."
165
-
166
- except Exception as e:
167
- return f"Sorry, I couldn't process the image. Error: {str(e)}"
168
-
169
- else:
170
- # Text-only analysis
171
- prompt = prompt = f"""
172
- You are an Enterprise Operations Coordination AI used inside a professional organization.
173
-
174
- Your responsibility is to:
175
- • analyze the request
176
- • determine which department should handle it
177
- • produce a concise, executive-style coordination plan
178
-
179
- Write formally and professionally.
180
- Do NOT use conversational tone.
181
- Do NOT use emojis.
182
- Be precise, structured, and action-oriented.
183
-
184
- AVAILABLE DEPARTMENTS:
185
- - Administration: management, approvals, policies, finance, coordination
186
- - Production: manufacturing, maintenance, equipment, operations, logistics
187
- - Magazine: content creation, publishing, marketing materials, communication
188
-
189
- REQUEST:
190
- Requestor: {user_name}
191
- Origin Department: {department}
192
- Message: {user_message}
193
-
194
- Return your answer STRICTLY using this format:
195
-
196
- === EXECUTIVE SUMMARY ===
197
- 2–3 sentence professional summary.
198
-
199
- === RECOMMENDED TARGET DEPARTMENT ===
200
- Choose ONLY ONE: Administration | Production | Magazine
201
- Brief justification.
202
 
203
  === DEPARTMENTS INVOLVED ===
204
- • Department – responsibility
205
 
206
  === ACTION PLAN ===
207
- 1. Step
208
- 2. Step
209
- 3. Step
210
 
211
- === PRIORITY ===
212
- Low | Medium | High with reason
213
 
214
  === FOLLOW-UP ===
215
- Required monitoring or reporting actions
216
  """
217
 
218
- try:
219
- response = requests.post(
220
- "https://openrouter.ai/api/v1/chat/completions",
221
- headers={
222
- "Authorization": f"Bearer {OPENROUTER_API_KEY}",
223
- "Content-Type": "application/json",
224
- },
225
- json={
226
- "model": "google/gemma-3-27b-it:free",
227
- "messages": [{"role": "user", "content": prompt}],
228
- "temperature": 0.3
229
- },
230
- timeout=30
231
- )
232
-
233
- if response.status_code == 200:
234
- data = response.json()
235
- return data["choices"][0]["message"]["content"]
236
- else:
237
- return "I'm having trouble analyzing your request right now. Please try again in a moment."
238
-
239
- except Exception as e:
240
- return f"Sorry, I couldn't process your request. Error: {str(e)}"
241
-
242
- def send_department_email(sender_dept, recipient_dept, subject, message, user_name, urgency="Normal", image=None):
243
- """Send email between departments with optional image attachment"""
244
- try:
245
- # Determine recipient email
246
- recipient_email = departments[recipient_dept]["email"]
247
- if not recipient_email:
248
- # If no department email configured, use the current report email
249
- recipient_email = current_report_email
250
-
251
- # Create professional email content
252
- image_note = "<p style='margin: 5px 0;'><strong>📎 Attachment:</strong> Image included with request</p>" if image else ""
253
- urgency_class = f"urgency-{urgency.lower()}" if urgency.lower() in ['high', 'medium'] else "urgency-normal"
254
- image_footer = "<p><em>Note: An image was included with this request. Please check the original system for image details.</em></p>" if image else ""
255
-
256
- html_content = f"""<html>
257
- <head>
258
- <style>
259
- body {{ font-family: Arial, sans-serif; margin: 20px; }}
260
- .header {{ background-color: #f4f4f4; padding: 20px; border-radius: 8px; margin-bottom: 20px; }}
261
- .urgency-high {{ border-left: 5px solid #dc2626; background-color: #fef2f2; }}
262
- .urgency-medium {{ border-left: 5px solid #d97706; background-color: #fffbeb; }}
263
- .urgency-normal {{ border-left: 5px solid #2563eb; background-color: #eff6ff; }}
264
- .message-content {{ padding: 20px; background-color: white; border-radius: 8px; margin: 15px 0; }}
265
- .user-info {{ background-color: #f8fafc; padding: 10px 15px; border-radius: 6px; margin: 10px 0; }}
266
- </style>
267
- </head>
268
- <body>
269
- <div class="header">
270
- <h1 style="margin: 0; color: #1f2937;">🏢 Inter-Department Communication</h1>
271
- <p style="margin: 5px 0;"><strong>From:</strong> {departments[sender_dept]['name']}</p>
272
- <p style="margin: 5px 0;"><strong>Requested by:</strong> {user_name}</p>
273
- <p style="margin: 5px 0;"><strong>To:</strong> {departments[recipient_dept]['name']}</p>
274
- <p style="margin: 5px 0;"><strong>Date:</strong> {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
275
- <p style="margin: 5px 0;"><strong>Urgency:</strong> {urgency}</p>
276
- {image_note}
277
- </div>
278
-
279
- <div class="user-info">
280
- <strong>👤 Requestor Details:</strong><br>
281
- Name: {user_name}<br>
282
- Department: {departments[sender_dept]['name']}
283
- </div>
284
-
285
- <div class="message-content {urgency_class}">
286
- <h3 style="margin-top: 0;">{subject}</h3>
287
- <div style="white-space: pre-line;">{message}</div>
288
- </div>
289
-
290
- <div style="color: #6b7280; font-size: 0.9em; margin-top: 20px;">
291
- <p>This is an automated message from the AI Coordination System.</p>
292
- {image_footer}
293
- </div>
294
- </body>
295
- </html>"""
296
-
297
- # Send email using Brevo API
298
- from_name = f"{departments[sender_dept]['name']}"
299
- email_status = send_email_brevo_api(recipient_email, f"[{urgency}] {subject}", html_content, from_name)
300
- return email_status
301
-
302
- except Exception as e:
303
- return f"❌ Failed to send email: {str(e)}"
304
-
305
- def send_email_report(conversation_data):
306
- """Send comprehensive coordination report to administration"""
307
- if not BREVO_API_KEY or not current_report_email:
308
- return "Email reporting not configured - missing Brevo API key or report email"
309
-
310
- try:
311
- # Calculate department activity
312
- dept_activity = {}
313
- user_activity = {}
314
- for entry in conversation_data:
315
- dept = entry.get('department', 'Unknown')
316
- user = entry.get('user_name', 'Unknown')
317
- dept_activity[dept] = dept_activity.get(dept, 0) + 1
318
- user_activity[user] = user_activity.get(user, 0) + 1
319
-
320
- # Format email content
321
- subject = f"Coordination Report - {datetime.datetime.now().strftime('%Y-%m-%d %H:%M')}"
322
-
323
- # Create department activity HTML
324
- dept_activity_html = ""
325
- for dept, count in dept_activity.items():
326
- dept_activity_html += f"<p><strong>{dept.title()}:</strong> {count} interactions</p>"
327
-
328
- # Create user activity HTML
329
- user_activity_html = ""
330
- for user, count in user_activity.items():
331
- if user != 'Unknown':
332
- user_activity_html += f"<p><strong>{user}:</strong> {count} requests</p>"
333
-
334
- # Create recent activities HTML
335
- recent_activities_html = ""
336
- for i, entry in enumerate(conversation_data[-10:], 1):
337
- dept_badge = f"<span class='department-badge'>{entry.get('department', 'General').title()}</span>" if entry.get('department') else ""
338
- user_badge = f"<span class='user-badge'>{entry.get('user_name', 'User')}</span>" if entry.get('user_name') else ""
339
- image_indicator = " <span class='image-indicator'>📷</span>" if entry.get('image_uploaded') else ""
340
- email_indicator = " 📧" if entry.get('email_sent') else ""
341
-
342
- recent_activities_html += f"""<div class="exchange">
343
- <div style="display: flex; justify-content: between; align-items: center; margin-bottom: 10px;">
344
- <h4 style="margin: 0; color: #374151;">Activity #{i}</h4>
345
- <div>
346
- {dept_badge}
347
- {user_badge}
348
- {image_indicator}
349
- </div>
350
- </div>
351
- <p class="user"><strong>💬 Message:</strong> {entry['user_input']}{email_indicator}</p>
352
- <p class="ai"><strong>🤖 AI Coordination:</strong> {entry['ai_response']}</p>
353
- <p class="timestamp">{entry['timestamp']}</p>
354
- </div>"""
355
-
356
- # Create comprehensive HTML report
357
- html_content = f"""<html>
358
- <head>
359
- <style>
360
- body {{ font-family: Arial, sans-serif; margin: 20px; }}
361
- .header {{ background-color: #1f2937; color: white; padding: 25px; border-radius: 8px; margin-bottom: 20px; }}
362
- .stats {{ display: flex; justify-content: space-between; margin: 20px 0; }}
363
- .stat-card {{ background-color: #f8fafc; padding: 15px; border-radius: 8px; text-align: center; flex: 1; margin: 0 10px; }}
364
- .exchange {{ border: 1px solid #e0e0e0; margin: 15px 0; padding: 15px; border-radius: 8px; background-color: #fafafa; }}
365
- .user {{ color: #2563eb; font-weight: 600; }}
366
- .ai {{ color: #059669; }}
367
- .timestamp {{ color: #6b7280; font-size: 0.8em; font-style: italic; }}
368
- .department-badge {{ background-color: #3b82f6; color: white; padding: 2px 8px; border-radius: 12px; font-size: 0.8em; }}
369
- .user-badge {{ background-color: #10b981; color: white; padding: 2px 8px; border-radius: 12px; font-size: 0.8em; margin-left: 5px; }}
370
- .image-indicator {{ background-color: #f59e0b; color: white; padding: 2px 6px; border-radius: 10px; font-size: 0.7em; margin-left: 5px; }}
371
- </style>
372
- </head>
373
- <body>
374
- <div class="header">
375
- <h1 style="margin: 0;">🤖 AI Coordination System Report</h1>
376
- <p style="margin: 5px 0; opacity: 0.9;">Comprehensive inter-department coordination summary</p>
377
- <p style="margin: 5px 0;"><strong>Generated:</strong> {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
378
- </div>
379
-
380
- <div class="stats">
381
- <div class="stat-card">
382
- <h3 style="margin: 0; color: #3b82f6;">{len(conversation_data)}</h3>
383
- <p style="margin: 5px 0;">Total Interactions</p>
384
- </div>
385
- <div class="stat-card">
386
- <h3 style="margin: 0; color: #10b981;">{len(dept_activity)}</h3>
387
- <p style="margin: 5px 0;">Active Departments</p>
388
- </div>
389
- <div class="stat-card">
390
- <h3 style="margin: 0; color: #f59e0b;">{sum(1 for entry in conversation_history if entry.get('email_sent'))}</h3>
391
- <p style="margin: 5px 0;">Emails Sent</p>
392
- </div>
393
- </div>
394
-
395
- <h3>📊 Department Activity</h3>
396
- {dept_activity_html}
397
-
398
- <h3>👥 User Activity</h3>
399
- {user_activity_html if user_activity_html else "<p>No user activity data</p>"}
400
-
401
- <h3>🔄 Recent Coordination Activities</h3>
402
- {recent_activities_html if recent_activities_html else "<p>No recent activities</p>"}
403
-
404
- <div style="margin-top: 30px; padding: 15px; background-color: #f0fdf4; border-radius: 8px;">
405
- <p style="margin: 0;"><strong>🤖 AI Note:</strong> This report is automatically generated by the coordination system. All inter-department communications are logged and monitored for efficiency.</p>
406
- </div>
407
- </body>
408
- </html>"""
409
-
410
- # Send email using Brevo API
411
- email_status = send_email_brevo_api(current_report_email, subject, html_content, "AI Coordination System")
412
- return email_status
413
-
414
- except Exception as e:
415
- return f"Failed to send report: {str(e)}"
416
-
417
- def add_to_conversation_history(user_input, department, user_name, ai_response, email_sent=False, image_uploaded=False):
418
- """Add current exchange to conversation history"""
419
- entry = {
420
- 'timestamp': datetime.datetime.now().isoformat(),
421
- 'user_input': user_input,
422
- 'department': department,
423
- 'user_name': user_name,
424
- 'ai_response': ai_response,
425
- 'email_sent': email_sent,
426
- 'image_uploaded': image_uploaded
427
- }
428
- conversation_history.append(entry)
429
-
430
- # Keep only last 50 exchanges to prevent memory issues
431
- if len(conversation_history) > 50:
432
- conversation_history.pop(0)
433
-
434
- def process_coordination_request(name, department, message, image, recipient_dept, send_email, urgency):
435
- """Process coordination requests between departments with image support"""
436
- if not message.strip():
437
- return "Please enter a coordination message."
438
-
439
- if not department:
440
- return "Please select your department."
441
-
442
- if not name.strip():
443
- return "Please enter your name."
444
-
445
- # Get AI analysis and suggestions (with image if provided)
446
- ai_analysis = analyze_coordination_needs(message, department, name, image)
447
-
448
- # Prepare response
449
- response_parts = []
450
- response_parts.append(f"**👤 Request from:** {name} | **🏢 Department:** {departments[department]['name']}")
451
-
452
- if image:
453
- response_parts.append("**📷 Image attached and analyzed**")
454
-
455
- response_parts.append(f"\n**🤖 Coordination Guidance:**\n{ai_analysis}")
456
-
457
- # Send email if requested
458
- email_status = ""
459
- if send_email and recipient_dept:
460
- subject = f"Coordination Request from {departments[department]['name']} - {name}"
461
-
462
- # Build email message
463
- email_lines = [
464
- f"Requestor: {name}",
465
- f"Department: {departments[department]['name']}",
466
- "",
467
- "Message:",
468
- message,
469
- ""
470
- ]
471
-
472
- if image:
473
- email_lines.append("Note: An image was included with this request. Please check the system for visual details.")
474
- email_lines.append("")
475
-
476
- email_lines.extend([
477
- "---",
478
- "Coordination Suggestions:",
479
- ai_analysis
480
- ])
481
-
482
- email_message = "\n".join(email_lines)
483
- email_status = send_department_email(department, recipient_dept, subject, email_message, name, urgency, image)
484
- response_parts.append(f"\n**📧 Email Status:** {email_status}")
485
-
486
- full_response = "\n".join(response_parts)
487
-
488
- # Add to conversation history
489
- add_to_conversation_history(
490
- user_input=message,
491
- department=department,
492
- user_name=name,
493
- ai_response=full_response,
494
- email_sent=bool(send_email and recipient_dept),
495
- image_uploaded=image is not None
496
- )
497
-
498
- return full_response
499
-
500
- def get_conversation_stats():
501
- """Get statistics about current coordination activities"""
502
- if not conversation_history:
503
- return "No coordination activities yet"
504
-
505
- total_exchanges = len(conversation_history)
506
- dept_activity = {}
507
- user_activity = {}
508
- emails_sent = sum(1 for entry in conversation_history if entry.get('email_sent'))
509
- images_uploaded = sum(1 for entry in conversation_history if entry.get('image_uploaded'))
510
-
511
- for entry in conversation_history:
512
- dept = entry.get('department', 'Unknown')
513
- user = entry.get('user_name', 'Unknown')
514
- dept_activity[dept] = dept_activity.get(dept, 0) + 1
515
- if user != 'Unknown':
516
- user_activity[user] = user_activity.get(user, 0) + 1
517
-
518
- stats_text = f"📊 **Coordination Summary:**\n"
519
- stats_text += f"• Total Activities: {total_exchanges}\n"
520
- stats_text += f"• Emails Sent: {emails_sent}\n"
521
- stats_text += f"• Images Shared: {images_uploaded}\n\n"
522
-
523
- stats_text += "**Department Activity:**\n"
524
- for dept, count in dept_activity.items():
525
- stats_text += f"• {dept.title()}: {count} requests\n"
526
-
527
- if user_activity:
528
- stats_text += f"\n**Active Team Members:** {', '.join(user_activity.keys())}"
529
-
530
- return stats_text
531
-
532
- def clear_conversation():
533
- """Clear the conversation history"""
534
- global conversation_history
535
- conversation_history = []
536
- return "🗑️ Coordination history cleared!"
537
-
538
- def get_current_email():
539
- """Get the current report email address"""
540
- return current_report_email if current_report_email else "Not set"
541
-
542
- def clear_form():
543
- """Clear the form fields"""
544
- return ["", None, "", None, "administration", "Normal", False]
545
-
546
- # Gradio Interface
547
- # Add this at the top of your Gradio Blocks
548
- with gr.Blocks(
549
- theme=gr.themes.Soft(),
550
- title="AI Coordination System"
551
- ) as ui:
552
- gr.Markdown("# 🏢 AI Department Coordination System")
553
- gr.Markdown("*Streamline communication between Administration, Production, and Magazine Management*")
554
-
555
  with gr.Row():
 
556
  with gr.Column(scale=1):
557
- gr.Markdown("### ⚙️ System Settings")
558
- email_input = gr.Textbox(
559
- label="Administration Report Email",
560
- value=get_current_email,
561
- placeholder="admin@company.com"
562
- )
563
- email_status = gr.Textbox(
564
- label="Email Status",
565
- value=get_current_email,
566
- interactive=False,
567
- max_lines=2
568
- )
569
- update_email_btn = gr.Button("💾 Save Email", variant="primary")
570
-
571
- gr.Markdown("---")
572
- gr.Markdown("### 📝 New Coordination Request")
573
-
574
- with gr.Group():
575
- gr.Markdown("#### 👤 Your Information")
576
- name_input = gr.Textbox(
577
- label="Your Name",
578
- placeholder="Enter your full name"
579
- )
580
-
581
- department_dropdown = gr.Dropdown(
582
- choices=["administration", "production", "magazine"],
583
- label="Your Department"
584
- )
585
-
586
- with gr.Group():
587
- gr.Markdown("#### 💬 Request Details")
588
- message_input = gr.Textbox(
589
- label="What do you need help with?",
590
- lines=4,
591
- placeholder="Describe what you need from other departments..."
592
- )
593
-
594
- image_input = gr.Image(
595
- label="📷 Attach Image (Optional)",
596
- type="pil"
597
- )
598
-
599
- with gr.Group():
600
- gr.Markdown("#### 📧 Notification Options")
601
- recipient_dropdown = gr.Dropdown(
602
- choices=["administration", "production", "magazine"],
603
- label="Notify Department"
604
- )
605
-
606
- urgency_dropdown = gr.Dropdown(
607
- choices=["Normal", "Medium", "High"],
608
- value="Normal",
609
- label="Priority Level"
610
- )
611
-
612
- send_email_checkbox = gr.Checkbox(
613
- label="Send email notification",
614
- value=True
615
- )
616
-
617
- with gr.Row():
618
- submit_btn = gr.Button("🚀 Get Coordination Help", variant="primary")
619
- clear_form_btn = gr.Button("🗑️ Clear Form", variant="secondary")
620
-
621
- with gr.Row():
622
- report_btn = gr.Button("📋 Submit & Send Report", variant="secondary")
623
- clear_btn = gr.Button("🗂️ Clear History", variant="stop")
624
- stats_btn = gr.Button("📈 View Stats")
625
-
626
- status_display = gr.Textbox(
627
- label="System Status",
628
- interactive=False,
629
- max_lines=2
630
- )
631
-
632
- stats_display = gr.Textbox(
633
- label="Activity Summary",
634
- interactive=False,
635
- max_lines=6
636
- )
637
-
638
  with gr.Column(scale=2):
639
- gr.Markdown("### 💡 Coordination Guidance")
640
- output = gr.Textbox(
641
- label="Recommended Actions",
642
- lines=18,
643
- show_copy_button=True
644
- )
645
-
646
- with gr.Accordion("🏢 Department Overview", open=True):
647
- gr.Markdown("**Administration**: Overall management, decision making, and coordination \n**Production**: Manufacturing, quality control, and production planning \n**Magazine Management**: Content creation, publishing, and distribution \n \n*The AI will analyze your message and any attached images to provide specific coordination recommendations.*")
648
-
649
- with gr.Accordion("📜 Recent Activity", open=False):
650
- history_display = gr.JSON(
651
- label="Activity Log",
652
- value=conversation_history[-10:] if conversation_history else []
653
- )
654
-
655
- # Event handlers
656
- update_email_btn.click(
657
- fn=update_report_email,
658
- inputs=[email_input],
659
- outputs=email_status
660
- )
661
-
662
- email_input.submit(
663
- fn=update_report_email,
664
- inputs=[email_input],
665
- outputs=email_status
666
- )
667
 
668
- submit_btn.click(
669
- fn=process_coordination_request,
670
- inputs=[name_input, department_dropdown, message_input, image_input, recipient_dropdown, send_email_checkbox, urgency_dropdown],
671
- outputs=output
672
- )
673
-
674
- report_btn.click(
675
- fn=lambda name, dept, msg, img, rec, send, urg: process_coordination_request(name, dept, msg, img, rec, send, urg) + "\n\n---\n" + send_email_report(conversation_history),
676
- inputs=[name_input, department_dropdown, message_input, image_input, recipient_dropdown, send_email_checkbox, urgency_dropdown],
677
  outputs=output
678
  )
679
-
680
- message_input.submit(
681
- fn=process_coordination_request,
682
- inputs=[name_input, department_dropdown, message_input, image_input, recipient_dropdown, send_email_checkbox, urgency_dropdown],
683
- outputs=output
684
- )
685
-
686
- clear_btn.click(
687
- fn=clear_conversation,
688
- inputs=[],
689
- outputs=status_display
690
- )
691
-
692
- clear_form_btn.click(
693
- fn=clear_form,
694
- inputs=[],
695
- outputs=[name_input, image_input, message_input, recipient_dropdown, department_dropdown, urgency_dropdown, send_email_checkbox]
696
- )
697
-
698
- stats_btn.click(
699
- fn=get_conversation_stats,
700
- inputs=[],
701
- outputs=stats_display
702
- )
703
 
704
- if __name__ == "__main__":
705
- ui.launch(share=True )
 
 
706
 
 
 
 
 
 
 
 
707
 
 
 
 
2
  import requests
3
  import os
4
  import base64
 
5
  import io
6
  import datetime
7
+ from PIL import Image
8
+
9
+ # ======================================================
10
+ # ENV
11
+ # ======================================================
12
 
 
13
  OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY")
 
14
  BREVO_API_KEY = os.getenv("BREVO_API_KEY")
15
+ BREVO_FROM_EMAIL = os.getenv("BREVO_FROM_EMAIL", "noreply@company.com")
16
 
 
17
  conversation_history = []
 
18
 
19
+ # ======================================================
20
+ # DEPARTMENTS
21
+ # ======================================================
22
+
23
  departments = {
24
+ "administration": {"name": "Administration", "email": os.getenv("ADMIN_EMAIL", "")},
25
+ "production": {"name": "Production", "email": os.getenv("PRODUCTION_EMAIL", "")},
26
+ "magazine": {"name": "Magazine Management", "email": os.getenv("MAGAZINE_EMAIL", "")},
 
 
 
 
 
 
 
 
 
 
 
 
27
  }
28
 
29
+ # ======================================================
30
+ # EMAIL
31
+ # ======================================================
32
+
33
+ def send_email_brevo_api(to_email, subject, html):
34
+ if not BREVO_API_KEY:
35
+ return "Email disabled"
36
+
37
+ r = requests.post(
38
+ "https://api.brevo.com/v3/smtp/email",
39
+ headers={
40
+ "accept": "application/json",
41
+ "content-type": "application/json",
42
+ "api-key": BREVO_API_KEY
43
+ },
44
+ json={
45
+ "sender": {"name": "AI Coordination System", "email": BREVO_FROM_EMAIL},
46
+ "to": [{"email": to_email}],
47
+ "subject": subject,
48
+ "htmlContent": html
49
+ }
50
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
+ return "Email sent" if r.status_code == 201 else "Email failed"
 
53
 
 
 
54
 
55
+ # ======================================================
56
+ # LLM PROFESSIONAL PROMPT
57
+ # ======================================================
58
+
59
+ SYSTEM_PROMPT = """
60
+ You are an Enterprise Operations Coordination Assistant.
61
+
62
+ Write professionally and formally.
63
+ Be concise, structured, and executive-style.
64
+ Do not use emojis or casual language.
65
+ Always provide clear action steps.
66
  """
67
+
68
+ def call_llm(messages):
69
+ r = requests.post(
70
+ "https://openrouter.ai/api/v1/chat/completions",
71
+ headers={
72
+ "Authorization": f"Bearer {OPENROUTER_API_KEY}",
73
+ "Content-Type": "application/json",
74
+ },
75
+ json={
76
+ "model": "google/gemma-3-27b-it:free",
77
+ "messages": messages,
78
+ "temperature": 0.1,
79
+ "max_tokens": 800
80
+ }
81
+ )
82
+
83
+ if r.status_code == 200:
84
+ return r.json()["choices"][0]["message"]["content"]
85
+
86
+ return "LLM request failed"
87
+
88
+
89
+ def analyze(message, department, user):
90
+
91
+ prompt = f"""
92
+ Department: {department}
93
+ Requestor: {user}
94
+ Message: {message}
95
+
96
+ Return strictly:
97
+
98
+ === COORDINATION SUMMARY ===
99
+ Short executive summary
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
  === DEPARTMENTS INVOLVED ===
102
+ Bullets
103
 
104
  === ACTION PLAN ===
105
+ Numbered steps
 
 
106
 
107
+ === PRIORITY LEVEL ===
108
+ Low | Medium | High with justification
109
 
110
  === FOLLOW-UP ===
111
+ Next actions
112
  """
113
 
114
+ return call_llm([
115
+ {"role": "system", "content": SYSTEM_PROMPT},
116
+ {"role": "user", "content": prompt}
117
+ ])
118
+
119
+
120
+ # ======================================================
121
+ # CORE LOGIC
122
+ # ======================================================
123
+
124
+ def process(name, dept, message, img, recipient, send_email, urgency):
125
+
126
+ if not name or not dept or not message:
127
+ return "Fill all required fields."
128
+
129
+ result = analyze(message, dept, name)
130
+
131
+ output = f"""
132
+ Requestor: {name}
133
+ Department: {departments[dept]['name']}
134
+
135
+ {result}
136
+ """
137
+
138
+ if send_email and recipient:
139
+ email = departments[recipient]["email"]
140
+ status = send_email_brevo_api(email, "Coordination Request", f"<pre>{output}</pre>")
141
+ output += f"\n\nEmail status: {status}"
142
+
143
+ conversation_history.append(output)
144
+ return output
145
+
146
+
147
+ # ======================================================
148
+ # EXAMPLES (NEW)
149
+ # ======================================================
150
+
151
+ examples = [
152
+ [
153
+ "Ali Ben Salah",
154
+ "production",
155
+ "Packaging machine #4 stopped working and production is blocked. Need urgent maintenance approval.",
156
+ None,
157
+ "administration",
158
+ True,
159
+ "High"
160
+ ],
161
+ [
162
+ "Sara Trabelsi",
163
+ "magazine",
164
+ "We need design assets approved before tomorrow's publication. Please coordinate with administration.",
165
+ None,
166
+ "administration",
167
+ True,
168
+ "Medium"
169
+ ],
170
+ [
171
+ "Mohamed Kefi",
172
+ "administration",
173
+ "Budget approval required for new raw materials purchase for next production cycle.",
174
+ None,
175
+ "production",
176
+ True,
177
+ "Medium"
178
+ ],
179
+ [
180
+ "Ines Haddad",
181
+ "production",
182
+ "Quality inspection shows defect rate increased to 7%. Root cause investigation required.",
183
+ None,
184
+ "administration",
185
+ False,
186
+ "High"
187
+ ],
188
+ [
189
+ "Karim Jaziri",
190
+ "magazine",
191
+ "Printing vendor delayed delivery. Need alternative supplier coordination.",
192
+ None,
193
+ "administration",
194
+ True,
195
+ "High"
196
+ ],
197
+ [
198
+ "Admin Test",
199
+ "administration",
200
+ "Monthly inter-department performance review meeting preparation.",
201
+ None,
202
+ "production",
203
+ False,
204
+ "Low"
205
+ ],
206
+ ]
207
+
208
+ # ======================================================
209
+ # UI
210
+ # ======================================================
211
+
212
+ with gr.Blocks(theme=gr.themes.Soft(), title="AI Coordination System") as ui:
213
+
214
+ gr.Markdown("# AI Department Coordination System")
215
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  with gr.Row():
217
+
218
  with gr.Column(scale=1):
219
+
220
+ name = gr.Textbox(label="Name")
221
+ dept = gr.Dropdown(list(departments.keys()), label="Department")
222
+ message = gr.Textbox(label="Request", lines=4)
223
+ img = gr.Image(type="pil", label="Optional Image")
224
+
225
+ recipient = gr.Dropdown(list(departments.keys()), label="Notify Department")
226
+ urgency = gr.Dropdown(["Low", "Medium", "High"], value="Medium")
227
+ send_email = gr.Checkbox(label="Send Email", value=True)
228
+
229
+ submit = gr.Button("Analyze", variant="primary")
230
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
  with gr.Column(scale=2):
232
+ output = gr.Textbox(lines=20, show_copy_button=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
 
234
+ submit.click(
235
+ process,
236
+ inputs=[name, dept, message, img, recipient, send_email, urgency],
 
 
 
 
 
 
237
  outputs=output
238
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
 
240
+ # =========================
241
+ # 🔥 EXAMPLES COMPONENT
242
+ # =========================
243
+ gr.Markdown("## Quick Test Examples")
244
 
245
+ gr.Examples(
246
+ examples=examples,
247
+ inputs=[name, dept, message, img, recipient, send_email, urgency],
248
+ label="Click any example to auto-fill and test"
249
+ )
250
+
251
+ # ======================================================
252
 
253
+ if __name__ == "__main__":
254
+ ui.launch()