HAigene_FastAPI / send_discord.py
mlbench123's picture
Upload 4 files
39b7b21 verified
import requests
import cv2
import numpy as np
from datetime import datetime
from pathlib import Path
import logging
import base64
import io
import json
logger = logging.getLogger(__name__)
class DiscordAlertManager:
"""Manages Discord webhook alerts for hygiene violations."""
def __init__(self, discord_config: dict):
"""
discord_config: {
'webhook_url': 'your_webhook_url'
}
"""
self.webhook_url = discord_config['webhook_url']
self.alert_cooldown = 300
self.last_alert_time = None
self.dirty_start_time = None
self.dirty_threshold_seconds = 10
self.dirty_coverage_threshold = 0.06
def should_send_alert(self, dirty_coverage: float, current_time: datetime) -> bool:
"""Same logic as before"""
if dirty_coverage < self.dirty_coverage_threshold:
self.dirty_start_time = None
return False
if self.dirty_start_time is None:
self.dirty_start_time = current_time
return False
dirty_duration = (current_time - self.dirty_start_time).total_seconds()
if dirty_duration < self.dirty_threshold_seconds:
return False
if self.last_alert_time is not None:
time_since_last = (current_time - self.last_alert_time).total_seconds()
if time_since_last < self.alert_cooldown:
return False
return True
def generate_heatmap_image(self, frame: np.ndarray, gmm_heatmap: np.ndarray,
output_path: str) -> str:
"""Generate heatmap visualization"""
result = frame.copy()
height, width = result.shape[:2]
if gmm_heatmap.shape != (height, width):
heatmap_resized = cv2.resize(gmm_heatmap, (width, height))
else:
heatmap_resized = gmm_heatmap
heatmap_colored = cv2.applyColorMap(
(heatmap_resized * 255).astype(np.uint8),
cv2.COLORMAP_JET
)
alpha = 0.5
result = cv2.addWeighted(frame, 1 - alpha, heatmap_colored, alpha, 0)
# Add info panel
avg_dirt = np.mean(heatmap_resized)
max_dirt = np.max(heatmap_resized)
dirty_pixels = np.sum(heatmap_resized > 0.60)
coverage_percent = (dirty_pixels / heatmap_resized.size) * 100
cv2.rectangle(result, (10, 10), (400, 120), (0, 0, 0), -1)
cv2.rectangle(result, (10, 10), (400, 120), (255, 255, 255), 2)
info_text = [
f"Average Dirt: {avg_dirt:.2f}",
f"Maximum Dirt: {max_dirt:.2f}",
f"Red Zone: {coverage_percent:.1f}%",
f"Time: {datetime.now().strftime('%H:%M:%S')}"
]
for i, text in enumerate(info_text):
cv2.putText(result, text, (20, 35 + i * 25),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 1)
cv2.imwrite(output_path, result)
return output_path
def send_alert(self, camera_name: str, dirty_coverage: float,
dirty_duration: int, frame: np.ndarray,
gmm_heatmap: np.ndarray) -> bool:
"""Send Discord webhook alert with embedded image"""
try:
# Generate image
temp_image_path = f"tmp/heatmap_{datetime.now().timestamp()}.png"
self.generate_heatmap_image(frame, gmm_heatmap, temp_image_path)
# Calculate duration
duration_mins = dirty_duration // 60
duration_secs = dirty_duration % 60
# Create rich embed
embed = {
"title": "🚨 CLEANING ALERT",
"description": f"**{camera_name}** requires immediate attention!",
"color": 15158332, # Red color (#E74C3C)
"fields": [
{
"name": "πŸ“ Location",
"value": camera_name,
"inline": True
},
{
"name": "πŸ”΄ Coverage",
"value": f"{dirty_coverage*100:.1f}%",
"inline": True
},
{
"name": "⏱ Duration",
"value": f"{duration_mins}m {duration_secs}s",
"inline": True
},
{
"name": "⚠️ Action Required",
"value": "Table has exceeded cleanliness threshold and needs cleaning.",
"inline": False
}
],
"footer": {
"text": "Kitchen Hygiene Monitoring System"
},
"timestamp": datetime.utcnow().isoformat()
}
# Prepare webhook payload with embeds
payload = {
"username": "Hygiene Monitor Bot",
"avatar_url": "https://cdn-icons-png.flaticon.com/512/3699/3699516.png",
"embeds": [embed]
}
# Read the image file
with open(temp_image_path, 'rb') as f:
image_data = f.read()
# Prepare the multipart form data
files = {
'payload_json': (None, json.dumps(payload), 'application/json'),
'file': ('heatmap.png', image_data, 'image/png')
}
# Send the request
response = requests.post(self.webhook_url, files=files)
if response.status_code in [200, 204]:
self.last_alert_time = datetime.now()
logger.info(f"βœ… Discord alert sent for {camera_name}")
Path(temp_image_path).unlink(missing_ok=True)
return True
else:
logger.error(f"Discord webhook error: {response.status_code} - {response.text}")
return False
except Exception as e:
logger.error(f"Failed to send Discord alert: {str(e)}")
import traceback
logger.error(traceback.format_exc())
return False