@xuda.io/ai_module 1.1.4679 → 1.1.4680

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.
Files changed (2) hide show
  1. package/index.mjs +630 -0
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -9729,3 +9729,633 @@ export const get_person_info = async function (uid, name, email, account_profile
9729
9729
  return getDefaultPersonInfo(name, email, email_context, error.message);
9730
9730
  }
9731
9731
  };
9732
+
9733
+ export const analyze_email_account_type = async function (uid, name, email, account_profile_info, email_context = '') {
9734
+ // ========== HELPER FUNCTIONS ==========
9735
+
9736
+ function enhanceEmailAnalysis(data, name, email, emailContext) {
9737
+ const domain = email.split('@')[1] || '';
9738
+ const localPart = email.split('@')[0] || '';
9739
+ const nameParts = name.toLowerCase().split(/\s+/);
9740
+ const firstName = nameParts[0] || '';
9741
+ const lastName = nameParts.slice(-1)[0] || '';
9742
+
9743
+ // Enhanced business company detection
9744
+ if (data.account_type === 'business' && !data.business_company_name) {
9745
+ data.business_company_name = inferCompanyFromDomain(domain);
9746
+ }
9747
+
9748
+ // Enhanced person detection
9749
+ if (!data.is_real_person) {
9750
+ data.is_real_person = detectRealPerson(localPart, name, domain);
9751
+ }
9752
+
9753
+ if (!data.person_name_in_email) {
9754
+ data.person_name_in_email = checkNameInEmail(localPart, firstName, lastName);
9755
+ }
9756
+
9757
+ // Enhanced pattern analysis
9758
+ if (data.email_pattern === 'unknown') {
9759
+ data.email_pattern = analyzeEmailPattern(localPart, domain);
9760
+ }
9761
+
9762
+ // Enhanced personal provider detection
9763
+ if (data.account_type === 'personal' && !data.personal_account_provider) {
9764
+ data.personal_account_provider = identifyPersonalProvider(domain);
9765
+ }
9766
+
9767
+ // Enhanced risk assessment
9768
+ if (data.spam_risk_level === 'unknown') {
9769
+ data.spam_risk_level = assessSpamRisk(localPart, domain, data.account_type);
9770
+ }
9771
+
9772
+ // Enhanced activity assessment
9773
+ if (!data.is_likely_active) {
9774
+ data.is_likely_active = assessEmailActivity(localPart, domain, data.account_type, data.business_account_category);
9775
+ }
9776
+
9777
+ // Add domain analysis
9778
+ data.domain_analysis = {
9779
+ domain: domain,
9780
+ is_public_provider: isPublicEmailProvider(domain),
9781
+ is_custom_domain: isCustomDomain(domain),
9782
+ is_free_email: isFreeEmailDomain(domain),
9783
+ is_education: isEducationDomain(domain),
9784
+ is_government: isGovernmentDomain(domain),
9785
+ tld: domain.split('.').pop() || '',
9786
+ };
9787
+
9788
+ // Add name-email correlation score
9789
+ data.name_email_correlation = calculateNameEmailCorrelation(localPart, firstName, lastName);
9790
+
9791
+ // Add professional score
9792
+ data.professional_score = calculateProfessionalScore(data);
9793
+
9794
+ // Add structured recommendations
9795
+ data.recommendations = generateRecommendations(data);
9796
+
9797
+ // Add verification suggestions
9798
+ data.verification_suggestions = generateVerificationSuggestions(data, emailContext);
9799
+
9800
+ // Add timestamp
9801
+ data.analysis_timestamp = data.analysis_timestamp || new Date().toISOString();
9802
+
9803
+ return data;
9804
+ }
9805
+
9806
+ function inferCompanyFromDomain(domain) {
9807
+ if (!domain) return 'Unknown';
9808
+
9809
+ // Remove common TLDs and public providers
9810
+ const baseDomain = domain.replace(/\.(com|org|net|co|io|ai|tech|app|dev)$/, '');
9811
+
9812
+ // Remove common subdomains
9813
+ const cleanDomain = baseDomain.replace(/^(mail\.|email\.|webmail\.|smtp\.|mx\.|imap\.)/, '').replace(/\.(com|org|net)$/, '');
9814
+
9815
+ // Convert to readable company name
9816
+ const companyName = cleanDomain
9817
+ .split(/[\.\-]/)
9818
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
9819
+ .join(' ');
9820
+
9821
+ return companyName || 'Unknown';
9822
+ }
9823
+
9824
+ function detectRealPerson(localPart, name, domain) {
9825
+ // Check for generic email addresses
9826
+ const genericPatterns = [
9827
+ 'info',
9828
+ 'support',
9829
+ 'sales',
9830
+ 'contact',
9831
+ 'hello',
9832
+ 'noreply',
9833
+ 'no-reply',
9834
+ 'admin',
9835
+ 'administrator',
9836
+ 'webmaster',
9837
+ 'postmaster',
9838
+ 'hostmaster',
9839
+ 'abuse',
9840
+ 'security',
9841
+ 'billing',
9842
+ 'accounts',
9843
+ 'finance',
9844
+ 'hr',
9845
+ 'humanresources',
9846
+ 'marketing',
9847
+ 'pr',
9848
+ 'press',
9849
+ 'media',
9850
+ 'legal',
9851
+ 'it',
9852
+ 'techsupport',
9853
+ 'help',
9854
+ 'service',
9855
+ 'customerservice',
9856
+ 'feedback',
9857
+ 'inquiries',
9858
+ ];
9859
+
9860
+ const localLower = localPart.toLowerCase();
9861
+
9862
+ // If it matches generic patterns, likely not a real person
9863
+ if (genericPatterns.some((pattern) => localLower === pattern || localLower.startsWith(pattern + '.') || localLower.endsWith('.' + pattern))) {
9864
+ return false;
9865
+ }
9866
+
9867
+ // Check for role-based patterns
9868
+ const rolePatterns = ['ceo', 'cto', 'cfo', 'coo', 'cm', 'director', 'manager', 'head', 'lead', 'senior', 'junior', 'associate', 'analyst', 'engineer', 'developer', 'designer', 'architect', 'consultant', 'advisor'];
9869
+
9870
+ // If contains role patterns but not name, might be generic
9871
+ const hasRolePattern = rolePatterns.some((role) => localLower.includes(role));
9872
+ const hasNameElements = checkNameInEmail(localPart, name.toLowerCase().split(' ')[0], name.toLowerCase().split(' ').slice(-1)[0]);
9873
+
9874
+ if (hasRolePattern && !hasNameElements) {
9875
+ return false;
9876
+ }
9877
+
9878
+ // Check for numeric-only or random strings
9879
+ if (/^\d+$/.test(localPart) || /^[a-f0-9]{32}$/.test(localPart)) {
9880
+ return false;
9881
+ }
9882
+
9883
+ // Check for obvious spam patterns
9884
+ if (localLower.includes('spam') || localLower.includes('bot') || localLower.includes('test')) {
9885
+ return false;
9886
+ }
9887
+
9888
+ return true;
9889
+ }
9890
+
9891
+ function checkNameInEmail(localPart, firstName, lastName) {
9892
+ if (!firstName && !lastName) return false;
9893
+
9894
+ const localLower = localPart.toLowerCase();
9895
+ const firstLower = firstName.toLowerCase();
9896
+ const lastLower = lastName.toLowerCase();
9897
+
9898
+ // Check various name patterns
9899
+ const patterns = [
9900
+ `${firstLower}.${lastLower}`, // john.doe
9901
+ `${firstLower}${lastLower}`, // johndoe
9902
+ `${firstLower.charAt(0)}${lastLower}`, // jdoe
9903
+ `${firstLower}_${lastLower}`, // john_doe
9904
+ `${firstLower}-${lastLower}`, // john-doe
9905
+ `${lastLower}.${firstLower}`, // doe.john
9906
+ `${firstLower.charAt(0)}.${lastLower}`, // j.doe
9907
+ `${lastLower}${firstLower}`, // doejohn
9908
+ `${firstLower}`, // john
9909
+ `${lastLower}`, // doe
9910
+ ];
9911
+
9912
+ return patterns.some((pattern) => localLower === pattern || localLower.startsWith(pattern + '.') || localLower.includes('.' + pattern));
9913
+ }
9914
+
9915
+ function analyzeEmailPattern(localPart, domain) {
9916
+ const localLower = localPart.toLowerCase();
9917
+
9918
+ // Common business patterns
9919
+ if (/^[a-z]+\.[a-z]+$/.test(localLower)) return 'first.last@company.com';
9920
+ if (/^[a-z]+[a-z]+$/.test(localLower) && localLower.length > 5) return 'firstlast@company.com';
9921
+ if (/^[a-z]\.[a-z]+$/.test(localLower)) return 'f.last@company.com';
9922
+ if (/^[a-z][a-z]+$/.test(localLower) && localLower.length <= 5) return 'flast@company.com';
9923
+ if (/^[a-z]+$/.test(localLower) && localLower.length <= 8) return 'first@company.com';
9924
+ if (/^[a-z]+\.[a-z]+\.[a-z]+$/.test(localLower)) return 'first.m.last@company.com';
9925
+
9926
+ // Generic patterns
9927
+ if (/^(info|support|sales|contact|hello)$/.test(localLower)) return 'role@company.com';
9928
+ if (/^(hr|finance|marketing|it|legal)$/.test(localLower)) return 'department@company.com';
9929
+
9930
+ // Personal patterns
9931
+ if (isPublicEmailProvider(domain)) {
9932
+ if (/^[a-z]+\.[a-z]+$/.test(localLower)) return 'first.last@domain.com';
9933
+ if (/^[a-z]+[0-9]+$/.test(localLower)) return 'personal@provider.com';
9934
+ return 'custom@personal.com';
9935
+ }
9936
+
9937
+ return 'unknown';
9938
+ }
9939
+
9940
+ function identifyPersonalProvider(domain) {
9941
+ const providers = {
9942
+ 'gmail.com': 'Google Gmail',
9943
+ 'googlemail.com': 'Google Gmail',
9944
+ 'outlook.com': 'Microsoft Outlook',
9945
+ 'hotmail.com': 'Microsoft Hotmail',
9946
+ 'live.com': 'Microsoft Live',
9947
+ 'yahoo.com': 'Yahoo Mail',
9948
+ 'ymail.com': 'Yahoo Mail',
9949
+ 'aol.com': 'AOL Mail',
9950
+ 'icloud.com': 'Apple iCloud',
9951
+ 'me.com': 'Apple iCloud',
9952
+ 'mac.com': 'Apple iCloud',
9953
+ 'protonmail.com': 'ProtonMail',
9954
+ 'proton.me': 'ProtonMail',
9955
+ 'zoho.com': 'Zoho Mail',
9956
+ 'yandex.com': 'Yandex Mail',
9957
+ 'mail.com': 'Mail.com',
9958
+ 'gmx.com': 'GMX Mail',
9959
+ };
9960
+
9961
+ return providers[domain.toLowerCase()] || 'Custom/Unknown';
9962
+ }
9963
+
9964
+ function isPublicEmailProvider(domain) {
9965
+ const publicProviders = ['gmail.com', 'googlemail.com', 'outlook.com', 'hotmail.com', 'live.com', 'yahoo.com', 'ymail.com', 'aol.com', 'icloud.com', 'me.com', 'mac.com', 'protonmail.com', 'proton.me', 'zoho.com', 'yandex.com', 'mail.com', 'gmx.com'];
9966
+
9967
+ return publicProviders.includes(domain.toLowerCase());
9968
+ }
9969
+
9970
+ function isFreeEmailDomain(domain) {
9971
+ const freeDomains = ['gmail.com', 'yahoo.com', 'outlook.com', 'hotmail.com', 'aol.com', 'mail.com', 'gmx.com', 'yandex.com', 'zoho.com'];
9972
+
9973
+ return freeDomains.includes(domain.toLowerCase());
9974
+ }
9975
+
9976
+ function isCustomDomain(domain) {
9977
+ const publicProviders = ['gmail.com', 'googlemail.com', 'outlook.com', 'hotmail.com', 'live.com', 'yahoo.com', 'ymail.com', 'aol.com', 'icloud.com', 'me.com', 'mac.com', 'protonmail.com', 'proton.me', 'zoho.com', 'yandex.com', 'mail.com', 'gmx.com', 'edu', 'gov', 'mil', 'org', 'net'];
9978
+
9979
+ return !publicProviders.some((provider) => domain.toLowerCase().includes(provider));
9980
+ }
9981
+
9982
+ function isEducationDomain(domain) {
9983
+ return domain.toLowerCase().endsWith('.edu') || domain.toLowerCase().includes('.ac.');
9984
+ }
9985
+
9986
+ function isGovernmentDomain(domain) {
9987
+ return domain.toLowerCase().endsWith('.gov') || domain.toLowerCase().endsWith('.mil');
9988
+ }
9989
+
9990
+ function assessSpamRisk(localPart, domain, accountType) {
9991
+ const localLower = localPart.toLowerCase();
9992
+
9993
+ // High risk indicators
9994
+ if (localLower.includes('spam') || localLower.includes('bot')) return 'high';
9995
+ if (/^[a-f0-9]{32}$/.test(localLower)) return 'high'; // MD5 hash-like
9996
+ if (/^\d+$/.test(localLower)) return 'high'; // Numbers only
9997
+ if (localLower.includes('temp') || localLower.includes('throwaway')) return 'high';
9998
+
9999
+ // Medium risk indicators
10000
+ if (localLower.includes('test') || localLower.includes('demo')) return 'medium';
10001
+ if (accountType === 'personal' && localLower.includes('+')) return 'medium'; // Plus addressing
10002
+
10003
+ // Check disposable email domains
10004
+ if (isDisposableDomain(domain)) return 'high';
10005
+
10006
+ return 'low';
10007
+ }
10008
+
10009
+ function isDisposableDomain(domain) {
10010
+ // Common disposable/temporary email domains
10011
+ const disposableDomains = ['tempmail.com', 'mailinator.com', 'guerrillamail.com', '10minutemail.com', 'yopmail.com', 'trashmail.com', 'dispostable.com', 'fakeinbox.com', 'throwawaymail.com', 'temp-mail.org'];
10012
+
10013
+ return disposableDomains.some((d) => domain.toLowerCase().includes(d));
10014
+ }
10015
+
10016
+ function assessEmailActivity(localPart, domain, accountType, businessCategory) {
10017
+ // Generic/role emails are usually monitored
10018
+ if (accountType === 'business' && ['generic_role', 'department', 'catch_all'].includes(businessCategory)) {
10019
+ return true;
10020
+ }
10021
+
10022
+ // Personal emails with name patterns are likely active
10023
+ if (accountType === 'personal' && /^[a-z]+\.[a-z]+$/.test(localPart.toLowerCase())) {
10024
+ return true;
10025
+ }
10026
+
10027
+ // Education and government emails are usually active
10028
+ if (isEducationDomain(domain) || isGovernmentDomain(domain)) {
10029
+ return true;
10030
+ }
10031
+
10032
+ // Disposable domains are usually inactive after short period
10033
+ if (isDisposableDomain(domain)) {
10034
+ return false;
10035
+ }
10036
+
10037
+ // Default assumption
10038
+ return true;
10039
+ }
10040
+
10041
+ function calculateNameEmailCorrelation(localPart, firstName, lastName) {
10042
+ if (!firstName && !lastName) return 0;
10043
+
10044
+ let score = 0;
10045
+ const localLower = localPart.toLowerCase();
10046
+ const firstLower = firstName.toLowerCase();
10047
+ const lastLower = lastName.toLowerCase();
10048
+
10049
+ // Exact name patterns
10050
+ if (localLower === `${firstLower}.${lastLower}`) score += 40;
10051
+ if (localLower === `${firstLower}${lastLower}`) score += 35;
10052
+ if (localLower === `${firstLower.charAt(0)}${lastLower}`) score += 30;
10053
+ if (localLower === `${firstLower}_${lastLower}`) score += 25;
10054
+
10055
+ // Partial matches
10056
+ if (localLower.includes(firstLower)) score += 15;
10057
+ if (localLower.includes(lastLower)) score += 15;
10058
+
10059
+ // Initial matches
10060
+ if (localLower.startsWith(firstLower.charAt(0))) score += 10;
10061
+
10062
+ // Length consideration (shorter emails with names are better)
10063
+ if (localLower.length <= 20) score += 5;
10064
+
10065
+ return Math.min(score, 100);
10066
+ }
10067
+
10068
+ function calculateProfessionalScore(data) {
10069
+ let score = 50; // Base score
10070
+
10071
+ // Account type weights
10072
+ if (data.account_type === 'business') score += 30;
10073
+ else if (data.account_type === 'personal') score += 10;
10074
+
10075
+ // Real person bonus
10076
+ if (data.is_real_person) score += 20;
10077
+
10078
+ // Active email bonus
10079
+ if (data.is_likely_active) score += 15;
10080
+
10081
+ // Low spam risk bonus
10082
+ if (data.spam_risk_level === 'low') score += 10;
10083
+ else if (data.spam_risk_level === 'high') score -= 20;
10084
+
10085
+ // Name-email correlation bonus
10086
+ score += (data.name_email_correlation / 100) * 20;
10087
+
10088
+ // Business category bonus
10089
+ if (data.business_account_category === 'personal_employee') score += 15;
10090
+
10091
+ return Math.max(0, Math.min(100, score));
10092
+ }
10093
+
10094
+ function generateRecommendations(data) {
10095
+ const recommendations = [];
10096
+
10097
+ if (data.account_type === 'business' && data.is_real_person) {
10098
+ if (data.business_account_category === 'personal_employee') {
10099
+ recommendations.push('Ideal for direct professional outreach');
10100
+ recommendations.push('Suitable for sales, recruitment, and partnership discussions');
10101
+ } else if (data.business_account_category === 'department') {
10102
+ recommendations.push('Best for department-specific inquiries');
10103
+ recommendations.push('Use for customer support or service requests');
10104
+ }
10105
+ } else if (data.account_type === 'personal') {
10106
+ recommendations.push('Suitable for networking and personal connections');
10107
+ recommendations.push('May be used for freelance or consulting work');
10108
+ }
10109
+
10110
+ if (data.spam_risk_level === 'high') {
10111
+ recommendations.push('Consider verifying before important communications');
10112
+ }
10113
+
10114
+ if (!data.is_likely_active) {
10115
+ recommendations.push('Email may not be actively monitored');
10116
+ }
10117
+
10118
+ return recommendations;
10119
+ }
10120
+
10121
+ function generateVerificationSuggestions(data, emailContext) {
10122
+ const suggestions = [];
10123
+
10124
+ if (data.account_type === 'business' && !data.business_company_name) {
10125
+ suggestions.push('Verify company name through LinkedIn or company website');
10126
+ }
10127
+
10128
+ if (!data.is_real_person && data.account_type === 'business') {
10129
+ suggestions.push('Check if this is a role-based email that forwards to individuals');
10130
+ }
10131
+
10132
+ if (data.spam_risk_level === 'medium' || data.spam_risk_level === 'high') {
10133
+ suggestions.push('Send verification email before important communications');
10134
+ }
10135
+
10136
+ if (data.domain_analysis.is_custom_domain) {
10137
+ suggestions.push('Check company website for email format patterns');
10138
+ }
10139
+
10140
+ return suggestions;
10141
+ }
10142
+
10143
+ function getDefaultEmailAnalysis(name, email, emailContext = '', error = null) {
10144
+ const domain = email.split('@')[1] || '';
10145
+ const localPart = email.split('@')[0] || '';
10146
+ const nameParts = name.toLowerCase().split(/\s+/);
10147
+ const firstName = nameParts[0] || '';
10148
+ const lastName = nameParts.slice(-1)[0] || '';
10149
+
10150
+ const isPublicProvider = isPublicEmailProvider(domain);
10151
+ const accountType = isPublicProvider ? 'personal' : 'business';
10152
+ const isRealPerson = detectRealPerson(localPart, name, domain);
10153
+
10154
+ return {
10155
+ success: false,
10156
+ account_type: accountType,
10157
+ account_type_confidence: 70,
10158
+
10159
+ personal_account_provider: isPublicProvider ? identifyPersonalProvider(domain) : undefined,
10160
+ personal_account_type: 'unknown',
10161
+ personal_account_age_indicator: 'unknown',
10162
+
10163
+ business_company_name: !isPublicProvider ? inferCompanyFromDomain(domain) : undefined,
10164
+ business_company_domain: !isPublicProvider ? domain : undefined,
10165
+ business_account_category: !isPublicProvider ? (isRealPerson ? 'personal_employee' : 'generic_role') : undefined,
10166
+ business_account_role: undefined,
10167
+ business_department: undefined,
10168
+
10169
+ is_real_person: isRealPerson,
10170
+ person_name_in_email: checkNameInEmail(localPart, firstName, lastName),
10171
+ person_title_inferred: undefined,
10172
+
10173
+ email_pattern: analyzeEmailPattern(localPart, domain),
10174
+
10175
+ context_supports_business: undefined,
10176
+ context_supports_personal: undefined,
10177
+ context_company_mentions: [],
10178
+
10179
+ is_high_quality_contact: isRealPerson && !isPublicProvider,
10180
+ is_likely_active: true,
10181
+ spam_risk_level: assessSpamRisk(localPart, domain, accountType),
10182
+
10183
+ suggested_use_case: isRealPerson && !isPublicProvider ? 'sales_outreach' : 'networking',
10184
+
10185
+ analysis_timestamp: new Date().toISOString(),
10186
+ analysis_notes: ['Default analysis due to API failure'],
10187
+
10188
+ // Enhanced fields
10189
+ domain_analysis: {
10190
+ domain: domain,
10191
+ is_public_provider: isPublicProvider,
10192
+ is_custom_domain: isCustomDomain(domain),
10193
+ is_free_email: isFreeEmailDomain(domain),
10194
+ is_education: isEducationDomain(domain),
10195
+ is_government: isGovernmentDomain(domain),
10196
+ tld: domain.split('.').pop() || '',
10197
+ },
10198
+
10199
+ name_email_correlation: calculateNameEmailCorrelation(localPart, firstName, lastName),
10200
+ professional_score: calculateProfessionalScore({
10201
+ account_type: accountType,
10202
+ is_real_person: isRealPerson,
10203
+ is_likely_active: true,
10204
+ spam_risk_level: assessSpamRisk(localPart, domain, accountType),
10205
+ name_email_correlation: calculateNameEmailCorrelation(localPart, firstName, lastName),
10206
+ business_account_category: !isPublicProvider ? (isRealPerson ? 'personal_employee' : 'generic_role') : undefined,
10207
+ }),
10208
+
10209
+ recommendations: generateRecommendations({
10210
+ account_type: accountType,
10211
+ is_real_person: isRealPerson,
10212
+ business_account_category: !isPublicProvider ? (isRealPerson ? 'personal_employee' : 'generic_role') : undefined,
10213
+ spam_risk_level: assessSpamRisk(localPart, domain, accountType),
10214
+ is_likely_active: true,
10215
+ }),
10216
+
10217
+ verification_suggestions: generateVerificationSuggestions(
10218
+ {
10219
+ account_type: accountType,
10220
+ business_company_name: !isPublicProvider ? inferCompanyFromDomain(domain) : undefined,
10221
+ is_real_person: isRealPerson,
10222
+ spam_risk_level: assessSpamRisk(localPart, domain, accountType),
10223
+ domain_analysis: { is_custom_domain: isCustomDomain(domain) },
10224
+ },
10225
+ emailContext,
10226
+ ),
10227
+
10228
+ error: error || 'API call failed',
10229
+ };
10230
+ }
10231
+
10232
+ const analysis_ret = await submit_chat_gpt_prompt({
10233
+ uid,
10234
+ prompt: `Analyze this email account: "${email}" for person: "${name}"
10235
+
10236
+ EMAIL CONTEXT (if provided):
10237
+ "${email_context.substring(0, 400)}${email_context.length > 400 ? '...' : ''}"
10238
+
10239
+ ANALYSIS TASKS:
10240
+ 1. Determine if this is a PERSONAL or BUSINESS email account
10241
+ 2. For BUSINESS accounts:
10242
+ - Identify the company/organization
10243
+ - Determine if this email belongs to a REAL PERSON at the company
10244
+ - Or if it's a generic/role-based account
10245
+ 3. For PERSONAL accounts:
10246
+ - Identify which personal email provider is used
10247
+ - Determine if it's likely a primary or secondary personal account
10248
+
10249
+ ANALYSIS CRITERIA:
10250
+ BUSINESS EMAIL INDICATORS:
10251
+ - Domain matches a known company (not public email providers)
10252
+ - Email format matches company naming conventions
10253
+ - Email is mentioned in professional context
10254
+ - Contains company-specific signature or details
10255
+
10256
+ PERSONAL EMAIL INDICATORS:
10257
+ - Domain is from public email providers (gmail.com, outlook.com, yahoo.com, etc.)
10258
+ - Email format is personal/creative
10259
+ - No company affiliation in context
10260
+ - Used for personal communications
10261
+
10262
+ PERSON VS GENERIC BUSINESS ACCOUNT:
10263
+ - PERSON: Contains personal name elements (john.doe@company.com)
10264
+ - GENERIC: info@, support@, sales@, contact@, hello@, noreply@, etc.
10265
+ - DEPARTMENT: hr@, finance@, marketing@, it@, etc.
10266
+
10267
+ COMPANY DETECTION:
10268
+ - Extract company from email domain when possible
10269
+ - Use name patterns to identify likely companies
10270
+ - Consider email context for company references
10271
+
10272
+ PROVIDE DETAILED ANALYSIS WITH CONFIDENCE LEVELS.`,
10273
+ model: 'gpt-4o-minai',
10274
+ response_format: z.object({
10275
+ // Primary Classification
10276
+ account_type: z.enum(['personal', 'business', 'ambiguous']),
10277
+ account_type_confidence: z.number().min(0).max(100),
10278
+
10279
+ // Personal Account Details
10280
+ personal_account_provider: z.string().optional().describe('Email provider for personal accounts'),
10281
+ personal_account_type: z.enum(['primary', 'secondary', 'disposable', 'unknown']).optional(),
10282
+ personal_account_age_indicator: z.enum(['new', 'established', 'old', 'unknown']).optional(),
10283
+
10284
+ // Business Account Details
10285
+ business_company_name: z.string().optional().describe('Company name if business account'),
10286
+ business_company_domain: z.string().optional().describe('Company domain'),
10287
+ business_account_category: z.enum(['personal_employee', 'generic_role', 'department', 'catch_all', 'unknown']).optional(),
10288
+ business_account_role: z.string().optional().describe('Role suggested by email address'),
10289
+ business_department: z.string().optional().describe('Department if applicable'),
10290
+
10291
+ // Person Analysis
10292
+ is_real_person: z.boolean().describe('Whether email belongs to a real person'),
10293
+ person_name_in_email: z.boolean().describe("Whether person's name appears in email address"),
10294
+ person_title_inferred: z.string().optional().describe('Inferred job title from email pattern'),
10295
+
10296
+ // Email Pattern Analysis
10297
+ email_pattern: z.enum([
10298
+ 'first.last@company.com',
10299
+ 'first.last@domain.com',
10300
+ 'firstlast@company.com',
10301
+ 'flast@company.com',
10302
+ 'first@company.com',
10303
+ 'f.last@company.com',
10304
+ 'initial.last@company.com',
10305
+ 'role@company.com',
10306
+ 'department@company.com',
10307
+ 'info@company.com',
10308
+ 'generic@company.com',
10309
+ 'personal@provider.com',
10310
+ 'custom@personal.com',
10311
+ 'unknown',
10312
+ ]),
10313
+
10314
+ // Context Analysis
10315
+ context_supports_business: z.boolean().optional().describe('Email context suggests business use'),
10316
+ context_supports_personal: z.boolean().optional().describe('Email context suggests personal use'),
10317
+ context_company_mentions: z.array(z.string()).optional().describe('Companies mentioned in context'),
10318
+
10319
+ // Risk & Quality Assessment
10320
+ is_high_quality_contact: z.boolean().describe('Good contact for professional outreach'),
10321
+ is_likely_active: z.boolean().describe('Email likely actively monitored'),
10322
+ spam_risk_level: z.enum(['low', 'medium', 'high', 'unknown']),
10323
+
10324
+ // Recommendations
10325
+ suggested_use_case: z.enum(['sales_outreach', 'recruitment', 'customer_support', 'partnership', 'networking', 'personal_contact', 'avoid']),
10326
+
10327
+ // Metadata
10328
+ analysis_timestamp: z.string().describe('When analysis was performed'),
10329
+ analysis_notes: z.array(z.string()).optional().describe('Key observations from analysis'),
10330
+ }),
10331
+ metadata: {
10332
+ func: 'analyze_email_account_type',
10333
+ person_name: name,
10334
+ person_email: email,
10335
+ has_email_context: !!email_context,
10336
+ email_length: email_context?.length || 0,
10337
+ },
10338
+ account_profile_info,
10339
+ tools: [{ type: 'web_search_preview' }],
10340
+ });
10341
+
10342
+ try {
10343
+ if (analysis_ret.code > -1) {
10344
+ const data = typeof analysis_ret.data === 'string' ? JSON.parse(analysis_ret.data) : analysis_ret.data;
10345
+
10346
+ // Enhance with additional analysis
10347
+ const enhancedData = enhanceEmailAnalysis(data, name, email, email_context);
10348
+
10349
+ return {
10350
+ success: true,
10351
+ ...enhancedData,
10352
+ };
10353
+ } else {
10354
+ console.error('Email analysis API call failed:', analysis_ret);
10355
+ return getDefaultEmailAnalysis(name, email, email_context);
10356
+ }
10357
+ } catch (error) {
10358
+ console.error('Error in analyze_email_account_type:', error);
10359
+ return getDefaultEmailAnalysis(name, email, email_context, error.message);
10360
+ }
10361
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xuda.io/ai_module",
3
- "version": "1.1.4679",
3
+ "version": "1.1.4680",
4
4
  "description": "Xuda AI Module",
5
5
  "main": "index.mjs",
6
6
  "type": "module",