first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"node": "n8n-nodes-base.awsRekognition",
|
||||
"nodeVersion": "1.0",
|
||||
"codexVersion": "1.0",
|
||||
"categories": ["Development"],
|
||||
"resources": {
|
||||
"credentialDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/credentials/aws/"
|
||||
}
|
||||
],
|
||||
"primaryDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.awsrekognition/"
|
||||
}
|
||||
],
|
||||
"generic": [
|
||||
{
|
||||
"label": "7 no-code workflow automations for Amazon Web Services",
|
||||
"url": "https://n8n.io/blog/aws-workflow-automation/"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,465 @@
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeConnectionTypes } from 'n8n-workflow';
|
||||
|
||||
import { awsApiRequestREST, keysTPascalCase } from './GenericFunctions';
|
||||
import { awsNodeAuthOptions, awsNodeCredentials } from '../utils';
|
||||
|
||||
export class AwsRekognition implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'AWS Rekognition',
|
||||
name: 'awsRekognition',
|
||||
icon: 'file:rekognition.svg',
|
||||
group: ['output'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
||||
description: 'Sends data to AWS Rekognition',
|
||||
schemaPath: 'Aws/Rekognition',
|
||||
defaults: {
|
||||
name: 'AWS Rekognition',
|
||||
},
|
||||
inputs: [NodeConnectionTypes.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
credentials: awsNodeCredentials,
|
||||
properties: [
|
||||
awsNodeAuthOptions,
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
options: [
|
||||
{
|
||||
name: 'Image',
|
||||
value: 'image',
|
||||
},
|
||||
],
|
||||
default: 'image',
|
||||
},
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
options: [
|
||||
{
|
||||
name: 'Analyze',
|
||||
value: 'analyze',
|
||||
},
|
||||
],
|
||||
default: 'analyze',
|
||||
},
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['analyze'],
|
||||
resource: ['image'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Detect Faces',
|
||||
value: 'detectFaces',
|
||||
},
|
||||
{
|
||||
name: 'Detect Labels',
|
||||
value: 'detectLabels',
|
||||
},
|
||||
{
|
||||
name: 'Detect Moderation Labels',
|
||||
value: 'detectModerationLabels',
|
||||
},
|
||||
{
|
||||
name: 'Detect Text',
|
||||
value: 'detectText',
|
||||
},
|
||||
{
|
||||
name: 'Recognize Celebrity',
|
||||
value: 'recognizeCelebrity',
|
||||
},
|
||||
],
|
||||
default: 'detectFaces',
|
||||
},
|
||||
{
|
||||
displayName: 'Binary File',
|
||||
name: 'binaryData',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['analyze'],
|
||||
resource: ['image'],
|
||||
},
|
||||
},
|
||||
description: 'Whether the image to analyze should be taken from binary field',
|
||||
},
|
||||
{
|
||||
displayName: 'Input Binary Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['analyze'],
|
||||
resource: ['image'],
|
||||
binaryData: [true],
|
||||
},
|
||||
},
|
||||
name: 'binaryPropertyName',
|
||||
type: 'string',
|
||||
default: 'data',
|
||||
hint: 'The name of the input binary field containing the file to be written',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Bucket',
|
||||
name: 'bucket',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['analyze'],
|
||||
resource: ['image'],
|
||||
binaryData: [false],
|
||||
},
|
||||
},
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'Name of the S3 bucket',
|
||||
},
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['analyze'],
|
||||
resource: ['image'],
|
||||
binaryData: [false],
|
||||
},
|
||||
},
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'S3 object key name',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['analyze'],
|
||||
resource: ['image'],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Regions of Interest',
|
||||
name: 'regionsOfInterestUi',
|
||||
type: 'fixedCollection',
|
||||
default: {},
|
||||
placeholder: 'Add Region of Interest',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/type': ['detectText'],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'regionsOfInterestValues',
|
||||
displayName: 'Region of Interest',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Height',
|
||||
name: 'height',
|
||||
type: 'number',
|
||||
description:
|
||||
'Height of the bounding box as a ratio of the overall image height',
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Left',
|
||||
name: 'left',
|
||||
type: 'number',
|
||||
description:
|
||||
'Left coordinate of the bounding box as a ratio of overall image width',
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Top',
|
||||
name: 'top',
|
||||
type: 'number',
|
||||
description:
|
||||
'Top coordinate of the bounding box as a ratio of overall image height',
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Width',
|
||||
name: 'Width',
|
||||
type: 'number',
|
||||
description: 'Width of the bounding box as a ratio of the overall image width',
|
||||
default: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Version',
|
||||
name: 'version',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/binaryData': [false],
|
||||
},
|
||||
},
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'If the bucket is versioning enabled, you can specify the object version',
|
||||
},
|
||||
{
|
||||
displayName: 'Word Filter',
|
||||
name: 'wordFilterUi',
|
||||
type: 'collection',
|
||||
default: {},
|
||||
placeholder: 'Add Word Filter',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/type': ['detectText'],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Min Bounding Box Height',
|
||||
name: 'MinBoundingBoxHeight',
|
||||
type: 'number',
|
||||
description:
|
||||
'Sets the minimum height of the word bounding box. Words with bounding box heights lesser than this value will be excluded from the result. Value is relative to the video frame height.',
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Min Bounding Box Width',
|
||||
name: 'MinBoundingBoxWidth',
|
||||
type: 'number',
|
||||
description:
|
||||
'Sets the minimum width of the word bounding box. Words with bounding boxes widths lesser than this value will be excluded from the result. Value is relative to the video frame width.',
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Min Confidence',
|
||||
name: 'MinConfidence',
|
||||
type: 'number',
|
||||
description:
|
||||
'Sets the confidence of word detection. Words with detection confidence below this will be excluded from the result. Values should be between 50 and 100 as Text in Video will not return any result below 50.',
|
||||
default: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Max Labels',
|
||||
name: 'maxLabels',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/type': ['detectModerationLabels', 'detectLabels'],
|
||||
},
|
||||
},
|
||||
default: 0,
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
},
|
||||
description:
|
||||
'Maximum number of labels you want the service to return in the response. The service returns the specified number of highest confidence labels.',
|
||||
},
|
||||
{
|
||||
displayName: 'Min Confidence',
|
||||
name: 'minConfidence',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/type': ['detectModerationLabels', 'detectLabels'],
|
||||
},
|
||||
},
|
||||
default: 0,
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
maxValue: 100,
|
||||
},
|
||||
description:
|
||||
"Specifies the minimum confidence level for the labels to return. Amazon Rekognition doesn't return any labels with a confidence level lower than this specified value.",
|
||||
},
|
||||
{
|
||||
displayName: 'Attributes',
|
||||
name: 'attributes',
|
||||
type: 'multiOptions',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/type': ['detectFaces'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'All',
|
||||
value: 'all',
|
||||
},
|
||||
{
|
||||
name: 'Default',
|
||||
value: 'default',
|
||||
},
|
||||
],
|
||||
default: [],
|
||||
description: 'An array of facial attributes you want to be returned',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const returnData: IDataObject[] = [];
|
||||
let responseData;
|
||||
const resource = this.getNodeParameter('resource', 0);
|
||||
const operation = this.getNodeParameter('operation', 0);
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
try {
|
||||
if (resource === 'image') {
|
||||
//https://docs.aws.amazon.com/rekognition/latest/dg/API_DetectModerationLabels.html#API_DetectModerationLabels_RequestSyntax
|
||||
if (operation === 'analyze') {
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i);
|
||||
|
||||
let action = undefined;
|
||||
|
||||
const body: IDataObject = {};
|
||||
|
||||
const type = this.getNodeParameter('type', 0) as string;
|
||||
|
||||
if (type === 'detectModerationLabels') {
|
||||
action = 'RekognitionService.DetectModerationLabels';
|
||||
|
||||
// property = 'ModerationLabels';
|
||||
|
||||
if (additionalFields.minConfidence) {
|
||||
body.MinConfidence = additionalFields.minConfidence as number;
|
||||
}
|
||||
}
|
||||
|
||||
if (type === 'detectFaces') {
|
||||
action = 'RekognitionService.DetectFaces';
|
||||
|
||||
// TODO: Add a later point make it possible to activate via option.
|
||||
// If activated add an index to each of the found faces/tags/...
|
||||
// to not loose the reference to the image it got found on if
|
||||
// multiple ones got supplied.
|
||||
// property = 'FaceDetails';
|
||||
|
||||
if (additionalFields.attributes) {
|
||||
body.Attributes = additionalFields.attributes as string;
|
||||
}
|
||||
}
|
||||
|
||||
if (type === 'detectLabels') {
|
||||
action = 'RekognitionService.DetectLabels';
|
||||
|
||||
if (additionalFields.minConfidence) {
|
||||
body.MinConfidence = additionalFields.minConfidence as number;
|
||||
}
|
||||
|
||||
if (additionalFields.maxLabels) {
|
||||
body.MaxLabels = additionalFields.maxLabels as number;
|
||||
}
|
||||
}
|
||||
|
||||
if (type === 'recognizeCelebrity') {
|
||||
action = 'RekognitionService.RecognizeCelebrities';
|
||||
}
|
||||
|
||||
if (type === 'detectText') {
|
||||
action = 'RekognitionService.DetectText';
|
||||
}
|
||||
body.Filters = {};
|
||||
|
||||
const box =
|
||||
((additionalFields.regionsOfInterestUi as IDataObject)
|
||||
?.regionsOfInterestValues as IDataObject[]) || [];
|
||||
|
||||
if (box.length !== 0) {
|
||||
//@ts-ignore
|
||||
body.Filters.RegionsOfInterest = box.map((entry: IDataObject) => {
|
||||
return { BoundingBox: keysTPascalCase(entry) };
|
||||
});
|
||||
}
|
||||
|
||||
const wordFilter = (additionalFields.wordFilterUi as IDataObject) || {};
|
||||
if (Object.keys(wordFilter).length !== 0) {
|
||||
//@ts-ignore
|
||||
body.Filters.WordFilter = keysTPascalCase(wordFilter);
|
||||
}
|
||||
|
||||
const isBinaryData = this.getNodeParameter('binaryData', i);
|
||||
if (isBinaryData) {
|
||||
const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i);
|
||||
const binaryPropertyData = this.helpers.assertBinaryData(i, binaryPropertyName);
|
||||
Object.assign(body, {
|
||||
Image: {
|
||||
Bytes: binaryPropertyData.data,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
const bucket = this.getNodeParameter('bucket', i) as string;
|
||||
const name = this.getNodeParameter('name', i) as string;
|
||||
|
||||
Object.assign(body, {
|
||||
Image: {
|
||||
S3Object: {
|
||||
Bucket: bucket,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (additionalFields.version) {
|
||||
//@ts-ignore
|
||||
body.Image.S3Object.Version = additionalFields.version as string;
|
||||
}
|
||||
}
|
||||
responseData = await awsApiRequestREST.call(
|
||||
this,
|
||||
'rekognition',
|
||||
'POST',
|
||||
'',
|
||||
JSON.stringify(body),
|
||||
{},
|
||||
{ 'X-Amz-Target': action, 'Content-Type': 'application/x-amz-json-1.1' },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(responseData as IDataObject),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
returnData.push(...executionData);
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
returnData.push({ error: error.message });
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
return [returnData as INodeExecutionData[]];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
import { pascalCase } from 'change-case';
|
||||
import get from 'lodash/get';
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
IHookFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
IWebhookFunctions,
|
||||
IHttpRequestOptions,
|
||||
IHttpRequestMethods,
|
||||
} from 'n8n-workflow';
|
||||
import { parseString } from 'xml2js';
|
||||
import { getAwsCredentials } from '../GenericFunctions';
|
||||
|
||||
export async function awsApiRequest(
|
||||
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
|
||||
service: string,
|
||||
method: IHttpRequestMethods,
|
||||
path: string,
|
||||
body?: string | Buffer | IDataObject,
|
||||
_query: IDataObject = {},
|
||||
headers?: object,
|
||||
option: IDataObject = {},
|
||||
_region?: string,
|
||||
): Promise<any> {
|
||||
const { credentials, credentialsType } = await getAwsCredentials(this);
|
||||
|
||||
const requestOptions = {
|
||||
qs: {
|
||||
service,
|
||||
path,
|
||||
},
|
||||
method,
|
||||
body,
|
||||
url: '',
|
||||
headers,
|
||||
region: credentials?.region as string,
|
||||
} as IHttpRequestOptions;
|
||||
|
||||
if (Object.keys(option).length !== 0) {
|
||||
Object.assign(requestOptions, option);
|
||||
}
|
||||
return await this.helpers.requestWithAuthentication.call(this, credentialsType, requestOptions);
|
||||
}
|
||||
|
||||
export async function awsApiRequestREST(
|
||||
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
|
||||
service: string,
|
||||
method: IHttpRequestMethods,
|
||||
path: string,
|
||||
body?: string,
|
||||
query: IDataObject = {},
|
||||
headers?: object,
|
||||
options: IDataObject = {},
|
||||
region?: string,
|
||||
): Promise<any> {
|
||||
const response = await awsApiRequest.call(
|
||||
this,
|
||||
service,
|
||||
method,
|
||||
path,
|
||||
body,
|
||||
query,
|
||||
headers,
|
||||
options,
|
||||
region,
|
||||
);
|
||||
try {
|
||||
return JSON.parse(response as string);
|
||||
} catch (error) {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
export async function awsApiRequestSOAP(
|
||||
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
|
||||
service: string,
|
||||
method: IHttpRequestMethods,
|
||||
path: string,
|
||||
body?: string | Buffer | IDataObject,
|
||||
query: IDataObject = {},
|
||||
headers?: object,
|
||||
option: IDataObject = {},
|
||||
region?: string,
|
||||
): Promise<any> {
|
||||
const response = await awsApiRequest.call(
|
||||
this,
|
||||
service,
|
||||
method,
|
||||
path,
|
||||
body,
|
||||
query,
|
||||
headers,
|
||||
option,
|
||||
region,
|
||||
);
|
||||
try {
|
||||
return await new Promise((resolve, reject) => {
|
||||
parseString(response as string, { explicitArray: false }, (err, data) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
resolve(data);
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function awsApiRequestSOAPAllItems(
|
||||
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
|
||||
propertyName: string,
|
||||
service: string,
|
||||
method: IHttpRequestMethods,
|
||||
path: string,
|
||||
body?: string,
|
||||
query: IDataObject = {},
|
||||
headers: IDataObject = {},
|
||||
option: IDataObject = {},
|
||||
region?: string,
|
||||
): Promise<any> {
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
let responseData;
|
||||
|
||||
do {
|
||||
responseData = await awsApiRequestSOAP.call(
|
||||
this,
|
||||
service,
|
||||
method,
|
||||
path,
|
||||
body,
|
||||
query,
|
||||
headers,
|
||||
option,
|
||||
region,
|
||||
);
|
||||
|
||||
//https://forums.aws.amazon.com/thread.jspa?threadID=55746
|
||||
if (get(responseData, [propertyName.split('.')[0], 'NextContinuationToken'])) {
|
||||
query['continuation-token'] = get(responseData, [
|
||||
propertyName.split('.')[0],
|
||||
'NextContinuationToken',
|
||||
]);
|
||||
}
|
||||
if (get(responseData, propertyName)) {
|
||||
if (Array.isArray(get(responseData, propertyName))) {
|
||||
returnData.push.apply(returnData, get(responseData, propertyName) as IDataObject[]);
|
||||
} else {
|
||||
returnData.push(get(responseData, propertyName) as IDataObject);
|
||||
}
|
||||
}
|
||||
const limit = query.limit as number | undefined;
|
||||
if (limit && limit <= returnData.length) {
|
||||
return returnData;
|
||||
}
|
||||
} while (
|
||||
get(responseData, [propertyName.split('.')[0], 'IsTruncated']) !== undefined &&
|
||||
get(responseData, [propertyName.split('.')[0], 'IsTruncated']) !== 'false'
|
||||
);
|
||||
|
||||
return returnData;
|
||||
}
|
||||
|
||||
export function keysTPascalCase(object: IDataObject) {
|
||||
const data: IDataObject = {};
|
||||
for (const key of Object.keys(object)) {
|
||||
data[pascalCase(key)] = object[key];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"TextDetections": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Confidence": {
|
||||
"type": "number"
|
||||
},
|
||||
"DetectedText": {
|
||||
"type": "string"
|
||||
},
|
||||
"Geometry": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"BoundingBox": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Height": {
|
||||
"type": "number"
|
||||
},
|
||||
"Left": {
|
||||
"type": "number"
|
||||
},
|
||||
"Top": {
|
||||
"type": "number"
|
||||
},
|
||||
"Width": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Polygon": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"X": {
|
||||
"type": "number"
|
||||
},
|
||||
"Y": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"ParentId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"Type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"TextModelVersion": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#fff" fill-rule="evenodd" stroke="#000" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 74.375 85"><use xlink:href="#a" x="2.188" y="2.5"/><symbol id="a" overflow="visible"><g stroke="none"><path fill="#5294cf" d="M2.886 52.8 16.8 51.268V28.732L2.886 27.2z"/><g fill="#19486f"><path d="m67.207 28.898-6.462 2.43-36.237-5.346L34.99 0z"/><path d="M3.504 28.966 35 12.234 45.543 26 16.81 30.224l-13.305-1.26z"/></g><g fill="#205b99"><path d="M35 24 0 30.624V16.556L35 0l17.016 18.478z"/><path d="M7.008 16.478 0 19.395v44.05l7.008 3.307z"/></g><path fill="#5294cf" d="M70 16.566 35 0v24l35 6.624v-14.06z"/><g fill="#99bce3"><path d="M1.154 51.26 34.99 80l10.554-26-28.734-4.224z"/><path d="m67.64 51.142-6.493-2.527-36.64 5.405 10.48 25.22 32.65-28.097z"/></g><path fill="#205b99" d="m67.207 51.103-13.965-1.327v-19.55L67.207 28.9v22.205zM35 56l15.13-16L35 24 16.356 40z"/><path fill="#5294cf" d="M53.624 40 35 56V24l18.634 16z"/><path fill="#205b99" d="M0 49.376 35 56l19.21 7.873L35 80 0 63.444z"/><g fill="#5294cf"><path d="M70 63.435 35 80V56l35-6.624z"/><path d="M62.97 66.75 70 63.434V16.566l-7.03-3.327z"/></g></g></symbol></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,303 @@
|
||||
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
|
||||
import nock from 'nock';
|
||||
|
||||
import { credentials } from '../../__tests__/credentials';
|
||||
|
||||
const responseLabels = [
|
||||
{
|
||||
LabelModelVersion: '3.0',
|
||||
Labels: [
|
||||
{
|
||||
Aliases: [],
|
||||
Categories: [
|
||||
{
|
||||
Name: 'Food and Beverage',
|
||||
},
|
||||
],
|
||||
Confidence: 99.81004333496094,
|
||||
Instances: [],
|
||||
Name: 'Alcohol',
|
||||
Parents: [
|
||||
{
|
||||
Name: 'Beverage',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
Aliases: [
|
||||
{
|
||||
Name: 'Drink',
|
||||
},
|
||||
],
|
||||
Categories: [
|
||||
{
|
||||
Name: 'Food and Beverage',
|
||||
},
|
||||
],
|
||||
Confidence: 99.81004333496094,
|
||||
Instances: [],
|
||||
Name: 'Beverage',
|
||||
Parents: [],
|
||||
},
|
||||
{
|
||||
Aliases: [],
|
||||
Categories: [
|
||||
{
|
||||
Name: 'Food and Beverage',
|
||||
},
|
||||
],
|
||||
Confidence: 99.81004333496094,
|
||||
Instances: [],
|
||||
Name: 'Liquor',
|
||||
Parents: [
|
||||
{
|
||||
Name: 'Alcohol',
|
||||
},
|
||||
{
|
||||
Name: 'Beverage',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
Aliases: [],
|
||||
Categories: [
|
||||
{
|
||||
Name: 'Food and Beverage',
|
||||
},
|
||||
],
|
||||
Confidence: 99.75448608398438,
|
||||
Instances: [],
|
||||
Name: 'Red Wine',
|
||||
Parents: [
|
||||
{
|
||||
Name: 'Alcohol',
|
||||
},
|
||||
{
|
||||
Name: 'Beverage',
|
||||
},
|
||||
{
|
||||
Name: 'Liquor',
|
||||
},
|
||||
{
|
||||
Name: 'Wine',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
Aliases: [],
|
||||
Categories: [
|
||||
{
|
||||
Name: 'Food and Beverage',
|
||||
},
|
||||
],
|
||||
Confidence: 99.75448608398438,
|
||||
Instances: [],
|
||||
Name: 'Wine',
|
||||
Parents: [
|
||||
{
|
||||
Name: 'Alcohol',
|
||||
},
|
||||
{
|
||||
Name: 'Beverage',
|
||||
},
|
||||
{
|
||||
Name: 'Liquor',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
Aliases: [],
|
||||
Categories: [
|
||||
{
|
||||
Name: 'Everyday Objects',
|
||||
},
|
||||
],
|
||||
Confidence: 99.52116394042969,
|
||||
Instances: [],
|
||||
Name: 'Bottle',
|
||||
Parents: [],
|
||||
},
|
||||
{
|
||||
Aliases: [],
|
||||
Categories: [
|
||||
{
|
||||
Name: 'Food and Beverage',
|
||||
},
|
||||
],
|
||||
Confidence: 94.69605255126953,
|
||||
Instances: [],
|
||||
Name: 'Wine Bottle',
|
||||
Parents: [
|
||||
{
|
||||
Name: 'Alcohol',
|
||||
},
|
||||
{
|
||||
Name: 'Beverage',
|
||||
},
|
||||
{
|
||||
Name: 'Bottle',
|
||||
},
|
||||
{
|
||||
Name: 'Liquor',
|
||||
},
|
||||
{
|
||||
Name: 'Wine',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
Aliases: [],
|
||||
Categories: [
|
||||
{
|
||||
Name: 'Food and Beverage',
|
||||
},
|
||||
],
|
||||
Confidence: 90.0589370727539,
|
||||
Instances: [],
|
||||
Name: 'Food',
|
||||
Parents: [],
|
||||
},
|
||||
{
|
||||
Aliases: [],
|
||||
Categories: [
|
||||
{
|
||||
Name: 'Food and Beverage',
|
||||
},
|
||||
],
|
||||
Confidence: 90.0589370727539,
|
||||
Instances: [
|
||||
{
|
||||
BoundingBox: {
|
||||
Height: 0.9467026591300964,
|
||||
Left: 0.23295101523399353,
|
||||
Top: 0.02573961764574051,
|
||||
Width: 0.5303559899330139,
|
||||
},
|
||||
Confidence: 90.0589370727539,
|
||||
},
|
||||
],
|
||||
Name: 'Ketchup',
|
||||
Parents: [
|
||||
{
|
||||
Name: 'Food',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
Aliases: [],
|
||||
Categories: [
|
||||
{
|
||||
Name: 'Food and Beverage',
|
||||
},
|
||||
],
|
||||
Confidence: 65.56095123291016,
|
||||
Instances: [],
|
||||
Name: 'Beer',
|
||||
Parents: [
|
||||
{
|
||||
Name: 'Alcohol',
|
||||
},
|
||||
{
|
||||
Name: 'Beverage',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
Aliases: [],
|
||||
Categories: [
|
||||
{
|
||||
Name: 'Text and Documents',
|
||||
},
|
||||
],
|
||||
Confidence: 61.83842468261719,
|
||||
Instances: [],
|
||||
Name: 'Document',
|
||||
Parents: [
|
||||
{
|
||||
Name: 'Text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
Aliases: [],
|
||||
Categories: [
|
||||
{
|
||||
Name: 'Text and Documents',
|
||||
},
|
||||
],
|
||||
Confidence: 61.83842468261719,
|
||||
Instances: [],
|
||||
Name: 'Id Cards',
|
||||
Parents: [
|
||||
{
|
||||
Name: 'Document',
|
||||
},
|
||||
{
|
||||
Name: 'Text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
Aliases: [],
|
||||
Categories: [
|
||||
{
|
||||
Name: 'Text and Documents',
|
||||
},
|
||||
],
|
||||
Confidence: 61.83842468261719,
|
||||
Instances: [
|
||||
{
|
||||
BoundingBox: {
|
||||
Height: 0.5003108382225037,
|
||||
Left: 0.2603513300418854,
|
||||
Top: 0.2912488579750061,
|
||||
Width: 0.4734913110733032,
|
||||
},
|
||||
Confidence: 61.83842468261719,
|
||||
},
|
||||
],
|
||||
Name: 'Passport',
|
||||
Parents: [
|
||||
{
|
||||
Name: 'Document',
|
||||
},
|
||||
{
|
||||
Name: 'Id Cards',
|
||||
},
|
||||
{
|
||||
Name: 'Text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
Aliases: [],
|
||||
Categories: [
|
||||
{
|
||||
Name: 'Text and Documents',
|
||||
},
|
||||
],
|
||||
Confidence: 61.83842468261719,
|
||||
Instances: [],
|
||||
Name: 'Text',
|
||||
Parents: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
describe('Test AWS Rekogntion Node', () => {
|
||||
describe('Image Labels Recognition', () => {
|
||||
const baseUrl = 'https://rekognition.eu-central-1.amazonaws.com';
|
||||
let mock: nock.Scope;
|
||||
|
||||
beforeAll(async () => {
|
||||
mock = nock(baseUrl);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
mock.post('/').reply(200, responseLabels);
|
||||
});
|
||||
|
||||
new NodeTestHarness().setupTests({ credentials });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,344 @@
|
||||
{
|
||||
"name": "node-37-aws-rekognition-empty-response-data",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"id": "6b79e1a7-8d17-470a-9423-d97042060170",
|
||||
"name": "When clicking \"Execute Workflow\"",
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
40,
|
||||
280
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"type": "detectText",
|
||||
"bucket": "test",
|
||||
"name": "test",
|
||||
"additionalFields": {}
|
||||
},
|
||||
"id": "86b957c8-fdec-462e-b55d-40dccf7bc253",
|
||||
"name": "AWS Rekognition",
|
||||
"type": "n8n-nodes-base.awsRekognition",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
500,
|
||||
280
|
||||
],
|
||||
"credentials": {
|
||||
"aws": {
|
||||
"id": "114",
|
||||
"name": "NodeQA"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"pinData": {
|
||||
"AWS Rekognition": [
|
||||
{
|
||||
"json": {
|
||||
"LabelModelVersion": "3.0",
|
||||
"Labels": [
|
||||
{
|
||||
"Aliases": [],
|
||||
"Categories": [
|
||||
{
|
||||
"Name": "Food and Beverage"
|
||||
}
|
||||
],
|
||||
"Confidence": 99.81004333496094,
|
||||
"Instances": [],
|
||||
"Name": "Alcohol",
|
||||
"Parents": [
|
||||
{
|
||||
"Name": "Beverage"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Aliases": [
|
||||
{
|
||||
"Name": "Drink"
|
||||
}
|
||||
],
|
||||
"Categories": [
|
||||
{
|
||||
"Name": "Food and Beverage"
|
||||
}
|
||||
],
|
||||
"Confidence": 99.81004333496094,
|
||||
"Instances": [],
|
||||
"Name": "Beverage",
|
||||
"Parents": []
|
||||
},
|
||||
{
|
||||
"Aliases": [],
|
||||
"Categories": [
|
||||
{
|
||||
"Name": "Food and Beverage"
|
||||
}
|
||||
],
|
||||
"Confidence": 99.81004333496094,
|
||||
"Instances": [],
|
||||
"Name": "Liquor",
|
||||
"Parents": [
|
||||
{
|
||||
"Name": "Alcohol"
|
||||
},
|
||||
{
|
||||
"Name": "Beverage"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Aliases": [],
|
||||
"Categories": [
|
||||
{
|
||||
"Name": "Food and Beverage"
|
||||
}
|
||||
],
|
||||
"Confidence": 99.75448608398438,
|
||||
"Instances": [],
|
||||
"Name": "Red Wine",
|
||||
"Parents": [
|
||||
{
|
||||
"Name": "Alcohol"
|
||||
},
|
||||
{
|
||||
"Name": "Beverage"
|
||||
},
|
||||
{
|
||||
"Name": "Liquor"
|
||||
},
|
||||
{
|
||||
"Name": "Wine"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Aliases": [],
|
||||
"Categories": [
|
||||
{
|
||||
"Name": "Food and Beverage"
|
||||
}
|
||||
],
|
||||
"Confidence": 99.75448608398438,
|
||||
"Instances": [],
|
||||
"Name": "Wine",
|
||||
"Parents": [
|
||||
{
|
||||
"Name": "Alcohol"
|
||||
},
|
||||
{
|
||||
"Name": "Beverage"
|
||||
},
|
||||
{
|
||||
"Name": "Liquor"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Aliases": [],
|
||||
"Categories": [
|
||||
{
|
||||
"Name": "Everyday Objects"
|
||||
}
|
||||
],
|
||||
"Confidence": 99.52116394042969,
|
||||
"Instances": [],
|
||||
"Name": "Bottle",
|
||||
"Parents": []
|
||||
},
|
||||
{
|
||||
"Aliases": [],
|
||||
"Categories": [
|
||||
{
|
||||
"Name": "Food and Beverage"
|
||||
}
|
||||
],
|
||||
"Confidence": 94.69605255126953,
|
||||
"Instances": [],
|
||||
"Name": "Wine Bottle",
|
||||
"Parents": [
|
||||
{
|
||||
"Name": "Alcohol"
|
||||
},
|
||||
{
|
||||
"Name": "Beverage"
|
||||
},
|
||||
{
|
||||
"Name": "Bottle"
|
||||
},
|
||||
{
|
||||
"Name": "Liquor"
|
||||
},
|
||||
{
|
||||
"Name": "Wine"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Aliases": [],
|
||||
"Categories": [
|
||||
{
|
||||
"Name": "Food and Beverage"
|
||||
}
|
||||
],
|
||||
"Confidence": 90.0589370727539,
|
||||
"Instances": [],
|
||||
"Name": "Food",
|
||||
"Parents": []
|
||||
},
|
||||
{
|
||||
"Aliases": [],
|
||||
"Categories": [
|
||||
{
|
||||
"Name": "Food and Beverage"
|
||||
}
|
||||
],
|
||||
"Confidence": 90.0589370727539,
|
||||
"Instances": [
|
||||
{
|
||||
"BoundingBox": {
|
||||
"Height": 0.9467026591300964,
|
||||
"Left": 0.23295101523399353,
|
||||
"Top": 0.02573961764574051,
|
||||
"Width": 0.5303559899330139
|
||||
},
|
||||
"Confidence": 90.0589370727539
|
||||
}
|
||||
],
|
||||
"Name": "Ketchup",
|
||||
"Parents": [
|
||||
{
|
||||
"Name": "Food"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Aliases": [],
|
||||
"Categories": [
|
||||
{
|
||||
"Name": "Food and Beverage"
|
||||
}
|
||||
],
|
||||
"Confidence": 65.56095123291016,
|
||||
"Instances": [],
|
||||
"Name": "Beer",
|
||||
"Parents": [
|
||||
{
|
||||
"Name": "Alcohol"
|
||||
},
|
||||
{
|
||||
"Name": "Beverage"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Aliases": [],
|
||||
"Categories": [
|
||||
{
|
||||
"Name": "Text and Documents"
|
||||
}
|
||||
],
|
||||
"Confidence": 61.83842468261719,
|
||||
"Instances": [],
|
||||
"Name": "Document",
|
||||
"Parents": [
|
||||
{
|
||||
"Name": "Text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Aliases": [],
|
||||
"Categories": [
|
||||
{
|
||||
"Name": "Text and Documents"
|
||||
}
|
||||
],
|
||||
"Confidence": 61.83842468261719,
|
||||
"Instances": [],
|
||||
"Name": "Id Cards",
|
||||
"Parents": [
|
||||
{
|
||||
"Name": "Document"
|
||||
},
|
||||
{
|
||||
"Name": "Text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Aliases": [],
|
||||
"Categories": [
|
||||
{
|
||||
"Name": "Text and Documents"
|
||||
}
|
||||
],
|
||||
"Confidence": 61.83842468261719,
|
||||
"Instances": [
|
||||
{
|
||||
"BoundingBox": {
|
||||
"Height": 0.5003108382225037,
|
||||
"Left": 0.2603513300418854,
|
||||
"Top": 0.2912488579750061,
|
||||
"Width": 0.4734913110733032
|
||||
},
|
||||
"Confidence": 61.83842468261719
|
||||
}
|
||||
],
|
||||
"Name": "Passport",
|
||||
"Parents": [
|
||||
{
|
||||
"Name": "Document"
|
||||
},
|
||||
{
|
||||
"Name": "Id Cards"
|
||||
},
|
||||
{
|
||||
"Name": "Text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Aliases": [],
|
||||
"Categories": [
|
||||
{
|
||||
"Name": "Text and Documents"
|
||||
}
|
||||
],
|
||||
"Confidence": 61.83842468261719,
|
||||
"Instances": [],
|
||||
"Name": "Text",
|
||||
"Parents": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"connections": {
|
||||
"When clicking \"Execute Workflow\"": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "AWS Rekognition",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {},
|
||||
"versionId": "26ee97c0-3122-4281-96ac-ad4ded7b4ee5",
|
||||
"id": "55",
|
||||
"meta": {
|
||||
"instanceId": "8e9416f42a954d0a370d988ac3c0f916f44074a6e45189164b1a8559394a7516"
|
||||
},
|
||||
"tags": []
|
||||
}
|
||||
Reference in New Issue
Block a user