updated discord webhook message

This commit is contained in:
Madison 2025-07-06 16:14:58 -07:00
parent cb01e0da4a
commit a2dc15cf10
4 changed files with 69 additions and 86 deletions

View File

@ -1,26 +1,18 @@
/**
* Sends a message to Discord webhook with rich metadata
* Sends a message to Discord webhook with session tracking
*/
export async function sendToDiscordWebhook(data: {
message: string;
username?: string;
metadata?: {
url?: string;
sessionId?: string;
messageNumber?: number;
pathname?: string;
timestamp?: string;
userAgent?: string;
viewport?: string;
isHomePage?: boolean;
isScrolled?: boolean;
messageLength?: number;
messageType?: string;
sessionMessageCount?: number;
timeOnPage?: number;
scrollDepth?: number;
referrer?: string;
language?: string;
timezone?: string;
chatExpanded?: boolean;
isFollowUp?: boolean;
};
}) {
const webhookUrl = process.env.DISCORD_WEBHOOK_URL;
@ -33,54 +25,27 @@ export async function sendToDiscordWebhook(data: {
try {
const { message, username, metadata } = data;
// Create a rich embed with metadata
const embed = {
title: "💬 AI Chat Message",
description: message.length > 100 ? message.substring(0, 100) + "..." : message,
color: metadata?.messageType === 'starter-prompt' ? 0x10b981 : 0x3b82f6, // Green for starter prompts, blue for custom
fields: [
// Message Info
...(metadata?.messageType ? [{ name: "📝 Type", value: metadata.messageType === 'starter-prompt' ? "Starter Prompt" : "Custom Message", inline: true }] : []),
...(metadata?.messageLength ? [{ name: "📏 Length", value: `${metadata.messageLength} chars`, inline: true }] : []),
...(metadata?.chatExpanded !== undefined ? [{ name: "🔍 Chat Mode", value: metadata.chatExpanded ? "Expanded" : "Normal", inline: true }] : []),
// Page Context
...(metadata?.pathname ? [{ name: "📄 Page", value: metadata.pathname, inline: true }] : []),
...(metadata?.isHomePage !== undefined ? [{ name: "🏠 Homepage", value: metadata.isHomePage ? "Yes" : "No", inline: true }] : []),
...(metadata?.isScrolled !== undefined ? [{ name: "📜 Scrolled", value: metadata.isScrolled ? "Yes" : "No", inline: true }] : []),
// Session Data
...(metadata?.sessionMessageCount ? [{ name: "💬 Session Messages", value: metadata.sessionMessageCount.toString(), inline: true }] : []),
...(metadata?.timeOnPage ? [{ name: "⏱️ Time on Page", value: formatTime(metadata.timeOnPage), inline: true }] : []),
...(metadata?.scrollDepth !== undefined ? [{ name: "📊 Scroll Depth", value: `${metadata.scrollDepth}%`, inline: true }] : []),
// Technical Info
...(metadata?.viewport ? [{ name: "📱 Viewport", value: metadata.viewport, inline: true }] : []),
...(metadata?.language ? [{ name: "🌐 Language", value: metadata.language, inline: true }] : []),
...(metadata?.timezone ? [{ name: "⏰ Timezone", value: metadata.timezone, inline: true }] : []),
],
timestamp: metadata?.timestamp || new Date().toISOString(),
footer: {
text: "Stack Auth Docs AI Chat",
icon_url: "https://cdn.discordapp.com/embed/avatars/0.png"
}
};
// Add full message as a separate field if it was truncated
if (message.length > 100) {
embed.fields.unshift({ name: "📝 Full Message", value: message, inline: false });
}
// Extract browser info from user agent
// Format message with clean text structure
const sessionPrefix = metadata?.sessionId ? metadata.sessionId.slice(-8) : 'unknown';
const messageNumber = metadata?.messageNumber || 1;
const isFollowUp = metadata?.isFollowUp || false;
const messageType = metadata?.messageType === 'starter-prompt' ? '🟢 Starter' : '🔵 Custom';
const timeOnPage = metadata?.timeOnPage ? formatTime(metadata.timeOnPage) : 'N/A';
const browserInfo = extractBrowserInfo(metadata?.userAgent || '');
if (browserInfo) {
embed.fields.push({ name: "🌐 Browser", value: browserInfo, inline: true });
}
const page = metadata?.pathname || 'Unknown';
// Create formatted message
const formattedMessage = `${isFollowUp ? '🔄 **FOLLOW-UP**' : '💬 **NEW CONVERSATION**'}
**Session:** \`${sessionPrefix}\` **|** **Message #${messageNumber}** **|** ${messageType}
// Add referrer info
if (metadata?.referrer && metadata.referrer !== 'Direct') {
embed.fields.push({ name: "🔗 Referrer", value: metadata.referrer, inline: true });
}
**Question:**
> ${message}
**Context:**
📄 **Page:** ${page}
**Time on Page:** ${timeOnPage}${browserInfo ? `\n🌐 **Browser:** ${browserInfo}` : ''}
---`;
const response = await fetch(webhookUrl, {
method: 'POST',
@ -88,9 +53,9 @@ export async function sendToDiscordWebhook(data: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
content: formattedMessage,
username: username || 'Stack Auth Docs User',
avatar_url: 'https://cdn.discordapp.com/embed/avatars/0.png',
embeds: [embed],
}),
});

View File

@ -22,7 +22,7 @@ export async function POST(request: Request) {
const { messages, docsContent } = await request.json();
// Create a comprehensive system prompt that restricts AI to Stack Auth topics
const systemPrompt = `You are Stack Auth's AI assistant. You ONLY answer questions about Stack Auth - a complete authentication and user management solution for React applications.
const systemPrompt = `You are Stack Auth's AI assistant. You ONLY answer questions about Stack Auth - a complete authentication and user management solution..
DOCUMENTATION CONTEXT:
${docsContent || 'Documentation not available'}
@ -46,10 +46,10 @@ RESPONSE FORMAT:
Remember: You are Stack Auth's dedicated assistant. Stay focused on Stack Auth topics only.`;
try {
const result = streamText({
model: google('gemini-1.5-flash'),
const result = streamText({
model: google('gemini-2.0-flash'),
system: systemPrompt,
messages,
messages,
maxTokens: 1000,
temperature: 0.3,
tools: {

View File

@ -18,3 +18,4 @@ export async function POST(request: NextRequest) {
return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
}
}

View File

@ -35,35 +35,59 @@ export function AIChatDrawer() {
const [isHomePage, setIsHomePage] = useState(false);
const [isScrolled, setIsScrolled] = useState(false);
const [pageLoadTime] = useState(Date.now());
const [sessionId] = useState(() => {
// Generate or retrieve session ID
const existing = localStorage.getItem('ai-chat-session-id');
if (existing) {
return existing;
}
const newId = `session_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
localStorage.setItem('ai-chat-session-id', newId);
return newId;
});
const [sessionData, setSessionData] = useState({
messagesCount: 0,
starterPromptsUsed: 0,
timeOnPage: 0,
scrollDepth: 0,
messageCount: 0,
});
// Track session data
useEffect(() => {
const updateSessionData = () => {
const timeOnPage = Math.floor((Date.now() - pageLoadTime) / 1000);
const scrollDepth = Math.floor((window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100);
setSessionData(prev => ({
...prev,
timeOnPage,
scrollDepth: Math.max(prev.scrollDepth, scrollDepth || 0),
}));
};
const interval = setInterval(updateSessionData, 5000); // Update every 5 seconds
window.addEventListener('scroll', updateSessionData);
return () => {
clearInterval(interval);
window.removeEventListener('scroll', updateSessionData);
};
}, [pageLoadTime]);
// Reset session ID if user has been inactive for too long
useEffect(() => {
const checkSessionExpiry = () => {
const lastActivity = localStorage.getItem('ai-chat-last-activity');
if (lastActivity) {
const timeSinceActivity = Date.now() - parseInt(lastActivity);
const ONE_HOUR = 60 * 60 * 1000;
if (timeSinceActivity > ONE_HOUR) {
// Generate new session ID
const newId = `session_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
localStorage.setItem('ai-chat-session-id', newId);
setSessionData(prev => ({ ...prev, messageCount: 0 }));
}
}
};
checkSessionExpiry();
}, []);
// Detect if we're on homepage and scroll state
useEffect(() => {
const checkHomePage = () => {
@ -144,28 +168,23 @@ export function AIChatDrawer() {
// Function to send message to Discord webhook
const sendToDiscord = async (message: string) => {
try {
// Gather additional context
// Update message count and last activity
const newMessageCount = sessionData.messageCount + 1;
localStorage.setItem('ai-chat-last-activity', Date.now().toString());
// Gather only essential context
const context = {
message: message,
username: 'Stack Auth Docs User',
metadata: {
url: window.location.href,
sessionId: sessionId,
messageNumber: newMessageCount,
pathname: window.location.pathname,
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent,
viewport: `${window.innerWidth}x${window.innerHeight}`,
isHomePage: isHomePage,
isScrolled: isScrolled,
messageLength: message.length,
messageType: starterPrompts.some(p => p.prompt === message) ? 'starter-prompt' : 'custom',
sessionMessageCount: messages.length + 1,
// Enhanced session data
timeOnPage: sessionData.timeOnPage,
scrollDepth: sessionData.scrollDepth,
referrer: document.referrer || 'Direct',
language: navigator.language,
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
chatExpanded: isChatExpanded,
isFollowUp: newMessageCount > 1,
}
};
@ -186,11 +205,9 @@ export function AIChatDrawer() {
if (!input.trim()) return;
// Update session data
const isStarterPrompt = starterPrompts.some(p => p.prompt === input.trim());
setSessionData(prev => ({
...prev,
messagesCount: prev.messagesCount + 1,
starterPromptsUsed: prev.starterPromptsUsed + (isStarterPrompt ? 1 : 0),
messageCount: prev.messageCount + 1,
}));
// Send message to Discord webhook