-
Notifications
You must be signed in to change notification settings - Fork 192
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Addition of OpenAI Template Generator
- Loading branch information
1 parent
0bad308
commit 6cababd
Showing
15 changed files
with
642 additions
and
1 deletion.
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
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
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,3 @@ | ||
# OpenAI | ||
|
||
This Zapier integration project is generated by the `zapier init` CLI command. This integration in particular is using the OpenAI API to generate responses to prompts from users. For this integration, there is a `constants.js` file that will allow you to swap out the base URL and version of the API to swap if you are using an OpenAI compatible API to get started. |
46 changes: 46 additions & 0 deletions
46
packages/cli/src/generators/templates/openai/authentication.js
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,46 @@ | ||
const { API_URL } = require('./constants'); | ||
// You want to make a request to an endpoint that is either specifically designed | ||
// to test auth, or one that every user will have access to. eg: `/me`. | ||
// By returning the entire request object, you have access to the request and | ||
// response data for testing purposes. Your connection label can access any data | ||
// from the returned response using the `json.` prefix. eg: `{{json.username}}`. | ||
const test = (z, bundle) => z.request({ url: `${API_URL}/me` }); | ||
|
||
module.exports = { | ||
// "custom" is the catch-all auth type. The user supplies some info and Zapier can | ||
// make authenticated requests with it | ||
type: 'custom', | ||
|
||
// Define any input app's auth requires here. The user will be prompted to enter | ||
// this info when they connect their account. | ||
fields: [ | ||
{ | ||
key: 'api_key', | ||
label: 'API Key', | ||
required: true, | ||
helpText: | ||
'Generate an API Key in your [Platform settings page](https://platform.openai.com/api-keys).', | ||
}, | ||
// This field is optional and can be removed if not needed | ||
{ | ||
key: 'organization_id', | ||
required: false, | ||
label: 'Organization ID', | ||
helpText: | ||
'**Optional** Only required if your OpenAI account belongs to multiple organizations. If not using OpenAI, this field will be disregarded. If your OpenAI account belongs to multiple organizations, optionally add the [Organization ID](https://platform.openai.com/account/org-settings) that this connection should use. If left blank, your [default organization](https://platform.openai.com/account/api-keys) will be used.', | ||
}, | ||
], | ||
|
||
// The test method allows Zapier to verify that the credentials a user provides | ||
// are valid. We'll execute this method whenever a user connects their account for | ||
// the first time. | ||
test, | ||
|
||
// This template string can access all the data returned from the auth test. If | ||
// you return the test object, you'll access the returned data with a label like | ||
// `{{json.X}}`. If you return `response.data` from your test, then your label can | ||
// be `{{X}}`. This can also be a function that returns a label. That function has | ||
// the standard args `(z, bundle)` and data returned from the test can be accessed | ||
// in `bundle.inputData.X`. | ||
connectionLabel: '{{json.email}}', | ||
}; |
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,10 @@ | ||
const BASE_URL = 'https://api.openai.com'; | ||
const VERSION = 'v1'; | ||
const API_URL = `${BASE_URL}/${VERSION}`; | ||
|
||
const DEFAULT_MODEL = 'gpt-4o-mini'; | ||
|
||
module.exports = { | ||
API_URL, | ||
DEFAULT_MODEL, | ||
}; |
164 changes: 164 additions & 0 deletions
164
packages/cli/src/generators/templates/openai/creates/chat_completion.js
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,164 @@ | ||
/* eslint-disable camelcase */ | ||
const { API_URL, DEFAULT_MODEL } = require('../constants'); | ||
|
||
const sample = require('../samples/chat.json'); | ||
|
||
async function getAdvancedFields(_z, bundle) { | ||
if (bundle.inputData.show_advanced === true) { | ||
return [ | ||
{ | ||
key: 'info_advanced', | ||
type: 'copy', | ||
helpText: | ||
"The following fields are for advanced users and should be used with caution as they may affect performance. In most cases, the default options are sufficient. If you'd like to explore these options further, you can [learn more here](https://help.zapier.com/hc/en-us/articles/22497191078797).", | ||
}, | ||
{ | ||
key: 'developer_message', | ||
label: 'Developer/System Message', | ||
type: 'text', | ||
helpText: | ||
'Instructions to the model that are prioritized ahead of user messages, following [chain of command](https://cdn.openai.com/spec/model-spec-2024-05-08.html#follow-the-chain-of-command).', | ||
}, | ||
{ | ||
key: 'temperature', | ||
label: 'Temperature', | ||
type: 'number', | ||
helpText: | ||
'Higher values mean the model will take more risks. Try 0.9 for more creative applications, and 0 for ones with a well-defined answer.\n\nUse a decimal between 0 and 1.', | ||
}, | ||
{ | ||
key: 'max_completion_tokens', | ||
label: 'Maximum Length', | ||
type: 'integer', | ||
helpText: 'The maximum number of tokens for the completion.', | ||
}, | ||
]; | ||
} | ||
return []; | ||
} | ||
|
||
async function perform(z, bundle) { | ||
const { | ||
user_message, | ||
model, | ||
files, | ||
developer_message, | ||
temperature, | ||
max_completion_tokens, | ||
} = bundle.inputData; | ||
|
||
const developerMessage = { | ||
role: 'developer', | ||
content: [ | ||
{ | ||
type: 'text', | ||
text: developer_message || 'You are a helpful assistant.', | ||
}, | ||
], | ||
}; | ||
|
||
const userMessage = { | ||
role: 'user', | ||
content: [ | ||
{ | ||
type: 'text', | ||
text: user_message, | ||
}, | ||
...(files | ||
? files.map((file) => ({ | ||
type: 'image_url', | ||
image_url: { | ||
url: file, | ||
}, | ||
})) | ||
: []), | ||
], | ||
}; | ||
|
||
const messages = [developerMessage, userMessage]; | ||
|
||
const response = await z.request({ | ||
url: `${API_URL}/chat/completions`, | ||
method: 'POST', | ||
body: JSON.stringify({ | ||
model, | ||
messages, | ||
temperature, | ||
max_completion_tokens, | ||
}), | ||
}); | ||
return response.data; | ||
} | ||
|
||
module.exports = { | ||
key: 'chat_completion', | ||
noun: 'Chat', | ||
display: { | ||
label: 'Chat Completion', | ||
description: 'Sends a Chat to OpenAI and generates a Completion.', | ||
}, | ||
operation: { | ||
perform, | ||
inputFields: [ | ||
{ | ||
key: 'info_data_usage', | ||
type: 'copy', | ||
helpText: | ||
"Data sent to OpenAI through this Zap is via an API. Under OpenAI's [API data usage policy](https://openai.com/policies/api-data-usage-policies), OpenAI will not use API-submitted data to train or improve their models unless you explicitly decide to share your data with them for that purpose (such as by opting in). For more information, please review OpenAI's article about [when/how data may be used to improve model performance](https://help.openai.com/en/articles/5722486-how-your-data-is-used-to-improve-model-performance).", | ||
}, | ||
{ | ||
key: 'user_message', | ||
label: 'User Message', | ||
type: 'text', | ||
helpText: | ||
"Instructions that request some output from the model. Similar to messages you'd type in [ChatGPT](https://chatgpt.com) as an end user.", | ||
required: true, | ||
}, | ||
{ | ||
key: 'files', | ||
label: 'Images', | ||
type: 'file', | ||
helpText: 'Images to include along with your message.', | ||
list: true, | ||
}, | ||
{ | ||
key: 'model', | ||
label: 'Model', | ||
type: 'string', | ||
required: true, | ||
default: DEFAULT_MODEL, // Optional to default to a specific model for most users | ||
dynamic: 'list_models.id.name', | ||
altersDynamicFields: false, | ||
}, | ||
{ | ||
key: 'show_advanced', | ||
label: 'Show Advanced Options', | ||
type: 'boolean', | ||
default: 'false', | ||
altersDynamicFields: true, | ||
}, | ||
getAdvancedFields, | ||
], | ||
// Rename some of the output fields to be more descriptive for a user | ||
outputFields: [ | ||
{ key: 'id', type: 'string', label: 'Completion ID' }, | ||
{ key: 'model', type: 'string', label: 'Model' }, | ||
{ | ||
key: 'usage__prompt_tokens', | ||
type: 'number', | ||
label: 'Usage: Prompt Tokens', | ||
}, | ||
{ | ||
key: 'usage__completion_tokens', | ||
type: 'number', | ||
label: 'Usage: Completion Tokens', | ||
}, | ||
{ | ||
key: 'usage__total_tokens', | ||
type: 'number', | ||
label: 'Usage: Total Tokens', | ||
}, | ||
], | ||
sample, | ||
}, | ||
}; |
7 changes: 7 additions & 0 deletions
7
packages/cli/src/generators/templates/openai/creates/index.js
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,7 @@ | ||
/* eslint-disable camelcase */ | ||
const chat_completion = require('./chat_completion'); | ||
|
||
// If you add a new create, make sure it is exported here to display in the Zapier Editor | ||
module.exports = { | ||
[chat_completion.key]: chat_completion, | ||
}; |
7 changes: 7 additions & 0 deletions
7
packages/cli/src/generators/templates/openai/dynamic_dropdowns/index.js
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,7 @@ | ||
/* eslint-disable camelcase */ | ||
const list_models = require('./list_models.js'); | ||
|
||
// If you add a new Dynamic Dropdown, make sure it is exported here to display in the Zapier Editor | ||
module.exports = { | ||
[list_models.key]: list_models, | ||
}; |
24 changes: 24 additions & 0 deletions
24
packages/cli/src/generators/templates/openai/dynamic_dropdowns/list_models.js
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,24 @@ | ||
const { API_URL } = require('../constants'); | ||
|
||
const perform = async (z, bundle) => { | ||
const response = await z.request({ url: `${API_URL}/models` }); | ||
|
||
const responseData = response.data; | ||
|
||
return responseData.data.map((model) => ({ | ||
id: model.id, | ||
name: model.id, | ||
})); | ||
}; | ||
|
||
module.exports = { | ||
key: 'list_models', | ||
noun: 'Model', | ||
display: { | ||
label: 'List of Models', | ||
description: | ||
'This is a hidden trigger, and is used in a Dynamic Dropdown of another trigger.', | ||
hidden: true, | ||
}, | ||
operation: { perform }, | ||
}; |
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,33 @@ | ||
/* eslint-disable camelcase */ | ||
const authentication = require('./authentication'); | ||
const middleware = require('./middleware'); | ||
const dynamic_dropdowns = require('./dynamic_dropdowns'); | ||
const creates = require('./creates'); | ||
|
||
module.exports = { | ||
// This is just shorthand to reference the installed dependencies you have. | ||
// Zapier will need to know these before we can upload. | ||
version: require('./package.json').version, | ||
platformVersion: require('zapier-platform-core').version, | ||
|
||
authentication, | ||
|
||
beforeRequest: [...middleware.befores], | ||
|
||
afterResponse: [...middleware.afters], | ||
|
||
// If you want your trigger to show up, you better include it here! | ||
triggers: { | ||
...dynamic_dropdowns, | ||
}, | ||
|
||
// If you want your searches to show up, you better include it here! | ||
searches: {}, | ||
|
||
// If you want your creates to show up, you better include it here! | ||
creates: { | ||
...creates, | ||
}, | ||
|
||
resources: {}, | ||
}; |
50 changes: 50 additions & 0 deletions
50
packages/cli/src/generators/templates/openai/middleware.js
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 @@ | ||
/* eslint-disable camelcase */ | ||
// This function runs after every outbound request. You can use it to check for | ||
// errors or modify the response. You can have as many as you need. They'll need | ||
// to each be registered in your index.js file. | ||
const handleBadResponses = (response, z, bundle) => { | ||
if (response.data.error) { | ||
throw new z.errors.Error( | ||
response.data.error.message, | ||
response.data.error.code, | ||
response.status, | ||
); | ||
} | ||
|
||
return response; | ||
}; | ||
|
||
const includeOrgId = (request, z, bundle) => { | ||
const { organization_id } = bundle.authData; | ||
if (organization_id) { | ||
request.headers['OpenAI-Organization'] = organization_id; | ||
} | ||
return request; | ||
}; | ||
|
||
// This function runs before every outbound request. You can have as many as you | ||
// need. They'll need to each be registered in your index.js file. | ||
const includeApiKey = (request, z, bundle) => { | ||
const { api_key } = bundle.authData; | ||
if (api_key) { | ||
// Use these lines to include the API key in the querystring | ||
// request.params = request.params || {}; | ||
// request.params.api_key = api_key; | ||
|
||
// If you want to include the API key in the header: | ||
request.headers.Authorization = `Bearer ${api_key}`; | ||
} | ||
|
||
return request; | ||
}; | ||
|
||
const jsonHeaders = (request) => { | ||
request.headers['Content-Type'] = 'application/json'; | ||
request.headers.Accept = 'application/json'; | ||
return request; | ||
}; | ||
|
||
module.exports = { | ||
befores: [includeApiKey, includeOrgId, jsonHeaders], | ||
afters: [handleBadResponses], | ||
}; |
Oops, something went wrong.