Update app.py
Browse files
app.py
CHANGED
|
@@ -1,33 +1,33 @@
|
|
| 1 |
import gradio as gr
|
| 2 |
import os
|
| 3 |
import pandas as pd
|
| 4 |
-
import
|
|
|
|
|
|
|
| 5 |
from supabase import create_client, Client
|
| 6 |
|
| 7 |
# --- 設定 ---
|
| 8 |
SUPABASE_URL = os.getenv("SUPABASE_URL")
|
| 9 |
SUPABASE_KEY = os.getenv("SUPABASE_KEY")
|
| 10 |
-
|
| 11 |
-
|
|
|
|
| 12 |
|
| 13 |
supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
|
| 14 |
-
resend.api_key = RESEND_API_KEY
|
| 15 |
|
| 16 |
def get_bookings():
|
| 17 |
-
# 加入 email 和 remarks 欄位
|
| 18 |
response = supabase.table("bookings").select("*").order("created_at", desc=True).execute()
|
| 19 |
if not response.data: return pd.DataFrame()
|
| 20 |
df = pd.DataFrame(response.data)
|
| 21 |
-
# 確保欄位存在,避免報錯
|
| 22 |
cols = ['id', 'date', 'time', 'name', 'tel', 'email', 'pax', 'remarks', 'status']
|
| 23 |
for c in cols:
|
| 24 |
if c not in df.columns: df[c] = ""
|
| 25 |
return df[cols]
|
| 26 |
|
| 27 |
def send_confirmation_email(booking_id):
|
| 28 |
-
"""
|
| 29 |
try:
|
| 30 |
-
# 1.
|
| 31 |
res = supabase.table("bookings").select("*").eq("id", booking_id).execute()
|
| 32 |
if not res.data: return "❌ 找不到該訂單"
|
| 33 |
booking = res.data[0]
|
|
@@ -35,35 +35,42 @@ def send_confirmation_email(booking_id):
|
|
| 35 |
email = booking.get('email')
|
| 36 |
if not email or "@" not in email: return "❌ 客人未填寫有效 Email"
|
| 37 |
|
| 38 |
-
# 2.
|
| 39 |
confirm_link = f"{PUBLIC_SPACE_URL}/?id={booking_id}&action=confirm"
|
| 40 |
|
| 41 |
-
# 3.
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
""
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
supabase.table("bookings").update({"status": "已發確認信"}).eq("id", booking_id).execute()
|
| 66 |
-
return f"✅
|
| 67 |
|
| 68 |
except Exception as e:
|
| 69 |
return f"❌ 發信失敗: {str(e)}"
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
import os
|
| 3 |
import pandas as pd
|
| 4 |
+
import smtplib
|
| 5 |
+
from email.mime.text import MIMEText
|
| 6 |
+
from email.mime.multipart import MIMEMultipart
|
| 7 |
from supabase import create_client, Client
|
| 8 |
|
| 9 |
# --- 設定 ---
|
| 10 |
SUPABASE_URL = os.getenv("SUPABASE_URL")
|
| 11 |
SUPABASE_KEY = os.getenv("SUPABASE_KEY")
|
| 12 |
+
MAIL_USERNAME = os.getenv("MAIL_USERNAME") # Gmail 帳號
|
| 13 |
+
MAIL_PASSWORD = os.getenv("MAIL_PASSWORD") # Gmail 應用程式密碼
|
| 14 |
+
PUBLIC_SPACE_URL = "https://deeplearning101-ciecietaipei.hf.space"
|
| 15 |
|
| 16 |
supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
|
|
|
|
| 17 |
|
| 18 |
def get_bookings():
|
|
|
|
| 19 |
response = supabase.table("bookings").select("*").order("created_at", desc=True).execute()
|
| 20 |
if not response.data: return pd.DataFrame()
|
| 21 |
df = pd.DataFrame(response.data)
|
|
|
|
| 22 |
cols = ['id', 'date', 'time', 'name', 'tel', 'email', 'pax', 'remarks', 'status']
|
| 23 |
for c in cols:
|
| 24 |
if c not in df.columns: df[c] = ""
|
| 25 |
return df[cols]
|
| 26 |
|
| 27 |
def send_confirmation_email(booking_id):
|
| 28 |
+
"""改用 Gmail SMTP 發送確認信"""
|
| 29 |
try:
|
| 30 |
+
# 1. 抓取資料
|
| 31 |
res = supabase.table("bookings").select("*").eq("id", booking_id).execute()
|
| 32 |
if not res.data: return "❌ 找不到該訂單"
|
| 33 |
booking = res.data[0]
|
|
|
|
| 35 |
email = booking.get('email')
|
| 36 |
if not email or "@" not in email: return "❌ 客人未填寫有效 Email"
|
| 37 |
|
| 38 |
+
# 2. 產生連結
|
| 39 |
confirm_link = f"{PUBLIC_SPACE_URL}/?id={booking_id}&action=confirm"
|
| 40 |
|
| 41 |
+
# 3. 準備信件內容 (HTML)
|
| 42 |
+
msg = MIMEMultipart()
|
| 43 |
+
msg['From'] = f"Cié Cié Taipei <{MAIL_USERNAME}>"
|
| 44 |
+
msg['To'] = email
|
| 45 |
+
msg['Subject'] = f"[{booking['date']}] Cié Cié Taipei 訂位確認"
|
| 46 |
+
|
| 47 |
+
html_content = f"""
|
| 48 |
+
<div style="padding: 20px; background: #111; color: #d4af37; font-family: sans-serif; border-radius: 10px;">
|
| 49 |
+
<h2 style="border-bottom: 1px solid #d4af37; padding-bottom: 10px;">訂位保留確認</h2>
|
| 50 |
+
<p>{booking['name']} 您好,我們已為您保留座位:</p>
|
| 51 |
+
<ul style="color: #eee;">
|
| 52 |
+
<li>日期:{booking['date']}</li>
|
| 53 |
+
<li>時間:{booking['time']}</li>
|
| 54 |
+
<li>人數:{booking['pax']} 位</li>
|
| 55 |
+
</ul>
|
| 56 |
+
<p>請點擊下方按鈕確認出席:</p>
|
| 57 |
+
<a href="{confirm_link}" style="background: #d4af37; color: black; padding: 12px 24px; text-decoration: none; border-radius: 5px; font-weight: bold; display: inline-block; margin-top: 10px;">✅ 我會出席 (Confirm)</a>
|
| 58 |
+
<br><br>
|
| 59 |
+
<hr style="border: 0; border-top: 1px solid #333;">
|
| 60 |
+
<p style="color: #666; font-size: 12px;">若需取消,請直接回覆此信或致電 02-2709-3446。</p>
|
| 61 |
+
</div>
|
| 62 |
+
"""
|
| 63 |
+
msg.attach(MIMEText(html_content, 'html'))
|
| 64 |
+
|
| 65 |
+
# 4. 透過 Gmail 發送
|
| 66 |
+
# Gmail SMTP Server: smtp.gmail.com, Port: 465 (SSL)
|
| 67 |
+
with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:
|
| 68 |
+
server.login(MAIL_USERNAME, MAIL_PASSWORD)
|
| 69 |
+
server.send_message(msg)
|
| 70 |
+
|
| 71 |
+
# 5. 更新狀態
|
| 72 |
supabase.table("bookings").update({"status": "已發確認信"}).eq("id", booking_id).execute()
|
| 73 |
+
return f"✅ 已透過 Gmail 發送確認信給 {booking['name']} ({email})"
|
| 74 |
|
| 75 |
except Exception as e:
|
| 76 |
return f"❌ 發信失敗: {str(e)}"
|