Skip to content

Instantly share code, notes, and snippets.

@stephenlb
Last active February 7, 2024 20:27
Show Gist options
  • Save stephenlb/de558e9802a6f950951eb0939ab71bcd to your computer and use it in GitHub Desktop.
Save stephenlb/de558e9802a6f950951eb0939ab71bcd to your computer and use it in GitHub Desktop.
Using OpenAI's Function Calling with a JavaScript Fetch API.
//
// Import Modules
//
const pubnub = require('pubnub');
const xhr = require('xhr');
const vault = require('vault');
//
// Request Event Handler (Main)
//
export default (request, response) => {
// Natural language request input for AI model
let naturalCommand = request.body;
// Ask AI to make decisions and provide progress updates
return getOpenaiApiKey().then(apikey => {
return openAI(naturalCommand).then(aiResponse => {
console.log("OPENAI TASK RESULT:", aiResponse);
return response.send(aiResponse);
});
});
};
//
// Get API Key for OpenAI
// Key is populated via Vault Secret Manager
//
let OPENAI_API_KEY = null;
function getOpenaiApiKey() {
// Use cached key
if (OPENAI_API_KEY) {
return new Promise(resolve => resolve(OPENAI_API_KEY));
}
// Fetch key from vault
return vault.get("OPENAI_API_KEY").then(apikey => {
OPENAI_API_KEY = apikey;
return new Promise(resolve => resolve(OPENAI_API_KEY));
});
}
//
// Publish a Message to a Channel
//
function publishMessage(channel, message) {
return pubnub.publish({
channel: channel,
message: message,
});
}
publishMessage.instructions = {
"name": "publishMessage",
"description": "Send a message to a channel",
"parameters": {
"type": "object",
"properties": {
"channel": {
"type": "string",
"description": "The name of the channel to send a message to",
},
"message": {"type": "object", "properties": {
"text" : { "type": "string", "description": "The message text that will be sent to the channel"}
}},
},
"required": ["channel", "message"],
}
};
//
// Get the Last Message from a Channel
//
function lastMessage(channel) {
return pubnub.history({
channel: channel,
count: 1,
});
}
lastMessage.instructions = {
"name": "lastMessage",
"description": "Get the most recent message that was sent to a channel",
"parameters": {
"type": "object",
"properties": {
"channel": {
"type": "string",
"description": "The name of the channel to send a message to",
},
},
"required": ["channel"],
}
};
//
// API Call to OpenAI asking the AI to run functions if it thinks it needs to
//
function openAI(naturalCommand, messages) {
// Generate Function Instructions for the AI
const functions = [publishMessage, lastMessage].map(fn => fn.instructions);
const url = 'https://api.openai.com/v1/chat/completions';
let msgs = messages || [{"role": "user", "content": naturalCommand}];
const http_options = {
'method': 'POST',
'headers': {
"Content-Type": "application/json",
"Authorization": `Bearer ${OPENAI_API_KEY}`,
},
'body': JSON.stringify({
"model": "gpt-3.5-turbo-0613",
"messages": msgs,
"functions": functions,
"function_call": "auto",
}),
};
return xhr.fetch(url, http_options)
.then((resp) => {
const body = JSON.parse(resp.body);
const function_call = body.choices[0].finish_reason === "function_call";
const message = body.choices[0].message;
// Call function and resend to OpenAI the result
if (function_call) {
return handelFunctionCalls(message).then(result => {
msgs.push(message);
msgs.push({
"role": "function",
"name": message.function_call.name,
"content": JSON.stringify(result),
});
return openAI(naturalCommand, msgs);
});
}
// Send status update about completed task
const content = message.content;
return new Promise(resolve => resolve(content));
})
.catch((err) => {
return new Promise((_, reject) => reject(err));
});
}
//
// Handel Function Calls from OpenAI Requests
//
function handelFunctionCalls(message) {
let args = JSON.parse(message.function_call.arguments);
switch (message.function_call.name) {
case "publishMessage":
return publishMessage(args.channel, args.message);
break;
case "lastMessage":
return lastMessage(args.channel);
break;
}
}
@stephenlb
Copy link
Author

@stephenlb
Copy link
Author

stephenlb commented Jun 21, 2023

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment