save work
This commit is contained in:
@ -3,20 +3,132 @@ import { getDataSource } from '../lib/database';
|
||||
import { Customer } from '../lib/database/entities/Customer';
|
||||
import { ContactRecord } from '../lib/database/entities/ContactRecord';
|
||||
import { sendEmail } from '../lib/email';
|
||||
import axios from 'axios';
|
||||
|
||||
// Get command line arguments
|
||||
const args = process.argv.slice(2);
|
||||
const emailCountArg = args.find(arg => arg.startsWith('--count='));
|
||||
const lmStudioUrlArg = args.find(arg => arg.startsWith('--lmstudio-url='));
|
||||
const modelArg = args.find(arg => arg.startsWith('--model='));
|
||||
const temperatureArg = args.find(arg => arg.startsWith('--temperature='));
|
||||
const dryRunArg = args.find(arg => arg.startsWith('--dry-run='));
|
||||
|
||||
// Parse arguments with defaults
|
||||
const defaultEmailCount = 0;
|
||||
const emailCount = emailCountArg
|
||||
? parseInt(emailCountArg.split('=')[1], 10)
|
||||
: defaultEmailCount;
|
||||
|
||||
// LMStudio API settings
|
||||
const lmStudioUrl = lmStudioUrlArg
|
||||
? lmStudioUrlArg.split('=')[1]
|
||||
: 'http://localhost:3000/v1/chat/completions'; // Default LMStudio API endpoint
|
||||
const model = modelArg
|
||||
? modelArg.split('=')[1]
|
||||
: 'local-model'; // Default model name
|
||||
const temperature = temperatureArg
|
||||
? parseFloat(temperatureArg.split('=')[1])
|
||||
: 0.7; // Default temperature
|
||||
|
||||
// Dry run mode - generate content but don't send emails or create records
|
||||
const dryRun = dryRunArg
|
||||
? dryRunArg.split('=')[1].toLowerCase() === 'true'
|
||||
: false;
|
||||
|
||||
if (isNaN(emailCount) || emailCount < 0) {
|
||||
console.error('Error: Email count must be a non-negative number');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Function to generate email content using LMStudio API
|
||||
async function generateEmailContent(
|
||||
customer: Customer,
|
||||
emailCount: number
|
||||
): Promise<{ subject: string; body: string }> {
|
||||
try {
|
||||
console.log(`Generating email content for ${customer.name} using LMStudio API...`);
|
||||
|
||||
// Create a prompt based on customer info and email count
|
||||
let prompt = '';
|
||||
if (emailCount === 0) {
|
||||
prompt = `Generate a welcome email for a new customer named ${customer.name} from ${customer.url}.
|
||||
This is the first contact with them. The email should be professional but friendly.
|
||||
Return ONLY a JSON object with 'subject' and 'body' fields. The body should be in HTML format.`;
|
||||
}/* else if (emailCount === 1) {
|
||||
prompt = `Generate a follow-up email for customer ${customer.name} from ${customer.url}.
|
||||
This is the second contact with them. The email should reference a previous welcome email and provide more value.
|
||||
Return ONLY a JSON object with 'subject' and 'body' fields. The body should be in HTML format.`;
|
||||
} else {
|
||||
prompt = `Generate a relationship-building email for a regular customer named ${customer.name} from ${customer.url}.
|
||||
This is contact number ${emailCount + 1} with them. The email should be personalized and provide specific value.
|
||||
Return ONLY a JSON object with 'subject' and 'body' fields. The body should be in HTML format.`;
|
||||
} */
|
||||
|
||||
// Call LMStudio API
|
||||
const response = await axios.post(
|
||||
lmStudioUrl,
|
||||
{
|
||||
model: model,
|
||||
messages: [
|
||||
{ role: 'system', content: 'You are an expert email copywriter who creates engaging, professional emails.' },
|
||||
{ role: 'user', content: prompt }
|
||||
],
|
||||
temperature: temperature,
|
||||
max_tokens: 1000
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Parse the response to extract the JSON
|
||||
const assistantMessage = response.data.choices[0].message.content;
|
||||
|
||||
// Try to extract JSON from the response
|
||||
try {
|
||||
// Look for JSON object in the response
|
||||
const jsonMatch = assistantMessage.match(/\{[\s\S]*\}/);
|
||||
if (jsonMatch) {
|
||||
const jsonStr = jsonMatch[0];
|
||||
const emailContent = JSON.parse(jsonStr);
|
||||
|
||||
if (emailContent.subject && emailContent.body) {
|
||||
return {
|
||||
subject: emailContent.subject,
|
||||
body: emailContent.body
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// If we couldn't parse JSON or it doesn't have required fields
|
||||
throw new Error('Could not parse valid JSON from LMStudio response');
|
||||
} catch (parseError) {
|
||||
console.warn('Failed to parse JSON from LMStudio response, using fallback content');
|
||||
console.warn('LMStudio response:', assistantMessage);
|
||||
|
||||
// Fallback content
|
||||
return {
|
||||
subject: `Update from Our Company - Contact #${emailCount + 1}`,
|
||||
body: `<h1>Hello ${customer.name}!</h1><p>Thank you for your continued interest in our services. We appreciate your business.</p>`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error
|
||||
? error.message
|
||||
: 'Unknown error occurred';
|
||||
|
||||
console.error('Error calling LMStudio API:', errorMessage);
|
||||
|
||||
// Fallback content in case of API error
|
||||
return {
|
||||
subject: `Important Update - Contact #${emailCount + 1}`,
|
||||
body: `<h1>Hello ${customer.name}!</h1><p>Thank you for your interest in our services. We look forward to working with you!</p>`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
console.log('Initializing database connection...');
|
||||
@ -71,39 +183,42 @@ async function main() {
|
||||
console.log('\nSending emails to customers...');
|
||||
|
||||
// Send emails to each customer
|
||||
let emailSubject = 'Welcome to Our Service';
|
||||
let emailBody = 'Thank you for your interest in our services. We look forward to working with you!';
|
||||
|
||||
// Customize email based on email count
|
||||
if (emailCount === 0) {
|
||||
emailSubject = 'Welcome to Our Service';
|
||||
emailBody = 'Thank you for your interest in our services. We look forward to working with you!';
|
||||
} else if (emailCount === 1) {
|
||||
emailSubject = 'Follow-up on Our Services';
|
||||
emailBody = 'We hope you found our previous information helpful. Here are some additional details about our services.';
|
||||
} else {
|
||||
emailSubject = `Important Update - Contact #${emailCount + 1}`;
|
||||
emailBody = 'We wanted to share some important updates about our services that might interest you.';
|
||||
}
|
||||
|
||||
for (const customer of filteredCustomers) {
|
||||
console.log(`Sending email to ${customer.name} (${customer.email})...`);
|
||||
console.log(`Processing email for ${customer.name} (${customer.email})...`);
|
||||
|
||||
try {
|
||||
const result = await sendEmail(
|
||||
customer.id,
|
||||
emailSubject,
|
||||
emailBody,
|
||||
`<h1>Hello ${customer.name}!</h1><p>${emailBody}</p>`
|
||||
);
|
||||
// Generate email content using LMStudio
|
||||
const emailContent = await generateEmailContent(customer, emailCount);
|
||||
|
||||
if (result.success) {
|
||||
console.log(`✅ Email sent successfully to ${customer.email}`);
|
||||
console.log(`Generated subject: ${emailContent.subject}`);
|
||||
|
||||
if (dryRun) {
|
||||
console.log(`[DRY RUN] Would send email to ${customer.name} (${customer.email})`);
|
||||
console.log(`[DRY RUN] Subject: ${emailContent.subject}`);
|
||||
console.log(`[DRY RUN] Body: ${emailContent.body.replace(/<[^>]*>/g, '')}`);
|
||||
console.log(`[DRY RUN] No email sent and no contact record created.`);
|
||||
} else {
|
||||
console.error(`❌ Failed to send email to ${customer.email}: ${result.error}`);
|
||||
console.log(`Sending email to ${customer.name}...`);
|
||||
|
||||
const result = await sendEmail(
|
||||
customer.id,
|
||||
emailContent.subject,
|
||||
emailContent.body.replace(/<[^>]*>/g, ''), // Plain text version (strip HTML)
|
||||
emailContent.body // HTML version
|
||||
);
|
||||
|
||||
if (result.success) {
|
||||
console.log(`✅ Email sent successfully to ${customer.email}`);
|
||||
} else {
|
||||
console.error(`❌ Failed to send email to ${customer.email}: ${result.error}`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`❌ Error sending email to ${customer.email}:`, error);
|
||||
const errorMessage = error instanceof Error
|
||||
? error.message
|
||||
: 'Unknown error occurred';
|
||||
|
||||
console.error(`❌ Error sending email to ${customer.email}:`, errorMessage);
|
||||
}
|
||||
|
||||
// Add a small delay between emails to avoid rate limiting
|
||||
@ -114,13 +229,21 @@ async function main() {
|
||||
await dataSource.destroy();
|
||||
|
||||
} catch (error) {
|
||||
console.error('An error occurred:', error);
|
||||
const errorMessage = error instanceof Error
|
||||
? error.message
|
||||
: 'Unknown error occurred';
|
||||
|
||||
console.error('An error occurred:', errorMessage);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Run the main function
|
||||
main().catch(error => {
|
||||
console.error('Unhandled error:', error);
|
||||
const errorMessage = error instanceof Error
|
||||
? error.message
|
||||
: 'Unknown error occurred';
|
||||
|
||||
console.error('Unhandled error:', errorMessage);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user