feat: add telegram webhook handler to receive phone replies and push to visitor chat

This commit is contained in:
ssbg04 committed 2026-10-18 13:16:49 +08:00
1 parent 1941064933
commit a73c2aa8e5
2 files changed
+87 -3

No files matched your search

+30 -3
View File
@@ -11,8 +11,35 @@ interface ChatMessage {
time: number;
}
// Global in-memory session store across endpoints in the same runtime instance
const sessions = new Map<string, ChatMessage[]>();
export function addCrisReply(sessionId: string, text: string) {
const crisMsg: ChatMessage = {
id: 'cris_' + Date.now(),
sender: 'cris',
text,
time: Date.now(),
};
// Find matching session (direct or prefix match)
let key = sessionId;
if (!sessions.has(sessionId)) {
for (const k of sessions.keys()) {
if (k.startsWith(sessionId) || sessionId.startsWith(k)) {
key = k;
break;
}
}
}
const history = sessions.get(key) || [];
history.push(crisMsg);
if (history.length > 30) history.shift();
sessions.set(key, history);
return crisMsg;
}
export const POST: APIRoute = async ({ request }) => {
try {
const { sessionId, message, userName } = await request.json();
@@ -36,7 +63,6 @@ export const POST: APIRoute = async ({ request }) => {
const history = sessions.get(sessionId) || [];
history.push(userMsg);
// Keep last 30 messages per session
if (history.length > 30) history.shift();
sessions.set(sessionId, history);
@@ -47,10 +73,11 @@ export const POST: APIRoute = async ({ request }) => {
if (botToken && chatId) {
const telegramText =
`💬 *New Portfolio Live Message*\n\n` +
`👤 *From:* ${userName || 'Visitor'} (\`#${sessionId.slice(0, 8)}\`)\n` +
`👤 *From:* ${userName || 'Visitor'}\n` +
`🔑 *Session:* #${sessionId}\n` +
`📍 *Origin:* ${locationStr}\n\n` +
`📝 *Message:*\n"${message.trim()}"\n\n` +
`_To reply to this visitor, swipe right and reply to this message!_`;
`_👉 To reply to this visitor, swipe right and reply to this message!_`;
try {
await fetch(`https://api.telegram.org/bot${botToken}/sendMessage`, {
+57
View File
@@ -0,0 +1,57 @@
import type { APIRoute } from 'astro';
import { addCrisReply } from './live-chat';
export const prerender = false;
/**
* Telegram Webhook Handler
* Telegram sends an update whenever you reply to a message in the bot chat.
*/
export const POST: APIRoute = async ({ request }) => {
try {
const payload = await request.json();
// Check if the update is a message reply
const message = payload?.message;
if (!message || !message.text) {
return new Response(JSON.stringify({ ok: true, note: 'No text message' }), { status: 200 });
}
const replyToMessage = message.reply_to_message;
const replyText = message.text.trim();
// Find the session ID from the replied message
// When visitor sends message, we tagged it with (#user_xxxxxxxx)
let targetSessionId = '';
if (replyToMessage?.text) {
const match = replyToMessage.text.match(/#([a-zA-Z0-9_-]+)/);
if (match && match[1]) {
targetSessionId = match[1];
}
}
// If you replied without swiping or session wasn't found, check caption or fallback
if (!targetSessionId && replyToMessage?.caption) {
const match = replyToMessage.caption.match(/#([a-zA-Z0-9_-]+)/);
if (match && match[1]) targetSessionId = match[1];
}
if (targetSessionId) {
addCrisReply(targetSessionId, replyText);
return new Response(JSON.stringify({ ok: true, matchedSession: targetSessionId }), { status: 200 });
}
return new Response(JSON.stringify({ ok: true, note: 'No session ID found in reply' }), { status: 200 });
} catch (err: any) {
console.error('Telegram webhook error:', err);
return new Response(JSON.stringify({ error: err.message }), { status: 500 });
}
};
export const GET: APIRoute = async () => {
return new Response(
JSON.stringify({ status: 'Telegram Webhook Endpoint Active' }),
{ status: 200, headers: { 'Content-Type': 'application/json' } }
);
};