@xuda.io/ai_module 1.1.4356 → 1.1.4358
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 +198 -195
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -5290,8 +5290,8 @@ setTimeout(async () => {
|
|
|
5290
5290
|
// },
|
|
5291
5291
|
// });
|
|
5292
5292
|
|
|
5293
|
-
// ret = await
|
|
5294
|
-
// ret = await
|
|
5293
|
+
// ret = await get_profile_picture(uid, 'business', 'ioshka media', {}, account_profile_info);
|
|
5294
|
+
// ret = await get_profile_picture(
|
|
5295
5295
|
// uid,
|
|
5296
5296
|
// 'personal',
|
|
5297
5297
|
// 'Glenn Willett',
|
|
@@ -5679,72 +5679,74 @@ export const create_profile_avatar = async function (req, job_id, headers) {
|
|
|
5679
5679
|
const uniqueId = Date.now() + '_' + Math.random().toString(36).substring(7);
|
|
5680
5680
|
const tempOutputPath = path.join(tempDir, `output_${uniqueId}.png`);
|
|
5681
5681
|
|
|
5682
|
-
|
|
5683
|
-
const inputBuffer = Buffer.from(base64Image, 'base64');
|
|
5682
|
+
const { url, uid, account_obj, prompt, is_profile_avatar, account_profile_info, docType = 'account', _id, metadata = {} } = req;
|
|
5684
5683
|
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
fit: 'contain', // Preserve aspect ratio, fit within 211x211
|
|
5688
|
-
background: { r: 0, g: 0, b: 0, alpha: 0 }, // Transparent background for padding
|
|
5689
|
-
})
|
|
5690
|
-
.png({
|
|
5691
|
-
quality: 100,
|
|
5692
|
-
compressionLevel: 9,
|
|
5693
|
-
force: true,
|
|
5694
|
-
})
|
|
5695
|
-
.toBuffer();
|
|
5684
|
+
// async function normalizeBase64To1024(base64Image) {
|
|
5685
|
+
// const inputBuffer = Buffer.from(base64Image, 'base64');
|
|
5696
5686
|
|
|
5697
|
-
|
|
5698
|
-
|
|
5687
|
+
// const normalizedBuffer = await sharp(inputBuffer)
|
|
5688
|
+
// .resize(1024, 1024, {
|
|
5689
|
+
// fit: 'contain', // Preserve aspect ratio, fit within 211x211
|
|
5690
|
+
// background: { r: 0, g: 0, b: 0, alpha: 0 }, // Transparent background for padding
|
|
5691
|
+
// })
|
|
5692
|
+
// .png({
|
|
5693
|
+
// quality: 100,
|
|
5694
|
+
// compressionLevel: 9,
|
|
5695
|
+
// force: true,
|
|
5696
|
+
// })
|
|
5697
|
+
// .toBuffer();
|
|
5699
5698
|
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
const metadata = await image.metadata();
|
|
5699
|
+
// return normalizedBuffer.toString('base64'); // Return normalized base64 string
|
|
5700
|
+
// }
|
|
5703
5701
|
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
}
|
|
5702
|
+
// async function hasTransparentBackground(filePath) {
|
|
5703
|
+
// const image = sharp(filePath);
|
|
5704
|
+
// const metadata = await image.metadata();
|
|
5708
5705
|
|
|
5709
|
-
|
|
5710
|
-
|
|
5706
|
+
// // If the image doesn't have an alpha channel at all → no transparency possible
|
|
5707
|
+
// if (!metadata.hasAlpha) {
|
|
5708
|
+
// return false;
|
|
5709
|
+
// }
|
|
5711
5710
|
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
const alphaOffset = channels === 2 ? 1 : channels === 4 ? 3 : -1;
|
|
5711
|
+
// // For images with alpha channel, check if any pixel actually has alpha < 255
|
|
5712
|
+
// const { data, info } = await image.raw().toBuffer({ resolveWithObject: true });
|
|
5715
5713
|
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
}
|
|
5714
|
+
// // Determine position of alpha channel based on number of channels
|
|
5715
|
+
// const channels = info.channels; // 2 (grayscale+alpha), 4 (RGBA), etc.
|
|
5716
|
+
// const alphaOffset = channels === 2 ? 1 : channels === 4 ? 3 : -1;
|
|
5720
5717
|
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
}
|
|
5718
|
+
// if (alphaOffset === -1) {
|
|
5719
|
+
// // Unusual channel count – be conservative and assume it might have transparency
|
|
5720
|
+
// return true;
|
|
5721
|
+
// }
|
|
5726
5722
|
|
|
5727
|
-
|
|
5728
|
-
|
|
5723
|
+
// for (let i = alphaOffset; i < data.length; i += channels) {
|
|
5724
|
+
// if (data[i] < 255) {
|
|
5725
|
+
// return true; // Found at least one transparent/semi-transparent pixel
|
|
5726
|
+
// }
|
|
5727
|
+
// }
|
|
5729
5728
|
|
|
5730
|
-
|
|
5731
|
-
|
|
5729
|
+
// return false; // Has alpha channel but all pixels are fully opaque
|
|
5730
|
+
// }
|
|
5732
5731
|
|
|
5733
|
-
|
|
5732
|
+
// async function imageToPngBlob(filePath) {
|
|
5733
|
+
// const ext = path.extname(filePath).toLowerCase();
|
|
5734
5734
|
|
|
5735
|
-
|
|
5736
|
-
if (ext === '.png') {
|
|
5737
|
-
buffer = await fs.promises.readFile(filePath);
|
|
5738
|
-
is_transparent = await hasTransparentBackground(filePath);
|
|
5739
|
-
} else {
|
|
5740
|
-
console.log(`Converting ${path.basename(filePath)} to PNG...`);
|
|
5741
|
-
buffer = await sharp(filePath).png({ quality: 100, compressionLevel: 9, force: true }).toBuffer();
|
|
5742
|
-
}
|
|
5735
|
+
// let buffer;
|
|
5743
5736
|
|
|
5744
|
-
|
|
5737
|
+
// let is_transparent = false;
|
|
5738
|
+
// if (ext === '.png') {
|
|
5739
|
+
// buffer = await fs.promises.readFile(filePath);
|
|
5740
|
+
// is_transparent = await hasTransparentBackground(filePath);
|
|
5741
|
+
// } else {
|
|
5742
|
+
// console.log(`Converting ${path.basename(filePath)} to PNG...`);
|
|
5743
|
+
// buffer = await sharp(filePath).png({ quality: 100, compressionLevel: 9, force: true }).toBuffer();
|
|
5744
|
+
// }
|
|
5745
5745
|
|
|
5746
|
-
|
|
5747
|
-
|
|
5746
|
+
// // Create a Blob with correct MIME type
|
|
5747
|
+
|
|
5748
|
+
// return { is_transparent, image_blob: new Blob([buffer], { type: 'image/png' }) };
|
|
5749
|
+
// }
|
|
5748
5750
|
|
|
5749
5751
|
const detect_real_person_in_image = async function (base64) {
|
|
5750
5752
|
const ret = await submit_chat_gpt_prompt({
|
|
@@ -5777,59 +5779,60 @@ export const create_profile_avatar = async function (req, job_id, headers) {
|
|
|
5777
5779
|
};
|
|
5778
5780
|
|
|
5779
5781
|
// const drive_module = await import(`${module_path}/drive_module/index.mjs`);
|
|
5780
|
-
|
|
5782
|
+
|
|
5781
5783
|
if (!is_profile_avatar) {
|
|
5782
5784
|
await update_profile_avatar_status(account_obj._id, 2);
|
|
5783
5785
|
}
|
|
5784
5786
|
try {
|
|
5785
|
-
if (!url) {
|
|
5786
|
-
|
|
5787
|
-
}
|
|
5787
|
+
// if (!url) {
|
|
5788
|
+
// throw new Error('No URL provided in request');
|
|
5789
|
+
// }
|
|
5788
5790
|
|
|
5789
5791
|
// 3. Download the image to a Buffer
|
|
5790
|
-
const res = await fetch(url);
|
|
5791
|
-
if (!res.ok) {
|
|
5792
|
-
|
|
5793
|
-
}
|
|
5792
|
+
// const res = await fetch(url);
|
|
5793
|
+
// if (!res.ok) {
|
|
5794
|
+
// throw new Error(`Failed to fetch image URL: ${res.status} ${res.statusText}`);
|
|
5795
|
+
// }
|
|
5794
5796
|
|
|
5795
|
-
const arrayBuffer = await res.arrayBuffer();
|
|
5796
|
-
const imageBuffer = Buffer.from(arrayBuffer);
|
|
5797
|
+
// const arrayBuffer = await res.arrayBuffer();
|
|
5798
|
+
// const imageBuffer = Buffer.from(arrayBuffer);
|
|
5797
5799
|
|
|
5798
|
-
const tempDir = os.tmpdir();
|
|
5799
|
-
const uniqueId = Date.now() + '_' + Math.random().toString(36).substring(7);
|
|
5800
|
+
// const tempDir = os.tmpdir();
|
|
5801
|
+
// const uniqueId = Date.now() + '_' + Math.random().toString(36).substring(7);
|
|
5800
5802
|
|
|
5801
|
-
const inputExt = path.extname(url) || '.jpg';
|
|
5802
|
-
const tempInputPath = path.join(tempDir, `input_${uniqueId}${inputExt}`);
|
|
5803
|
-
const tempOutputPath = path.join(tempDir, `output_${uniqueId}.png`); // Output is always PNG (transparent)
|
|
5803
|
+
// const inputExt = path.extname(url) || '.jpg';
|
|
5804
|
+
// const tempInputPath = path.join(tempDir, `input_${uniqueId}${inputExt}`);
|
|
5805
|
+
// const tempOutputPath = path.join(tempDir, `output_${uniqueId}.png`); // Output is always PNG (transparent)
|
|
5804
5806
|
|
|
5805
5807
|
// 5. Write the downloaded image to disk
|
|
5806
|
-
fs.writeFileSync(tempInputPath, imageBuffer);
|
|
5808
|
+
// fs.writeFileSync(tempInputPath, imageBuffer);
|
|
5807
5809
|
/////////////////////////////////
|
|
5808
5810
|
|
|
5809
|
-
const imageFiles = [tempInputPath];
|
|
5811
|
+
// const imageFiles = [tempInputPath];
|
|
5810
5812
|
|
|
5811
|
-
const images = await Promise.all(
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5813
|
+
// const images = await Promise.all(
|
|
5814
|
+
// imageFiles.map(async (filePath) => {
|
|
5815
|
+
// const img_ret = await imageToPngBlob(filePath);
|
|
5816
|
+
// const blob = img_ret.image_blob;
|
|
5815
5817
|
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5818
|
+
// // OpenAI expects a filename for logging/debugging
|
|
5819
|
+
// const filename = path.basename(filePath, path.extname(filePath)) + '.png';
|
|
5820
|
+
// blob.name = filename; // Optional but helpful
|
|
5821
|
+
// // @ts-ignore – name is allowed in Node 20+
|
|
5822
|
+
// blob.lastModified = Date.now();
|
|
5821
5823
|
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
);
|
|
5824
|
+
// return { is_transparent: img_ret.is_transparent, image_blob: blob };
|
|
5825
|
+
// }),
|
|
5826
|
+
// );
|
|
5825
5827
|
|
|
5826
5828
|
let imageBase64;
|
|
5829
|
+
const image_blob_ret = await get_image_blob_from_downloaded_image(url);
|
|
5827
5830
|
let avatar_source = '';
|
|
5828
5831
|
if (prompt) {
|
|
5829
5832
|
const model = 'chatgpt-image-latest';
|
|
5830
5833
|
const ai_avatar_response = await client.images.edit({
|
|
5831
5834
|
model, // 'gpt-image-1',
|
|
5832
|
-
image:
|
|
5835
|
+
image: image_blob_ret.image_blob, //base photo
|
|
5833
5836
|
prompt,
|
|
5834
5837
|
background: 'transparent',
|
|
5835
5838
|
});
|
|
@@ -5837,13 +5840,13 @@ export const create_profile_avatar = async function (req, job_id, headers) {
|
|
|
5837
5840
|
record_chat_usage(uid, ai_avatar_response.usage.input_tokens, ai_avatar_response.usage.output_tokens, 'profile avatar', prompt, model, { url }, account_profile_info);
|
|
5838
5841
|
} else {
|
|
5839
5842
|
//////////////////
|
|
5840
|
-
imageBase64 = Buffer.from(await
|
|
5843
|
+
imageBase64 = Buffer.from(await image_blob_ret.image_blob.arrayBuffer()).toString('base64');
|
|
5841
5844
|
if (account_obj.account_info.account_type === 'business') {
|
|
5842
5845
|
// create avatar from logo - BUSINESS
|
|
5843
5846
|
const { bio, business_name, country, mainCategory, subCategory } = account_obj.account_info;
|
|
5844
5847
|
// const ai_avatar_response = await client.images.edit({
|
|
5845
5848
|
// model: 'chatgpt-image-latest',
|
|
5846
|
-
// image:
|
|
5849
|
+
// image: image_blob_ret.image_blob, // only one image allowed
|
|
5847
5850
|
// 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.
|
|
5848
5851
|
// Context: ${JSON.stringify({ bio, business_name, country, mainCategory, subCategory })}`,
|
|
5849
5852
|
// background: 'transparent',
|
|
@@ -5851,7 +5854,7 @@ export const create_profile_avatar = async function (req, job_id, headers) {
|
|
|
5851
5854
|
///////////////////
|
|
5852
5855
|
// const ai_avatar_response = await client.images.edit({
|
|
5853
5856
|
// model: 'chatgpt-image-latest',
|
|
5854
|
-
// image:
|
|
5857
|
+
// image: image_blob_ret.image_blob, //base photo
|
|
5855
5858
|
// prompt: `Create a transparent PNG profile image for a business account featuring building branded as ${business_name}.
|
|
5856
5859
|
// Display the attached logo clearly as prominent exterior signage.
|
|
5857
5860
|
// The building’s architecture and overall atmosphere should reflect the nature of the business, aligning with ${mainCategory} and ${subCategory}.
|
|
@@ -5899,7 +5902,7 @@ export const create_profile_avatar = async function (req, job_id, headers) {
|
|
|
5899
5902
|
const model = 'chatgpt-image-latest';
|
|
5900
5903
|
const ai_avatar_response = await client.images.edit({
|
|
5901
5904
|
model,
|
|
5902
|
-
image:
|
|
5905
|
+
image: image_blob_ret.image_blob, //logo
|
|
5903
5906
|
prompt: `
|
|
5904
5907
|
Create a transparent PNG profile image for a business account featuring building branded as ${business_name}.
|
|
5905
5908
|
Display the attached logo clearly as prominent exterior signage.
|
|
@@ -5922,7 +5925,7 @@ export const create_profile_avatar = async function (req, job_id, headers) {
|
|
|
5922
5925
|
const model = 'chatgpt-image-latest';
|
|
5923
5926
|
const ai_avatar_response = await client.images.edit({
|
|
5924
5927
|
model,
|
|
5925
|
-
image:
|
|
5928
|
+
image: image_blob_ret.image_blob,
|
|
5926
5929
|
|
|
5927
5930
|
prompt: `Completely remove the background, enhance and color-correct the subject, and return only a centered head-and-shoulders portrait facing the camera. Add extra top margin, include no labels or text, and export the result as a clean transparent PNG.
|
|
5928
5931
|
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.
|
|
@@ -5945,9 +5948,9 @@ export const create_profile_avatar = async function (req, job_id, headers) {
|
|
|
5945
5948
|
// personal account
|
|
5946
5949
|
const is_real_person_in_picture = await detect_real_person_in_image(imageBase64);
|
|
5947
5950
|
if (is_real_person_in_picture) {
|
|
5948
|
-
if (
|
|
5951
|
+
if (image_blob_ret.is_transparent) {
|
|
5949
5952
|
// keep the original
|
|
5950
|
-
imageBase64 = Buffer.from(await
|
|
5953
|
+
imageBase64 = Buffer.from(await image_blob_ret.image_blob.arrayBuffer()).toString('base64');
|
|
5951
5954
|
avatar_source = 'authentic profile';
|
|
5952
5955
|
} else {
|
|
5953
5956
|
// create avatar from profile picture
|
|
@@ -6198,72 +6201,72 @@ const create_ai_agent_image = async function (req, job_id, headers) {
|
|
|
6198
6201
|
const uniqueId = Date.now() + '_' + Math.random().toString(36).substring(7);
|
|
6199
6202
|
const tempOutputPath = path.join(tempDir, `output_${uniqueId}.png`);
|
|
6200
6203
|
|
|
6201
|
-
async function normalizeBase64To1024(base64Image) {
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
}
|
|
6218
|
-
|
|
6219
|
-
async function hasTransparentBackground(filePath) {
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
|
|
6240
|
-
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
}
|
|
6248
|
-
|
|
6249
|
-
async function imageToPngBlob(filePath) {
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
|
|
6266
|
-
}
|
|
6204
|
+
// async function normalizeBase64To1024(base64Image) {
|
|
6205
|
+
// const inputBuffer = Buffer.from(base64Image, 'base64');
|
|
6206
|
+
|
|
6207
|
+
// const normalizedBuffer = await sharp(inputBuffer)
|
|
6208
|
+
// .resize(1024, 1024, {
|
|
6209
|
+
// fit: 'contain', // Preserve aspect ratio, fit within 211x211
|
|
6210
|
+
// background: { r: 0, g: 0, b: 0, alpha: 0 }, // Transparent background for padding
|
|
6211
|
+
// })
|
|
6212
|
+
// .png({
|
|
6213
|
+
// quality: 100,
|
|
6214
|
+
// compressionLevel: 9,
|
|
6215
|
+
// force: true,
|
|
6216
|
+
// })
|
|
6217
|
+
// .toBuffer();
|
|
6218
|
+
|
|
6219
|
+
// return normalizedBuffer.toString('base64'); // Return normalized base64 string
|
|
6220
|
+
// }
|
|
6221
|
+
|
|
6222
|
+
// async function hasTransparentBackground(filePath) {
|
|
6223
|
+
// const image = sharp(filePath);
|
|
6224
|
+
// const metadata = await image.metadata();
|
|
6225
|
+
|
|
6226
|
+
// // If the image doesn't have an alpha channel at all → no transparency possible
|
|
6227
|
+
// if (!metadata.hasAlpha) {
|
|
6228
|
+
// return false;
|
|
6229
|
+
// }
|
|
6230
|
+
|
|
6231
|
+
// // For images with alpha channel, check if any pixel actually has alpha < 255
|
|
6232
|
+
// const { data, info } = await image.raw().toBuffer({ resolveWithObject: true });
|
|
6233
|
+
|
|
6234
|
+
// // Determine position of alpha channel based on number of channels
|
|
6235
|
+
// const channels = info.channels; // 2 (grayscale+alpha), 4 (RGBA), etc.
|
|
6236
|
+
// const alphaOffset = channels === 2 ? 1 : channels === 4 ? 3 : -1;
|
|
6237
|
+
|
|
6238
|
+
// if (alphaOffset === -1) {
|
|
6239
|
+
// // Unusual channel count – be conservative and assume it might have transparency
|
|
6240
|
+
// return true;
|
|
6241
|
+
// }
|
|
6242
|
+
|
|
6243
|
+
// for (let i = alphaOffset; i < data.length; i += channels) {
|
|
6244
|
+
// if (data[i] < 255) {
|
|
6245
|
+
// return true; // Found at least one transparent/semi-transparent pixel
|
|
6246
|
+
// }
|
|
6247
|
+
// }
|
|
6248
|
+
|
|
6249
|
+
// return false; // Has alpha channel but all pixels are fully opaque
|
|
6250
|
+
// }
|
|
6251
|
+
|
|
6252
|
+
// async function imageToPngBlob(filePath) {
|
|
6253
|
+
// const ext = path.extname(filePath).toLowerCase();
|
|
6254
|
+
|
|
6255
|
+
// let buffer;
|
|
6256
|
+
|
|
6257
|
+
// let is_transparent = false;
|
|
6258
|
+
// if (ext === '.png') {
|
|
6259
|
+
// buffer = await fs.promises.readFile(filePath);
|
|
6260
|
+
// is_transparent = await hasTransparentBackground(filePath);
|
|
6261
|
+
// } else {
|
|
6262
|
+
// console.log(`Converting ${path.basename(filePath)} to PNG...`);
|
|
6263
|
+
// buffer = await sharp(filePath).png({ quality: 100, compressionLevel: 9, force: true }).toBuffer();
|
|
6264
|
+
// }
|
|
6265
|
+
|
|
6266
|
+
// // Create a Blob with correct MIME type
|
|
6267
|
+
|
|
6268
|
+
// return { is_transparent, image_blob: new Blob([buffer], { type: 'image/png' }) };
|
|
6269
|
+
// }
|
|
6267
6270
|
|
|
6268
6271
|
const { app_id, uid, ai_agent_id, tags, account_profile_info } = req;
|
|
6269
6272
|
|
|
@@ -6312,55 +6315,55 @@ const create_ai_agent_image = async function (req, job_id, headers) {
|
|
|
6312
6315
|
let url = account_doc.account_info.profile_avatar;
|
|
6313
6316
|
|
|
6314
6317
|
try {
|
|
6315
|
-
if (!url) {
|
|
6316
|
-
|
|
6317
|
-
}
|
|
6318
|
+
// if (!url) {
|
|
6319
|
+
// throw new Error('No URL provided in request');
|
|
6320
|
+
// }
|
|
6318
6321
|
|
|
6319
|
-
// 3. Download the image to a Buffer
|
|
6320
|
-
const res = await fetch(url);
|
|
6321
|
-
if (!res.ok) {
|
|
6322
|
-
|
|
6323
|
-
}
|
|
6322
|
+
// // 3. Download the image to a Buffer
|
|
6323
|
+
// const res = await fetch(url);
|
|
6324
|
+
// if (!res.ok) {
|
|
6325
|
+
// throw new Error(`Failed to fetch image URL: ${res.status} ${res.statusText}`);
|
|
6326
|
+
// }
|
|
6324
6327
|
|
|
6325
|
-
const arrayBuffer = await res.arrayBuffer();
|
|
6326
|
-
const imageBuffer = Buffer.from(arrayBuffer);
|
|
6328
|
+
// const arrayBuffer = await res.arrayBuffer();
|
|
6329
|
+
// const imageBuffer = Buffer.from(arrayBuffer);
|
|
6327
6330
|
|
|
6328
|
-
const tempDir = os.tmpdir();
|
|
6329
|
-
const uniqueId = Date.now() + '_' + Math.random().toString(36).substring(7);
|
|
6331
|
+
// const tempDir = os.tmpdir();
|
|
6332
|
+
// const uniqueId = Date.now() + '_' + Math.random().toString(36).substring(7);
|
|
6330
6333
|
|
|
6331
|
-
const inputExt = path.extname(url) || '.jpg';
|
|
6332
|
-
const tempInputPath = path.join(tempDir, `input_${uniqueId}${inputExt}`);
|
|
6333
|
-
const tempOutputPath = path.join(tempDir, `output_${uniqueId}.png`); // Output is always PNG (transparent)
|
|
6334
|
+
// const inputExt = path.extname(url) || '.jpg';
|
|
6335
|
+
// const tempInputPath = path.join(tempDir, `input_${uniqueId}${inputExt}`);
|
|
6336
|
+
// const tempOutputPath = path.join(tempDir, `output_${uniqueId}.png`); // Output is always PNG (transparent)
|
|
6334
6337
|
|
|
6335
6338
|
// 5. Write the downloaded image to disk
|
|
6336
|
-
fs.writeFileSync(tempInputPath, imageBuffer);
|
|
6339
|
+
// fs.writeFileSync(tempInputPath, imageBuffer);
|
|
6337
6340
|
/////////////////////////////////
|
|
6338
6341
|
|
|
6339
|
-
const imageFiles = [tempInputPath];
|
|
6342
|
+
// const imageFiles = [tempInputPath];
|
|
6340
6343
|
|
|
6341
|
-
const images = await Promise.all(
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6344
|
+
// const images = await Promise.all(
|
|
6345
|
+
// imageFiles.map(async (filePath) => {
|
|
6346
|
+
// const img_ret = await imageToPngBlob(filePath);
|
|
6347
|
+
// const blob = img_ret.image_blob;
|
|
6345
6348
|
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6349
|
+
// // OpenAI expects a filename for logging/debugging
|
|
6350
|
+
// const filename = path.basename(filePath, path.extname(filePath)) + '.png';
|
|
6351
|
+
// blob.name = filename; // Optional but helpful
|
|
6352
|
+
// // @ts-ignore – name is allowed in Node 20+
|
|
6353
|
+
// blob.lastModified = Date.now();
|
|
6351
6354
|
|
|
6352
|
-
|
|
6353
|
-
|
|
6354
|
-
);
|
|
6355
|
+
// return { is_transparent: img_ret.is_transparent, image_blob: blob };
|
|
6356
|
+
// }),
|
|
6357
|
+
// );
|
|
6355
6358
|
|
|
6356
6359
|
let imageBase64;
|
|
6357
|
-
|
|
6360
|
+
const image_blob_ret = await get_image_blob_from_downloaded_image(url);
|
|
6358
6361
|
//////////////////
|
|
6359
|
-
imageBase64 = Buffer.from(await
|
|
6362
|
+
imageBase64 = Buffer.from(await image_blob_ret.image_blob.arrayBuffer()).toString('base64');
|
|
6360
6363
|
const model = 'chatgpt-image-latest';
|
|
6361
6364
|
const ai_avatar_response = await client.images.edit({
|
|
6362
6365
|
model,
|
|
6363
|
-
image:
|
|
6366
|
+
image: image_blob_ret.image_blob,
|
|
6364
6367
|
|
|
6365
6368
|
prompt: `
|
|
6366
6369
|
Create a futuristic, profile portrait with a transparent background.
|
|
@@ -6742,7 +6745,7 @@ export const is_business_contact = async function (uid, email, name, subject, bo
|
|
|
6742
6745
|
} catch (error) {}
|
|
6743
6746
|
};
|
|
6744
6747
|
|
|
6745
|
-
const
|
|
6748
|
+
export const get_profile_picture = async function (uid, account_type = 'business', name, facts = {}, account_profile_info, job_id, headers) {
|
|
6746
6749
|
const tempDir = os.tmpdir();
|
|
6747
6750
|
const uniqueId = Date.now() + '_' + Math.random().toString(36).substring(7);
|
|
6748
6751
|
const tempOutputPath = path.join(tempDir, `output_${uniqueId}.png`);
|
|
@@ -6756,7 +6759,7 @@ const get_profile_image = async function (uid, account_type = 'business', name,
|
|
|
6756
6759
|
.replace(/^_+|_+$/g, ''); // trim leading/trailing underscores
|
|
6757
6760
|
}
|
|
6758
6761
|
|
|
6759
|
-
let prompt, factual_prompt, originalname, factual_image_mode, imageBase64,
|
|
6762
|
+
let prompt, factual_prompt, originalname, factual_image_mode, imageBase64, image_blob_ret, file;
|
|
6760
6763
|
|
|
6761
6764
|
switch (account_type) {
|
|
6762
6765
|
case 'personal': {
|
|
@@ -6785,7 +6788,7 @@ const get_profile_image = async function (uid, account_type = 'business', name,
|
|
|
6785
6788
|
uid,
|
|
6786
6789
|
prompt,
|
|
6787
6790
|
model: 'gpt-5-nano',
|
|
6788
|
-
metadata: { func: '
|
|
6791
|
+
metadata: { func: 'get_profile_picture' },
|
|
6789
6792
|
account_profile_info,
|
|
6790
6793
|
tools: [{ type: 'web_search_preview' }],
|
|
6791
6794
|
});
|
|
@@ -6808,7 +6811,7 @@ const get_profile_image = async function (uid, account_type = 'business', name,
|
|
|
6808
6811
|
// success
|
|
6809
6812
|
|
|
6810
6813
|
try {
|
|
6811
|
-
|
|
6814
|
+
image_blob_ret = await get_image_blob_from_downloaded_image(url);
|
|
6812
6815
|
} catch (err) {
|
|
6813
6816
|
if (!err.message.includes('Failed to fetch image URL')) {
|
|
6814
6817
|
console.error(err);
|
|
@@ -6827,7 +6830,7 @@ const get_profile_image = async function (uid, account_type = 'business', name,
|
|
|
6827
6830
|
`;
|
|
6828
6831
|
const image_response = await client.images.edit({
|
|
6829
6832
|
model,
|
|
6830
|
-
image: image_blob,
|
|
6833
|
+
image: image_blob_ret.image_blob,
|
|
6831
6834
|
prompt,
|
|
6832
6835
|
background: 'transparent',
|
|
6833
6836
|
});
|
|
@@ -6968,5 +6971,5 @@ const get_image_blob_from_downloaded_image = async function (url) {
|
|
|
6968
6971
|
}),
|
|
6969
6972
|
);
|
|
6970
6973
|
|
|
6971
|
-
return images[0]
|
|
6974
|
+
return images[0];
|
|
6972
6975
|
};
|