StemGraph_AI / feed.py
Subh775's picture
msg indent fix.. x2
394f587
Raw
History Blame Contribute Delete
5.18 kB
"""
feed.py — Feedback email sender for STEM Copilot.
Uses Resend API to deliver user feedback to subhansh.stembotix@gmail.com.
Set RESEND_API_KEY in HF Secrets (or .env) before deploying.
"""
import os
import base64
import resend #type:ignore
RESEND_API_KEY = os.environ.get("RESEND_API_KEY", "")
resend.api_key = RESEND_API_KEY
TO_EMAIL = "subhansh.stembotix@gmail.com"
FROM_EMAIL = "STEM Copilot <onboarding@resend.dev>"
_STAR_FILLED = "&#9733;"
_STAR_EMPTY = "&#9734;"
_RATING_LABELS = {"1": "Poor", "2": "Fair", "3": "Good", "4": "Excellent"}
_CATEGORY_LABELS = {
"bug": "Technical Issue / Bug Report",
"feature": "Feature Request",
"iam": "IAM / Access Policy",
"documentation": "Documentation",
"other": "Other",
}
def _stars(n: int, max_n: int = 5) -> str:
return _STAR_FILLED * n + _STAR_EMPTY * (max_n - n)
def _row(label: str, value: str) -> str:
return f"""
<tr>
<td style="padding:8px 14px;color:#888;font-size:13px;white-space:nowrap;">{label}</td>
<td style="padding:8px 14px;color:#e8e8e8;font-size:14px;">{value}</td>
</tr>"""
def build_html(
user_id: str,
user_email: str,
user_name: str,
overall: int,
ease: int,
quality: int,
category: str,
message: str,
) -> str:
overall_stars = _stars(overall)
ease_label = _RATING_LABELS.get(str(ease), str(ease))
quality_label = _RATING_LABELS.get(str(quality), str(quality))
category_label = _CATEGORY_LABELS.get(category, category)
display_from = user_email or user_id
if user_name and user_name.strip():
display_from = f"{user_name.strip()} &lt;{user_email}&gt;" if user_email else user_name.strip()
return f"""<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"></head>
<body style="margin:0;padding:0;background:#0a0a0a;font-family:'Segoe UI',sans-serif;">
<table width="100%" cellpadding="0" cellspacing="0" style="background:#0a0a0a;padding:32px 0;">
<tr><td align="center">
<table width="600" cellpadding="0" cellspacing="0"
style="background:#141414;border:1px solid #222;border-radius:16px;overflow:hidden;">
<!-- Header -->
<tr>
<td style="background:linear-gradient(135deg,#EC642B,#f07d4a);padding:24px 32px;">
<h1 style="margin:0;color:#fff;font-size:22px;font-weight:700;">
New Feedback &mdash; STEM Copilot
</h1>
</td>
</tr>
<!-- Ratings table -->
<tr><td style="padding:24px 32px 8px;">
<table cellpadding="0" cellspacing="0" width="100%"
style="background:#1a1a1a;border:1px solid #2a2a2a;border-radius:10px;">
{_row("From", display_from)}
{_row("Overall Rating", f"<span style='font-size:18px;letter-spacing:2px;color:#f5a623;'>{overall_stars}</span> ({overall}/5)")}
{_row("Ease of Use", ease_label)}
{_row("Response Quality", quality_label)}
{_row("Category", category_label)}
</table>
</td></tr>
<!-- Message body -->
<tr><td style="padding:16px 32px;">
<div style="background:#1a1a1a;border:1px solid #2a2a2a;border-radius:10px;padding:16px;">
<p style="margin:0 0 6px;color:#888;font-size:12px;text-transform:uppercase;letter-spacing:1px;">Message</p>
<p style="margin:0;color:#e8e8e8;font-size:14px;line-height:1.7;white-space:pre-wrap;">{message}</p>
</div>
</td></tr>
<!-- Footer -->
<tr><td style="padding:16px 32px 28px;">
<p style="margin:0;color:#555;font-size:11px;text-align:center;">
Sent automatically by STEM Copilot · STEMbotix
</p>
</td></tr>
</table>
</td></tr>
</table>
</body>
</html>"""
def send_feedback(
user_id: str,
user_email: str,
user_name: str = "",
overall: int = 5,
ease: int = 4,
quality: int = 4,
category: str = "other",
message: str = "",
attachments: list[dict] | None = None,
) -> bool:
"""
Send feedback email via Resend.
attachments: list of {"filename": str, "content": base64_str, "content_type": str}
Returns True on success.
"""
if not RESEND_API_KEY:
print("[FEED] RESEND_API_KEY not set — skipping email.")
return False
html = build_html(user_id, user_email, user_name, overall, ease, quality, category, message)
payload: dict = {
"from": FROM_EMAIL,
"to": [TO_EMAIL],
"subject": f"[STEM Copilot Feedback] {_CATEGORY_LABELS.get(category, category)} ({overall}/5)",
"html": html,
}
if attachments:
payload["attachments"] = [
{
"filename": a["filename"],
"content": a["content"], # base64 string
}
for a in attachments[:5] # cap at 5
]
try:
resp = resend.Emails.send(payload)
print(f"[FEED] Email sent — id={resp.get('id')}")
return True
except Exception as exc:
print(f"[FEED] Exception: {exc}")
return False