@xuda.io/ai_module 1.1.4865 → 1.1.4867

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 +188 -188
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -5470,6 +5470,194 @@ export const get_profile_avatar = async function (profile_picture, uid, prompt,
5470
5470
  }
5471
5471
  };
5472
5472
 
5473
+ export const get_profile_picture = async function (uid, account_type = 'business', name, metadata = {}, account_profile_info, job_id, headers = {}) {
5474
+ const tempDir = os.tmpdir();
5475
+ const uniqueId = Date.now() + '_' + Math.random().toString(36).substring(7);
5476
+ const tempOutputPath = path.join(tempDir, `output_${uniqueId}.png`);
5477
+
5478
+ const { email, create_avatar } = metadata;
5479
+
5480
+ let prompt,
5481
+ url,
5482
+ factual_prompt,
5483
+ originalname,
5484
+ factual_image_mode,
5485
+ imageBase64,
5486
+ image_blob_ret,
5487
+ file,
5488
+ profile_picture_source,
5489
+ drive_ret = { code: 1, data: {} },
5490
+ resize = {};
5491
+
5492
+ switch (account_type) {
5493
+ case 'personal': {
5494
+ prompt = `find "${name}" person profile image base on the following facts: "${JSON.stringify(metadata)}", Return only png,jpg image url single result e.g: "https://fb.com/person_image.png", nothing else`;
5495
+ factual_prompt = `analyze the the person info base on the name and the facts: {"name": "${name || ''}", facts: "${JSON.stringify(
5496
+ metadata,
5497
+ )}" and create realistic fictional profile picture transparent background ,person in the center of the picture add top margin the person should cover the whole picture`;
5498
+ originalname = normalizeFilename(name) + '_xu_profile.png';
5499
+ resize = {
5500
+ fit: 'inside', // Scale up/down to fit inside 1024×1024 while preserving aspect ratio
5501
+ withoutEnlargement: false, // Allow enlargement if original is smaller
5502
+ background: { r: 0, g: 0, b: 0, alpha: 0 },
5503
+ };
5504
+ break;
5505
+ }
5506
+
5507
+ case 'business': {
5508
+ prompt = `Search for a large, high-quality "${name}" logo or icon in PNG or JPG format. Output **exclusively** a single valid image URL, like this: "https://example.com/large-logo.png". Do not include any other text, descriptions, or additional information.`;
5509
+ factual_prompt = `create logo for the company named: "${name}" the logo should only be initials of the name or geometric shape`;
5510
+ originalname = normalizeFilename(name) + '_xu_logo.png';
5511
+ resize = {
5512
+ fit: 'cover', // Fill the 1024×1024 area (may crop edges)
5513
+ position: 'centre', // Center the crop
5514
+ background: { r: 0, g: 0, b: 0, alpha: 0 },
5515
+ };
5516
+ break;
5517
+ }
5518
+
5519
+ default:
5520
+ throw new Error('account_type not supported');
5521
+ break;
5522
+ }
5523
+
5524
+ const getUserPhotoByEmail = async function (email) {
5525
+ try {
5526
+ const auth = admin.auth();
5527
+ const userRecord = await auth.getUserByEmail(email);
5528
+
5529
+ // photoURL is the profile picture URL (or null if not set)
5530
+ const photoURL = userRecord.photoURL;
5531
+ // console.log(`User found: ${JSON.stringify(userRecord)}`);
5532
+
5533
+ // console.log(`User found: ${userRecord.uid}`);
5534
+ // console.log(`Display name: ${userRecord.displayName || 'None'}`);
5535
+ // console.log(`Email verified: ${userRecord.emailVerified}`);
5536
+ // console.log(`Profile picture URL: ${photoURL || 'No photo set'}`);
5537
+
5538
+ return photoURL;
5539
+ } catch (error) {
5540
+ if (error.code === 'auth/user-not-found') {
5541
+ console.log('getUserPhotoByEmail', `No user found with email: ${email}`);
5542
+ return null;
5543
+ }
5544
+
5545
+ console.error('Error fetching user:', error);
5546
+ // throw error;
5547
+ }
5548
+ };
5549
+
5550
+ const get_url = async function () {
5551
+ const ret = await submit_chat_gpt_prompt({
5552
+ uid,
5553
+ prompt,
5554
+ model: 'gpt-5-nano',
5555
+ metadata: { func: 'get_profile_picture' },
5556
+ account_profile_info,
5557
+ tools: [{ type: 'web_search_preview' }],
5558
+ });
5559
+
5560
+ return ret.data;
5561
+ };
5562
+
5563
+ // debugger;
5564
+ try {
5565
+ url = await getUserPhotoByEmail(email);
5566
+ if (url) {
5567
+ try {
5568
+ image_blob_ret = await get_image_blob_from_downloaded_image(url);
5569
+ profile_picture_source = 'google';
5570
+ drive_ret.data = { file_url: url };
5571
+ } catch (err) {
5572
+ if (!err.message.includes('Failed to fetch image URL')) {
5573
+ console.error(err);
5574
+ return '';
5575
+ }
5576
+ url = '';
5577
+ }
5578
+ }
5579
+
5580
+ if (!url && create_avatar) {
5581
+ // first attempt
5582
+ if (account_type === 'business') {
5583
+ url = await get_url();
5584
+
5585
+ if (url.substr(0, 8) !== 'https://') {
5586
+ profile_picture_source = 'factual';
5587
+ // second attempt
5588
+ url = await get_url();
5589
+ if (url.substr(0, 8) !== 'https://') {
5590
+ factual_image_mode = true;
5591
+ profile_picture_source = 'factual';
5592
+ }
5593
+ } else {
5594
+ // success
5595
+ profile_picture_source = 'internet search';
5596
+ try {
5597
+ image_blob_ret = await get_image_blob_from_downloaded_image(url);
5598
+ } catch (err) {
5599
+ if (!err.message.includes('Failed to fetch image URL')) {
5600
+ console.error(err);
5601
+ return '';
5602
+ }
5603
+ profile_picture_source = 'factual';
5604
+ factual_image_mode = true;
5605
+ }
5606
+ }
5607
+ } else {
5608
+ factual_image_mode = true;
5609
+ profile_picture_source = 'factual';
5610
+ }
5611
+
5612
+ if (factual_image_mode) {
5613
+ imageBase64 = await create_image(uid, factual_prompt, undefined, undefined, 1, undefined, undefined, {}, account_profile_info);
5614
+ } else {
5615
+ const model = 'gpt-image-1-mini'; // 'chatgpt-image-latest';
5616
+ const prompt = `
5617
+ extract the logo from the image
5618
+ `;
5619
+ let image_response;
5620
+ try {
5621
+ image_response = await client.images.edit({
5622
+ model,
5623
+ image: image_blob_ret.image_blob,
5624
+ prompt,
5625
+ background: 'transparent',
5626
+ });
5627
+ report_ai_status(model);
5628
+ } catch (err) {
5629
+ report_ai_status(model, err);
5630
+ throw err;
5631
+ }
5632
+
5633
+ imageBase64 = await normalizeBase64To1024(image_response.data[0].b64_json, resize);
5634
+ account_module.record_ai_usage(uid, image_response.usage.input_tokens, image_response.usage.output_tokens, 'profile image', prompt, model, { url }, account_profile_info);
5635
+ }
5636
+
5637
+ const outputBuffer = Buffer.from(imageBase64, 'base64');
5638
+ const outputPath = tempOutputPath;
5639
+ await fs.promises.writeFile(outputPath, outputBuffer);
5640
+
5641
+ console.log('Success! Saved →', outputPath);
5642
+
5643
+ console.log(file);
5644
+
5645
+ const file_obj = {
5646
+ originalname,
5647
+ path: outputPath,
5648
+ mimetype: `image/png`,
5649
+ };
5650
+
5651
+ drive_ret = await drive_module.upload_drive_file_user({ uid, path: '/Profile Images' }, job_id, headers, file_obj);
5652
+ drive_ret.profile_picture_source = profile_picture_source;
5653
+ }
5654
+ return drive_ret;
5655
+ } catch (err) {
5656
+ console.error(err);
5657
+ return;
5658
+ }
5659
+ };
5660
+
5473
5661
  export const conversation_actions = async function (req, job_id, headers) {
5474
5662
  const { conversation_id, item_id, action, uid, account_profile_info } = req;
5475
5663
  try {
@@ -6154,194 +6342,6 @@ function normalizeFilename(name) {
6154
6342
  .replace(/^_+|_+$/g, ''); // trim leading/trailing underscores
6155
6343
  }
6156
6344
 
6157
- export const get_profile_picture = async function (uid, account_type = 'business', name, metadata = {}, account_profile_info, job_id, headers = {}) {
6158
- const tempDir = os.tmpdir();
6159
- const uniqueId = Date.now() + '_' + Math.random().toString(36).substring(7);
6160
- const tempOutputPath = path.join(tempDir, `output_${uniqueId}.png`);
6161
-
6162
- const { email, create_avatar } = metadata;
6163
-
6164
- let prompt,
6165
- url,
6166
- factual_prompt,
6167
- originalname,
6168
- factual_image_mode,
6169
- imageBase64,
6170
- image_blob_ret,
6171
- file,
6172
- profile_picture_source,
6173
- drive_ret = { code: 1, data: {} },
6174
- resize = {};
6175
-
6176
- switch (account_type) {
6177
- case 'personal': {
6178
- prompt = `find "${name}" person profile image base on the following facts: "${JSON.stringify(metadata)}", Return only png,jpg image url single result e.g: "https://fb.com/person_image.png", nothing else`;
6179
- factual_prompt = `analyze the the person info base on the name and the facts: {"name": "${name || ''}", facts: "${JSON.stringify(
6180
- metadata,
6181
- )}" and create realistic fictional profile picture transparent background ,person in the center of the picture add top margin the person should cover the whole picture`;
6182
- originalname = normalizeFilename(name) + '_xu_profile.png';
6183
- resize = {
6184
- fit: 'inside', // Scale up/down to fit inside 1024×1024 while preserving aspect ratio
6185
- withoutEnlargement: false, // Allow enlargement if original is smaller
6186
- background: { r: 0, g: 0, b: 0, alpha: 0 },
6187
- };
6188
- break;
6189
- }
6190
-
6191
- case 'business': {
6192
- prompt = `Search for a large, high-quality "${name}" logo or icon in PNG or JPG format. Output **exclusively** a single valid image URL, like this: "https://example.com/large-logo.png". Do not include any other text, descriptions, or additional information.`;
6193
- factual_prompt = `create logo for the company named: "${name}" the logo should only be initials of the name or geometric shape`;
6194
- originalname = normalizeFilename(name) + '_xu_logo.png';
6195
- resize = {
6196
- fit: 'cover', // Fill the 1024×1024 area (may crop edges)
6197
- position: 'centre', // Center the crop
6198
- background: { r: 0, g: 0, b: 0, alpha: 0 },
6199
- };
6200
- break;
6201
- }
6202
-
6203
- default:
6204
- throw new Error('account_type not supported');
6205
- break;
6206
- }
6207
-
6208
- const getUserPhotoByEmail = async function (email) {
6209
- try {
6210
- const auth = admin.auth();
6211
- const userRecord = await auth.getUserByEmail(email);
6212
-
6213
- // photoURL is the profile picture URL (or null if not set)
6214
- const photoURL = userRecord.photoURL;
6215
- // console.log(`User found: ${JSON.stringify(userRecord)}`);
6216
-
6217
- // console.log(`User found: ${userRecord.uid}`);
6218
- // console.log(`Display name: ${userRecord.displayName || 'None'}`);
6219
- // console.log(`Email verified: ${userRecord.emailVerified}`);
6220
- // console.log(`Profile picture URL: ${photoURL || 'No photo set'}`);
6221
-
6222
- return photoURL;
6223
- } catch (error) {
6224
- if (error.code === 'auth/user-not-found') {
6225
- console.log(`No user found with email: ${email}`);
6226
- return null;
6227
- }
6228
-
6229
- console.error('Error fetching user:', error);
6230
- // throw error;
6231
- }
6232
- };
6233
-
6234
- const get_url = async function () {
6235
- const ret = await submit_chat_gpt_prompt({
6236
- uid,
6237
- prompt,
6238
- model: 'gpt-5-nano',
6239
- metadata: { func: 'get_profile_picture' },
6240
- account_profile_info,
6241
- tools: [{ type: 'web_search_preview' }],
6242
- });
6243
-
6244
- return ret.data;
6245
- };
6246
-
6247
- // debugger;
6248
- try {
6249
- url = await getUserPhotoByEmail(email);
6250
- if (url) {
6251
- try {
6252
- image_blob_ret = await get_image_blob_from_downloaded_image(url);
6253
- profile_picture_source = 'google';
6254
- drive_ret.data = { file_url: url };
6255
- } catch (err) {
6256
- if (!err.message.includes('Failed to fetch image URL')) {
6257
- console.error(err);
6258
- return '';
6259
- }
6260
- url = '';
6261
- }
6262
- }
6263
-
6264
- if (!url && create_avatar) {
6265
- // first attempt
6266
- if (account_type === 'business') {
6267
- url = await get_url();
6268
-
6269
- if (url.substr(0, 8) !== 'https://') {
6270
- profile_picture_source = 'factual';
6271
- // second attempt
6272
- url = await get_url();
6273
- if (url.substr(0, 8) !== 'https://') {
6274
- factual_image_mode = true;
6275
- profile_picture_source = 'factual';
6276
- }
6277
- } else {
6278
- // success
6279
- profile_picture_source = 'internet search';
6280
- try {
6281
- image_blob_ret = await get_image_blob_from_downloaded_image(url);
6282
- } catch (err) {
6283
- if (!err.message.includes('Failed to fetch image URL')) {
6284
- console.error(err);
6285
- return '';
6286
- }
6287
- profile_picture_source = 'factual';
6288
- factual_image_mode = true;
6289
- }
6290
- }
6291
- } else {
6292
- factual_image_mode = true;
6293
- profile_picture_source = 'factual';
6294
- }
6295
-
6296
- if (factual_image_mode) {
6297
- imageBase64 = await create_image(uid, factual_prompt, undefined, undefined, 1, undefined, undefined, {}, account_profile_info);
6298
- } else {
6299
- const model = 'gpt-image-1-mini'; // 'chatgpt-image-latest';
6300
- const prompt = `
6301
- extract the logo from the image
6302
- `;
6303
- let image_response;
6304
- try {
6305
- image_response = await client.images.edit({
6306
- model,
6307
- image: image_blob_ret.image_blob,
6308
- prompt,
6309
- background: 'transparent',
6310
- });
6311
- report_ai_status(model);
6312
- } catch (err) {
6313
- report_ai_status(model, err);
6314
- throw err;
6315
- }
6316
-
6317
- imageBase64 = await normalizeBase64To1024(image_response.data[0].b64_json, resize);
6318
- account_module.record_ai_usage(uid, image_response.usage.input_tokens, image_response.usage.output_tokens, 'profile image', prompt, model, { url }, account_profile_info);
6319
- }
6320
-
6321
- const outputBuffer = Buffer.from(imageBase64, 'base64');
6322
- const outputPath = tempOutputPath;
6323
- await fs.promises.writeFile(outputPath, outputBuffer);
6324
-
6325
- console.log('Success! Saved →', outputPath);
6326
-
6327
- console.log(file);
6328
-
6329
- const file_obj = {
6330
- originalname,
6331
- path: outputPath,
6332
- mimetype: `image/png`,
6333
- };
6334
-
6335
- drive_ret = await drive_module.upload_drive_file_user({ uid, path: '/Profile Images' }, job_id, headers, file_obj);
6336
- drive_ret.profile_picture_source = profile_picture_source;
6337
- }
6338
- return drive_ret;
6339
- } catch (err) {
6340
- console.error(err);
6341
- return;
6342
- }
6343
- };
6344
-
6345
6345
  async function normalizeBase64To1024(
6346
6346
  base64Image,
6347
6347
  resize = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xuda.io/ai_module",
3
- "version": "1.1.4865",
3
+ "version": "1.1.4867",
4
4
  "description": "Xuda AI Module",
5
5
  "main": "index.mjs",
6
6
  "type": "module",