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

This commit is contained in:
2026-03-17 16:22:57 +03:30
commit 3d5eaf9445
15349 changed files with 2847338 additions and 0 deletions
@@ -0,0 +1,24 @@
{
"node": "n8n-nodes-base.awsComprehend",
"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.awscomprehend/"
}
],
"generic": [
{
"label": "7 no-code workflow automations for Amazon Web Services",
"url": "https://n8n.io/blog/aws-workflow-automation/"
}
]
}
}
@@ -0,0 +1,291 @@
import type {
IExecuteFunctions,
IDataObject,
INodeExecutionData,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import { awsApiRequestREST } from './GenericFunctions';
import { awsNodeAuthOptions, awsNodeCredentials } from '../utils';
export class AwsComprehend implements INodeType {
description: INodeTypeDescription = {
displayName: 'AWS Comprehend',
name: 'awsComprehend',
icon: 'file:comprehend.svg',
group: ['output'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Sends data to Amazon Comprehend',
schemaPath: 'Aws/Comprehend',
defaults: {
name: 'AWS Comprehend',
},
inputs: [NodeConnectionTypes.Main],
outputs: [NodeConnectionTypes.Main],
credentials: awsNodeCredentials,
properties: [
awsNodeAuthOptions,
{
displayName: 'Resource',
name: 'resource',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Text',
value: 'text',
},
],
default: 'text',
description: 'The resource to perform',
},
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Detect Dominant Language',
value: 'detectDominantLanguage',
description: 'Identify the dominant language',
action: 'Identify the dominant language',
},
{
name: 'Detect Entities',
value: 'detectEntities',
description: 'Inspects text for named entities, and returns information about them',
action: 'Inspect text for named entities, and returns information about them',
},
{
name: 'Detect Sentiment',
value: 'detectSentiment',
description: 'Analyse the sentiment of the text',
action: 'Analyze the sentiment of the text',
},
],
default: 'detectDominantLanguage',
},
{
displayName: 'Language Code',
name: 'languageCode',
type: 'options',
options: [
{
name: 'Arabic',
value: 'ar',
},
{
name: 'Chinese',
value: 'zh',
},
{
name: 'Chinese (T)',
value: 'zh-TW',
},
{
name: 'English',
value: 'en',
},
{
name: 'French',
value: 'fr',
},
{
name: 'German',
value: 'de',
},
{
name: 'Hindi',
value: 'hi',
},
{
name: 'Italian',
value: 'it',
},
{
name: 'Japanese',
value: 'ja',
},
{
name: 'Korean',
value: 'ko',
},
{
name: 'Portuguese',
value: 'pt',
},
{
name: 'Spanish',
value: 'es',
},
],
default: 'en',
displayOptions: {
show: {
resource: ['text'],
operation: ['detectSentiment', 'detectEntities'],
},
},
description: 'The language code for text',
},
{
displayName: 'Text',
name: 'text',
type: 'string',
default: '',
displayOptions: {
show: {
resource: ['text'],
},
},
description: 'The text to send',
},
{
displayName: 'Simplify',
name: 'simple',
type: 'boolean',
displayOptions: {
show: {
resource: ['text'],
operation: ['detectDominantLanguage'],
},
},
default: true,
description:
'Whether to return a simplified version of the response instead of the raw data',
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
displayOptions: {
show: {
resource: ['text'],
operation: ['detectEntities'],
},
},
default: {},
options: [
{
displayName: 'Endpoint Arn',
name: 'endpointArn',
type: 'string',
default: '',
description:
'The Amazon Resource Name of an endpoint that is associated with a custom entity recognition model',
},
],
},
],
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const returnData: INodeExecutionData[] = [];
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 === 'text') {
//https://docs.aws.amazon.com/comprehend/latest/dg/API_DetectDominantLanguage.html
if (operation === 'detectDominantLanguage') {
const text = this.getNodeParameter('text', i) as string;
const simple = this.getNodeParameter('simple', i) as boolean;
const body: IDataObject = {
Text: text,
};
const action = 'Comprehend_20171127.DetectDominantLanguage';
responseData = await awsApiRequestREST.call(
this,
'comprehend',
'POST',
'',
JSON.stringify(body),
{ 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' },
);
if (simple) {
responseData = responseData.Languages.reduce(
(accumulator: { [key: string]: number }, currentValue: IDataObject) => {
accumulator[currentValue.LanguageCode as string] = currentValue.Score as number;
return accumulator;
},
{},
);
}
}
//https://docs.aws.amazon.com/comprehend/latest/dg/API_DetectSentiment.html
if (operation === 'detectSentiment') {
const action = 'Comprehend_20171127.DetectSentiment';
const text = this.getNodeParameter('text', i) as string;
const languageCode = this.getNodeParameter('languageCode', i) as string;
const body: IDataObject = {
Text: text,
LanguageCode: languageCode,
};
responseData = await awsApiRequestREST.call(
this,
'comprehend',
'POST',
'',
JSON.stringify(body),
{ 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' },
);
}
//https://docs.aws.amazon.com/comprehend/latest/dg/API_DetectEntities.html
if (operation === 'detectEntities') {
const action = 'Comprehend_20171127.DetectEntities';
const text = this.getNodeParameter('text', i) as string;
const languageCode = this.getNodeParameter('languageCode', i) as string;
const additionalFields = this.getNodeParameter('additionalFields', i);
const body: IDataObject = {
Text: text,
LanguageCode: languageCode,
};
if (additionalFields.endpointArn) {
body.EndpointArn = additionalFields.endpointArn;
}
responseData = await awsApiRequestREST.call(
this,
'comprehend',
'POST',
'',
JSON.stringify(body),
{ 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' },
);
responseData = responseData.Entities;
}
}
const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData),
{ itemData: { item: i } },
);
returnData.push(...executionData);
} catch (error) {
if (this.continueOnFail()) {
const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray({ error: error.message }),
{ itemData: { item: i } },
);
returnData.push(...executionData);
continue;
}
throw error;
}
}
return [returnData];
}
}
@@ -0,0 +1,73 @@
import type {
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,
headers?: object,
): Promise<any> {
const { credentials, credentialsType } = await getAwsCredentials(this);
const requestOptions = {
qs: {
service,
path,
},
method,
body,
url: '',
headers,
region: credentials?.region as string,
} as IHttpRequestOptions;
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,
headers?: object,
): Promise<any> {
const response = await awsApiRequest.call(this, service, method, path, body, headers);
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,
headers?: object,
): Promise<any> {
const response = await awsApiRequest.call(this, service, method, path, body, headers);
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 response;
}
}
@@ -0,0 +1,21 @@
{
"type": "object",
"properties": {
"BeginOffset": {
"type": "integer"
},
"EndOffset": {
"type": "integer"
},
"Score": {
"type": "number"
},
"Text": {
"type": "string"
},
"Type": {
"type": "string"
}
},
"version": 1
}
@@ -0,0 +1,26 @@
{
"type": "object",
"properties": {
"Sentiment": {
"type": "string"
},
"SentimentScore": {
"type": "object",
"properties": {
"Mixed": {
"type": "number"
},
"Negative": {
"type": "number"
},
"Neutral": {
"type": "number"
},
"Positive": {
"type": "number"
}
}
}
},
"version": 1
}
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 75 75"><defs><linearGradient id="a" x1="617.46" x2="723.53" y1="-674.53" y2="-568.46" gradientTransform="rotate(-90 683.5 24.5)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#055f4e"/><stop offset="1" stop-color="#56c0a7"/></linearGradient></defs><path fill="url(#a)" d="M0 0h75v75H0z" data-name="Turquoise Gradient"/><path fill="#fff" d="M44.5 34.2v-9.7a1 1 0 0 0-.29-.71l-11-11a1 1 0 0 0-.71-.29h-19a1 1 0 0 0-1 1v43a1 1 0 0 0 1 1h30a1 1 0 0 0 1-1v-4.44a11.8 11.8 0 0 1-2-2.3v5.74h-28v-41h17v10a1 1 0 0 0 1 1h10v11a11.6 11.6 0 0 1 2-2.3m-11-10.7v-7.59l7.59 7.59zm-10 8h-6v-2h6zm16 0h-14v-2h14zm0 6h-22v-2h22zm15.44 25h-4.88a1 1 0 0 1-.93-.62l-1.21-3a1 1 0 0 1 .09-.94 1 1 0 0 1 .83-.44h7.32a1 1 0 0 1 .83.44 1 1 0 0 1 .09.94l-1.21 3a1 1 0 0 1-.93.62m-4.21-2h3.54l.4-1h-4.34zm11.64-19a10 10 0 0 0-19.87 1.62 10 10 0 0 0 4.28 8.2 4 4 0 0 1 .72.59v3.59a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-3.6a4.3 4.3 0 0 1 .71-.57 9.92 9.92 0 0 0 4.29-8.2 10 10 0 0 0-.13-1.65zm-5.32 8.2c-.58.4-1.55 1.07-1.55 2.1v2.7h-2v-7h2v-2h-6v2h2v7h-2v-2.68c0-1-1-1.73-1.58-2.14A8 8 0 1 1 58 37.32a7.9 7.9 0 0 1 2.39 4.47 8 8 0 0 1-3.34 7.91M28.5 25.5h-11v-2h11zm1 18h-12v-2h12zm10 0h-8v-2h8zm-9 6h-13v-2h13z" data-name="Icon Test"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@@ -0,0 +1,37 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
import { credentials } from '../../__tests__/credentials';
describe('Test AWS Comprehend Node', () => {
describe('Detect Language', () => {
let mock: nock.Scope;
const now = 1683028800000;
const response = {
Languages: [
{
LanguageCode: 'en',
Score: 0.9774383902549744,
},
{
LanguageCode: 'de',
Score: 0.010717987082898617,
},
],
};
beforeAll(async () => {
jest.useFakeTimers({ doNotFake: ['nextTick'], now });
const baseUrl = 'https://comprehend.eu-central-1.amazonaws.com';
mock = nock(baseUrl);
});
beforeEach(async () => {
mock.post('/').reply(200, response);
});
new NodeTestHarness().setupTests({ credentials });
});
});
@@ -0,0 +1,113 @@
{
"name": "node-aws-comprehend",
"nodes": [
{
"parameters": {},
"id": "53b6020d-5aa2-435f-9ee1-407111c0e3ee",
"name": "When clicking Execute workflow",
"type": "n8n-nodes-base.manualTrigger",
"position": [680, 380],
"typeVersion": 1
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "51b7eee5-8cc9-4e09-a2f4-65ffb3cc17f6",
"name": "text",
"value": "This is a test.",
"type": "string"
}
]
},
"options": {}
},
"id": "b3beaf43-fe4c-43e1-a8cb-5a0740050611",
"name": "Edit Fields",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [900, 380]
},
{
"parameters": {
"text": "={{ $json.text }}"
},
"id": "a6a8a24c-0e58-40e7-8bf4-13a56edc6264",
"name": "AWS Comprehend",
"type": "n8n-nodes-base.awsComprehend",
"typeVersion": 1,
"position": [1100, 380],
"credentials": {
"aws": {
"id": "TyNATsPCTvPF0tvG",
"name": "AWS account"
}
}
},
{
"parameters": {},
"id": "bfc4b84d-8cf1-4650-bf3c-2b1cdc677afc",
"name": "No Operation, do nothing",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [1320, 380]
}
],
"pinData": {
"No Operation, do nothing": [
{
"json": {
"de": 0.010717987082898617,
"en": 0.9774383902549744
}
}
]
},
"connections": {
"Edit Fields": {
"main": [
[
{
"node": "AWS Comprehend",
"type": "main",
"index": 0
}
]
]
},
"When clicking Execute workflow": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
},
"AWS Comprehend": {
"main": [
[
{
"node": "No Operation, do nothing",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "eae3c601-56b8-42ec-a0b7-14df8d697043",
"meta": {
"templateCredsSetupCompleted": true,
"instanceId": "be251a83c052a9862eeac953816fbb1464f89dfbf79d7ac490a8e336a8cc8bfd"
},
"id": "fuOmKcLPWAxKi0bn",
"tags": []
}