117 lines
3.6 KiB
TypeScript
117 lines
3.6 KiB
TypeScript
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<string> {
|
|
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<string> {
|
|
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<string> {
|
|
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();
|
|
}
|