-
Notifications
You must be signed in to change notification settings - Fork 9.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(OpenAI Node): Add a node to work with OpenAI (#4932)
* feat(OpenAI Node): Add a node to work with OpenAI * Added codex file for OpenAi node * Minor tweaks to Operation Image. * Minor tweaks to Resource Text. * Minor copy modification to Image:Create. * Removed "a Text" in Text operations names. * ⚡ Connect Response Format parameter and other improvements * ✨ Add "filter" postReceiveAction * ⚡ Rename operations and add spelling mistake again to example * ⚡ Rename another operation Co-authored-by: Jonathan Bennetts <jonathan.bennetts@gmail.com> Co-authored-by: Giulio Andreini <andreini@netseven.it>
- Loading branch information
1 parent
3028ad3
commit 7a984bb
Showing
9 changed files
with
821 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { | ||
IAuthenticateGeneric, | ||
ICredentialTestRequest, | ||
ICredentialType, | ||
INodeProperties, | ||
} from 'n8n-workflow'; | ||
|
||
export class OpenAiApi implements ICredentialType { | ||
name = 'openAiApi'; | ||
|
||
displayName = 'OpenAi'; | ||
|
||
documentationUrl = 'openAiApi'; | ||
|
||
properties: INodeProperties[] = [ | ||
{ | ||
displayName: 'API Key', | ||
name: 'apiKey', | ||
type: 'string', | ||
typeOptions: { password: true }, | ||
required: true, | ||
default: '', | ||
}, | ||
{ | ||
displayName: 'Organization ID', | ||
name: 'organizationId', | ||
type: 'string', | ||
default: '', | ||
description: | ||
"For users who belong to multiple organizations, you can set which organization is used for an API request. Usage from these API requests will count against the specified organization's subscription quota.", | ||
}, | ||
]; | ||
|
||
authenticate: IAuthenticateGeneric = { | ||
type: 'generic', | ||
properties: { | ||
headers: { | ||
Authorization: '=Bearer {{$credentials.apiKey}}', | ||
'OpenAI-Organization': '={{$credentials.organizationId}}', | ||
}, | ||
}, | ||
}; | ||
|
||
test: ICredentialTestRequest = { | ||
request: { | ||
baseURL: 'https://api.openai.com', | ||
url: '/v1/models', | ||
}, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
import { INodeExecutionData, INodeProperties } from 'n8n-workflow'; | ||
|
||
export const imageOperations: INodeProperties[] = [ | ||
{ | ||
displayName: 'Operation', | ||
name: 'operation', | ||
type: 'options', | ||
noDataExpression: true, | ||
displayOptions: { | ||
show: { | ||
resource: ['image'], | ||
}, | ||
}, | ||
options: [ | ||
{ | ||
name: 'Create', | ||
value: 'create', | ||
action: 'Create an Image', | ||
description: 'Create an image for a given text', | ||
routing: { | ||
request: { | ||
method: 'POST', | ||
url: '/v1/images/generations', | ||
}, | ||
}, | ||
}, | ||
], | ||
routing: { | ||
output: { | ||
postReceive: [ | ||
{ | ||
type: 'rootProperty', | ||
properties: { | ||
property: 'data', | ||
}, | ||
}, | ||
], | ||
}, | ||
}, | ||
default: 'create', | ||
}, | ||
]; | ||
|
||
const createOperations: INodeProperties[] = [ | ||
{ | ||
displayName: 'Prompt', | ||
name: 'prompt', | ||
type: 'string', | ||
placeholder: 'e.g. A cute cat eating a dinosaur', | ||
description: | ||
'A text description of the desired image(s). The maximum length is 1000 characters.', | ||
displayOptions: { | ||
show: { | ||
resource: ['image'], | ||
operation: ['create'], | ||
}, | ||
}, | ||
default: '', | ||
routing: { | ||
send: { | ||
type: 'body', | ||
property: 'prompt', | ||
}, | ||
}, | ||
}, | ||
{ | ||
displayName: 'Response Format', | ||
name: 'responseFormat', | ||
type: 'options', | ||
default: 'binaryData', | ||
description: 'The format in which to return the image(s)', | ||
displayOptions: { | ||
show: { | ||
resource: ['image'], | ||
operation: ['create'], | ||
}, | ||
}, | ||
options: [ | ||
{ | ||
name: 'Binary Data', | ||
value: 'binaryData', | ||
}, | ||
{ | ||
name: 'Image Url', | ||
value: 'imageUrl', | ||
}, | ||
], | ||
routing: { | ||
send: { | ||
type: 'body', | ||
property: 'response_format', | ||
value: '={{ $value === "imageUrl" ? "url" : "b64_json" }}', | ||
}, | ||
output: { | ||
postReceive: [ | ||
async function (items: INodeExecutionData[]): Promise<INodeExecutionData[]> { | ||
if (this.getNode().parameters.responseFormat === 'imageUrl') { | ||
return items; | ||
} | ||
|
||
const result: INodeExecutionData[] = []; | ||
for (let i = 0; i < items.length; i++) { | ||
result.push({ | ||
json: {}, | ||
binary: { | ||
data: await this.helpers.prepareBinaryData( | ||
Buffer.from(items[i].json.b64_json as string, 'base64'), | ||
'data', | ||
), | ||
}, | ||
} as INodeExecutionData); | ||
} | ||
|
||
return result; | ||
}, | ||
], | ||
}, | ||
}, | ||
}, | ||
{ | ||
displayName: 'Options', | ||
name: 'options', | ||
placeholder: 'Add Option', | ||
description: 'Additional options to add', | ||
type: 'collection', | ||
default: {}, | ||
displayOptions: { | ||
show: { | ||
resource: ['image'], | ||
operation: ['create'], | ||
}, | ||
}, | ||
options: [ | ||
{ | ||
displayName: 'Number of Images', | ||
name: 'n', | ||
default: 1, | ||
description: 'Number of images to generate', | ||
type: 'number', | ||
typeOptions: { | ||
minValue: 1, | ||
maxValue: 10, | ||
}, | ||
routing: { | ||
send: { | ||
type: 'body', | ||
property: 'n', | ||
}, | ||
}, | ||
}, | ||
{ | ||
displayName: 'Resolution', | ||
name: 'size', | ||
type: 'options', | ||
options: [ | ||
{ | ||
name: '256x256', | ||
value: '256x256', | ||
}, | ||
{ | ||
name: '512x512', | ||
value: '512x512', | ||
}, | ||
{ | ||
name: '1024x1024', | ||
value: '1024x1024', | ||
}, | ||
], | ||
routing: { | ||
send: { | ||
type: 'body', | ||
property: 'size', | ||
}, | ||
}, | ||
default: '1024x1024', | ||
}, | ||
], | ||
}, | ||
]; | ||
|
||
export const imageFields: INodeProperties[] = [ | ||
/* -------------------------------------------------------------------------- */ | ||
/* image:create */ | ||
/* -------------------------------------------------------------------------- */ | ||
...createOperations, | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"node": "n8n-nodes-base.openAi", | ||
"nodeVersion": "1.0", | ||
"codexVersion": "1.0", | ||
"categories": ["Utility"], | ||
"resources": { | ||
"credentialDocumentation": [ | ||
{ | ||
"url": "https://docs.n8n.io/credentials/openAiApi" | ||
} | ||
], | ||
"primaryDocumentation": [ | ||
{ | ||
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.openai/" | ||
} | ||
] | ||
}, | ||
"alias": ["ChatGPT", "DallE"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { INodeType, INodeTypeDescription } from 'n8n-workflow'; | ||
import { imageFields, imageOperations } from './ImageDescription'; | ||
import { textFields, textOperations } from './TextDescription'; | ||
|
||
export class OpenAi implements INodeType { | ||
description: INodeTypeDescription = { | ||
displayName: 'OpenAI', | ||
name: 'openAi', | ||
icon: 'file:openAi.svg', | ||
group: ['transform'], | ||
version: 1, | ||
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', | ||
description: 'Consume Open AI', | ||
defaults: { | ||
name: 'OpenAI', | ||
}, | ||
inputs: ['main'], | ||
outputs: ['main'], | ||
credentials: [ | ||
{ | ||
name: 'openAiApi', | ||
required: true, | ||
}, | ||
], | ||
requestDefaults: { | ||
baseURL: 'https://api.openai.com', | ||
}, | ||
properties: [ | ||
{ | ||
displayName: 'Resource', | ||
name: 'resource', | ||
type: 'options', | ||
noDataExpression: true, | ||
options: [ | ||
{ | ||
name: 'Image', | ||
value: 'image', | ||
}, | ||
{ | ||
name: 'Text', | ||
value: 'text', | ||
}, | ||
], | ||
default: 'text', | ||
}, | ||
|
||
...imageOperations, | ||
...imageFields, | ||
|
||
...textOperations, | ||
...textFields, | ||
], | ||
}; | ||
} |
Oops, something went wrong.