@xuda.io/ai_module 1.1.4711 → 1.1.4713
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.mjs +705 -697
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -5533,7 +5533,15 @@ setTimeout(async () => {
|
|
|
5533
5533
|
// await init_studio_units();
|
|
5534
5534
|
let ret;
|
|
5535
5535
|
// ret = await is_spam_email(uid, 'dsgr8-2994400420@gigs.craigslist.org', 'To: You, From: Us - 70% Off Stickers & Labels Today Only');
|
|
5536
|
-
ret = await is_spam_email(uid, 'noreply@tm.openai.com', 'Please update your Plus payment method', account_profile_info);
|
|
5536
|
+
// ret = await is_spam_email(uid, 'noreply@tm.openai.com', 'Please update your Plus payment method', account_profile_info);
|
|
5537
|
+
ret = await is_business_contact(
|
|
5538
|
+
uid,
|
|
5539
|
+
'noreply@tm.openai.com',
|
|
5540
|
+
'OpenAI',
|
|
5541
|
+
'Please update your Plus payment method',
|
|
5542
|
+
'Summary: Your ChatGPT Plus payment failed, but your access remains active for now. Please update your payment method to continue enjoying Plus benefits, including extended limits on messaging, file uploads, and voice mode; more image and video generation; and extended access to deep research and reasoning models. If you have questions, contact support@openai.com. Best regards, The ChatGPT Team.',
|
|
5543
|
+
account_profile_info,
|
|
5544
|
+
);
|
|
5537
5545
|
// ret = await delete_depended_chats(uid);
|
|
5538
5546
|
// ret = await run_plugin(app_id, uid, '@xuda.io/xuda-library-plugin-studio-ai-app-builder', 'table_builder', { name: 'test2', prompt: 'build items table', save: true });
|
|
5539
5547
|
// ret = await run_plugin(app_id, uid, '@xuda.io/xuda-library-plugin-studio-ai-app-builder', 'folder_builder', { name: 'test', prompt: 'build boaz folder', save: true, parentId: 'programs' });
|
|
@@ -10418,792 +10426,792 @@ PROVIDE DETAILED ANALYSIS WITH CONFIDENCE LEVELS.`,
|
|
|
10418
10426
|
}
|
|
10419
10427
|
};
|
|
10420
10428
|
|
|
10421
|
-
export const detect_email_type = async function (uid, name, email, account_profile_info, email_body = '', email_subject = '') {
|
|
10422
|
-
|
|
10423
|
-
|
|
10424
|
-
|
|
10425
|
-
|
|
10426
|
-
|
|
10427
|
-
|
|
10428
|
-
|
|
10429
|
-
|
|
10430
|
-
|
|
10431
|
-
|
|
10432
|
-
|
|
10433
|
-
|
|
10434
|
-
|
|
10435
|
-
function enhanceEmailDetection(data, name, email, emailBody, emailSubject) {
|
|
10436
|
-
// Run additional local analysis
|
|
10437
|
-
const localAnalysis = analyzeEmailLocally(emailBody, emailSubject, email, name);
|
|
10438
|
-
|
|
10439
|
-
// Combine AI analysis with local analysis
|
|
10440
|
-
const combinedData = {
|
|
10441
|
-
...data,
|
|
10442
|
-
// Override with local analysis if confidence is high
|
|
10443
|
-
spam_confidence: Math.max(data.spam_confidence, localAnalysis.spamScore),
|
|
10444
|
-
phishing_risk: localAnalysis.phishingScore > 70 ? 'high' : data.phishing_risk,
|
|
10445
|
-
|
|
10446
|
-
// Add local analysis results
|
|
10447
|
-
local_analysis: localAnalysis,
|
|
10448
|
-
|
|
10449
|
-
// Enhance sender analysis
|
|
10450
|
-
sender_analysis: analyzeSender(email, name, emailBody),
|
|
10451
|
-
|
|
10452
|
-
// Content statistics
|
|
10453
|
-
content_stats: {
|
|
10454
|
-
word_count: (emailBody.match(/\S+/g) || []).length,
|
|
10455
|
-
sentence_count: (emailBody.match(/[.!?]+/g) || []).length,
|
|
10456
|
-
link_count: (emailBody.match(/https?:\/\/[^\s]+/g) || []).length,
|
|
10457
|
-
uppercase_ratio: calculateUppercaseRatio(emailBody),
|
|
10458
|
-
exclamation_count: (emailBody.match(/!/g) || []).length,
|
|
10459
|
-
dollar_sign_count: (emailBody.match(/\$/g) || []).length,
|
|
10460
|
-
phone_patterns: (emailBody.match(/\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g) || []).length,
|
|
10461
|
-
},
|
|
10462
|
-
|
|
10463
|
-
// Behavioral patterns
|
|
10464
|
-
behavioral_patterns: detectBehavioralPatterns(emailBody, emailSubject),
|
|
10465
|
-
|
|
10466
|
-
// Domain reputation
|
|
10467
|
-
domain_reputation: assessDomainReputation(email),
|
|
10468
|
-
|
|
10469
|
-
// Add comprehensive risk assessment
|
|
10470
|
-
comprehensive_risk_score: calculateComprehensiveRisk(data, localAnalysis),
|
|
10471
|
-
|
|
10472
|
-
// Filter rules that matched
|
|
10473
|
-
matched_filters: detectMatchedFilters(emailBody, emailSubject, email, name),
|
|
10474
|
-
|
|
10475
|
-
// Timeline analysis
|
|
10476
|
-
temporal_analysis: {
|
|
10477
|
-
is_time_sensitive: detectTimeSensitivity(emailBody),
|
|
10478
|
-
has_expiry: detectExpiryDate(emailBody),
|
|
10479
|
-
is_follow_up: detectFollowUpPattern(emailBody, emailSubject),
|
|
10480
|
-
},
|
|
10481
|
-
|
|
10482
|
-
// Relationship context
|
|
10483
|
-
relationship_context: analyzeRelationshipContext(emailBody, emailSubject, name),
|
|
10484
|
-
|
|
10485
|
-
// Update timestamp
|
|
10486
|
-
analysis_timestamp: new Date().toISOString(),
|
|
10487
|
-
content_length: emailBody.length,
|
|
10488
|
-
};
|
|
10489
|
-
|
|
10490
|
-
// Calculate final classification confidence
|
|
10491
|
-
combinedData.final_confidence = calculateFinalConfidence(combinedData);
|
|
10492
|
-
|
|
10493
|
-
// Generate detailed explanation
|
|
10494
|
-
combinedData.explanation = generateExplanation(combinedData);
|
|
10495
|
-
|
|
10496
|
-
// Add compliance flags
|
|
10497
|
-
combinedData.compliance_flags = checkCompliance(emailBody, emailSubject);
|
|
10498
|
-
|
|
10499
|
-
return combinedData;
|
|
10500
|
-
}
|
|
10501
|
-
|
|
10502
|
-
function analyzeEmailLocally(body, subject, email, name) {
|
|
10503
|
-
const text = (subject + ' ' + body).toLowerCase();
|
|
10504
|
-
let spamScore = 0;
|
|
10505
|
-
let phishingScore = 0;
|
|
10506
|
-
let promotionalScore = 0;
|
|
10507
|
-
let transactionalScore = 0;
|
|
10508
|
-
|
|
10509
|
-
// SPAM indicators
|
|
10510
|
-
const spamKeywords = [
|
|
10511
|
-
'congratulations',
|
|
10512
|
-
'winner',
|
|
10513
|
-
'prize',
|
|
10514
|
-
'lottery',
|
|
10515
|
-
'free',
|
|
10516
|
-
'guaranteed',
|
|
10517
|
-
'risk-free',
|
|
10518
|
-
'act now',
|
|
10519
|
-
'limited time',
|
|
10520
|
-
'urgent',
|
|
10521
|
-
'important',
|
|
10522
|
-
'attention',
|
|
10523
|
-
'alert',
|
|
10524
|
-
'click here',
|
|
10525
|
-
'buy now',
|
|
10526
|
-
'order now',
|
|
10527
|
-
'discount',
|
|
10528
|
-
'save big',
|
|
10529
|
-
'cheap',
|
|
10530
|
-
'viagra',
|
|
10531
|
-
'cialis',
|
|
10532
|
-
'pharmacy',
|
|
10533
|
-
'prescription',
|
|
10534
|
-
'enlarge',
|
|
10535
|
-
'weight loss',
|
|
10536
|
-
'nigerian',
|
|
10537
|
-
'prince',
|
|
10538
|
-
'inheritance',
|
|
10539
|
-
'unclaimed',
|
|
10540
|
-
'bank account',
|
|
10541
|
-
'password',
|
|
10542
|
-
'account suspended',
|
|
10543
|
-
'verify',
|
|
10544
|
-
'security alert',
|
|
10545
|
-
'dear friend',
|
|
10546
|
-
'dear customer',
|
|
10547
|
-
'dear account holder',
|
|
10548
|
-
];
|
|
10549
|
-
|
|
10550
|
-
spamKeywords.forEach((keyword) => {
|
|
10551
|
-
if (text.includes(keyword)) spamScore += 2;
|
|
10552
|
-
});
|
|
10553
|
-
|
|
10554
|
-
// Phishing indicators
|
|
10555
|
-
const phishingPatterns = [/login\s*(?:here|now)/i, /verify\s*(?:your|my)\s*account/i, /password\s*(?:reset|expired|change)/i, /suspended\s*account/i, /unauthorized\s*activity/i, /security\s*breach/i, /update\s*(?:your|my)\s*information/i, /confirm\s*(?:your|my)\s*identity/i];
|
|
10556
|
-
|
|
10557
|
-
phishingPatterns.forEach((pattern) => {
|
|
10558
|
-
if (pattern.test(text)) phishingScore += 15;
|
|
10559
|
-
});
|
|
10560
|
-
|
|
10561
|
-
// Promotional indicators
|
|
10562
|
-
const promotionalKeywords = ['newsletter', 'subscribe', 'unsubscribe', 'marketing', 'promotion', 'sale', 'offer', 'deal', 'coupon', 'voucher', 'discount code', 'new product', 'announcement', 'launch', 'event', 'webinar', 'limited offer', 'exclusive', 'special offer', 'members only'];
|
|
10563
|
-
|
|
10564
|
-
promotionalKeywords.forEach((keyword) => {
|
|
10565
|
-
if (text.includes(keyword)) promotionalScore += 3;
|
|
10566
|
-
});
|
|
10567
|
-
|
|
10568
|
-
// Transactional indicators
|
|
10569
|
-
const transactionalKeywords = ['order', 'invoice', 'receipt', 'payment', 'booking', 'reservation', 'confirmation', 'shipping', 'delivery', 'tracking', 'shipment', 'appointment', 'meeting', 'reminder', 'bill', 'statement', 'account', 'statement', 'balance', 'transaction'];
|
|
10570
|
-
|
|
10571
|
-
transactionalKeywords.forEach((keyword) => {
|
|
10572
|
-
if (text.includes(keyword)) transactionalScore += 3;
|
|
10573
|
-
});
|
|
10574
|
-
|
|
10575
|
-
// Link analysis
|
|
10576
|
-
const links = body.match(/https?:\/\/[^\s]+/g) || [];
|
|
10577
|
-
const suspiciousDomains = ['bit.ly', 'tinyurl', 'shorte.st', 'adf.ly', 'goo.gl'];
|
|
10578
|
-
|
|
10579
|
-
links.forEach((link) => {
|
|
10580
|
-
if (suspiciousDomains.some((domain) => link.includes(domain))) {
|
|
10581
|
-
spamScore += 10;
|
|
10582
|
-
phishingScore += 10;
|
|
10583
|
-
}
|
|
10584
|
-
});
|
|
10585
|
-
|
|
10586
|
-
// Grammar/spelling analysis (simple)
|
|
10587
|
-
const misspellings = body.match(/\b(?:recieve|seperate|definately|occured|tomm?orrow)\b/gi) || [];
|
|
10588
|
-
spamScore += misspellings.length * 2;
|
|
10589
|
-
|
|
10590
|
-
// Urgency analysis
|
|
10591
|
-
const urgencyWords = ['urgent', 'immediately', 'asap', 'right now', 'today only'];
|
|
10592
|
-
let urgencyCount = 0;
|
|
10593
|
-
urgencyWords.forEach((word) => {
|
|
10594
|
-
if (text.includes(word)) urgencyCount++;
|
|
10595
|
-
});
|
|
10596
|
-
spamScore += urgencyCount * 5;
|
|
10597
|
-
|
|
10598
|
-
// Personalization check
|
|
10599
|
-
const hasName = name && body.toLowerCase().includes(name.toLowerCase().split(' ')[0]);
|
|
10600
|
-
const personalPronouns = ['you', 'your', 'yours'];
|
|
10601
|
-
let personalCount = 0;
|
|
10602
|
-
personalPronouns.forEach((pronoun) => {
|
|
10603
|
-
const regex = new RegExp(`\\b${pronoun}\\b`, 'gi');
|
|
10604
|
-
personalCount += (body.match(regex) || []).length;
|
|
10605
|
-
});
|
|
10606
|
-
|
|
10607
|
-
const personalizationScore = hasName ? 30 : Math.min(personalCount * 2, 20);
|
|
10608
|
-
|
|
10609
|
-
return {
|
|
10610
|
-
spamScore: Math.min(spamScore, 100),
|
|
10611
|
-
phishingScore: Math.min(phishingScore, 100),
|
|
10612
|
-
promotionalScore: Math.min(promotionalScore, 100),
|
|
10613
|
-
transactionalScore: Math.min(transactionalScore, 100),
|
|
10614
|
-
personalizationScore,
|
|
10615
|
-
linkCount: links.length,
|
|
10616
|
-
hasUnsubscribe: text.includes('unsubscribe') || text.includes('opt-out'),
|
|
10617
|
-
hasPhone: /\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/.test(body),
|
|
10618
|
-
hasAddress: /\b\d+\s+[\w\s]+(?:street|st|avenue|ave|road|rd|boulevard|blvd|way)\b/i.test(body),
|
|
10619
|
-
urgencyCount,
|
|
10620
|
-
misspellingCount: misspellings.length,
|
|
10621
|
-
};
|
|
10622
|
-
}
|
|
10623
|
-
|
|
10624
|
-
function analyzeSender(email, name, body) {
|
|
10625
|
-
const domain = email.split('@')[1] || '';
|
|
10626
|
-
const localPart = email.split('@')[0] || '';
|
|
10627
|
-
|
|
10628
|
-
return {
|
|
10629
|
-
email: email,
|
|
10630
|
-
domain: domain,
|
|
10631
|
-
local_part: localPart,
|
|
10632
|
-
is_public_domain: isPublicEmailDomain(domain),
|
|
10633
|
-
is_generic_sender: isGenericSender(localPart, name),
|
|
10634
|
-
domain_age_indicator: assessDomainAge(domain),
|
|
10635
|
-
sender_consistency: checkSenderConsistency(name, email, body),
|
|
10636
|
-
};
|
|
10637
|
-
}
|
|
10638
|
-
|
|
10639
|
-
function isPublicEmailDomain(domain) {
|
|
10640
|
-
const publicDomains = ['gmail.com', 'yahoo.com', 'outlook.com', 'hotmail.com', 'aol.com', 'icloud.com', 'protonmail.com', 'zoho.com', 'yandex.com'];
|
|
10641
|
-
return publicDomains.includes(domain.toLowerCase());
|
|
10642
|
-
}
|
|
10643
|
-
|
|
10644
|
-
function isGenericSender(localPart, name) {
|
|
10645
|
-
const genericSenders = ['info', 'support', 'sales', 'contact', 'hello', 'noreply', 'admin', 'newsletter', 'marketing', 'team', 'notifications'];
|
|
10646
|
-
|
|
10647
|
-
const localLower = localPart.toLowerCase();
|
|
10648
|
-
const nameLower = name.toLowerCase();
|
|
10649
|
-
|
|
10650
|
-
return genericSenders.some((sender) => localLower.includes(sender) || nameLower.includes(sender));
|
|
10651
|
-
}
|
|
10652
|
-
|
|
10653
|
-
function assessDomainAge(domain) {
|
|
10654
|
-
// This is a simplified version - in production, you'd use a domain age API
|
|
10655
|
-
const newDomains = ['xyz', 'online', 'site', 'top', 'club', 'shop'];
|
|
10656
|
-
const tld = domain.split('.').pop() || '';
|
|
10657
|
-
|
|
10658
|
-
if (newDomains.includes(tld)) return 'likely_new';
|
|
10659
|
-
if (['com', 'org', 'net', 'edu', 'gov'].includes(tld)) return 'likely_established';
|
|
10660
|
-
return 'unknown';
|
|
10661
|
-
}
|
|
10429
|
+
// export const detect_email_type = async function (uid, name, email, account_profile_info, email_body = '', email_subject = '') {
|
|
10430
|
+
// // ========== HELPER FUNCTIONS ==========
|
|
10431
|
+
|
|
10432
|
+
// async function hashString(str) {
|
|
10433
|
+
// const encoder = new TextEncoder();
|
|
10434
|
+
// const data = encoder.encode(str);
|
|
10435
|
+
// const hashBuffer = await crypto.subtle.digest('SHA-256', data);
|
|
10436
|
+
// const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
10437
|
+
// return hashArray
|
|
10438
|
+
// .map((b) => b.toString(16).padStart(2, '0'))
|
|
10439
|
+
// .join('')
|
|
10440
|
+
// .substring(0, 16);
|
|
10441
|
+
// }
|
|
10662
10442
|
|
|
10663
|
-
|
|
10664
|
-
|
|
10665
|
-
|
|
10443
|
+
// function enhanceEmailDetection(data, name, email, emailBody, emailSubject) {
|
|
10444
|
+
// // Run additional local analysis
|
|
10445
|
+
// const localAnalysis = analyzeEmailLocally(emailBody, emailSubject, email, name);
|
|
10446
|
+
|
|
10447
|
+
// // Combine AI analysis with local analysis
|
|
10448
|
+
// const combinedData = {
|
|
10449
|
+
// ...data,
|
|
10450
|
+
// // Override with local analysis if confidence is high
|
|
10451
|
+
// spam_confidence: Math.max(data.spam_confidence, localAnalysis.spamScore),
|
|
10452
|
+
// phishing_risk: localAnalysis.phishingScore > 70 ? 'high' : data.phishing_risk,
|
|
10453
|
+
|
|
10454
|
+
// // Add local analysis results
|
|
10455
|
+
// local_analysis: localAnalysis,
|
|
10456
|
+
|
|
10457
|
+
// // Enhance sender analysis
|
|
10458
|
+
// sender_analysis: analyzeSender(email, name, emailBody),
|
|
10459
|
+
|
|
10460
|
+
// // Content statistics
|
|
10461
|
+
// content_stats: {
|
|
10462
|
+
// word_count: (emailBody.match(/\S+/g) || []).length,
|
|
10463
|
+
// sentence_count: (emailBody.match(/[.!?]+/g) || []).length,
|
|
10464
|
+
// link_count: (emailBody.match(/https?:\/\/[^\s]+/g) || []).length,
|
|
10465
|
+
// uppercase_ratio: calculateUppercaseRatio(emailBody),
|
|
10466
|
+
// exclamation_count: (emailBody.match(/!/g) || []).length,
|
|
10467
|
+
// dollar_sign_count: (emailBody.match(/\$/g) || []).length,
|
|
10468
|
+
// phone_patterns: (emailBody.match(/\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g) || []).length,
|
|
10469
|
+
// },
|
|
10666
10470
|
|
|
10667
|
-
|
|
10668
|
-
|
|
10471
|
+
// // Behavioral patterns
|
|
10472
|
+
// behavioral_patterns: detectBehavioralPatterns(emailBody, emailSubject),
|
|
10669
10473
|
|
|
10670
|
-
|
|
10671
|
-
|
|
10672
|
-
const firstName = nameParts[0] || '';
|
|
10673
|
-
const lastName = nameParts.slice(-1)[0] || '';
|
|
10474
|
+
// // Domain reputation
|
|
10475
|
+
// domain_reputation: assessDomainReputation(email),
|
|
10674
10476
|
|
|
10675
|
-
|
|
10477
|
+
// // Add comprehensive risk assessment
|
|
10478
|
+
// comprehensive_risk_score: calculateComprehensiveRisk(data, localAnalysis),
|
|
10676
10479
|
|
|
10677
|
-
|
|
10480
|
+
// // Filter rules that matched
|
|
10481
|
+
// matched_filters: detectMatchedFilters(emailBody, emailSubject, email, name),
|
|
10678
10482
|
|
|
10679
|
-
|
|
10680
|
-
|
|
10681
|
-
|
|
10682
|
-
|
|
10683
|
-
|
|
10684
|
-
|
|
10483
|
+
// // Timeline analysis
|
|
10484
|
+
// temporal_analysis: {
|
|
10485
|
+
// is_time_sensitive: detectTimeSensitivity(emailBody),
|
|
10486
|
+
// has_expiry: detectExpiryDate(emailBody),
|
|
10487
|
+
// is_follow_up: detectFollowUpPattern(emailBody, emailSubject),
|
|
10488
|
+
// },
|
|
10685
10489
|
|
|
10686
|
-
|
|
10687
|
-
|
|
10688
|
-
if (letters.length === 0) return 0;
|
|
10490
|
+
// // Relationship context
|
|
10491
|
+
// relationship_context: analyzeRelationshipContext(emailBody, emailSubject, name),
|
|
10689
10492
|
|
|
10690
|
-
|
|
10691
|
-
|
|
10692
|
-
|
|
10493
|
+
// // Update timestamp
|
|
10494
|
+
// analysis_timestamp: new Date().toISOString(),
|
|
10495
|
+
// content_length: emailBody.length,
|
|
10496
|
+
// };
|
|
10693
10497
|
|
|
10694
|
-
|
|
10695
|
-
|
|
10696
|
-
const patterns = [];
|
|
10498
|
+
// // Calculate final classification confidence
|
|
10499
|
+
// combinedData.final_confidence = calculateFinalConfidence(combinedData);
|
|
10697
10500
|
|
|
10698
|
-
|
|
10699
|
-
|
|
10700
|
-
}
|
|
10501
|
+
// // Generate detailed explanation
|
|
10502
|
+
// combinedData.explanation = generateExplanation(combinedData);
|
|
10701
10503
|
|
|
10702
|
-
|
|
10703
|
-
|
|
10704
|
-
}
|
|
10504
|
+
// // Add compliance flags
|
|
10505
|
+
// combinedData.compliance_flags = checkCompliance(emailBody, emailSubject);
|
|
10705
10506
|
|
|
10706
|
-
|
|
10707
|
-
|
|
10708
|
-
}
|
|
10709
|
-
|
|
10710
|
-
if (/urgent|important|alert|attention|warning/i.test(text)) {
|
|
10711
|
-
patterns.push('urgency_tactic');
|
|
10712
|
-
}
|
|
10507
|
+
// return combinedData;
|
|
10508
|
+
// }
|
|
10713
10509
|
|
|
10714
|
-
|
|
10715
|
-
|
|
10716
|
-
|
|
10510
|
+
// function analyzeEmailLocally(body, subject, email, name) {
|
|
10511
|
+
// const text = (subject + ' ' + body).toLowerCase();
|
|
10512
|
+
// let spamScore = 0;
|
|
10513
|
+
// let phishingScore = 0;
|
|
10514
|
+
// let promotionalScore = 0;
|
|
10515
|
+
// let transactionalScore = 0;
|
|
10516
|
+
|
|
10517
|
+
// // SPAM indicators
|
|
10518
|
+
// const spamKeywords = [
|
|
10519
|
+
// 'congratulations',
|
|
10520
|
+
// 'winner',
|
|
10521
|
+
// 'prize',
|
|
10522
|
+
// 'lottery',
|
|
10523
|
+
// 'free',
|
|
10524
|
+
// 'guaranteed',
|
|
10525
|
+
// 'risk-free',
|
|
10526
|
+
// 'act now',
|
|
10527
|
+
// 'limited time',
|
|
10528
|
+
// 'urgent',
|
|
10529
|
+
// 'important',
|
|
10530
|
+
// 'attention',
|
|
10531
|
+
// 'alert',
|
|
10532
|
+
// 'click here',
|
|
10533
|
+
// 'buy now',
|
|
10534
|
+
// 'order now',
|
|
10535
|
+
// 'discount',
|
|
10536
|
+
// 'save big',
|
|
10537
|
+
// 'cheap',
|
|
10538
|
+
// 'viagra',
|
|
10539
|
+
// 'cialis',
|
|
10540
|
+
// 'pharmacy',
|
|
10541
|
+
// 'prescription',
|
|
10542
|
+
// 'enlarge',
|
|
10543
|
+
// 'weight loss',
|
|
10544
|
+
// 'nigerian',
|
|
10545
|
+
// 'prince',
|
|
10546
|
+
// 'inheritance',
|
|
10547
|
+
// 'unclaimed',
|
|
10548
|
+
// 'bank account',
|
|
10549
|
+
// 'password',
|
|
10550
|
+
// 'account suspended',
|
|
10551
|
+
// 'verify',
|
|
10552
|
+
// 'security alert',
|
|
10553
|
+
// 'dear friend',
|
|
10554
|
+
// 'dear customer',
|
|
10555
|
+
// 'dear account holder',
|
|
10556
|
+
// ];
|
|
10557
|
+
|
|
10558
|
+
// spamKeywords.forEach((keyword) => {
|
|
10559
|
+
// if (text.includes(keyword)) spamScore += 2;
|
|
10560
|
+
// });
|
|
10561
|
+
|
|
10562
|
+
// // Phishing indicators
|
|
10563
|
+
// const phishingPatterns = [/login\s*(?:here|now)/i, /verify\s*(?:your|my)\s*account/i, /password\s*(?:reset|expired|change)/i, /suspended\s*account/i, /unauthorized\s*activity/i, /security\s*breach/i, /update\s*(?:your|my)\s*information/i, /confirm\s*(?:your|my)\s*identity/i];
|
|
10564
|
+
|
|
10565
|
+
// phishingPatterns.forEach((pattern) => {
|
|
10566
|
+
// if (pattern.test(text)) phishingScore += 15;
|
|
10567
|
+
// });
|
|
10568
|
+
|
|
10569
|
+
// // Promotional indicators
|
|
10570
|
+
// const promotionalKeywords = ['newsletter', 'subscribe', 'unsubscribe', 'marketing', 'promotion', 'sale', 'offer', 'deal', 'coupon', 'voucher', 'discount code', 'new product', 'announcement', 'launch', 'event', 'webinar', 'limited offer', 'exclusive', 'special offer', 'members only'];
|
|
10571
|
+
|
|
10572
|
+
// promotionalKeywords.forEach((keyword) => {
|
|
10573
|
+
// if (text.includes(keyword)) promotionalScore += 3;
|
|
10574
|
+
// });
|
|
10575
|
+
|
|
10576
|
+
// // Transactional indicators
|
|
10577
|
+
// const transactionalKeywords = ['order', 'invoice', 'receipt', 'payment', 'booking', 'reservation', 'confirmation', 'shipping', 'delivery', 'tracking', 'shipment', 'appointment', 'meeting', 'reminder', 'bill', 'statement', 'account', 'statement', 'balance', 'transaction'];
|
|
10578
|
+
|
|
10579
|
+
// transactionalKeywords.forEach((keyword) => {
|
|
10580
|
+
// if (text.includes(keyword)) transactionalScore += 3;
|
|
10581
|
+
// });
|
|
10582
|
+
|
|
10583
|
+
// // Link analysis
|
|
10584
|
+
// const links = body.match(/https?:\/\/[^\s]+/g) || [];
|
|
10585
|
+
// const suspiciousDomains = ['bit.ly', 'tinyurl', 'shorte.st', 'adf.ly', 'goo.gl'];
|
|
10586
|
+
|
|
10587
|
+
// links.forEach((link) => {
|
|
10588
|
+
// if (suspiciousDomains.some((domain) => link.includes(domain))) {
|
|
10589
|
+
// spamScore += 10;
|
|
10590
|
+
// phishingScore += 10;
|
|
10591
|
+
// }
|
|
10592
|
+
// });
|
|
10593
|
+
|
|
10594
|
+
// // Grammar/spelling analysis (simple)
|
|
10595
|
+
// const misspellings = body.match(/\b(?:recieve|seperate|definately|occured|tomm?orrow)\b/gi) || [];
|
|
10596
|
+
// spamScore += misspellings.length * 2;
|
|
10597
|
+
|
|
10598
|
+
// // Urgency analysis
|
|
10599
|
+
// const urgencyWords = ['urgent', 'immediately', 'asap', 'right now', 'today only'];
|
|
10600
|
+
// let urgencyCount = 0;
|
|
10601
|
+
// urgencyWords.forEach((word) => {
|
|
10602
|
+
// if (text.includes(word)) urgencyCount++;
|
|
10603
|
+
// });
|
|
10604
|
+
// spamScore += urgencyCount * 5;
|
|
10605
|
+
|
|
10606
|
+
// // Personalization check
|
|
10607
|
+
// const hasName = name && body.toLowerCase().includes(name.toLowerCase().split(' ')[0]);
|
|
10608
|
+
// const personalPronouns = ['you', 'your', 'yours'];
|
|
10609
|
+
// let personalCount = 0;
|
|
10610
|
+
// personalPronouns.forEach((pronoun) => {
|
|
10611
|
+
// const regex = new RegExp(`\\b${pronoun}\\b`, 'gi');
|
|
10612
|
+
// personalCount += (body.match(regex) || []).length;
|
|
10613
|
+
// });
|
|
10614
|
+
|
|
10615
|
+
// const personalizationScore = hasName ? 30 : Math.min(personalCount * 2, 20);
|
|
10717
10616
|
|
|
10718
|
-
|
|
10719
|
-
|
|
10720
|
-
|
|
10617
|
+
// return {
|
|
10618
|
+
// spamScore: Math.min(spamScore, 100),
|
|
10619
|
+
// phishingScore: Math.min(phishingScore, 100),
|
|
10620
|
+
// promotionalScore: Math.min(promotionalScore, 100),
|
|
10621
|
+
// transactionalScore: Math.min(transactionalScore, 100),
|
|
10622
|
+
// personalizationScore,
|
|
10623
|
+
// linkCount: links.length,
|
|
10624
|
+
// hasUnsubscribe: text.includes('unsubscribe') || text.includes('opt-out'),
|
|
10625
|
+
// hasPhone: /\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/.test(body),
|
|
10626
|
+
// hasAddress: /\b\d+\s+[\w\s]+(?:street|st|avenue|ave|road|rd|boulevard|blvd|way)\b/i.test(body),
|
|
10627
|
+
// urgencyCount,
|
|
10628
|
+
// misspellingCount: misspellings.length,
|
|
10629
|
+
// };
|
|
10630
|
+
// }
|
|
10721
10631
|
|
|
10722
|
-
|
|
10723
|
-
|
|
10632
|
+
// function analyzeSender(email, name, body) {
|
|
10633
|
+
// const domain = email.split('@')[1] || '';
|
|
10634
|
+
// const localPart = email.split('@')[0] || '';
|
|
10724
10635
|
|
|
10725
|
-
|
|
10726
|
-
|
|
10636
|
+
// return {
|
|
10637
|
+
// email: email,
|
|
10638
|
+
// domain: domain,
|
|
10639
|
+
// local_part: localPart,
|
|
10640
|
+
// is_public_domain: isPublicEmailDomain(domain),
|
|
10641
|
+
// is_generic_sender: isGenericSender(localPart, name),
|
|
10642
|
+
// domain_age_indicator: assessDomainAge(domain),
|
|
10643
|
+
// sender_consistency: checkSenderConsistency(name, email, body),
|
|
10644
|
+
// };
|
|
10645
|
+
// }
|
|
10727
10646
|
|
|
10728
|
-
|
|
10729
|
-
|
|
10647
|
+
// function isPublicEmailDomain(domain) {
|
|
10648
|
+
// const publicDomains = ['gmail.com', 'yahoo.com', 'outlook.com', 'hotmail.com', 'aol.com', 'icloud.com', 'protonmail.com', 'zoho.com', 'yandex.com'];
|
|
10649
|
+
// return publicDomains.includes(domain.toLowerCase());
|
|
10650
|
+
// }
|
|
10730
10651
|
|
|
10731
|
-
|
|
10732
|
-
|
|
10733
|
-
}
|
|
10652
|
+
// function isGenericSender(localPart, name) {
|
|
10653
|
+
// const genericSenders = ['info', 'support', 'sales', 'contact', 'hello', 'noreply', 'admin', 'newsletter', 'marketing', 'team', 'notifications'];
|
|
10734
10654
|
|
|
10735
|
-
|
|
10736
|
-
|
|
10737
|
-
const tld = domain.split('.').pop() || '';
|
|
10655
|
+
// const localLower = localPart.toLowerCase();
|
|
10656
|
+
// const nameLower = name.toLowerCase();
|
|
10738
10657
|
|
|
10739
|
-
|
|
10740
|
-
|
|
10741
|
-
}
|
|
10658
|
+
// return genericSenders.some((sender) => localLower.includes(sender) || nameLower.includes(sender));
|
|
10659
|
+
// }
|
|
10742
10660
|
|
|
10743
|
-
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
|
|
10747
|
-
}
|
|
10661
|
+
// function assessDomainAge(domain) {
|
|
10662
|
+
// // This is a simplified version - in production, you'd use a domain age API
|
|
10663
|
+
// const newDomains = ['xyz', 'online', 'site', 'top', 'club', 'shop'];
|
|
10664
|
+
// const tld = domain.split('.').pop() || '';
|
|
10748
10665
|
|
|
10749
|
-
|
|
10750
|
-
|
|
10666
|
+
// if (newDomains.includes(tld)) return 'likely_new';
|
|
10667
|
+
// if (['com', 'org', 'net', 'edu', 'gov'].includes(tld)) return 'likely_established';
|
|
10668
|
+
// return 'unknown';
|
|
10669
|
+
// }
|
|
10751
10670
|
|
|
10752
|
-
|
|
10753
|
-
|
|
10671
|
+
// function checkSenderConsistency(name, email, body) {
|
|
10672
|
+
// const emailName = email.split('@')[0].toLowerCase();
|
|
10673
|
+
// const bodyName = name.toLowerCase();
|
|
10754
10674
|
|
|
10755
|
-
|
|
10756
|
-
|
|
10757
|
-
case 'spam':
|
|
10758
|
-
risk += 80;
|
|
10759
|
-
break;
|
|
10760
|
-
case 'promotional':
|
|
10761
|
-
risk += 30;
|
|
10762
|
-
break;
|
|
10763
|
-
case 'transactional':
|
|
10764
|
-
risk += 10;
|
|
10765
|
-
break;
|
|
10766
|
-
case 'personal':
|
|
10767
|
-
risk += 5;
|
|
10768
|
-
break;
|
|
10769
|
-
case 'business':
|
|
10770
|
-
risk += 15;
|
|
10771
|
-
break;
|
|
10772
|
-
}
|
|
10675
|
+
// // Check if name appears in body
|
|
10676
|
+
// const nameInBody = body.toLowerCase().includes(bodyName.split(' ')[0]);
|
|
10773
10677
|
|
|
10774
|
-
|
|
10775
|
-
|
|
10776
|
-
|
|
10678
|
+
// // Check email-name consistency patterns
|
|
10679
|
+
// const nameParts = bodyName.split(' ');
|
|
10680
|
+
// const firstName = nameParts[0] || '';
|
|
10681
|
+
// const lastName = nameParts.slice(-1)[0] || '';
|
|
10777
10682
|
|
|
10778
|
-
|
|
10779
|
-
switch (aiData.phishing_risk) {
|
|
10780
|
-
case 'critical':
|
|
10781
|
-
risk += 40;
|
|
10782
|
-
break;
|
|
10783
|
-
case 'high':
|
|
10784
|
-
risk += 30;
|
|
10785
|
-
break;
|
|
10786
|
-
case 'medium':
|
|
10787
|
-
risk += 15;
|
|
10788
|
-
break;
|
|
10789
|
-
case 'low':
|
|
10790
|
-
risk += 5;
|
|
10791
|
-
break;
|
|
10792
|
-
}
|
|
10683
|
+
// const patterns = [`${firstName}.${lastName}`, `${firstName}${lastName}`, `${firstName.charAt(0)}${lastName}`, `${firstName}`];
|
|
10793
10684
|
|
|
10794
|
-
|
|
10795
|
-
if (aiData.is_unsolicited) risk += 20;
|
|
10685
|
+
// const consistent = patterns.some((pattern) => emailName.includes(pattern.toLowerCase()));
|
|
10796
10686
|
|
|
10797
|
-
|
|
10798
|
-
|
|
10687
|
+
// return {
|
|
10688
|
+
// name_in_body: nameInBody,
|
|
10689
|
+
// email_name_consistent: consistent,
|
|
10690
|
+
// consistency_score: (nameInBody ? 40 : 0) + (consistent ? 60 : 0),
|
|
10691
|
+
// };
|
|
10692
|
+
// }
|
|
10799
10693
|
|
|
10800
|
-
|
|
10801
|
-
|
|
10694
|
+
// function calculateUppercaseRatio(text) {
|
|
10695
|
+
// const letters = text.replace(/[^a-zA-Z]/g, '');
|
|
10696
|
+
// if (letters.length === 0) return 0;
|
|
10802
10697
|
|
|
10803
|
-
|
|
10804
|
-
|
|
10805
|
-
|
|
10698
|
+
// const uppercase = letters.replace(/[^A-Z]/g, '');
|
|
10699
|
+
// return (uppercase.length / letters.length) * 100;
|
|
10700
|
+
// }
|
|
10806
10701
|
|
|
10807
|
-
|
|
10808
|
-
|
|
10809
|
-
|
|
10810
|
-
if (/(?:nigerian|prince|inheritance|unclaimed)/i.test(text)) filters.push('inheritance_scam_filter');
|
|
10811
|
-
if (/password\s+reset|verify\s+account/i.test(text)) filters.push('account_verification_filter');
|
|
10702
|
+
// function detectBehavioralPatterns(body, subject) {
|
|
10703
|
+
// const text = (subject + ' ' + body).toLowerCase();
|
|
10704
|
+
// const patterns = [];
|
|
10812
10705
|
|
|
10813
|
-
|
|
10814
|
-
|
|
10815
|
-
|
|
10816
|
-
if (/webinar|event|conference/i.test(text)) filters.push('event_filter');
|
|
10706
|
+
// if (/(?:click|tap)\s+(?:here|this|link|button)/i.test(text)) {
|
|
10707
|
+
// patterns.push('call_to_action_link');
|
|
10708
|
+
// }
|
|
10817
10709
|
|
|
10818
|
-
|
|
10819
|
-
|
|
10820
|
-
|
|
10821
|
-
if (/appointment|meeting|reminder/i.test(text)) filters.push('calendar_filter');
|
|
10710
|
+
// if (/limited\s+time|offer\s+expires|only\s+\d+\s+left/i.test(text)) {
|
|
10711
|
+
// patterns.push('scarcity_tactic');
|
|
10712
|
+
// }
|
|
10822
10713
|
|
|
10823
|
-
|
|
10824
|
-
|
|
10714
|
+
// if (/\$\d+|\d+\s*%|\d+\s*off|discount|save|sale/i.test(text)) {
|
|
10715
|
+
// patterns.push('monetary_offer');
|
|
10716
|
+
// }
|
|
10825
10717
|
|
|
10826
|
-
|
|
10827
|
-
|
|
10828
|
-
|
|
10718
|
+
// if (/urgent|important|alert|attention|warning/i.test(text)) {
|
|
10719
|
+
// patterns.push('urgency_tactic');
|
|
10720
|
+
// }
|
|
10829
10721
|
|
|
10830
|
-
|
|
10831
|
-
|
|
10722
|
+
// if (/(?:please|kindly)\s+(?:help|assist|reply)/i.test(text)) {
|
|
10723
|
+
// patterns.push('polite_request');
|
|
10724
|
+
// }
|
|
10832
10725
|
|
|
10833
|
-
|
|
10834
|
-
|
|
10726
|
+
// if (/unsubscribe|opt.?out|preference|manage subscription/i.test(text)) {
|
|
10727
|
+
// patterns.push('subscription_management');
|
|
10728
|
+
// }
|
|
10835
10729
|
|
|
10836
|
-
|
|
10837
|
-
|
|
10730
|
+
// return patterns;
|
|
10731
|
+
// }
|
|
10838
10732
|
|
|
10839
|
-
|
|
10840
|
-
|
|
10841
|
-
return /follow.?up|following.?up|checking.?in|touch.?base|re:.?re:/i.test(text);
|
|
10842
|
-
}
|
|
10733
|
+
// function assessDomainReputation(email) {
|
|
10734
|
+
// const domain = email.split('@')[1] || '';
|
|
10843
10735
|
|
|
10844
|
-
|
|
10845
|
-
|
|
10846
|
-
const nameParts = name.toLowerCase().split(' ');
|
|
10847
|
-
const firstName = nameParts[0] || '';
|
|
10736
|
+
// // Known spam domains (simplified list)
|
|
10737
|
+
// const spamDomains = ['spam4.me', 'trashmail.com', 'mailinator.com', 'guerrillamail.com', 'tempmail.com', 'yopmail.com', 'dispostable.com'];
|
|
10848
10738
|
|
|
10849
|
-
|
|
10850
|
-
|
|
10851
|
-
|
|
10852
|
-
has_greeting: /^(?:hi|hello|hey|dear|greetings)\b/im.test(body),
|
|
10853
|
-
has_signature: /(?:best|regards|sincerely|thanks|thank you)\s*[,]?\s*\n/im.test(body),
|
|
10854
|
-
has_questions: /\?/.test(text) && /(?:can|could|would|will|do|are|is)\s+you/i.test(text),
|
|
10855
|
-
};
|
|
10739
|
+
// if (spamDomains.includes(domain.toLowerCase())) {
|
|
10740
|
+
// return 'known_spam_domain';
|
|
10741
|
+
// }
|
|
10856
10742
|
|
|
10857
|
-
|
|
10743
|
+
// // Professional domains
|
|
10744
|
+
// const professionalTLDs = ['com', 'org', 'net', 'edu', 'gov', 'io', 'ai', 'tech'];
|
|
10745
|
+
// const tld = domain.split('.').pop() || '';
|
|
10858
10746
|
|
|
10859
|
-
|
|
10860
|
-
|
|
10861
|
-
|
|
10862
|
-
likely_known_sender: relationshipScore >= 40,
|
|
10863
|
-
};
|
|
10864
|
-
}
|
|
10747
|
+
// if (professionalTLDs.includes(tld.toLowerCase())) {
|
|
10748
|
+
// return 'professional_domain';
|
|
10749
|
+
// }
|
|
10865
10750
|
|
|
10866
|
-
|
|
10867
|
-
|
|
10751
|
+
// // New/suspicious TLDs
|
|
10752
|
+
// const suspiciousTLDs = ['xyz', 'top', 'win', 'bid', 'download', 'stream'];
|
|
10753
|
+
// if (suspiciousTLDs.includes(tld.toLowerCase())) {
|
|
10754
|
+
// return 'suspicious_tld';
|
|
10755
|
+
// }
|
|
10868
10756
|
|
|
10869
|
-
|
|
10870
|
-
|
|
10871
|
-
confidence -= 20;
|
|
10872
|
-
}
|
|
10757
|
+
// return 'neutral';
|
|
10758
|
+
// }
|
|
10873
10759
|
|
|
10874
|
-
|
|
10875
|
-
|
|
10876
|
-
confidence += 15;
|
|
10877
|
-
}
|
|
10760
|
+
// function calculateComprehensiveRisk(aiData, localAnalysis) {
|
|
10761
|
+
// let risk = 0;
|
|
10878
10762
|
|
|
10879
|
-
|
|
10880
|
-
|
|
10881
|
-
|
|
10882
|
-
|
|
10763
|
+
// // Base on AI classification
|
|
10764
|
+
// switch (aiData.email_type) {
|
|
10765
|
+
// case 'spam':
|
|
10766
|
+
// risk += 80;
|
|
10767
|
+
// break;
|
|
10768
|
+
// case 'promotional':
|
|
10769
|
+
// risk += 30;
|
|
10770
|
+
// break;
|
|
10771
|
+
// case 'transactional':
|
|
10772
|
+
// risk += 10;
|
|
10773
|
+
// break;
|
|
10774
|
+
// case 'personal':
|
|
10775
|
+
// risk += 5;
|
|
10776
|
+
// break;
|
|
10777
|
+
// case 'business':
|
|
10778
|
+
// risk += 15;
|
|
10779
|
+
// break;
|
|
10780
|
+
// }
|
|
10883
10781
|
|
|
10884
|
-
|
|
10885
|
-
|
|
10886
|
-
|
|
10887
|
-
}
|
|
10782
|
+
// // Add local analysis scores
|
|
10783
|
+
// risk += localAnalysis.spamScore * 0.2;
|
|
10784
|
+
// risk += localAnalysis.phishingScore * 0.3;
|
|
10888
10785
|
|
|
10889
|
-
|
|
10890
|
-
|
|
10786
|
+
// // Adjust for phishing risk
|
|
10787
|
+
// switch (aiData.phishing_risk) {
|
|
10788
|
+
// case 'critical':
|
|
10789
|
+
// risk += 40;
|
|
10790
|
+
// break;
|
|
10791
|
+
// case 'high':
|
|
10792
|
+
// risk += 30;
|
|
10793
|
+
// break;
|
|
10794
|
+
// case 'medium':
|
|
10795
|
+
// risk += 15;
|
|
10796
|
+
// break;
|
|
10797
|
+
// case 'low':
|
|
10798
|
+
// risk += 5;
|
|
10799
|
+
// break;
|
|
10800
|
+
// }
|
|
10891
10801
|
|
|
10892
|
-
|
|
10893
|
-
|
|
10802
|
+
// // Adjust for unsolicited
|
|
10803
|
+
// if (aiData.is_unsolicited) risk += 20;
|
|
10894
10804
|
|
|
10895
|
-
|
|
10896
|
-
|
|
10897
|
-
if (data.spam_confidence > 70) explanations.push(`- High spam confidence (${data.spam_confidence}%)`);
|
|
10898
|
-
if (data.phishing_risk !== 'none') explanations.push(`- ${data.phishing_risk} phishing risk`);
|
|
10899
|
-
if (data.local_analysis.spamScore > 60) explanations.push('- Contains spam indicators');
|
|
10900
|
-
}
|
|
10805
|
+
// // Adjust for urgency
|
|
10806
|
+
// if (aiData.is_urgent) risk += 10;
|
|
10901
10807
|
|
|
10902
|
-
|
|
10903
|
-
|
|
10904
|
-
if (data.is_commercial) explanations.push('- Commercial intent detected');
|
|
10905
|
-
if (data.local_analysis.hasUnsubscribe) explanations.push('- Contains unsubscribe option');
|
|
10906
|
-
if (data.local_analysis.promotionalScore > 30) explanations.push('- Promotional content detected');
|
|
10907
|
-
}
|
|
10808
|
+
// return Math.min(risk, 100);
|
|
10809
|
+
// }
|
|
10908
10810
|
|
|
10909
|
-
|
|
10910
|
-
|
|
10911
|
-
|
|
10912
|
-
explanations.push(`- ${indicator}`);
|
|
10913
|
-
});
|
|
10914
|
-
}
|
|
10811
|
+
// function detectMatchedFilters(body, subject, email, name) {
|
|
10812
|
+
// const filters = [];
|
|
10813
|
+
// const text = (subject + ' ' + body).toLowerCase();
|
|
10915
10814
|
|
|
10916
|
-
|
|
10917
|
-
|
|
10815
|
+
// // Spam filters
|
|
10816
|
+
// if (/(?:viagra|cialis|penis|enlarge)/i.test(text)) filters.push('adult_content_filter');
|
|
10817
|
+
// if (/(?:lottery|winner|prize|jackpot)/i.test(text)) filters.push('lottery_scam_filter');
|
|
10818
|
+
// if (/(?:nigerian|prince|inheritance|unclaimed)/i.test(text)) filters.push('inheritance_scam_filter');
|
|
10819
|
+
// if (/password\s+reset|verify\s+account/i.test(text)) filters.push('account_verification_filter');
|
|
10918
10820
|
|
|
10919
|
-
|
|
10920
|
-
|
|
10921
|
-
|
|
10821
|
+
// // Promotional filters
|
|
10822
|
+
// if (/newsletter|subscribe|unsubscribe/i.test(text)) filters.push('newsletter_filter');
|
|
10823
|
+
// if (/sale|discount|offer|coupon/i.test(text)) filters.push('promotional_offer_filter');
|
|
10824
|
+
// if (/webinar|event|conference/i.test(text)) filters.push('event_filter');
|
|
10922
10825
|
|
|
10923
|
-
|
|
10924
|
-
|
|
10925
|
-
|
|
10926
|
-
|
|
10826
|
+
// // Transactional filters
|
|
10827
|
+
// if (/order|invoice|receipt|payment/i.test(text)) filters.push('transaction_filter');
|
|
10828
|
+
// if (/shipping|delivery|tracking/i.test(text)) filters.push('shipping_filter');
|
|
10829
|
+
// if (/appointment|meeting|reminder/i.test(text)) filters.push('calendar_filter');
|
|
10927
10830
|
|
|
10928
|
-
|
|
10929
|
-
|
|
10930
|
-
}
|
|
10831
|
+
// return filters;
|
|
10832
|
+
// }
|
|
10931
10833
|
|
|
10932
|
-
|
|
10933
|
-
|
|
10934
|
-
|
|
10834
|
+
// function detectTimeSensitivity(body) {
|
|
10835
|
+
// const text = body.toLowerCase();
|
|
10836
|
+
// const patterns = [/today|tomorrow|this\s+week|immediately|asap/i, /deadline|due\s+by|expires|limited\s+time/i, /urgent|important|attention|alert/i];
|
|
10935
10837
|
|
|
10936
|
-
|
|
10937
|
-
|
|
10938
|
-
flags.push('gdpr_mentions');
|
|
10939
|
-
}
|
|
10838
|
+
// return patterns.some((pattern) => pattern.test(text));
|
|
10839
|
+
// }
|
|
10940
10840
|
|
|
10941
|
-
|
|
10942
|
-
|
|
10943
|
-
}
|
|
10841
|
+
// function detectExpiryDate(body) {
|
|
10842
|
+
// const datePatterns = [/\b\d{1,2}\/\d{1,2}\/\d{2,4}\b/g, /\b\d{1,2}\s+(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*\s+\d{2,4}\b/gi, /\bexpires?\s+(?:on|by)?\s*[:]?\s*\d{1,2}\/\d{1,2}\/\d{2,4}\b/gi];
|
|
10944
10843
|
|
|
10945
|
-
|
|
10946
|
-
|
|
10844
|
+
// return datePatterns.some((pattern) => pattern.test(body.toLowerCase()));
|
|
10845
|
+
// }
|
|
10947
10846
|
|
|
10948
|
-
|
|
10949
|
-
|
|
10847
|
+
// function detectFollowUpPattern(body, subject) {
|
|
10848
|
+
// const text = (subject + ' ' + body).toLowerCase();
|
|
10849
|
+
// return /follow.?up|following.?up|checking.?in|touch.?base|re:.?re:/i.test(text);
|
|
10850
|
+
// }
|
|
10950
10851
|
|
|
10951
|
-
|
|
10952
|
-
|
|
10953
|
-
|
|
10954
|
-
|
|
10955
|
-
|
|
10852
|
+
// function analyzeRelationshipContext(body, subject, name) {
|
|
10853
|
+
// const text = (subject + ' ' + body).toLowerCase();
|
|
10854
|
+
// const nameParts = name.toLowerCase().split(' ');
|
|
10855
|
+
// const firstName = nameParts[0] || '';
|
|
10856
|
+
|
|
10857
|
+
// const indicators = {
|
|
10858
|
+
// uses_name: firstName && text.includes(firstName),
|
|
10859
|
+
// uses_personal_pronouns: /\b(?:i|me|my|mine|you|your|yours)\b/gi.test(text),
|
|
10860
|
+
// has_greeting: /^(?:hi|hello|hey|dear|greetings)\b/im.test(body),
|
|
10861
|
+
// has_signature: /(?:best|regards|sincerely|thanks|thank you)\s*[,]?\s*\n/im.test(body),
|
|
10862
|
+
// has_questions: /\?/.test(text) && /(?:can|could|would|will|do|are|is)\s+you/i.test(text),
|
|
10863
|
+
// };
|
|
10956
10864
|
|
|
10957
|
-
|
|
10958
|
-
const phishingRisk = localAnalysis.phishingScore > 50 ? 'medium' : 'low';
|
|
10865
|
+
// const relationshipScore = Object.values(indicators).filter(Boolean).length * 20;
|
|
10959
10866
|
|
|
10960
|
-
|
|
10961
|
-
|
|
10962
|
-
|
|
10963
|
-
|
|
10964
|
-
|
|
10867
|
+
// return {
|
|
10868
|
+
// ...indicators,
|
|
10869
|
+
// relationship_score: Math.min(relationshipScore, 100),
|
|
10870
|
+
// likely_known_sender: relationshipScore >= 40,
|
|
10871
|
+
// };
|
|
10872
|
+
// }
|
|
10965
10873
|
|
|
10966
|
-
|
|
10967
|
-
|
|
10968
|
-
malware_risk: 'none',
|
|
10874
|
+
// function calculateFinalConfidence(data) {
|
|
10875
|
+
// let confidence = data.email_type_confidence;
|
|
10969
10876
|
|
|
10970
|
-
|
|
10971
|
-
|
|
10972
|
-
|
|
10973
|
-
|
|
10877
|
+
// // Adjust based on local analysis
|
|
10878
|
+
// if (data.local_analysis.spamScore > 70 && data.email_type !== 'spam') {
|
|
10879
|
+
// confidence -= 20;
|
|
10880
|
+
// }
|
|
10974
10881
|
|
|
10975
|
-
|
|
10976
|
-
|
|
10882
|
+
// // Adjust based on phishing risk
|
|
10883
|
+
// if (data.phishing_risk === 'critical' || data.phishing_risk === 'high') {
|
|
10884
|
+
// confidence += 15;
|
|
10885
|
+
// }
|
|
10977
10886
|
|
|
10978
|
-
|
|
10979
|
-
|
|
10980
|
-
|
|
10981
|
-
|
|
10982
|
-
contains_address: localAnalysis.hasAddress,
|
|
10887
|
+
// // Adjust based on personalization
|
|
10888
|
+
// if (data.is_personalized) {
|
|
10889
|
+
// confidence += 10;
|
|
10890
|
+
// }
|
|
10983
10891
|
|
|
10984
|
-
|
|
10985
|
-
|
|
10986
|
-
|
|
10892
|
+
// // Adjust based on content stats
|
|
10893
|
+
// if (data.content_stats.link_count > 5) {
|
|
10894
|
+
// confidence += 5;
|
|
10895
|
+
// }
|
|
10987
10896
|
|
|
10988
|
-
|
|
10989
|
-
|
|
10990
|
-
inbox_priority: emailType === 'spam' ? 'ignore' : 'normal',
|
|
10897
|
+
// return Math.max(0, Math.min(100, confidence));
|
|
10898
|
+
// }
|
|
10991
10899
|
|
|
10992
|
-
|
|
10993
|
-
|
|
10994
|
-
legitimacy_signals: [],
|
|
10900
|
+
// function generateExplanation(data) {
|
|
10901
|
+
// const explanations = [];
|
|
10995
10902
|
|
|
10996
|
-
|
|
10997
|
-
|
|
10998
|
-
|
|
10903
|
+
// if (data.email_type === 'spam') {
|
|
10904
|
+
// explanations.push('Classified as spam due to:');
|
|
10905
|
+
// if (data.spam_confidence > 70) explanations.push(`- High spam confidence (${data.spam_confidence}%)`);
|
|
10906
|
+
// if (data.phishing_risk !== 'none') explanations.push(`- ${data.phishing_risk} phishing risk`);
|
|
10907
|
+
// if (data.local_analysis.spamScore > 60) explanations.push('- Contains spam indicators');
|
|
10908
|
+
// }
|
|
10999
10909
|
|
|
11000
|
-
|
|
11001
|
-
|
|
11002
|
-
|
|
11003
|
-
|
|
11004
|
-
|
|
11005
|
-
|
|
11006
|
-
link_count: localAnalysis.linkCount,
|
|
11007
|
-
uppercase_ratio: calculateUppercaseRatio(emailBody),
|
|
11008
|
-
exclamation_count: (emailBody.match(/!/g) || []).length,
|
|
11009
|
-
dollar_sign_count: (emailBody.match(/\$/g) || []).length,
|
|
11010
|
-
phone_patterns: (emailBody.match(/\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g) || []).length,
|
|
11011
|
-
},
|
|
10910
|
+
// if (data.email_type === 'promotional') {
|
|
10911
|
+
// explanations.push('Classified as promotional due to:');
|
|
10912
|
+
// if (data.is_commercial) explanations.push('- Commercial intent detected');
|
|
10913
|
+
// if (data.local_analysis.hasUnsubscribe) explanations.push('- Contains unsubscribe option');
|
|
10914
|
+
// if (data.local_analysis.promotionalScore > 30) explanations.push('- Promotional content detected');
|
|
10915
|
+
// }
|
|
11012
10916
|
|
|
11013
|
-
|
|
10917
|
+
// if (data.key_indicators && data.key_indicators.length > 0) {
|
|
10918
|
+
// explanations.push('Key indicators:');
|
|
10919
|
+
// data.key_indicators.forEach((indicator) => {
|
|
10920
|
+
// explanations.push(`- ${indicator}`);
|
|
10921
|
+
// });
|
|
10922
|
+
// }
|
|
11014
10923
|
|
|
11015
|
-
|
|
11016
|
-
|
|
11017
|
-
error: error || 'API call failed',
|
|
11018
|
-
};
|
|
11019
|
-
}
|
|
10924
|
+
// return explanations.join('\n');
|
|
10925
|
+
// }
|
|
11020
10926
|
|
|
11021
|
-
|
|
11022
|
-
|
|
11023
|
-
|
|
10927
|
+
// function checkCompliance(body, subject) {
|
|
10928
|
+
// const text = (subject + ' ' + body).toLowerCase();
|
|
10929
|
+
// const flags = [];
|
|
11024
10930
|
|
|
11025
|
-
|
|
11026
|
-
|
|
11027
|
-
|
|
10931
|
+
// // CAN-SPAM Act compliance (US)
|
|
10932
|
+
// if (text.includes('unsubscribe') || text.includes('opt-out')) {
|
|
10933
|
+
// flags.push('has_unsubscribe_option');
|
|
10934
|
+
// }
|
|
11028
10935
|
|
|
11029
|
-
|
|
10936
|
+
// if (/\b\d{10}\b/.test(body.replace(/\D/g, ''))) {
|
|
10937
|
+
// flags.push('contains_phone_number');
|
|
10938
|
+
// }
|
|
11030
10939
|
|
|
11031
|
-
|
|
11032
|
-
|
|
11033
|
-
|
|
11034
|
-
- Poor grammar/spelling
|
|
11035
|
-
- Urgent/panic-inducing language
|
|
11036
|
-
- Requests for personal information
|
|
11037
|
-
- Too good to be true offers
|
|
11038
|
-
- Hidden/unclear sender identity
|
|
11039
|
-
- Multiple recipient addresses visible
|
|
11040
|
-
- Stock/"spammy" subject lines
|
|
11041
|
-
|
|
11042
|
-
PROMOTIONAL INDICATORS:
|
|
11043
|
-
- Marketing/sales content
|
|
11044
|
-
- Product announcements
|
|
11045
|
-
- Newsletter content
|
|
11046
|
-
- Discount/coupon offers
|
|
11047
|
-
- Event invitations (commercial)
|
|
11048
|
-
- Company updates (marketing focused)
|
|
11049
|
-
- Clear opt-out/unsubscribe option
|
|
11050
|
-
- Professional branding/templates
|
|
11051
|
-
- Call-to-action buttons
|
|
11052
|
-
|
|
11053
|
-
TRANSACTIONAL INDICATORS:
|
|
11054
|
-
- Order confirmations
|
|
11055
|
-
- Shipping notifications
|
|
11056
|
-
- Invoice/billing
|
|
11057
|
-
- Account notifications
|
|
11058
|
-
- Password resets
|
|
11059
|
-
- Booking confirmations
|
|
11060
|
-
- Appointment reminders
|
|
11061
|
-
- Payment receipts
|
|
11062
|
-
- Service updates
|
|
11063
|
-
|
|
11064
|
-
PERSONAL/BUSINESS INDICATORS:
|
|
11065
|
-
- Direct communication to you
|
|
11066
|
-
- Known sender relationship
|
|
11067
|
-
- Work/project related
|
|
11068
|
-
- Personal conversations
|
|
11069
|
-
- One-on-one correspondence
|
|
11070
|
-
- Contains your name specifically
|
|
11071
|
-
- Contextually relevant to you
|
|
11072
|
-
|
|
11073
|
-
ADDITIONAL FACTORS TO CONSIDER:
|
|
11074
|
-
- Sender reputation (company vs personal)
|
|
11075
|
-
- Your relationship with sender
|
|
11076
|
-
- Email formatting quality
|
|
11077
|
-
- Personalization level
|
|
11078
|
-
- Expected vs unexpected content
|
|
11079
|
-
- Action requested (if any)
|
|
11080
|
-
|
|
11081
|
-
PROVIDE DETAILED ANALYSIS WITH CONFIDENCE SCORES.`,
|
|
11082
|
-
model: 'gpt-5-nano',
|
|
11083
|
-
response_format: z.object({
|
|
11084
|
-
// Primary Classification
|
|
11085
|
-
email_type: z.enum(['spam', 'promotional', 'transactional', 'personal', 'business', 'ambiguous']),
|
|
11086
|
-
email_type_confidence: z.number().min(0).max(100),
|
|
11087
|
-
|
|
11088
|
-
// Sub-classification
|
|
11089
|
-
email_subtype: z.enum([
|
|
11090
|
-
// Spam types
|
|
11091
|
-
'phishing_attempt',
|
|
11092
|
-
'scam_offer',
|
|
11093
|
-
'malware_risk',
|
|
11094
|
-
'adult_content',
|
|
11095
|
-
'financial_scam',
|
|
11096
|
-
'lottery_scam',
|
|
11097
|
-
'inheritance_scam',
|
|
11098
|
-
'romance_scam',
|
|
11099
|
-
'tech_support_scam',
|
|
11100
|
-
|
|
11101
|
-
// Promotional types
|
|
11102
|
-
'marketing_newsletter',
|
|
11103
|
-
'product_announcement',
|
|
11104
|
-
'discount_offer',
|
|
11105
|
-
'event_invitation',
|
|
11106
|
-
'company_update',
|
|
11107
|
-
'blog_newsletter',
|
|
11108
|
-
'educational_content',
|
|
11109
|
-
'lead_magnet',
|
|
11110
|
-
|
|
11111
|
-
// Transactional types
|
|
11112
|
-
'order_confirmation',
|
|
11113
|
-
'shipping_notification',
|
|
11114
|
-
'invoice_billing',
|
|
11115
|
-
'payment_receipt',
|
|
11116
|
-
'account_verification',
|
|
11117
|
-
'password_reset',
|
|
11118
|
-
'appointment_reminder',
|
|
11119
|
-
'service_notification',
|
|
11120
|
-
|
|
11121
|
-
// Personal/Business types
|
|
11122
|
-
'personal_message',
|
|
11123
|
-
'work_collaboration',
|
|
11124
|
-
'client_communication',
|
|
11125
|
-
'team_announcement',
|
|
11126
|
-
'meeting_invitation',
|
|
11127
|
-
'project_update',
|
|
11128
|
-
'direct_inquiry',
|
|
11129
|
-
'networking_request',
|
|
11130
|
-
]),
|
|
10940
|
+
// if (/address\s*[:]?\s*\d+\s+[\w\s]+/i.test(body)) {
|
|
10941
|
+
// flags.push('contains_physical_address');
|
|
10942
|
+
// }
|
|
11131
10943
|
|
|
11132
|
-
|
|
11133
|
-
|
|
11134
|
-
|
|
11135
|
-
|
|
10944
|
+
// // GDPR indicators (EU)
|
|
10945
|
+
// if (/privacy\s+policy|gdpr|data\s+protection/i.test(text)) {
|
|
10946
|
+
// flags.push('gdpr_mentions');
|
|
10947
|
+
// }
|
|
11136
10948
|
|
|
11137
|
-
|
|
11138
|
-
|
|
11139
|
-
|
|
11140
|
-
is_urgent: z.boolean().describe('Uses urgent/time-sensitive language'),
|
|
11141
|
-
is_personalized: z.boolean().describe('Content is personalized to recipient'),
|
|
10949
|
+
// if (/consent|opt.?in|permission/i.test(text)) {
|
|
10950
|
+
// flags.push('consent_mentions');
|
|
10951
|
+
// }
|
|
11142
10952
|
|
|
11143
|
-
|
|
11144
|
-
|
|
11145
|
-
sender_intent: z.enum(['inform', 'sell', 'scam', 'build_relationship', 'request_action', 'unknown']),
|
|
10953
|
+
// return flags;
|
|
10954
|
+
// }
|
|
11146
10955
|
|
|
11147
|
-
|
|
11148
|
-
|
|
11149
|
-
contains_attachments: z.boolean(),
|
|
11150
|
-
contains_unsubscribe: z.boolean(),
|
|
11151
|
-
contains_phone_number: z.boolean(),
|
|
11152
|
-
contains_address: z.boolean(),
|
|
10956
|
+
// function getDefaultEmailDetection(name, email, emailBody, emailSubject, error = null) {
|
|
10957
|
+
// const localAnalysis = analyzeEmailLocally(emailBody, emailSubject, email, name);
|
|
11153
10958
|
|
|
11154
|
-
|
|
11155
|
-
|
|
11156
|
-
|
|
11157
|
-
|
|
10959
|
+
// // Determine type based on local analysis
|
|
10960
|
+
// let emailType = 'ambiguous';
|
|
10961
|
+
// if (localAnalysis.spamScore > 70) emailType = 'spam';
|
|
10962
|
+
// else if (localAnalysis.promotionalScore > localAnalysis.transactionalScore && localAnalysis.promotionalScore > 30) emailType = 'promotional';
|
|
10963
|
+
// else if (localAnalysis.transactionalScore > 40) emailType = 'transactional';
|
|
11158
10964
|
|
|
11159
|
-
|
|
11160
|
-
|
|
10965
|
+
// const spamConfidence = localAnalysis.spamScore;
|
|
10966
|
+
// const phishingRisk = localAnalysis.phishingScore > 50 ? 'medium' : 'low';
|
|
11161
10967
|
|
|
11162
|
-
|
|
11163
|
-
|
|
10968
|
+
// return {
|
|
10969
|
+
// success: false,
|
|
10970
|
+
// email_type: emailType,
|
|
10971
|
+
// email_type_confidence: Math.max(50, spamConfidence),
|
|
10972
|
+
// email_subtype: 'personal_message',
|
|
10973
|
+
|
|
10974
|
+
// spam_confidence: spamConfidence,
|
|
10975
|
+
// phishing_risk: phishingRisk,
|
|
10976
|
+
// malware_risk: 'none',
|
|
10977
|
+
|
|
10978
|
+
// is_unsolicited: true,
|
|
10979
|
+
// is_commercial: localAnalysis.promotionalScore > 30,
|
|
10980
|
+
// is_urgent: localAnalysis.urgencyCount > 0,
|
|
10981
|
+
// is_personalized: localAnalysis.personalizationScore > 20,
|
|
10982
|
+
|
|
10983
|
+
// sender_legitimacy: 'unknown',
|
|
10984
|
+
// sender_intent: 'unknown',
|
|
10985
|
+
|
|
10986
|
+
// contains_links: localAnalysis.linkCount > 0,
|
|
10987
|
+
// contains_attachments: false,
|
|
10988
|
+
// contains_unsubscribe: localAnalysis.hasUnsubscribe,
|
|
10989
|
+
// contains_phone_number: localAnalysis.hasPhone,
|
|
10990
|
+
// contains_address: localAnalysis.hasAddress,
|
|
10991
|
+
|
|
10992
|
+
// language_quality: localAnalysis.misspellingCount > 3 ? 'poor' : 'average',
|
|
10993
|
+
// urgency_level: localAnalysis.urgencyCount > 2 ? 'high' : 'low',
|
|
10994
|
+
// personalization_score: localAnalysis.personalizationScore,
|
|
10995
|
+
|
|
10996
|
+
// suggested_action: emailType === 'spam' ? 'mark_as_spam' : 'keep_in_inbox',
|
|
10997
|
+
// auto_filter_suggestion: emailType === 'spam' ? 'spam_filter' : 'no_filter',
|
|
10998
|
+
// inbox_priority: emailType === 'spam' ? 'ignore' : 'normal',
|
|
10999
|
+
|
|
11000
|
+
// key_indicators: ['Local analysis only - API failed'],
|
|
11001
|
+
// risk_factors: [],
|
|
11002
|
+
// legitimacy_signals: [],
|
|
11003
|
+
|
|
11004
|
+
// analysis_timestamp: new Date().toISOString(),
|
|
11005
|
+
// content_length: emailBody.length,
|
|
11006
|
+
// analysis_complexity: 'simple',
|
|
11007
|
+
|
|
11008
|
+
// // Enhanced fields
|
|
11009
|
+
// local_analysis: localAnalysis,
|
|
11010
|
+
// sender_analysis: analyzeSender(email, name, emailBody),
|
|
11011
|
+
// content_stats: {
|
|
11012
|
+
// word_count: (emailBody.match(/\S+/g) || []).length,
|
|
11013
|
+
// sentence_count: (emailBody.match(/[.!?]+/g) || []).length,
|
|
11014
|
+
// link_count: localAnalysis.linkCount,
|
|
11015
|
+
// uppercase_ratio: calculateUppercaseRatio(emailBody),
|
|
11016
|
+
// exclamation_count: (emailBody.match(/!/g) || []).length,
|
|
11017
|
+
// dollar_sign_count: (emailBody.match(/\$/g) || []).length,
|
|
11018
|
+
// phone_patterns: (emailBody.match(/\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g) || []).length,
|
|
11019
|
+
// },
|
|
11164
11020
|
|
|
11165
|
-
|
|
11166
|
-
inbox_priority: z.enum(['critical', 'high', 'normal', 'low', 'ignore']),
|
|
11021
|
+
// comprehensive_risk_score: calculateComprehensiveRisk({ email_type: emailType, phishing_risk: phishingRisk, is_unsolicited: true, is_urgent: localAnalysis.urgencyCount > 0 }, localAnalysis),
|
|
11167
11022
|
|
|
11168
|
-
|
|
11169
|
-
|
|
11170
|
-
|
|
11171
|
-
|
|
11023
|
+
// final_confidence: Math.max(50, spamConfidence),
|
|
11024
|
+
// explanation: 'Default analysis due to API failure',
|
|
11025
|
+
// error: error || 'API call failed',
|
|
11026
|
+
// };
|
|
11027
|
+
// }
|
|
11172
11028
|
|
|
11173
|
-
|
|
11174
|
-
|
|
11175
|
-
|
|
11176
|
-
|
|
11177
|
-
|
|
11178
|
-
|
|
11179
|
-
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11183
|
-
|
|
11184
|
-
|
|
11185
|
-
|
|
11186
|
-
|
|
11187
|
-
|
|
11188
|
-
|
|
11029
|
+
// const detection_ret = await submit_chat_gpt_prompt({
|
|
11030
|
+
// uid,
|
|
11031
|
+
// prompt: `Analyze this email and determine if it's SPAM, PROMOTIONAL, TRANSACTIONAL, or PERSONAL/BUSINESS communication.
|
|
11032
|
+
|
|
11033
|
+
// FROM: "${name}" <${email}>
|
|
11034
|
+
// SUBJECT: "${email_subject}"
|
|
11035
|
+
// BODY: "${email_body.substring(0, 800)}${email_body.length > 800 ? '...' : ''}"
|
|
11036
|
+
|
|
11037
|
+
// ANALYSIS CRITERIA:
|
|
11038
|
+
|
|
11039
|
+
// SPAM INDICATORS:
|
|
11040
|
+
// - Unsolicited commercial content
|
|
11041
|
+
// - Phishing attempts or suspicious links
|
|
11042
|
+
// - Poor grammar/spelling
|
|
11043
|
+
// - Urgent/panic-inducing language
|
|
11044
|
+
// - Requests for personal information
|
|
11045
|
+
// - Too good to be true offers
|
|
11046
|
+
// - Hidden/unclear sender identity
|
|
11047
|
+
// - Multiple recipient addresses visible
|
|
11048
|
+
// - Stock/"spammy" subject lines
|
|
11049
|
+
|
|
11050
|
+
// PROMOTIONAL INDICATORS:
|
|
11051
|
+
// - Marketing/sales content
|
|
11052
|
+
// - Product announcements
|
|
11053
|
+
// - Newsletter content
|
|
11054
|
+
// - Discount/coupon offers
|
|
11055
|
+
// - Event invitations (commercial)
|
|
11056
|
+
// - Company updates (marketing focused)
|
|
11057
|
+
// - Clear opt-out/unsubscribe option
|
|
11058
|
+
// - Professional branding/templates
|
|
11059
|
+
// - Call-to-action buttons
|
|
11060
|
+
|
|
11061
|
+
// TRANSACTIONAL INDICATORS:
|
|
11062
|
+
// - Order confirmations
|
|
11063
|
+
// - Shipping notifications
|
|
11064
|
+
// - Invoice/billing
|
|
11065
|
+
// - Account notifications
|
|
11066
|
+
// - Password resets
|
|
11067
|
+
// - Booking confirmations
|
|
11068
|
+
// - Appointment reminders
|
|
11069
|
+
// - Payment receipts
|
|
11070
|
+
// - Service updates
|
|
11071
|
+
|
|
11072
|
+
// PERSONAL/BUSINESS INDICATORS:
|
|
11073
|
+
// - Direct communication to you
|
|
11074
|
+
// - Known sender relationship
|
|
11075
|
+
// - Work/project related
|
|
11076
|
+
// - Personal conversations
|
|
11077
|
+
// - One-on-one correspondence
|
|
11078
|
+
// - Contains your name specifically
|
|
11079
|
+
// - Contextually relevant to you
|
|
11080
|
+
|
|
11081
|
+
// ADDITIONAL FACTORS TO CONSIDER:
|
|
11082
|
+
// - Sender reputation (company vs personal)
|
|
11083
|
+
// - Your relationship with sender
|
|
11084
|
+
// - Email formatting quality
|
|
11085
|
+
// - Personalization level
|
|
11086
|
+
// - Expected vs unexpected content
|
|
11087
|
+
// - Action requested (if any)
|
|
11088
|
+
|
|
11089
|
+
// PROVIDE DETAILED ANALYSIS WITH CONFIDENCE SCORES.`,
|
|
11090
|
+
// model: 'gpt-5-nano',
|
|
11091
|
+
// response_format: z.object({
|
|
11092
|
+
// // Primary Classification
|
|
11093
|
+
// email_type: z.enum(['spam', 'promotional', 'transactional', 'personal', 'business', 'ambiguous']),
|
|
11094
|
+
// email_type_confidence: z.number().min(0).max(100),
|
|
11095
|
+
|
|
11096
|
+
// // Sub-classification
|
|
11097
|
+
// email_subtype: z.enum([
|
|
11098
|
+
// // Spam types
|
|
11099
|
+
// 'phishing_attempt',
|
|
11100
|
+
// 'scam_offer',
|
|
11101
|
+
// 'malware_risk',
|
|
11102
|
+
// 'adult_content',
|
|
11103
|
+
// 'financial_scam',
|
|
11104
|
+
// 'lottery_scam',
|
|
11105
|
+
// 'inheritance_scam',
|
|
11106
|
+
// 'romance_scam',
|
|
11107
|
+
// 'tech_support_scam',
|
|
11108
|
+
|
|
11109
|
+
// // Promotional types
|
|
11110
|
+
// 'marketing_newsletter',
|
|
11111
|
+
// 'product_announcement',
|
|
11112
|
+
// 'discount_offer',
|
|
11113
|
+
// 'event_invitation',
|
|
11114
|
+
// 'company_update',
|
|
11115
|
+
// 'blog_newsletter',
|
|
11116
|
+
// 'educational_content',
|
|
11117
|
+
// 'lead_magnet',
|
|
11118
|
+
|
|
11119
|
+
// // Transactional types
|
|
11120
|
+
// 'order_confirmation',
|
|
11121
|
+
// 'shipping_notification',
|
|
11122
|
+
// 'invoice_billing',
|
|
11123
|
+
// 'payment_receipt',
|
|
11124
|
+
// 'account_verification',
|
|
11125
|
+
// 'password_reset',
|
|
11126
|
+
// 'appointment_reminder',
|
|
11127
|
+
// 'service_notification',
|
|
11128
|
+
|
|
11129
|
+
// // Personal/Business types
|
|
11130
|
+
// 'personal_message',
|
|
11131
|
+
// 'work_collaboration',
|
|
11132
|
+
// 'client_communication',
|
|
11133
|
+
// 'team_announcement',
|
|
11134
|
+
// 'meeting_invitation',
|
|
11135
|
+
// 'project_update',
|
|
11136
|
+
// 'direct_inquiry',
|
|
11137
|
+
// 'networking_request',
|
|
11138
|
+
// ]),
|
|
11139
|
+
|
|
11140
|
+
// // Risk Assessment
|
|
11141
|
+
// spam_confidence: z.number().min(0).max(100).describe('Confidence this is spam'),
|
|
11142
|
+
// phishing_risk: z.enum(['none', 'low', 'medium', 'high', 'critical']),
|
|
11143
|
+
// malware_risk: z.enum(['none', 'low', 'medium', 'high']),
|
|
11144
|
+
|
|
11145
|
+
// // Content Analysis
|
|
11146
|
+
// is_unsolicited: z.boolean().describe('Email was not requested/expected'),
|
|
11147
|
+
// is_commercial: z.boolean().describe('Contains commercial intent'),
|
|
11148
|
+
// is_urgent: z.boolean().describe('Uses urgent/time-sensitive language'),
|
|
11149
|
+
// is_personalized: z.boolean().describe('Content is personalized to recipient'),
|
|
11150
|
+
|
|
11151
|
+
// // Sender Analysis
|
|
11152
|
+
// sender_legitimacy: z.enum(['verified', 'likely_legitimate', 'suspicious', 'likely_fake', 'unknown']),
|
|
11153
|
+
// sender_intent: z.enum(['inform', 'sell', 'scam', 'build_relationship', 'request_action', 'unknown']),
|
|
11154
|
+
|
|
11155
|
+
// // Content Characteristics
|
|
11156
|
+
// contains_links: z.boolean(),
|
|
11157
|
+
// contains_attachments: z.boolean(),
|
|
11158
|
+
// contains_unsubscribe: z.boolean(),
|
|
11159
|
+
// contains_phone_number: z.boolean(),
|
|
11160
|
+
// contains_address: z.boolean(),
|
|
11161
|
+
|
|
11162
|
+
// // Language Analysis
|
|
11163
|
+
// language_quality: z.enum(['excellent', 'good', 'average', 'poor', 'spammy']),
|
|
11164
|
+
// urgency_level: z.enum(['none', 'low', 'medium', 'high', 'extreme']),
|
|
11165
|
+
// personalization_score: z.number().min(0).max(100).describe('How personalized the content is'),
|
|
11166
|
+
|
|
11167
|
+
// // Action Recommendations
|
|
11168
|
+
// suggested_action: z.enum(['delete_immediately', 'mark_as_spam', 'move_to_promotions', 'respond_politely', 'follow_up', 'archive', 'keep_in_inbox', 'add_to_contacts', 'report_phishing']),
|
|
11169
|
+
|
|
11170
|
+
// // Filter Recommendations
|
|
11171
|
+
// auto_filter_suggestion: z.enum(['spam_filter', 'promotions_filter', 'social_filter', 'updates_filter', 'primary_inbox', 'no_filter']),
|
|
11172
|
+
|
|
11173
|
+
// // Priority
|
|
11174
|
+
// inbox_priority: z.enum(['critical', 'high', 'normal', 'low', 'ignore']),
|
|
11175
|
+
|
|
11176
|
+
// // Detailed Analysis
|
|
11177
|
+
// key_indicators: z.array(z.string()).describe('Key factors influencing classification'),
|
|
11178
|
+
// risk_factors: z.array(z.string()).describe('Specific risks identified'),
|
|
11179
|
+
// legitimacy_signals: z.array(z.string()).describe('Signals of legitimate communication'),
|
|
11180
|
+
|
|
11181
|
+
// // Metadata
|
|
11182
|
+
// analysis_timestamp: z.string(),
|
|
11183
|
+
// content_length: z.number().describe('Length of email body analyzed'),
|
|
11184
|
+
// analysis_complexity: z.enum(['simple', 'moderate', 'complex', 'ambiguous']),
|
|
11185
|
+
// }),
|
|
11186
|
+
// metadata: {
|
|
11187
|
+
// func: 'detect_email_type',
|
|
11188
|
+
// sender_name: name,
|
|
11189
|
+
// sender_email: email,
|
|
11190
|
+
// subject_length: email_subject?.length || 0,
|
|
11191
|
+
// body_length: email_body?.length || 0,
|
|
11192
|
+
// body_preview_hash: await hashString(email_body.substring(0, 200)),
|
|
11193
|
+
// },
|
|
11194
|
+
// account_profile_info,
|
|
11195
|
+
// tools: [{ type: 'web_search_preview' }],
|
|
11196
|
+
// });
|
|
11189
11197
|
|
|
11190
|
-
|
|
11191
|
-
|
|
11192
|
-
|
|
11198
|
+
// try {
|
|
11199
|
+
// if (detection_ret.code > -1) {
|
|
11200
|
+
// const data = typeof detection_ret.data === 'string' ? JSON.parse(detection_ret.data) : detection_ret.data;
|
|
11193
11201
|
|
|
11194
|
-
|
|
11195
|
-
|
|
11202
|
+
// // Enhance with additional analysis
|
|
11203
|
+
// const enhancedData = enhanceEmailDetection(data, name, email, email_body, email_subject);
|
|
11196
11204
|
|
|
11197
|
-
|
|
11198
|
-
|
|
11199
|
-
|
|
11200
|
-
|
|
11201
|
-
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
|
|
11205
|
-
|
|
11206
|
-
|
|
11207
|
-
|
|
11208
|
-
|
|
11209
|
-
};
|
|
11205
|
+
// return {
|
|
11206
|
+
// success: true,
|
|
11207
|
+
// ...enhancedData,
|
|
11208
|
+
// };
|
|
11209
|
+
// } else {
|
|
11210
|
+
// console.error('Email detection API call failed:', detection_ret);
|
|
11211
|
+
// return getDefaultEmailDetection(name, email, email_body, email_subject);
|
|
11212
|
+
// }
|
|
11213
|
+
// } catch (error) {
|
|
11214
|
+
// console.error('Error in detect_email_type:', error);
|
|
11215
|
+
// return getDefaultEmailDetection(name, email, email_body, email_subject, error.message);
|
|
11216
|
+
// }
|
|
11217
|
+
// };
|