@xuda.io/ai_module 1.1.4382 → 1.1.4384
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 +5 -272
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -5661,13 +5661,14 @@ const create_and_upload_image_to_drive = async function (drive_type, file_path,
|
|
|
5661
5661
|
};
|
|
5662
5662
|
|
|
5663
5663
|
export const create_account_profile_avatar = async function (req, job_id, headers) {
|
|
5664
|
-
const { uid } = req;
|
|
5664
|
+
const { uid, url } = req;
|
|
5665
5665
|
try {
|
|
5666
|
+
const account_profile_info = await get_active_account_profile_info(uid);
|
|
5666
5667
|
req.account_profile_info = await account_module.get_active_account_profile_info(uid);
|
|
5667
|
-
req.is_profile_avatar = true;
|
|
5668
|
+
// req.is_profile_avatar = true;
|
|
5668
5669
|
req.account_obj = await db_module.get_couch_doc_native('xuda_accounts', uid);
|
|
5669
5670
|
|
|
5670
|
-
return await get_profile_avatar(
|
|
5671
|
+
return await get_profile_avatar(url, uid, null, account_profile_info, 'business', 'account_profile', job_id, headers);
|
|
5671
5672
|
} catch (err) {
|
|
5672
5673
|
return {
|
|
5673
5674
|
code: -25,
|
|
@@ -5681,75 +5682,6 @@ export const get_profile_avatar = async function (profile_picture, uid, prompt,
|
|
|
5681
5682
|
const uniqueId = Date.now() + '_' + Math.random().toString(36).substring(7);
|
|
5682
5683
|
const tempOutputPath = path.join(tempDir, `output_${uniqueId}.png`);
|
|
5683
5684
|
|
|
5684
|
-
// const { url, uid, prompt, account_profile_info, account_type, docType = 'account', _id, metadata = {}, profile_picture, business_size = 'unknown', name, email } = req;
|
|
5685
|
-
|
|
5686
|
-
// async function normalizeBase64To1024(base64Image) {
|
|
5687
|
-
// const inputBuffer = Buffer.from(base64Image, 'base64');
|
|
5688
|
-
|
|
5689
|
-
// const normalizedBuffer = await sharp(inputBuffer)
|
|
5690
|
-
// .resize(1024, 1024, {
|
|
5691
|
-
// fit: 'contain', // Preserve aspect ratio, fit within 211x211
|
|
5692
|
-
// background: { r: 0, g: 0, b: 0, alpha: 0 }, // Transparent background for padding
|
|
5693
|
-
// })
|
|
5694
|
-
// .png({
|
|
5695
|
-
// quality: 100,
|
|
5696
|
-
// compressionLevel: 9,
|
|
5697
|
-
// force: true,
|
|
5698
|
-
// })
|
|
5699
|
-
// .toBuffer();
|
|
5700
|
-
|
|
5701
|
-
// return normalizedBuffer.toString('base64'); // Return normalized base64 string
|
|
5702
|
-
// }
|
|
5703
|
-
|
|
5704
|
-
// async function hasTransparentBackground(filePath) {
|
|
5705
|
-
// const image = sharp(filePath);
|
|
5706
|
-
// const metadata = await image.metadata();
|
|
5707
|
-
|
|
5708
|
-
// // If the image doesn't have an alpha channel at all → no transparency possible
|
|
5709
|
-
// if (!metadata.hasAlpha) {
|
|
5710
|
-
// return false;
|
|
5711
|
-
// }
|
|
5712
|
-
|
|
5713
|
-
// // For images with alpha channel, check if any pixel actually has alpha < 255
|
|
5714
|
-
// const { data, info } = await image.raw().toBuffer({ resolveWithObject: true });
|
|
5715
|
-
|
|
5716
|
-
// // Determine position of alpha channel based on number of channels
|
|
5717
|
-
// const channels = info.channels; // 2 (grayscale+alpha), 4 (RGBA), etc.
|
|
5718
|
-
// const alphaOffset = channels === 2 ? 1 : channels === 4 ? 3 : -1;
|
|
5719
|
-
|
|
5720
|
-
// if (alphaOffset === -1) {
|
|
5721
|
-
// // Unusual channel count – be conservative and assume it might have transparency
|
|
5722
|
-
// return true;
|
|
5723
|
-
// }
|
|
5724
|
-
|
|
5725
|
-
// for (let i = alphaOffset; i < data.length; i += channels) {
|
|
5726
|
-
// if (data[i] < 255) {
|
|
5727
|
-
// return true; // Found at least one transparent/semi-transparent pixel
|
|
5728
|
-
// }
|
|
5729
|
-
// }
|
|
5730
|
-
|
|
5731
|
-
// return false; // Has alpha channel but all pixels are fully opaque
|
|
5732
|
-
// }
|
|
5733
|
-
|
|
5734
|
-
// async function imageToPngBlob(filePath) {
|
|
5735
|
-
// const ext = path.extname(filePath).toLowerCase();
|
|
5736
|
-
|
|
5737
|
-
// let buffer;
|
|
5738
|
-
|
|
5739
|
-
// let is_transparent = false;
|
|
5740
|
-
// if (ext === '.png') {
|
|
5741
|
-
// buffer = await fs.promises.readFile(filePath);
|
|
5742
|
-
// is_transparent = await hasTransparentBackground(filePath);
|
|
5743
|
-
// } else {
|
|
5744
|
-
// console.log(`Converting ${path.basename(filePath)} to PNG...`);
|
|
5745
|
-
// buffer = await sharp(filePath).png({ quality: 100, compressionLevel: 9, force: true }).toBuffer();
|
|
5746
|
-
// }
|
|
5747
|
-
|
|
5748
|
-
// // Create a Blob with correct MIME type
|
|
5749
|
-
|
|
5750
|
-
// return { is_transparent, image_blob: new Blob([buffer], { type: 'image/png' }) };
|
|
5751
|
-
// }
|
|
5752
|
-
|
|
5753
5685
|
const detect_real_person_in_image = async function (base64) {
|
|
5754
5686
|
const ret = await submit_chat_gpt_prompt({
|
|
5755
5687
|
uid,
|
|
@@ -5780,60 +5712,14 @@ export const get_profile_avatar = async function (profile_picture, uid, prompt,
|
|
|
5780
5712
|
return res?.is_real_person_in_picture;
|
|
5781
5713
|
};
|
|
5782
5714
|
|
|
5783
|
-
// const drive_module = await import(`${module_path}/drive_module/index.mjs`);
|
|
5784
|
-
|
|
5785
|
-
// if (!is_profile_avatar) {
|
|
5786
|
-
// await update_profile_avatar_status(account_obj._id, 2);
|
|
5787
|
-
// }
|
|
5788
5715
|
try {
|
|
5789
|
-
// if (!url) {
|
|
5790
|
-
// throw new Error('No URL provided in request');
|
|
5791
|
-
// }
|
|
5792
|
-
|
|
5793
|
-
// 3. Download the image to a Buffer
|
|
5794
|
-
// const res = await fetch(url);
|
|
5795
|
-
// if (!res.ok) {
|
|
5796
|
-
// throw new Error(`Failed to fetch image URL: ${res.status} ${res.statusText}`);
|
|
5797
|
-
// }
|
|
5798
|
-
|
|
5799
|
-
// const arrayBuffer = await res.arrayBuffer();
|
|
5800
|
-
// const imageBuffer = Buffer.from(arrayBuffer);
|
|
5801
|
-
|
|
5802
|
-
// const tempDir = os.tmpdir();
|
|
5803
|
-
// const uniqueId = Date.now() + '_' + Math.random().toString(36).substring(7);
|
|
5804
|
-
|
|
5805
|
-
// const inputExt = path.extname(url) || '.jpg';
|
|
5806
|
-
// const tempInputPath = path.join(tempDir, `input_${uniqueId}${inputExt}`);
|
|
5807
|
-
// const tempOutputPath = path.join(tempDir, `output_${uniqueId}.png`); // Output is always PNG (transparent)
|
|
5808
|
-
|
|
5809
|
-
// 5. Write the downloaded image to disk
|
|
5810
|
-
// fs.writeFileSync(tempInputPath, imageBuffer);
|
|
5811
|
-
/////////////////////////////////
|
|
5812
|
-
|
|
5813
|
-
// const imageFiles = [tempInputPath];
|
|
5814
|
-
|
|
5815
|
-
// const images = await Promise.all(
|
|
5816
|
-
// imageFiles.map(async (filePath) => {
|
|
5817
|
-
// const img_ret = await imageToPngBlob(filePath);
|
|
5818
|
-
// const blob = img_ret.image_blob;
|
|
5819
|
-
|
|
5820
|
-
// // OpenAI expects a filename for logging/debugging
|
|
5821
|
-
// const filename = path.basename(filePath, path.extname(filePath)) + '.png';
|
|
5822
|
-
// blob.name = filename; // Optional but helpful
|
|
5823
|
-
// // @ts-ignore – name is allowed in Node 20+
|
|
5824
|
-
// blob.lastModified = Date.now();
|
|
5825
|
-
|
|
5826
|
-
// return { is_transparent: img_ret.is_transparent, image_blob: blob };
|
|
5827
|
-
// }),
|
|
5828
|
-
// );
|
|
5829
|
-
|
|
5830
5716
|
let imageBase64;
|
|
5831
5717
|
const image_blob_ret = await get_image_blob_from_downloaded_image(profile_picture);
|
|
5832
5718
|
let avatar_source = '';
|
|
5833
5719
|
if (prompt) {
|
|
5834
5720
|
const model = 'chatgpt-image-latest';
|
|
5835
5721
|
const ai_avatar_response = await client.images.edit({
|
|
5836
|
-
model,
|
|
5722
|
+
model,
|
|
5837
5723
|
image: image_blob_ret.image_blob, //base photo
|
|
5838
5724
|
prompt,
|
|
5839
5725
|
background: 'transparent',
|
|
@@ -5841,30 +5727,10 @@ export const get_profile_avatar = async function (profile_picture, uid, prompt,
|
|
|
5841
5727
|
imageBase64 = ai_avatar_response.data[0].b64_json;
|
|
5842
5728
|
record_chat_usage(uid, ai_avatar_response.usage.input_tokens, ai_avatar_response.usage.output_tokens, 'profile avatar', prompt, model, { profile_picture }, account_profile_info);
|
|
5843
5729
|
} else {
|
|
5844
|
-
//////////////////
|
|
5845
5730
|
imageBase64 = Buffer.from(await image_blob_ret.image_blob.arrayBuffer()).toString('base64');
|
|
5846
5731
|
if (account_type === 'business') {
|
|
5847
5732
|
// create avatar from logo - BUSINESS
|
|
5848
5733
|
const { bio, country, mainCategory, subCategory } = metadata;
|
|
5849
|
-
// const ai_avatar_response = await client.images.edit({
|
|
5850
|
-
// model: 'chatgpt-image-latest',
|
|
5851
|
-
// image: image_blob_ret.image_blob, // only one image allowed
|
|
5852
|
-
// prompt: `Generate a realistic fictional portrait wearing a hat. The portrait should be centered, head-and-shoulders only, on a transparent background. Place the provided logo on the hat, and ensure the subject is large enough to fill most of the frame. Use the supplied name, country, and context to guide the character’s appearance.
|
|
5853
|
-
// Context: ${JSON.stringify({ bio, business_name, country, mainCategory, subCategory })}`,
|
|
5854
|
-
// background: 'transparent',
|
|
5855
|
-
// });
|
|
5856
|
-
///////////////////
|
|
5857
|
-
// const ai_avatar_response = await client.images.edit({
|
|
5858
|
-
// model: 'chatgpt-image-latest',
|
|
5859
|
-
// image: image_blob_ret.image_blob, //base photo
|
|
5860
|
-
// prompt: `Create a transparent PNG profile image for a business account featuring building branded as ${business_name}.
|
|
5861
|
-
// Display the attached logo clearly as prominent exterior signage.
|
|
5862
|
-
// The building’s architecture and overall atmosphere should reflect the nature of the business, aligning with ${mainCategory} and ${subCategory}.
|
|
5863
|
-
// Use the provided bio (${bio}) to understand the company’s focus and personality, and adapt the architectural style to match the ${country} country’s local design language. Select an appropriate building type for the specific business category, and present a contemporary,
|
|
5864
|
-
// creative office environment with a strong, recognizable brand identity. The background should be fully removed, remove trees,clouds,sky or any landscape objects`,
|
|
5865
|
-
// background: 'transparent',
|
|
5866
|
-
// });
|
|
5867
|
-
/////////////////
|
|
5868
5734
|
|
|
5869
5735
|
// const obj = {
|
|
5870
5736
|
// free: {
|
|
@@ -7008,139 +6874,6 @@ const get_image_blob_from_downloaded_image = async function (url) {
|
|
|
7008
6874
|
return images[0];
|
|
7009
6875
|
};
|
|
7010
6876
|
|
|
7011
|
-
// export const get_business_info = async function (uid, name, email, account_profile_info) {
|
|
7012
|
-
// // 1. Prepare the valid values from your categories list
|
|
7013
|
-
// const categories = [
|
|
7014
|
-
// {
|
|
7015
|
-
// id: 'ind_technology',
|
|
7016
|
-
// name: 'Technology',
|
|
7017
|
-
// sub: ['Software Development', 'AI & Machine Learning', 'Cybersecurity', 'Cloud Computing', 'IT Services', 'SaaS & Platforms', 'Hardware & Electronics'],
|
|
7018
|
-
// },
|
|
7019
|
-
// {
|
|
7020
|
-
// id: 'ind_marketing',
|
|
7021
|
-
// name: 'Marketing & Advertising',
|
|
7022
|
-
// sub: ['Digital Marketing', 'PPC & SEO', 'Content Creation', 'Branding', 'Social Media Management', 'Email Marketing', 'Market Research'],
|
|
7023
|
-
// },
|
|
7024
|
-
// {
|
|
7025
|
-
// id: 'ind_sales',
|
|
7026
|
-
// name: 'Sales',
|
|
7027
|
-
// sub: ['B2B Sales', 'B2C Sales', 'Real Estate Sales', 'Account Management', 'Lead Generation', 'Inside Sales', 'Field Sales'],
|
|
7028
|
-
// },
|
|
7029
|
-
// {
|
|
7030
|
-
// id: 'ind_finance',
|
|
7031
|
-
// name: 'Finance & Accounting',
|
|
7032
|
-
// sub: ['Banking', 'Investment', 'Financial Planning', 'Accounting', 'Bookkeeping', 'Insurance', 'FinTech'],
|
|
7033
|
-
// },
|
|
7034
|
-
// {
|
|
7035
|
-
// id: 'ind_healthcare',
|
|
7036
|
-
// name: 'Healthcare',
|
|
7037
|
-
// sub: ['Medical Clinics', 'Hospitals', 'Pharma', 'Mental Health', 'Healthcare IT', 'Home Care', 'Medical Research'],
|
|
7038
|
-
// },
|
|
7039
|
-
// {
|
|
7040
|
-
// id: 'ind_realestate',
|
|
7041
|
-
// name: 'Real Estate',
|
|
7042
|
-
// sub: ['Residential Real Estate', 'Commercial Real Estate', 'Property Management', 'Investment & BRRRR', 'Construction', 'Architecture', 'Interior Design'],
|
|
7043
|
-
// },
|
|
7044
|
-
// {
|
|
7045
|
-
// id: 'ind_ecommerce',
|
|
7046
|
-
// name: 'E-commerce',
|
|
7047
|
-
// sub: ['Online Store', 'Dropshipping', 'Amazon FBA', 'Marketplace Selling', 'Retail', 'Inventory Management', 'Fulfillment & Logistics'],
|
|
7048
|
-
// },
|
|
7049
|
-
// {
|
|
7050
|
-
// id: 'ind_education',
|
|
7051
|
-
// name: 'Education',
|
|
7052
|
-
// sub: ['Schools', 'Universities', 'Private Tutoring', 'Online Courses', 'EdTech', 'Training & Development'],
|
|
7053
|
-
// },
|
|
7054
|
-
// {
|
|
7055
|
-
// id: 'ind_hospitality',
|
|
7056
|
-
// name: 'Hospitality & Travel',
|
|
7057
|
-
// sub: ['Hotels', 'Restaurants', 'Cafes & Bars', 'Travel Agencies', 'Tourism', 'Events & Catering', 'Transportation'],
|
|
7058
|
-
// },
|
|
7059
|
-
// {
|
|
7060
|
-
// id: 'ind_professional',
|
|
7061
|
-
// name: 'Professional Services',
|
|
7062
|
-
// sub: ['Legal', 'Consulting', 'HR & Recruiting', 'Accounting Firms', 'Business Services', 'Management Consulting'],
|
|
7063
|
-
// },
|
|
7064
|
-
// {
|
|
7065
|
-
// id: 'ind_manufacturing',
|
|
7066
|
-
// name: 'Manufacturing',
|
|
7067
|
-
// sub: ['Automotive', 'Industrial', 'Textile', 'Electronics', 'Food Production', 'Machinery', 'Chemicals'],
|
|
7068
|
-
// },
|
|
7069
|
-
// {
|
|
7070
|
-
// id: 'ind_nonprofit',
|
|
7071
|
-
// name: 'Nonprofit & Government',
|
|
7072
|
-
// sub: ['NGOs', 'Municipality', 'Government Services', 'Public Health', 'Community Organizations', 'Education Programs'],
|
|
7073
|
-
// },
|
|
7074
|
-
// {
|
|
7075
|
-
// id: 'ind_media',
|
|
7076
|
-
// name: 'Media & Entertainment',
|
|
7077
|
-
// sub: ['Film & Video', 'Music', 'Publishing', 'Gaming', 'News & Journalism', 'Influencers', 'Production Studios'],
|
|
7078
|
-
// },
|
|
7079
|
-
// {
|
|
7080
|
-
// id: 'ind_logistics',
|
|
7081
|
-
// name: 'Logistics & Transportation',
|
|
7082
|
-
// sub: ['Shipping', 'Trucking', 'Last-Mile Delivery', 'Warehousing', 'Freight Forwarding', 'Route Optimization'],
|
|
7083
|
-
// },
|
|
7084
|
-
// {
|
|
7085
|
-
// id: 'ind_energy',
|
|
7086
|
-
// name: 'Energy & Utilities',
|
|
7087
|
-
// sub: ['Solar', 'Oil & Gas', 'Electricity Providers', 'Water Utilities', 'Environmental Services', 'Renewable Energy'],
|
|
7088
|
-
// },
|
|
7089
|
-
// {
|
|
7090
|
-
// id: 'ind_construction',
|
|
7091
|
-
// name: 'Construction & Trades',
|
|
7092
|
-
// sub: ['General Contracting', 'Roofing', 'Plumbing', 'HVAC', 'Electrical', 'Renovation', 'Engineering'],
|
|
7093
|
-
// },
|
|
7094
|
-
// {
|
|
7095
|
-
// id: 'ind_food',
|
|
7096
|
-
// name: 'Food & Beverage',
|
|
7097
|
-
// sub: ['Restaurants', 'Catering', 'Food Manufacturing', 'Bakeries', 'Bars & Nightlife', 'Food Delivery'],
|
|
7098
|
-
// },
|
|
7099
|
-
// {
|
|
7100
|
-
// id: 'ind_retail',
|
|
7101
|
-
// name: 'Retail',
|
|
7102
|
-
// sub: ['Physical Stores', 'Boutiques', 'Supermarkets', 'Consumer Goods', 'Fashion Retail', 'Home Goods'],
|
|
7103
|
-
// },
|
|
7104
|
-
// ];
|
|
7105
|
-
// // Prepare enums for the model
|
|
7106
|
-
// const categoryNames = categories.map((c) => c.name);
|
|
7107
|
-
// const allSubCategories = categories.flatMap((c) => c.sub);
|
|
7108
|
-
|
|
7109
|
-
// const business_info_ret = await submit_chat_gpt_prompt({
|
|
7110
|
-
// uid,
|
|
7111
|
-
// prompt: `Research the company: "${name}" (${email}).
|
|
7112
|
-
// Tasks:
|
|
7113
|
-
// 1. Identify the company size.
|
|
7114
|
-
// 2. Select the most accurate Industry Category and Sub-Category from the provided lists.
|
|
7115
|
-
// 3. Identify the primary country and return its ISO 3166-1 alpha-2 code (e.g., 'US', 'GB', 'IL').`,
|
|
7116
|
-
// model: 'gpt-5-nano',
|
|
7117
|
-
// response_format: z.object({
|
|
7118
|
-
// business_size: z.enum(['unknown', 'small', 'medium', 'large', 'enterprise']),
|
|
7119
|
-
// business_category: z.enum(categoryNames),
|
|
7120
|
-
// business_sub_category: z.enum(allSubCategories),
|
|
7121
|
-
// business_country: z.string().length(2).describe("The 2-letter ISO country code, e.g., 'US'"),
|
|
7122
|
-
// }),
|
|
7123
|
-
// metadata: { func: 'get_business_info' },
|
|
7124
|
-
// account_profile_info,
|
|
7125
|
-
// tools: [{ type: 'web_search_preview' }],
|
|
7126
|
-
// });
|
|
7127
|
-
|
|
7128
|
-
// try {
|
|
7129
|
-
// if (business_info_ret.code > -1) {
|
|
7130
|
-
// const data = typeof business_info_ret.data === 'string' ? JSON.parse(business_info_ret.data) : business_info_ret.data;
|
|
7131
|
-
|
|
7132
|
-
// // Ensure the country code is always uppercase
|
|
7133
|
-
// if (data.business_country) {
|
|
7134
|
-
// data.business_country = data.business_country.toUpperCase();
|
|
7135
|
-
// }
|
|
7136
|
-
|
|
7137
|
-
// return data;
|
|
7138
|
-
// }
|
|
7139
|
-
// } catch (error) {
|
|
7140
|
-
// console.error('Error processing business info:', error);
|
|
7141
|
-
// }
|
|
7142
|
-
// };
|
|
7143
|
-
|
|
7144
6877
|
export const get_business_info = async function (uid, name, email, account_profile_info) {
|
|
7145
6878
|
// Extract lists from your JSON categories array
|
|
7146
6879
|
const categories = [
|