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.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;
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"BeginOffset": {
|
||||
"type": "integer"
|
||||
},
|
||||
"EndOffset": {
|
||||
"type": "integer"
|
||||
},
|
||||
"Score": {
|
||||
"type": "number"
|
||||
},
|
||||
"Text": {
|
||||
"type": "string"
|
||||
},
|
||||
"Type": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
+26
@@ -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": []
|
||||
}
|
||||
Reference in New Issue
Block a user