Skip to content

Commit cf9ded7

Browse files
authored
Merge pull request #741 from zackproser/codex/enhance-vectordatabases-tool-with-lead-tracking-and-ui-impro
Improve lead detection and comparison UI
2 parents 1036001 + 4f0be96 commit cf9ded7

File tree

4 files changed

+65
-8
lines changed

4 files changed

+65
-8
lines changed

src/app/api/vectordatabases/chat/route.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { z } from 'zod';
66
import { LeadAnalysis } from '@/types';
77
import { prisma } from '@/lib/prisma';
88
import { auth } from '../../../../../auth';
9+
import { sendLeadNotificationEmail } from '@/lib/postmark';
910

1011
// Allow this serverless function to run for up to 5 minutes
1112
export const maxDuration = 300;
@@ -95,6 +96,14 @@ Respond with a JSON object containing:
9596
nextSteps: result.nextSteps
9697
}
9798
});
99+
100+
if (result.confidence > 0.7) {
101+
await sendLeadNotificationEmail({
102+
messages,
103+
analysis: result,
104+
email,
105+
});
106+
}
98107
} catch (error) {
99108
console.error('Failed to process lead:', error);
100109
}

src/app/vectordatabases/compare/ComparePageClient.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,9 +264,9 @@ export default function ComparePageClient({
264264
const categoryObj = db[category] as { [feature: string]: any } || {};
265265
const value = categoryObj[feature];
266266
return (
267-
<TableCell key={db.name}>
267+
<TableCell key={db.name} className="text-center">
268268
{typeof value === 'boolean' ? (
269-
<span className={value ? 'text-green-600' : 'text-red-600'}>
269+
<span className={value ? 'text-green-600 text-xl' : 'text-red-600 text-xl'}>
270270
{getEmoji(value.toString())}
271271
</span>
272272
) : (

src/components/VectorDBComparison.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,9 @@ const renderComparison = (category, selectedDatabases, categories, features) =>
158158
{selectedDatabases.map((db) => {
159159
const value = db[category][feature];
160160
return (
161-
<TableCell key={db.name}>
161+
<TableCell key={db.name} className="text-center">
162162
{typeof value === 'boolean' ? (
163-
<span className={value ? 'text-green-600' : 'text-red-600'}>
163+
<span className={value ? 'text-green-600 text-xl' : 'text-red-600 text-xl'}>
164164
{getEmoji(value.toString())}
165165
</span>
166166
) : (

src/lib/postmark.ts

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ServerClient } from 'postmark'
22
// import { renderPaywalledContent, loadContent } from "./content-handlers"; // Note: loadContent might be deprecated, check content-handlers
33
import { getContentWithComponentByDirectorySlug } from "./content-handlers"; // Use this instead of loadContent
4-
import { ExtendedMetadata } from '@/types'
4+
import { ExtendedMetadata, LeadAnalysis } from '@/types'
55
import { emailLogger as logger } from '@/utils/logger' // Import centralized email logger
66
import { getContentUrlFromObject } from './content-url'
77

@@ -178,7 +178,7 @@ async function extractPreviewContent(productSlug: string): Promise<PreviewConten
178178
* @returns Postmark response
179179
*/
180180
const sendFreeChaptersEmail = async (
181-
input: SendFreeChaptersEmailInput
181+
input: SendFreeChaptersEmailInput
182182
): Promise<MessageSendingResponse | null> => {
183183
logger.info(`[START] Sending free chapters email to: ${input.To}`);
184184
logger.debug(`[CONFIG] Postmark API Key configured: ${!!process.env.POSTMARK_API_KEY}`);
@@ -268,7 +268,55 @@ You're receiving this email because you requested a preview from Zachary Proser.
268268
// Handle specific Postmark errors if needed
269269
// e.g., if (error.code === 406) { ... }
270270
return null;
271-
}
271+
}
272+
};
273+
274+
interface SendLeadNotificationInput {
275+
messages: { role: string; content: string }[];
276+
analysis: LeadAnalysis;
277+
email?: string | null;
278+
}
279+
280+
const sendLeadNotificationEmail = async (
281+
input: SendLeadNotificationInput
282+
): Promise<MessageSendingResponse | null> => {
283+
const adminEmail = process.env.ADMIN_EMAIL || '[email protected]';
284+
285+
const conversationText = input.messages
286+
.map((m) => `${m.role}: ${m.content}`)
287+
.join('\n');
288+
289+
const emailData = {
290+
291+
To: adminEmail,
292+
Subject: 'New Potential Lead from Chatbot',
293+
HtmlBody: `
294+
<h1>New Potential Lead Detected</h1>
295+
<p><strong>Email:</strong> ${input.email || 'unknown'}</p>
296+
<p><strong>Confidence:</strong> ${input.analysis.confidence}</p>
297+
<p><strong>Reasons:</strong> ${input.analysis.reasons.join(', ')}</p>
298+
<p><strong>Topics:</strong> ${input.analysis.topics.join(', ')}</p>
299+
<p><strong>Next Steps:</strong> ${input.analysis.nextSteps.join(', ')}</p>
300+
<pre style="white-space:pre-wrap">${conversationText}</pre>
301+
`,
302+
TextBody: `New Potential Lead\nEmail: ${input.email || 'unknown'}\nConfidence: ${input.analysis.confidence}\nReasons: ${input.analysis.reasons.join(', ')}\nTopics: ${input.analysis.topics.join(', ')}\nNext Steps: ${input.analysis.nextSteps.join(', ')}\nConversation:\n${conversationText}`,
303+
MessageStream: 'outbound',
304+
};
305+
306+
try {
307+
const response = await client.sendEmail(emailData);
308+
logger.info('[SUCCESS] Lead notification sent:', response);
309+
return response;
310+
} catch (error) {
311+
logger.error('[FAIL] Failed to send lead notification:', error);
312+
return null;
313+
}
272314
};
273315

274-
export { sendReceiptEmail, sendFreeChaptersEmail, type SendReceiptEmailInput, type SendFreeChaptersEmailInput };
316+
export {
317+
sendReceiptEmail,
318+
sendFreeChaptersEmail,
319+
sendLeadNotificationEmail,
320+
type SendReceiptEmailInput,
321+
type SendFreeChaptersEmailInput,
322+
};

0 commit comments

Comments
 (0)