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,18 @@
|
||||
{
|
||||
"node": "n8n-nodes-base.aiTransform",
|
||||
"nodeVersion": "1.0",
|
||||
"codexVersion": "1.0",
|
||||
"details": "Modify data by writing a prompt",
|
||||
"categories": ["Development", "Core Nodes"],
|
||||
"resources": {
|
||||
"primaryDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.aitransform/"
|
||||
}
|
||||
]
|
||||
},
|
||||
"alias": ["code", "Javascript", "JS", "Script", "Custom Code", "Function", "AI", "LLM"],
|
||||
"subcategories": {
|
||||
"Core Nodes": ["Data Transformation"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
import {
|
||||
NodeOperationError,
|
||||
NodeConnectionTypes,
|
||||
type IExecuteFunctions,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type INode,
|
||||
AI_TRANSFORM_CODE_GENERATED_FOR_PROMPT,
|
||||
AI_TRANSFORM_JS_CODE,
|
||||
ensureError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { JsTaskRunnerSandbox } from '../Code/JsTaskRunnerSandbox';
|
||||
|
||||
export class AiTransform implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'AI Transform',
|
||||
name: 'aiTransform',
|
||||
icon: 'file:aitransform.svg',
|
||||
group: ['transform'],
|
||||
version: 1,
|
||||
description: 'Modify data based on instructions written in plain english',
|
||||
defaults: {
|
||||
name: 'AI Transform',
|
||||
},
|
||||
inputs: [NodeConnectionTypes.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
parameterPane: 'wide',
|
||||
hints: [
|
||||
{
|
||||
message:
|
||||
"This node doesn't have access to the contents of binary files. To use those contents here, use the 'Extract from File' node first.",
|
||||
displayCondition: '={{ $input.all().some(i => i.binary) }}',
|
||||
location: 'outputPane',
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Instructions',
|
||||
name: 'instructions',
|
||||
type: 'button',
|
||||
default: '',
|
||||
description:
|
||||
"Provide instructions on how you want to transform the data, then click 'Generate code'. Use dot notation to refer to nested fields (e.g. address.street).",
|
||||
placeholder:
|
||||
"Example: Merge 'firstname' and 'lastname' into a field 'details.name' and sort by 'email'",
|
||||
typeOptions: {
|
||||
buttonConfig: {
|
||||
label: 'Generate code',
|
||||
hasInputField: true,
|
||||
inputFieldMaxLength: 500,
|
||||
action: {
|
||||
type: 'askAiCodeGeneration',
|
||||
target: AI_TRANSFORM_JS_CODE,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Code Generated For Prompt',
|
||||
name: AI_TRANSFORM_CODE_GENERATED_FOR_PROMPT,
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Generated JavaScript',
|
||||
name: AI_TRANSFORM_JS_CODE,
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
editor: 'jsEditor',
|
||||
editorIsReadOnly: true,
|
||||
},
|
||||
default: '',
|
||||
hint: 'Read-only. To edit this code, adjust the instructions or copy and paste it into a Code node.',
|
||||
noDataExpression: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions) {
|
||||
const workflowMode = this.getMode();
|
||||
const node = this.getNode();
|
||||
const code = getValidatedCode(this, node);
|
||||
|
||||
const sandbox = new JsTaskRunnerSandbox(workflowMode, this);
|
||||
return [await sandbox.runCodeAllItems(code)];
|
||||
}
|
||||
}
|
||||
|
||||
function getValidatedCode(executeFunctions: IExecuteFunctions, node: INode): string {
|
||||
try {
|
||||
const code = executeFunctions.getNodeParameter(AI_TRANSFORM_JS_CODE, 0) as string;
|
||||
if (code) {
|
||||
return code;
|
||||
}
|
||||
|
||||
const instructions = executeFunctions.getNodeParameter('instructions', 0) as string;
|
||||
if (!instructions) {
|
||||
throw new NodeOperationError(node, 'Missing instructions to generate code', {
|
||||
description: "Enter your prompt in the 'Instructions' parameter and click 'Generate code'",
|
||||
});
|
||||
}
|
||||
throw new NodeOperationError(node, 'Missing code for data transformation', {
|
||||
description: "Click the 'Generate code' button to create the code",
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof NodeOperationError) throw error;
|
||||
|
||||
throw new NodeOperationError(node, ensureError(error));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M39.4956 19.5195L34.8 18.006C31.7965 17.015 30.0369 14.5846 29.2111 11.5306L27.1447 1.46518C27.0908 1.2663 26.9593 1 26.5548 1C26.2144 1 26.0188 1.2663 25.9649 1.46518L23.8986 11.534C23.0693 14.588 21.3131 17.0184 18.3097 18.0094L13.6141 19.5229C12.95 19.7386 12.9399 20.6757 13.6006 20.9016L18.3299 22.5297C21.3232 23.5241 23.0693 25.9512 23.8986 28.9917L25.9683 38.9458C26.0222 39.1447 26.1335 39.502 26.5582 39.502C26.9977 39.502 27.0906 39.1585 27.1449 38.9577L27.1481 38.9458L29.2178 28.9917C30.047 25.9478 31.7931 23.5208 34.7865 22.5297L39.5158 20.9016C40.1697 20.6724 40.1596 19.7353 39.4956 19.5195ZM12.6028 28.277C9.82036 27.3584 9.54358 26.324 9.07959 24.5899L9.06681 24.5421L7.89038 20.4162C7.81959 20.1499 7.12519 20.1499 7.05103 20.4162L6.25214 24.2286C5.77684 25.9848 4.76558 27.3804 3.0397 27.9501L0.289074 29.1433C-0.0918337 29.2681 -0.0985755 29.8074 0.282332 29.9355L3.05318 30.9164C4.77233 31.4861 5.77684 32.8816 6.25551 34.6311L7.0544 38.2784C7.12856 38.5447 7.81959 38.5447 7.89038 38.2784L8.82748 34.648C9.30277 32.8884 10.0309 31.4895 12.3669 30.9164L14.9692 29.9355C15.3501 29.804 15.3467 29.2647 14.9625 29.14L12.6028 28.277ZM13.3255 2.03231C13.4169 1.65456 13.954 1.64852 14.0473 2.02833L14.0475 2.02889L15.0714 6.25591C15.2111 6.74054 15.5906 7.11618 16.0783 7.2487L18.6822 7.95026C19.0346 8.04918 19.0457 8.54279 18.7009 8.65979L18.7004 8.65996L15.97 9.57684C15.531 9.72415 15.1905 10.0756 15.0538 10.5179L14.0473 14.4327L14.0471 14.4337C13.9524 14.8153 13.4207 14.7996 13.3291 14.4333L12.3559 10.5303C12.2222 10.0878 11.8845 9.73333 11.4489 9.58314L8.72013 8.63869C8.37299 8.51471 8.40082 8.02141 8.75078 7.92932L8.75135 7.92917L11.3368 7.25837C11.8372 7.12876 12.2283 6.74382 12.3616 6.24505L13.3255 2.03231Z" fill="url(#paint0_linear_1373_20357)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_1373_20357" x1="0" y1="1" x2="47.0035" y2="13.8158" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#5B60E8"/>
|
||||
<stop offset="0.5" stop-color="#AA7BEC"/>
|
||||
<stop offset="1" stop-color="#EC7B8E"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
Reference in New Issue
Block a user