|
|
import gradio as gr |
|
|
import requests |
|
|
import os |
|
|
import base64 |
|
|
from PIL import Image |
|
|
import io |
|
|
import datetime |
|
|
|
|
|
|
|
|
OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY") |
|
|
DEFAULT_REPORT_EMAIL = os.getenv("REPORT_EMAIL") |
|
|
BREVO_API_KEY = os.getenv("BREVO_API_KEY") |
|
|
BREVO_FROM_EMAIL = os.getenv("BREVO_FROM_EMAIL", "noreply@yourdomain.com") |
|
|
|
|
|
|
|
|
DEMO_MODE = os.getenv("DEMO_MODE", "true").lower() == "true" |
|
|
|
|
|
|
|
|
conversation_history = [] |
|
|
current_report_email = DEFAULT_REPORT_EMAIL |
|
|
|
|
|
|
|
|
departments = { |
|
|
"administration": { |
|
|
"name": "Administration", |
|
|
"email": os.getenv("ADMIN_EMAIL", "admin@demo.com"), |
|
|
"responsibilities": "Overall management, decision making, and coordination" |
|
|
}, |
|
|
"production": { |
|
|
"name": "Production", |
|
|
"email": os.getenv("PRODUCTION_EMAIL", "production@demo.com"), |
|
|
"responsibilities": "Manufacturing, quality control, and production planning" |
|
|
}, |
|
|
"magazine": { |
|
|
"name": "Magazine Management", |
|
|
"email": os.getenv("MAGAZINE_EMAIL", "magazine@demo.com"), |
|
|
"responsibilities": "Content creation, publishing, and distribution" |
|
|
} |
|
|
} |
|
|
|
|
|
def update_report_email(new_email): |
|
|
"""Update the report email address""" |
|
|
global current_report_email |
|
|
if new_email and "@" in new_email and "." in new_email: |
|
|
current_report_email = new_email.strip() |
|
|
return f"β
Report email updated to: {current_report_email}" |
|
|
else: |
|
|
return "β Please enter a valid email address" |
|
|
|
|
|
def send_email_brevo_api(to_email, subject, html_content, from_name="AI Coordination System"): |
|
|
"""Send email using Brevo API""" |
|
|
try: |
|
|
|
|
|
if DEMO_MODE or not BREVO_API_KEY: |
|
|
return f"π§ͺ [DEMO MODE] Email simulated to {to_email}" |
|
|
|
|
|
response = requests.post( |
|
|
"https://api.brevo.com/v3/smtp/email", |
|
|
headers={ |
|
|
"accept": "application/json", |
|
|
"content-type": "application/json", |
|
|
"api-key": BREVO_API_KEY |
|
|
}, |
|
|
json={ |
|
|
"sender": { |
|
|
"name": from_name, |
|
|
"email": BREVO_FROM_EMAIL |
|
|
}, |
|
|
"to": [{"email": to_email}], |
|
|
"subject": subject, |
|
|
"htmlContent": html_content |
|
|
}, |
|
|
timeout=10 |
|
|
) |
|
|
|
|
|
if response.status_code == 201: |
|
|
return f"β
Email sent to {to_email}" |
|
|
else: |
|
|
error_msg = response.json().get('message', 'Unknown error') |
|
|
return f"β Failed to send email: {error_msg}" |
|
|
|
|
|
except Exception as e: |
|
|
return f"β Email error: {str(e)}" |
|
|
|
|
|
def get_mock_ai_response(user_message, department, user_name, has_image=False): |
|
|
"""Generate a mock AI response for demo/testing mode""" |
|
|
|
|
|
image_section = """ |
|
|
=== IMAGE OBSERVATIONS === |
|
|
β’ Mock analysis: Image appears to show office equipment |
|
|
β’ Suggested action: Forward to relevant department for review |
|
|
""" if has_image else "" |
|
|
|
|
|
responses = { |
|
|
"administration": { |
|
|
"equipment": f""" |
|
|
=== EXECUTIVE SUMMARY === |
|
|
Request from {user_name} regarding equipment needs requires coordination between Administration and Production departments for budget approval and implementation. |
|
|
|
|
|
{image_section} |
|
|
=== RECOMMENDED TARGET DEPARTMENT === |
|
|
Production |
|
|
This is primarily a production-related request that requires equipment or facility resources. |
|
|
|
|
|
=== DEPARTMENTS INVOLVED === |
|
|
β’ Production β Equipment assessment and implementation |
|
|
β’ Administration β Budget approval and procurement authorization |
|
|
|
|
|
=== ACTION PLAN === |
|
|
1. Production department to assess equipment specifications and requirements |
|
|
2. Administration to review budget implications and approve funding |
|
|
3. Production to coordinate installation and training |
|
|
|
|
|
=== PRIORITY === |
|
|
Medium β Standard equipment request requiring normal procurement timeline |
|
|
|
|
|
=== FOLLOW-UP === |
|
|
Weekly status updates until equipment is operational |
|
|
""", |
|
|
"default": f""" |
|
|
=== EXECUTIVE SUMMARY === |
|
|
Administrative request from {user_name} requires internal review and possible coordination with other departments. |
|
|
|
|
|
{image_section} |
|
|
=== RECOMMENDED TARGET DEPARTMENT === |
|
|
Administration |
|
|
This request should be handled within the Administration department. |
|
|
|
|
|
=== DEPARTMENTS INVOLVED === |
|
|
β’ Administration β Primary responsibility for coordination and decision-making |
|
|
|
|
|
=== ACTION PLAN === |
|
|
1. Review request details and requirements |
|
|
2. Determine resource allocation and timeline |
|
|
3. Coordinate with relevant stakeholders |
|
|
|
|
|
=== PRIORITY === |
|
|
Normal β Standard administrative workflow |
|
|
|
|
|
=== FOLLOW-UP === |
|
|
Monitor progress and provide status updates as needed |
|
|
""" |
|
|
}, |
|
|
"production": { |
|
|
"content": f""" |
|
|
=== EXECUTIVE SUMMARY === |
|
|
Production request from {user_name} involves content creation, requiring Magazine department collaboration. |
|
|
|
|
|
{image_section} |
|
|
=== RECOMMENDED TARGET DEPARTMENT === |
|
|
Magazine |
|
|
This request involves content creation and publishing activities. |
|
|
|
|
|
=== DEPARTMENTS INVOLVED === |
|
|
β’ Magazine β Content development and design |
|
|
β’ Production β Material production and quality control |
|
|
|
|
|
=== ACTION PLAN === |
|
|
1. Magazine to develop content and design specifications |
|
|
2. Production to review technical feasibility |
|
|
3. Coordinate timeline for material production |
|
|
|
|
|
=== PRIORITY === |
|
|
Medium β Requires cross-departmental coordination |
|
|
|
|
|
=== FOLLOW-UP === |
|
|
Bi-weekly alignment meetings until project completion |
|
|
""", |
|
|
"default": f""" |
|
|
=== EXECUTIVE SUMMARY === |
|
|
Production request from {user_name} requires assessment of manufacturing capabilities and resource allocation. |
|
|
|
|
|
{image_section} |
|
|
=== RECOMMENDED TARGET DEPARTMENT === |
|
|
Production |
|
|
Internal production department matter requiring operational attention. |
|
|
|
|
|
=== DEPARTMENTS INVOLVED === |
|
|
β’ Production β Manufacturing operations and quality assurance |
|
|
β’ Administration β Resource approval if needed |
|
|
|
|
|
=== ACTION PLAN === |
|
|
1. Assess current production capacity and requirements |
|
|
2. Identify resource needs and constraints |
|
|
3. Develop implementation timeline |
|
|
|
|
|
=== PRIORITY === |
|
|
Normal β Standard production workflow |
|
|
|
|
|
=== FOLLOW-UP === |
|
|
Regular progress monitoring through production meetings |
|
|
""" |
|
|
}, |
|
|
"magazine": { |
|
|
"printing": f""" |
|
|
=== EXECUTIVE SUMMARY === |
|
|
Magazine request from {user_name} regarding printing requires Production department involvement for manufacturing execution. |
|
|
|
|
|
{image_section} |
|
|
=== RECOMMENDED TARGET DEPARTMENT === |
|
|
Production |
|
|
Printing and manufacturing activities fall under Production responsibility. |
|
|
|
|
|
=== DEPARTMENTS INVOLVED === |
|
|
β’ Magazine β Content finalization and specifications |
|
|
β’ Production β Printing operations and quality control |
|
|
|
|
|
=== ACTION PLAN === |
|
|
1. Magazine to finalize all content and design specifications |
|
|
2. Production to schedule printing resources |
|
|
3. Coordinate delivery timeline and distribution |
|
|
|
|
|
=== PRIORITY === |
|
|
High β Publishing deadline-sensitive activity |
|
|
|
|
|
=== FOLLOW-UP === |
|
|
Daily updates during production phase |
|
|
""", |
|
|
"default": f""" |
|
|
=== EXECUTIVE SUMMARY === |
|
|
Magazine department request from {user_name} involves content development and publishing coordination. |
|
|
|
|
|
{image_section} |
|
|
=== RECOMMENDED TARGET DEPARTMENT === |
|
|
Magazine |
|
|
Editorial and publishing matter for Magazine department handling. |
|
|
|
|
|
=== DEPARTMENTS INVOLVED === |
|
|
β’ Magazine β Content creation and editorial oversight |
|
|
β’ Production β Technical production support if needed |
|
|
|
|
|
=== ACTION PLAN === |
|
|
1. Develop content strategy and editorial plan |
|
|
2. Coordinate with relevant stakeholders |
|
|
3. Execute publishing timeline |
|
|
|
|
|
=== PRIORITY === |
|
|
Normal β Standard editorial workflow |
|
|
|
|
|
=== FOLLOW-UP === |
|
|
Editorial review meetings and publication tracking |
|
|
""" |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
message_lower = user_message.lower() |
|
|
dept_responses = responses.get(department, responses["administration"]) |
|
|
|
|
|
for keyword, response in dept_responses.items(): |
|
|
if keyword != "default" and keyword in message_lower: |
|
|
return response |
|
|
|
|
|
return dept_responses["default"] |
|
|
|
|
|
def analyze_coordination_needs(user_message, department, user_name, image=None): |
|
|
"""Use LLM to analyze coordination needs and suggest actions - with image support""" |
|
|
|
|
|
|
|
|
if DEMO_MODE or not OPENROUTER_API_KEY: |
|
|
return get_mock_ai_response(user_message, department, user_name, has_image=image is not None) |
|
|
|
|
|
if image: |
|
|
|
|
|
buffered = io.BytesIO() |
|
|
image.save(buffered, format="PNG") |
|
|
img_base64 = base64.b64encode(buffered.getvalue()).decode() |
|
|
|
|
|
prompt = f""" |
|
|
You are an Enterprise Operations Coordination AI. |
|
|
|
|
|
Analyze the request AND the attached image to determine responsibility and next actions. |
|
|
|
|
|
Write formally and professionally. |
|
|
No casual tone. No emojis. |
|
|
|
|
|
AVAILABLE DEPARTMENTS: |
|
|
- Administration: approvals, management, coordination |
|
|
- Production: equipment, facilities, manufacturing, maintenance |
|
|
- Magazine: design, content, publishing |
|
|
|
|
|
REQUEST: |
|
|
Requestor: {user_name} |
|
|
Origin Department: {department} |
|
|
Message: {user_message} |
|
|
|
|
|
Provide: |
|
|
|
|
|
=== EXECUTIVE SUMMARY === |
|
|
Short professional summary |
|
|
|
|
|
=== IMAGE OBSERVATIONS === |
|
|
Important findings from the image |
|
|
|
|
|
=== RECOMMENDED TARGET DEPARTMENT === |
|
|
Choose ONLY ONE: Administration | Production | Magazine |
|
|
Reason |
|
|
|
|
|
=== ACTION PLAN === |
|
|
Numbered steps |
|
|
|
|
|
=== PRIORITY === |
|
|
Low | Medium | High with reason |
|
|
|
|
|
=== FOLLOW-UP === |
|
|
Monitoring or escalation steps |
|
|
""" |
|
|
try: |
|
|
response = requests.post( |
|
|
"https://openrouter.ai/api/v1/chat/completions", |
|
|
headers={ |
|
|
"Authorization": f"Bearer {OPENROUTER_API_KEY}", |
|
|
"Content-Type": "application/json", |
|
|
}, |
|
|
json={ |
|
|
"model": "google/gemma-3-27b-it:free", |
|
|
"messages": [ |
|
|
{ |
|
|
"role": "user", |
|
|
"content": [ |
|
|
{ |
|
|
"type": "text", |
|
|
"text": prompt |
|
|
}, |
|
|
{ |
|
|
"type": "image_url", |
|
|
"image_url": { |
|
|
"url": f"data:image/png;base64,{img_base64}" |
|
|
} |
|
|
} |
|
|
] |
|
|
} |
|
|
], |
|
|
"temperature": 0.3 |
|
|
}, |
|
|
timeout=60 |
|
|
) |
|
|
|
|
|
if response.status_code == 200: |
|
|
data = response.json() |
|
|
return data["choices"][0]["message"]["content"] |
|
|
else: |
|
|
return "I'm having trouble analyzing the image right now. Please try again in a moment." |
|
|
|
|
|
except Exception as e: |
|
|
return f"Sorry, I couldn't process the image. Error: {str(e)}" |
|
|
|
|
|
else: |
|
|
|
|
|
prompt = f""" |
|
|
You are an Enterprise Operations Coordination AI used inside a professional organization. |
|
|
|
|
|
Your responsibility is to: |
|
|
β’ analyze the request |
|
|
β’ determine which department should handle it |
|
|
β’ produce a concise, executive-style coordination plan |
|
|
|
|
|
Write formally and professionally. |
|
|
Do NOT use conversational tone. |
|
|
Do NOT use emojis. |
|
|
Be precise, structured, and action-oriented. |
|
|
|
|
|
AVAILABLE DEPARTMENTS: |
|
|
- Administration: management, approvals, policies, finance, coordination |
|
|
- Production: manufacturing, maintenance, equipment, operations, logistics |
|
|
- Magazine: content creation, publishing, marketing materials, communication |
|
|
|
|
|
REQUEST: |
|
|
Requestor: {user_name} |
|
|
Origin Department: {department} |
|
|
Message: {user_message} |
|
|
|
|
|
Return your answer STRICTLY using this format: |
|
|
|
|
|
=== EXECUTIVE SUMMARY === |
|
|
2β3 sentence professional summary. |
|
|
|
|
|
=== RECOMMENDED TARGET DEPARTMENT === |
|
|
Choose ONLY ONE: Administration | Production | Magazine |
|
|
Brief justification. |
|
|
|
|
|
=== DEPARTMENTS INVOLVED === |
|
|
β’ Department β responsibility |
|
|
|
|
|
=== ACTION PLAN === |
|
|
1. Step |
|
|
2. Step |
|
|
3. Step |
|
|
|
|
|
=== PRIORITY === |
|
|
Low | Medium | High with reason |
|
|
|
|
|
=== FOLLOW-UP === |
|
|
Required monitoring or reporting actions |
|
|
""" |
|
|
|
|
|
try: |
|
|
response = requests.post( |
|
|
"https://openrouter.ai/api/v1/chat/completions", |
|
|
headers={ |
|
|
"Authorization": f"Bearer {OPENROUTER_API_KEY}", |
|
|
"Content-Type": "application/json", |
|
|
}, |
|
|
json={ |
|
|
"model": "google/gemma-3-27b-it:free", |
|
|
"messages": [{"role": "user", "content": prompt}], |
|
|
"temperature": 0.3 |
|
|
}, |
|
|
timeout=30 |
|
|
) |
|
|
|
|
|
if response.status_code == 200: |
|
|
data = response.json() |
|
|
return data["choices"][0]["message"]["content"] |
|
|
else: |
|
|
return "I'm having trouble analyzing your request right now. Please try again in a moment." |
|
|
|
|
|
except Exception as e: |
|
|
return f"Sorry, I couldn't process your request. Error: {str(e)}" |
|
|
|
|
|
def send_department_email(sender_dept, recipient_dept, subject, message, user_name, urgency="Normal", image=None): |
|
|
"""Send email between departments with optional image attachment""" |
|
|
try: |
|
|
|
|
|
recipient_email = departments[recipient_dept]["email"] |
|
|
if not recipient_email: |
|
|
|
|
|
recipient_email = current_report_email |
|
|
|
|
|
|
|
|
image_note = "<p style='margin: 5px 0;'><strong>π Attachment:</strong> Image included with request</p>" if image else "" |
|
|
urgency_class = f"urgency-{urgency.lower()}" if urgency.lower() in ['high', 'medium'] else "urgency-normal" |
|
|
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 "" |
|
|
|
|
|
html_content = f"""<html> |
|
|
<head> |
|
|
<style> |
|
|
body {{ font-family: Arial, sans-serif; margin: 20px; }} |
|
|
.header {{ background-color: #f4f4f4; padding: 20px; border-radius: 8px; margin-bottom: 20px; }} |
|
|
.urgency-high {{ border-left: 5px solid #dc2626; background-color: #fef2f2; }} |
|
|
.urgency-medium {{ border-left: 5px solid #d97706; background-color: #fffbeb; }} |
|
|
.urgency-normal {{ border-left: 5px solid #2563eb; background-color: #eff6ff; }} |
|
|
.message-content {{ padding: 20px; background-color: white; border-radius: 8px; margin: 15px 0; }} |
|
|
.user-info {{ background-color: #f8fafc; padding: 10px 15px; border-radius: 6px; margin: 10px 0; }} |
|
|
</style> |
|
|
</head> |
|
|
<body> |
|
|
<div class="header"> |
|
|
<h1 style="margin: 0; color: #1f2937;">π’ Inter-Department Communication</h1> |
|
|
<p style="margin: 5px 0;"><strong>From:</strong> {departments[sender_dept]['name']}</p> |
|
|
<p style="margin: 5px 0;"><strong>Requested by:</strong> {user_name}</p> |
|
|
<p style="margin: 5px 0;"><strong>To:</strong> {departments[recipient_dept]['name']}</p> |
|
|
<p style="margin: 5px 0;"><strong>Date:</strong> {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p> |
|
|
<p style="margin: 5px 0;"><strong>Urgency:</strong> {urgency}</p> |
|
|
{image_note} |
|
|
</div> |
|
|
|
|
|
<div class="user-info"> |
|
|
<strong>π€ Requestor Details:</strong><br> |
|
|
Name: {user_name}<br> |
|
|
Department: {departments[sender_dept]['name']} |
|
|
</div> |
|
|
|
|
|
<div class="message-content {urgency_class}"> |
|
|
<h3 style="margin-top: 0;">{subject}</h3> |
|
|
<div style="white-space: pre-line;">{message}</div> |
|
|
</div> |
|
|
|
|
|
<div style="color: #6b7280; font-size: 0.9em; margin-top: 20px;"> |
|
|
<p>This is an automated message from the AI Coordination System.</p> |
|
|
{image_footer} |
|
|
</div> |
|
|
</body> |
|
|
</html>""" |
|
|
|
|
|
|
|
|
from_name = f"{departments[sender_dept]['name']}" |
|
|
email_status = send_email_brevo_api(recipient_email, f"[{urgency}] {subject}", html_content, from_name) |
|
|
return email_status |
|
|
|
|
|
except Exception as e: |
|
|
return f"β Failed to send email: {str(e)}" |
|
|
|
|
|
def send_email_report(conversation_data): |
|
|
"""Send comprehensive coordination report to administration""" |
|
|
|
|
|
if DEMO_MODE or not BREVO_API_KEY or not current_report_email: |
|
|
if DEMO_MODE: |
|
|
return "π§ͺ [DEMO MODE] Report email simulated successfully" |
|
|
else: |
|
|
return "Email reporting not configured - missing Brevo API key or report email" |
|
|
|
|
|
try: |
|
|
|
|
|
dept_activity = {} |
|
|
user_activity = {} |
|
|
for entry in conversation_data: |
|
|
dept = entry.get('department', 'Unknown') |
|
|
user = entry.get('user_name', 'Unknown') |
|
|
dept_activity[dept] = dept_activity.get(dept, 0) + 1 |
|
|
user_activity[user] = user_activity.get(user, 0) + 1 |
|
|
|
|
|
|
|
|
subject = f"Coordination Report - {datetime.datetime.now().strftime('%Y-%m-%d %H:%M')}" |
|
|
|
|
|
|
|
|
dept_activity_html = "" |
|
|
for dept, count in dept_activity.items(): |
|
|
dept_activity_html += f"<p><strong>{dept.title()}:</strong> {count} interactions</p>" |
|
|
|
|
|
|
|
|
user_activity_html = "" |
|
|
for user, count in user_activity.items(): |
|
|
if user != 'Unknown': |
|
|
user_activity_html += f"<p><strong>{user}:</strong> {count} requests</p>" |
|
|
|
|
|
|
|
|
recent_activities_html = "" |
|
|
for i, entry in enumerate(conversation_data[-10:], 1): |
|
|
dept_badge = f"<span class='department-badge'>{entry.get('department', 'General').title()}</span>" if entry.get('department') else "" |
|
|
user_badge = f"<span class='user-badge'>{entry.get('user_name', 'User')}</span>" if entry.get('user_name') else "" |
|
|
image_indicator = " <span class='image-indicator'>π·</span>" if entry.get('image_uploaded') else "" |
|
|
email_indicator = " π§" if entry.get('email_sent') else "" |
|
|
|
|
|
recent_activities_html += f"""<div class="exchange"> |
|
|
<div style="display: flex; justify-content: between; align-items: center; margin-bottom: 10px;"> |
|
|
<h4 style="margin: 0; color: #374151;">Activity #{i}</h4> |
|
|
<div> |
|
|
{dept_badge} |
|
|
{user_badge} |
|
|
{image_indicator} |
|
|
</div> |
|
|
</div> |
|
|
<p class="user"><strong>π¬ Message:</strong> {entry['user_input']}{email_indicator}</p> |
|
|
<p class="ai"><strong>π€ AI Coordination:</strong> {entry['ai_response']}</p> |
|
|
<p class="timestamp">{entry['timestamp']}</p> |
|
|
</div>""" |
|
|
|
|
|
|
|
|
html_content = f"""<html> |
|
|
<head> |
|
|
<style> |
|
|
body {{ font-family: Arial, sans-serif; margin: 20px; }} |
|
|
.header {{ background-color: #1f2937; color: white; padding: 25px; border-radius: 8px; margin-bottom: 20px; }} |
|
|
.stats {{ display: flex; justify-content: space-between; margin: 20px 0; }} |
|
|
.stat-card {{ background-color: #f8fafc; padding: 15px; border-radius: 8px; text-align: center; flex: 1; margin: 0 10px; }} |
|
|
.exchange {{ border: 1px solid #e0e0e0; margin: 15px 0; padding: 15px; border-radius: 8px; background-color: #fafafa; }} |
|
|
.user {{ color: #2563eb; font-weight: 600; }} |
|
|
.ai {{ color: #059669; }} |
|
|
.timestamp {{ color: #6b7280; font-size: 0.8em; font-style: italic; }} |
|
|
.department-badge {{ background-color: #3b82f6; color: white; padding: 2px 8px; border-radius: 12px; font-size: 0.8em; }} |
|
|
.user-badge {{ background-color: #10b981; color: white; padding: 2px 8px; border-radius: 12px; font-size: 0.8em; margin-left: 5px; }} |
|
|
.image-indicator {{ background-color: #f59e0b; color: white; padding: 2px 6px; border-radius: 10px; font-size: 0.7em; margin-left: 5px; }} |
|
|
</style> |
|
|
</head> |
|
|
<body> |
|
|
<div class="header"> |
|
|
<h1 style="margin: 0;">π€ AI Coordination System Report</h1> |
|
|
<p style="margin: 5px 0; opacity: 0.9;">Comprehensive inter-department coordination summary</p> |
|
|
<p style="margin: 5px 0;"><strong>Generated:</strong> {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p> |
|
|
</div> |
|
|
|
|
|
<div class="stats"> |
|
|
<div class="stat-card"> |
|
|
<h3 style="margin: 0; color: #3b82f6;">{len(conversation_data)}</h3> |
|
|
<p style="margin: 5px 0;">Total Interactions</p> |
|
|
</div> |
|
|
<div class="stat-card"> |
|
|
<h3 style="margin: 0; color: #10b981;">{len(dept_activity)}</h3> |
|
|
<p style="margin: 5px 0;">Active Departments</p> |
|
|
</div> |
|
|
<div class="stat-card"> |
|
|
<h3 style="margin: 0; color: #f59e0b;">{sum(1 for entry in conversation_history if entry.get('email_sent'))}</h3> |
|
|
<p style="margin: 5px 0;">Emails Sent</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<h3>π Department Activity</h3> |
|
|
{dept_activity_html} |
|
|
|
|
|
<h3>π₯ User Activity</h3> |
|
|
{user_activity_html if user_activity_html else "<p>No user activity data</p>"} |
|
|
|
|
|
<h3>π Recent Coordination Activities</h3> |
|
|
{recent_activities_html if recent_activities_html else "<p>No recent activities</p>"} |
|
|
|
|
|
<div style="margin-top: 30px; padding: 15px; background-color: #f0fdf4; border-radius: 8px;"> |
|
|
<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> |
|
|
</div> |
|
|
</body> |
|
|
</html>""" |
|
|
|
|
|
|
|
|
email_status = send_email_brevo_api(current_report_email, subject, html_content, "AI Coordination System") |
|
|
return email_status |
|
|
|
|
|
except Exception as e: |
|
|
return f"Failed to send report: {str(e)}" |
|
|
|
|
|
def add_to_conversation_history(user_input, department, user_name, ai_response, email_sent=False, image_uploaded=False): |
|
|
"""Add current exchange to conversation history""" |
|
|
entry = { |
|
|
'timestamp': datetime.datetime.now().isoformat(), |
|
|
'user_input': user_input, |
|
|
'department': department, |
|
|
'user_name': user_name, |
|
|
'ai_response': ai_response, |
|
|
'email_sent': email_sent, |
|
|
'image_uploaded': image_uploaded |
|
|
} |
|
|
conversation_history.append(entry) |
|
|
|
|
|
|
|
|
if len(conversation_history) > 50: |
|
|
conversation_history.pop(0) |
|
|
|
|
|
def process_coordination_request(name, department, message, image, recipient_dept, send_email, urgency): |
|
|
"""Process coordination requests between departments with image support""" |
|
|
if not message.strip(): |
|
|
return "Please enter a coordination message." |
|
|
|
|
|
if not department: |
|
|
return "Please select your department." |
|
|
|
|
|
if not name.strip(): |
|
|
return "Please enter your name." |
|
|
|
|
|
|
|
|
ai_analysis = analyze_coordination_needs(message, department, name, image) |
|
|
|
|
|
|
|
|
response_parts = [] |
|
|
|
|
|
|
|
|
if DEMO_MODE: |
|
|
response_parts.append("π§ͺ **DEMO MODE ACTIVE** - Using simulated AI responses") |
|
|
|
|
|
response_parts.append(f"**π€ Request from:** {name} | **π’ Department:** {departments[department]['name']}") |
|
|
|
|
|
if image: |
|
|
response_parts.append("**π· Image attached and analyzed**") |
|
|
|
|
|
response_parts.append(f"\n**π€ Coordination Guidance:**\n{ai_analysis}") |
|
|
|
|
|
|
|
|
email_status = "" |
|
|
if send_email and recipient_dept: |
|
|
subject = f"Coordination Request from {departments[department]['name']} - {name}" |
|
|
|
|
|
|
|
|
email_lines = [ |
|
|
f"Requestor: {name}", |
|
|
f"Department: {departments[department]['name']}", |
|
|
"", |
|
|
"Message:", |
|
|
message, |
|
|
"" |
|
|
] |
|
|
|
|
|
if image: |
|
|
email_lines.append("Note: An image was included with this request. Please check the system for visual details.") |
|
|
email_lines.append("") |
|
|
|
|
|
email_lines.extend([ |
|
|
"---", |
|
|
"Coordination Suggestions:", |
|
|
ai_analysis |
|
|
]) |
|
|
|
|
|
email_message = "\n".join(email_lines) |
|
|
email_status = send_department_email(department, recipient_dept, subject, email_message, name, urgency, image) |
|
|
response_parts.append(f"\n**π§ Email Status:** {email_status}") |
|
|
|
|
|
full_response = "\n".join(response_parts) |
|
|
|
|
|
|
|
|
add_to_conversation_history( |
|
|
user_input=message, |
|
|
department=department, |
|
|
user_name=name, |
|
|
ai_response=full_response, |
|
|
email_sent=bool(send_email and recipient_dept), |
|
|
image_uploaded=image is not None |
|
|
) |
|
|
|
|
|
return full_response |
|
|
|
|
|
def get_conversation_stats(): |
|
|
"""Get statistics about current coordination activities""" |
|
|
if not conversation_history: |
|
|
return "No coordination activities yet" |
|
|
|
|
|
total_exchanges = len(conversation_history) |
|
|
dept_activity = {} |
|
|
user_activity = {} |
|
|
emails_sent = sum(1 for entry in conversation_history if entry.get('email_sent')) |
|
|
images_uploaded = sum(1 for entry in conversation_history if entry.get('image_uploaded')) |
|
|
|
|
|
for entry in conversation_history: |
|
|
dept = entry.get('department', 'Unknown') |
|
|
user = entry.get('user_name', 'Unknown') |
|
|
dept_activity[dept] = dept_activity.get(dept, 0) + 1 |
|
|
if user != 'Unknown': |
|
|
user_activity[user] = user_activity.get(user, 0) + 1 |
|
|
|
|
|
stats_text = f"π **Coordination Summary:**\n" |
|
|
stats_text += f"β’ Total Activities: {total_exchanges}\n" |
|
|
stats_text += f"β’ Emails Sent: {emails_sent}\n" |
|
|
stats_text += f"β’ Images Shared: {images_uploaded}\n\n" |
|
|
|
|
|
stats_text += "**Department Activity:**\n" |
|
|
for dept, count in dept_activity.items(): |
|
|
stats_text += f"β’ {dept.title()}: {count} requests\n" |
|
|
|
|
|
if user_activity: |
|
|
stats_text += f"\n**Active Team Members:** {', '.join(user_activity.keys())}" |
|
|
|
|
|
return stats_text |
|
|
|
|
|
def clear_conversation(): |
|
|
"""Clear the conversation history""" |
|
|
global conversation_history |
|
|
conversation_history = [] |
|
|
return "ποΈ Coordination history cleared!" |
|
|
|
|
|
def get_current_email(): |
|
|
"""Get the current report email address""" |
|
|
return current_report_email if current_report_email else "demo@example.com" |
|
|
|
|
|
def clear_form(): |
|
|
"""Clear the form fields""" |
|
|
return ["", None, "", None, "administration", "Normal", False] |
|
|
|
|
|
def load_sample_request(sample_type): |
|
|
"""Load sample requests for testing""" |
|
|
samples = { |
|
|
"Equipment Request": { |
|
|
"name": "John Smith", |
|
|
"dept": "production", |
|
|
"message": "We need to upgrade our printing equipment. The current machines are outdated and causing quality issues.", |
|
|
"recipient": "administration", |
|
|
"urgency": "Medium" |
|
|
}, |
|
|
"Content Collaboration": { |
|
|
"name": "Sarah Johnson", |
|
|
"dept": "magazine", |
|
|
"message": "Need production support for our next magazine issue. We have special requirements for paper quality and binding.", |
|
|
"recipient": "production", |
|
|
"urgency": "High" |
|
|
}, |
|
|
"Budget Approval": { |
|
|
"name": "Mike Chen", |
|
|
"dept": "production", |
|
|
"message": "Requesting budget approval for preventive maintenance on critical machinery.", |
|
|
"recipient": "administration", |
|
|
"urgency": "Normal" |
|
|
} |
|
|
} |
|
|
|
|
|
if sample_type in samples: |
|
|
s = samples[sample_type] |
|
|
return s["name"], s["dept"], s["message"], s["recipient"], s["urgency"] |
|
|
return "", "administration", "", None, "Normal" |
|
|
|
|
|
def get_system_status(): |
|
|
"""Get current system configuration status""" |
|
|
status_lines = [] |
|
|
status_lines.append("**System Configuration:**") |
|
|
status_lines.append(f"β’ Demo Mode: {'π§ͺ ENABLED' if DEMO_MODE else 'β
DISABLED'}") |
|
|
status_lines.append(f"β’ OpenRouter API: {'β
Configured' if OPENROUTER_API_KEY else 'β Not configured (using demo)'}") |
|
|
status_lines.append(f"β’ Brevo Email API: {'β
Configured' if BREVO_API_KEY else 'β Not configured (simulated)'}") |
|
|
status_lines.append(f"β’ Report Email: {current_report_email if current_report_email else 'β Not set'}") |
|
|
return "\n".join(status_lines) |
|
|
|
|
|
|
|
|
with gr.Blocks( |
|
|
theme=gr.themes.Soft(), |
|
|
title="AI Coordination System" |
|
|
) as ui: |
|
|
gr.Markdown("# π’ AI Department Coordination System") |
|
|
gr.Markdown("*Streamline communication between Administration, Production, and Magazine Management*") |
|
|
|
|
|
|
|
|
if DEMO_MODE: |
|
|
gr.Markdown(""" |
|
|
<div style="background-color: #fef3c7; padding: 15px; border-radius: 8px; border-left: 4px solid #f59e0b; margin-bottom: 20px;"> |
|
|
<strong>π§ͺ DEMO MODE ACTIVE</strong><br> |
|
|
This space is running in demo mode with simulated AI responses. |
|
|
To enable full functionality, configure the required API keys in Settings β Repository Secrets. |
|
|
</div> |
|
|
""") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
with gr.Accordion("βοΈ System Settings", open=False): |
|
|
gr.Markdown("### Email Configuration") |
|
|
email_input = gr.Textbox( |
|
|
label="Administration Report Email", |
|
|
value=get_current_email, |
|
|
placeholder="admin@company.com" |
|
|
) |
|
|
email_status = gr.Textbox( |
|
|
label="Email Status", |
|
|
value=get_current_email, |
|
|
interactive=False, |
|
|
max_lines=2 |
|
|
) |
|
|
update_email_btn = gr.Button("πΎ Save Email", variant="primary") |
|
|
|
|
|
gr.Markdown("### System Status") |
|
|
system_status = gr.Textbox( |
|
|
label="Configuration", |
|
|
value=get_system_status, |
|
|
interactive=False, |
|
|
max_lines=6 |
|
|
) |
|
|
|
|
|
with gr.Accordion("π§ͺ Testing & Samples", open=True): |
|
|
gr.Markdown("### Quick Test Samples") |
|
|
sample_selector = gr.Radio( |
|
|
choices=["Equipment Request", "Content Collaboration", "Budget Approval"], |
|
|
label="Load Sample Request" |
|
|
) |
|
|
load_sample_btn = gr.Button("π Load Sample", variant="secondary") |
|
|
|
|
|
gr.Markdown("---") |
|
|
gr.Markdown("### π New Coordination Request") |
|
|
|
|
|
with gr.Group(): |
|
|
gr.Markdown("#### π€ Your Information") |
|
|
name_input = gr.Textbox( |
|
|
label="Your Name", |
|
|
placeholder="Enter your full name" |
|
|
) |
|
|
|
|
|
department_dropdown = gr.Dropdown( |
|
|
choices=["administration", "production", "magazine"], |
|
|
label="Your Department", |
|
|
value="administration" |
|
|
) |
|
|
|
|
|
with gr.Group(): |
|
|
gr.Markdown("#### π¬ Request Details") |
|
|
message_input = gr.Textbox( |
|
|
label="What do you need help with?", |
|
|
lines=4, |
|
|
placeholder="Describe what you need from other departments..." |
|
|
) |
|
|
|
|
|
image_input = gr.Image( |
|
|
label="π· Attach Image (Optional)", |
|
|
type="pil" |
|
|
) |
|
|
|
|
|
with gr.Group(): |
|
|
gr.Markdown("#### π§ Notification Options") |
|
|
recipient_dropdown = gr.Dropdown( |
|
|
choices=["administration", "production", "magazine"], |
|
|
label="Notify Department" |
|
|
) |
|
|
|
|
|
urgency_dropdown = gr.Dropdown( |
|
|
choices=["Normal", "Medium", "High"], |
|
|
value="Normal", |
|
|
label="Priority Level" |
|
|
) |
|
|
|
|
|
send_email_checkbox = gr.Checkbox( |
|
|
label="Send email notification", |
|
|
value=True |
|
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
submit_btn = gr.Button("π Get Coordination Help", variant="primary") |
|
|
clear_form_btn = gr.Button("ποΈ Clear Form", variant="secondary") |
|
|
|
|
|
with gr.Row(): |
|
|
report_btn = gr.Button("π Submit & Send Report", variant="secondary") |
|
|
clear_btn = gr.Button("ποΈ Clear History", variant="stop") |
|
|
stats_btn = gr.Button("π View Stats") |
|
|
|
|
|
status_display = gr.Textbox( |
|
|
label="System Status", |
|
|
interactive=False, |
|
|
max_lines=2 |
|
|
) |
|
|
|
|
|
stats_display = gr.Textbox( |
|
|
label="Activity Summary", |
|
|
interactive=False, |
|
|
max_lines=8 |
|
|
) |
|
|
|
|
|
with gr.Column(scale=2): |
|
|
gr.Markdown("### π‘ Coordination Guidance") |
|
|
output = gr.Textbox( |
|
|
label="Recommended Actions", |
|
|
lines=20, |
|
|
show_copy_button=True |
|
|
) |
|
|
|
|
|
with gr.Accordion("π’ Department Overview", open=True): |
|
|
gr.Markdown(""" |
|
|
**Administration**: Overall management, decision making, and coordination |
|
|
**Production**: Manufacturing, quality control, and production planning |
|
|
**Magazine Management**: Content creation, publishing, and distribution |
|
|
|
|
|
*The AI will analyze your message and any attached images to provide specific coordination recommendations.* |
|
|
|
|
|
--- |
|
|
|
|
|
**Testing Tips:** |
|
|
- Use the sample requests to quickly test functionality |
|
|
- Try different departments and priority levels |
|
|
- Upload images to test vision capabilities (if API configured) |
|
|
- Monitor the activity log to see coordination history |
|
|
""") |
|
|
|
|
|
with gr.Accordion("π Recent Activity", open=False): |
|
|
history_display = gr.JSON( |
|
|
label="Activity Log", |
|
|
value=lambda: conversation_history[-10:] if conversation_history else [] |
|
|
) |
|
|
|
|
|
|
|
|
update_email_btn.click( |
|
|
fn=update_report_email, |
|
|
inputs=[email_input], |
|
|
outputs=email_status |
|
|
) |
|
|
|
|
|
email_input.submit( |
|
|
fn=update_report_email, |
|
|
inputs=[email_input], |
|
|
outputs=email_status |
|
|
) |
|
|
|
|
|
load_sample_btn.click( |
|
|
fn=load_sample_request, |
|
|
inputs=[sample_selector], |
|
|
outputs=[name_input, department_dropdown, message_input, recipient_dropdown, urgency_dropdown] |
|
|
) |
|
|
|
|
|
submit_btn.click( |
|
|
fn=process_coordination_request, |
|
|
inputs=[name_input, department_dropdown, message_input, image_input, recipient_dropdown, send_email_checkbox, urgency_dropdown], |
|
|
outputs=output |
|
|
).then( |
|
|
fn=lambda: conversation_history[-10:] if conversation_history else [], |
|
|
inputs=[], |
|
|
outputs=history_display |
|
|
) |
|
|
|
|
|
report_btn.click( |
|
|
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), |
|
|
inputs=[name_input, department_dropdown, message_input, image_input, recipient_dropdown, send_email_checkbox, urgency_dropdown], |
|
|
outputs=output |
|
|
).then( |
|
|
fn=lambda: conversation_history[-10:] if conversation_history else [], |
|
|
inputs=[], |
|
|
outputs=history_display |
|
|
) |
|
|
|
|
|
message_input.submit( |
|
|
fn=process_coordination_request, |
|
|
inputs=[name_input, department_dropdown, message_input, image_input, recipient_dropdown, send_email_checkbox, urgency_dropdown], |
|
|
outputs=output |
|
|
).then( |
|
|
fn=lambda: conversation_history[-10:] if conversation_history else [], |
|
|
inputs=[], |
|
|
outputs=history_display |
|
|
) |
|
|
|
|
|
clear_btn.click( |
|
|
fn=clear_conversation, |
|
|
inputs=[], |
|
|
outputs=status_display |
|
|
).then( |
|
|
fn=lambda: [], |
|
|
inputs=[], |
|
|
outputs=history_display |
|
|
) |
|
|
|
|
|
clear_form_btn.click( |
|
|
fn=clear_form, |
|
|
inputs=[], |
|
|
outputs=[name_input, image_input, message_input, recipient_dropdown, department_dropdown, urgency_dropdown, send_email_checkbox] |
|
|
) |
|
|
|
|
|
stats_btn.click( |
|
|
fn=get_conversation_stats, |
|
|
inputs=[], |
|
|
outputs=stats_display |
|
|
) |
|
|
|
|
|
if __name__ == "__main__": |
|
|
ui.launch(share=True) |