import { ChatAnthropic } from '@langchain/anthropic'; import { ChatOpenAI } from '@langchain/openai'; import { ChatPromptTemplate } from '@langchain/core/prompts'; import { StringOutputParser } from '@langchain/core/output_parsers'; export type AIProvider = 'anthropic' | 'openai'; // Get model based on provider function getModel(provider: AIProvider = 'openai') { if (provider === 'openai') { return new ChatOpenAI({ modelName: 'gpt-4o-mini', openAIApiKey: process.env.OPENAI_API_KEY, }); } if (provider === 'anthropic') { return new ChatAnthropic({ modelName: 'claude-sonnet-4-20250514', anthropicApiKey: process.env.ANTHROPIC_API_KEY, }); } throw new Error(`Provider ${provider} not supported`); } // Email generation prompt const emailPrompt = ChatPromptTemplate.fromMessages([ ['system', `You are a professional wealth advisor writing to a valued client. Maintain a warm but professional tone. Incorporate personal details naturally. Keep emails concise (3-4 paragraphs max). Do not include subject line - just the body.`], ['human', `Advisor: {advisorName} Client: {clientName} Their interests: {interests} Recent notes: {notes} Purpose: {purpose} Generate a personalized email that feels genuine, not templated.`], ]); export interface GenerateEmailParams { advisorName: string; clientName: string; interests: string[]; notes: string; purpose: string; provider?: AIProvider; } export async function generateEmail(params: GenerateEmailParams): Promise { const model = getModel(params.provider); const parser = new StringOutputParser(); const chain = emailPrompt.pipe(model).pipe(parser); const response = await chain.invoke({ advisorName: params.advisorName, clientName: params.clientName, interests: params.interests.join(', ') || 'not specified', notes: params.notes || 'No recent notes', purpose: params.purpose, }); return response; } // Birthday message generation const birthdayPrompt = ChatPromptTemplate.fromMessages([ ['system', `Generate a thoughtful birthday message from a wealth advisor to their client. Should feel personal, not generic. Keep it brief (2-3 sentences) and sincere.`], ['human', `Client: {clientName} Years as client: {yearsAsClient} Interests: {interests} Generate a warm birthday message.`], ]); export interface GenerateBirthdayMessageParams { clientName: string; yearsAsClient: number; interests: string[]; provider?: AIProvider; } export async function generateBirthdayMessage(params: GenerateBirthdayMessageParams): Promise { const model = getModel(params.provider); const parser = new StringOutputParser(); const chain = birthdayPrompt.pipe(model).pipe(parser); const response = await chain.invoke({ clientName: params.clientName, yearsAsClient: params.yearsAsClient.toString(), interests: params.interests.join(', ') || 'not specified', }); return response; } // Email subject generation const subjectPrompt = ChatPromptTemplate.fromMessages([ ['system', `Generate a professional but warm email subject line for a wealth advisor's email. Keep it short (under 50 characters). Do not use quotes.`], ['human', `Purpose: {purpose} Client name: {clientName} Generate just the subject line, nothing else.`], ]); export async function generateSubject(purpose: string, clientName: string, provider?: AIProvider): Promise { const model = getModel(provider); const parser = new StringOutputParser(); const chain = subjectPrompt.pipe(model).pipe(parser); const response = await chain.invoke({ purpose, clientName }); return response.trim(); }