n8n-nodes-supermachine 0.10.0 → 0.10.2

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.
@@ -1331,6 +1331,206 @@ class Supermachine {
1331
1331
  }
1332
1332
  });
1333
1333
  }
1334
+ else if (operation === 'instructEdit') {
1335
+ const imageSource = this.getNodeParameter('imageSource', i);
1336
+ const instruction = this.getNodeParameter('instruction', i);
1337
+ const additionalOptions = this.getNodeParameter('additionalOptions', i, {});
1338
+ let imageUrl = '';
1339
+ if (imageSource === 'imageId') {
1340
+ const imageId = this.getNodeParameter('imageId', i);
1341
+ const imageDetails = await this.helpers.requestWithAuthentication.call(this, 'supermachineApi', {
1342
+ method: 'GET',
1343
+ url: `https://dev.supermachine.art/v1/images/${imageId}`,
1344
+ json: true,
1345
+ });
1346
+ imageUrl = imageDetails.url;
1347
+ if (!imageUrl) {
1348
+ throw new Error(`Image ID ${imageId} does not have a valid URL`);
1349
+ }
1350
+ }
1351
+ else if (imageSource === 'imageUrl') {
1352
+ imageUrl = this.getNodeParameter('imageUrl', i);
1353
+ }
1354
+ const imageBuffer = await this.helpers.httpRequest({
1355
+ method: 'GET',
1356
+ url: imageUrl,
1357
+ encoding: 'arraybuffer',
1358
+ returnFullResponse: false,
1359
+ });
1360
+ const base64Image = Buffer.from(imageBuffer).toString('base64');
1361
+ let mimeType = 'image/jpeg';
1362
+ if (imageUrl.toLowerCase().includes('.png')) {
1363
+ mimeType = 'image/png';
1364
+ }
1365
+ else if (imageUrl.toLowerCase().includes('.webp')) {
1366
+ mimeType = 'image/webp';
1367
+ }
1368
+ const dataUri = `data:${mimeType};base64,${base64Image}`;
1369
+ const body = {
1370
+ image: dataUri,
1371
+ instruction: instruction,
1372
+ };
1373
+ if (additionalOptions.folderId) {
1374
+ body.folderId = parseInt(additionalOptions.folderId, 10) || 0;
1375
+ }
1376
+ let instructResponse;
1377
+ try {
1378
+ instructResponse = await this.helpers.requestWithAuthentication.call(this, 'supermachineApi', {
1379
+ method: 'POST',
1380
+ url: 'https://dev.supermachine.art/v1/tools/instruct',
1381
+ json: true,
1382
+ body,
1383
+ });
1384
+ }
1385
+ catch (error) {
1386
+ throw new Error(`Failed to edit image: ${error.message}`);
1387
+ }
1388
+ const batchId = instructResponse.batchId;
1389
+ if (!batchId) {
1390
+ if (instructResponse.url || instructResponse.imageUrl) {
1391
+ returnData.push({
1392
+ json: {
1393
+ success: true,
1394
+ imageUrl: instructResponse.url || instructResponse.imageUrl,
1395
+ imageId: instructResponse.id || instructResponse.imageId,
1396
+ creditsCost: instructResponse.creditsCost,
1397
+ creditsRemaining: instructResponse.creditsRemaining,
1398
+ instruction,
1399
+ processedAt: new Date().toISOString(),
1400
+ ...instructResponse,
1401
+ }
1402
+ });
1403
+ continue;
1404
+ }
1405
+ throw new Error('No batchId or result returned from instruct edit API');
1406
+ }
1407
+ const skipPolling = additionalOptions.skipPolling;
1408
+ if (skipPolling) {
1409
+ returnData.push({
1410
+ json: {
1411
+ batchId,
1412
+ tool: instructResponse.tool || 'instruct-edit',
1413
+ creditsCost: instructResponse.creditsCost,
1414
+ creditsRemaining: instructResponse.creditsRemaining,
1415
+ instruction,
1416
+ status: 'submitted',
1417
+ message: 'Image edit submitted. Use List Images with this batchId to check status.',
1418
+ submittedAt: new Date().toISOString(),
1419
+ ...instructResponse,
1420
+ }
1421
+ });
1422
+ continue;
1423
+ }
1424
+ const pollingInterval = additionalOptions.pollingInterval || 2;
1425
+ const maxPollingTime = additionalOptions.maxPollingTime || 120;
1426
+ const startTime = Date.now();
1427
+ let completedResult = null;
1428
+ await new Promise((resolve) => setTimeout(resolve, 2000));
1429
+ while (!completedResult) {
1430
+ if ((Date.now() - startTime) / 1000 > maxPollingTime) {
1431
+ throw new Error(`Image edit timed out after ${maxPollingTime} seconds. Batch ID: ${batchId}`);
1432
+ }
1433
+ let pollResponse;
1434
+ try {
1435
+ pollResponse = await this.helpers.requestWithAuthentication.call(this, 'supermachineApi', {
1436
+ method: 'GET',
1437
+ url: `https://dev.supermachine.art/v1/images?batchId=${batchId}`,
1438
+ json: true,
1439
+ });
1440
+ }
1441
+ catch (error) {
1442
+ await new Promise((resolve) => setTimeout(resolve, pollingInterval * 1000));
1443
+ continue;
1444
+ }
1445
+ const pollItems = pollResponse.items;
1446
+ if (Array.isArray(pollItems) && pollItems.length > 0) {
1447
+ const firstItem = pollItems[0];
1448
+ const status = firstItem.status;
1449
+ if (status === 'completed') {
1450
+ completedResult = firstItem;
1451
+ break;
1452
+ }
1453
+ else if (status === 'failed') {
1454
+ throw new Error(`Image edit failed. Batch ID: ${batchId}. Error: ${firstItem.error || 'Unknown error'}`);
1455
+ }
1456
+ }
1457
+ await new Promise((resolve) => setTimeout(resolve, pollingInterval * 1000));
1458
+ }
1459
+ returnData.push({
1460
+ json: {
1461
+ batchId,
1462
+ success: true,
1463
+ operation: 'instructEdit',
1464
+ tool: 'instruct-edit',
1465
+ instruction,
1466
+ creditsCost: instructResponse.creditsCost,
1467
+ creditsRemaining: instructResponse.creditsRemaining,
1468
+ processedAt: new Date().toISOString(),
1469
+ ...completedResult,
1470
+ }
1471
+ });
1472
+ }
1473
+ else if (operation === 'imageToPrompt') {
1474
+ const imageSource = this.getNodeParameter('imageSource', i);
1475
+ let imageUrl = '';
1476
+ if (imageSource === 'imageId') {
1477
+ const imageId = this.getNodeParameter('imageId', i);
1478
+ const imageDetails = await this.helpers.requestWithAuthentication.call(this, 'supermachineApi', {
1479
+ method: 'GET',
1480
+ url: `https://dev.supermachine.art/v1/images/${imageId}`,
1481
+ json: true,
1482
+ });
1483
+ imageUrl = imageDetails.url;
1484
+ if (!imageUrl) {
1485
+ throw new Error(`Image ID ${imageId} does not have a valid URL`);
1486
+ }
1487
+ }
1488
+ else if (imageSource === 'imageUrl') {
1489
+ imageUrl = this.getNodeParameter('imageUrl', i);
1490
+ }
1491
+ const imageBuffer = await this.helpers.httpRequest({
1492
+ method: 'GET',
1493
+ url: imageUrl,
1494
+ encoding: 'arraybuffer',
1495
+ returnFullResponse: false,
1496
+ });
1497
+ const base64Image = Buffer.from(imageBuffer).toString('base64');
1498
+ let mimeType = 'image/jpeg';
1499
+ if (imageUrl.toLowerCase().includes('.png')) {
1500
+ mimeType = 'image/png';
1501
+ }
1502
+ else if (imageUrl.toLowerCase().includes('.webp')) {
1503
+ mimeType = 'image/webp';
1504
+ }
1505
+ const dataUri = `data:${mimeType};base64,${base64Image}`;
1506
+ const body = {
1507
+ image: dataUri,
1508
+ };
1509
+ let promptResponse;
1510
+ try {
1511
+ promptResponse = await this.helpers.requestWithAuthentication.call(this, 'supermachineApi', {
1512
+ method: 'POST',
1513
+ url: 'https://dev.supermachine.art/v1/tools/image-to-prompt',
1514
+ json: true,
1515
+ body,
1516
+ });
1517
+ }
1518
+ catch (error) {
1519
+ throw new Error(`Failed to generate prompt: ${error.message}`);
1520
+ }
1521
+ returnData.push({
1522
+ json: {
1523
+ success: true,
1524
+ operation: 'imageToPrompt',
1525
+ tool: 'image-to-prompt',
1526
+ prompt: promptResponse.prompt || promptResponse.text,
1527
+ creditsCost: promptResponse.creditsCost,
1528
+ creditsRemaining: promptResponse.creditsRemaining,
1529
+ processedAt: new Date().toISOString(),
1530
+ ...promptResponse,
1531
+ }
1532
+ });
1533
+ }
1334
1534
  else {
1335
1535
  throw new Error(`⚠️ Operation "${operation}" is coming soon.`);
1336
1536
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-supermachine",
3
- "version": "0.10.0",
3
+ "version": "0.10.2",
4
4
  "description": "n8n community node for Supermachine AI Image API — Generate images, manage models, LoRAs, and characters",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",