Skip to content

Building a ChatGPT Plugin Starter Kit for ExpressJS

I’ve recently started dabbling with the new ChatGPT eco-system. ChatGPT plugins allow ChatGPT to interact with external APIs. Does that not sound exciting? Well that actually means ChatGPT can pull in real-time data and perform actions like never before. Currently ChatGPT only has data until 2021 but now thanks to plugins you can use ChatGPT to book flights, get real-time stock data, or even control smart home devices. It’s absolutely mind-blowing 🀯. Additionally you could feed in data from platforms like Jira, Intercom (see my other blog post) and directly ask questions.

I’m a JavaScript/TypeScript enthusiast. Most stuff in the AI world is in Python. Even though I’m fairly decent at writing Python code, my preferred language is still JS/TS. So to no suprise the initial plugin boilerplate released by OpenAI for ChatGPT plugins is written in Python too. I’ve decided to release a separate boilerplate kit written in JS with ExpressJS. In this post I’ll walk you through the steps I took to write the boilerplate code and the structure of the repository. Let’s dive in 🀿 (yes thats a diving mask)!

Inspiration

The code is heavily inspired by an existing starter from OpenAI, which is written in Python. You can check it out here. I wanted to create a similar starter kit but using ExpressJS, which is probably one of the most popular web frameworks.

The repository is available here: https://github.com/kgoedecke/chatgpt-plugin-express-starter

Repository Structure

Here’s a brief overview of the repository structure:

Lets start with the ChatGPT Plugin specific files:

  • public/logo.png: Contains the logo for the ChatGPT plugin
  • public/.well-known/ai-plugin.json: Contains meta information for the ChatGPT plugin. This file must be publicly accessible for ChatGPT to parse it.
  • public/openapi.yaml: The API specification (OpenAPI 3 standard) which ChatGPT will use to send queries to your API. The ChatGPT API is smart enough to make sense from queries the users types to mapping them to your specific API. What the actual f**k 😎

Here are the Express specific files:

  • .env.example: Here, you can set your apps env variables (e.g. PORT variable and so on).
  • .eslintrc.cjs: This file contains linting rules since this starter kit supports ESLint.
  • README.md: Contains the README and documentation for the repository.
  • nodemon.json: Nodemon was added for hot reloading.
  • package.json: Lists the packages that your project depends on.
  • yarn.lock: We use YARN in this tutorial, not npm (feel free to change this).
  • src/routes: This folder contains all routes.
  • src/routes/todos.js: This file contains the routes needed for the dummy TODO list application we’re creating.
  • src/index.js : Contains the basic root route, here just a short hello world.

Building the Boilerplate

The process of building this boilerplate involved several steps:

Basic ExpressJS Setup

The first step was to set up a basic ExpressJS server. This involved installing ExpressJS and creating a simple server that listens on a specific port. This is fairly straightforward, have a look at the src/index.js file:

import express from 'express';
import path from 'path';
import cors from 'cors';
import 'dotenv/config';
import indexRouter from './routes/index.js';
import todosRouter from './routes/todos.js';

const PORT = process.env.PORT || 5003;

const app = express();

const corsConfig = {
  origin: 'http://chat.openai.com',
};

app.use(cors(corsConfig));
app.use(express.static(path.join(process.cwd(), 'public')));
app.use(express.json());

app.use('/', indexRouter);
app.use('/todos/', todosRouter);

app.listen(PORT, () => {
  // eslint-disable-next-line
  console.log(Example app listening on port ${PORT});
});

A few things to note here:

  • We load our environment variables from the .env file, this is done by simply importing dotenv/config.
  • We have to add https://chat.openai.com as a CORS origin so that our ChatGPT plugin doesn’t reject request from ChatGPT for CORS reasons.
  • We serve all files in public as static files, this is required since we need to have a few files publicly available for ChatGPT to use our API. In order to enable this we add the entire public as static files.
  • The actual routes for our application will be setup in the src/todos directory.

Adding the routes

The ChatGPT example code sets up a simple Todo List backend, which allows you to add todos on a per user basis.

You can take a look at the Python version here: https://github.com/openai/plugins-quickstart/blob/main/main.py

Basically we have 3 routes:

  • POST /:username: This route allows us to add a todo list item. It expects the username as a query param. Additionally we have to pass a JSON object containing the title/text of the Todo item. The JSON object will just look like this:
{
  "todo": "Please finish this boilerplate ChatGPT plugin"
}
  • GET /:username: This route simply returns all Todo list items based on the username that is passed as a query param.
  • DELETE /:username: This route allows us to delete todo list items based on their index for a certain user.
{
  "todo": "Please finish this boilerplate ChatGPT plugin"
}

Please note that these routes are listed our in the openapi.yaml file, which will later be used by ChatGPT to interact with your API.

Adding ESLint

To ensure code quality and consistency, I added ESLint to the project, using the Airbnb linting rules. Check out the eslintrc.cjs file if you want to modify the linting rules or disable some of them.

Creating the public files

The final step was to create the public files that are necessary for the ChatGPT plugin. This includes the logo, the ai-plugin.json file, and the openapi.yaml file.

Let’s have a look at each of them.

  • logo.png: Your Plugin Logo
    Not much to say here, this is the logo that will later on appear in the ChatGPT plugin store. The logo image should be a rectangle, ideally high resolution dimensions.
  • ai-plugin.json:
{
  "schema_version": "v1",
  "name_for_human": "TODO List (no auth)",
  "name_for_model": "todo",
  "description_for_human": "Manage your TODO list. You can add, remove and view your TODOs.",
  "description_for_model": "Plugin for managing a TODO list, you can add, remove and view your TODOs.",
  "auth": {
    "type": "none"
  },
  "api": {
    "type": "openapi",
    "url": "http://localhost:5003/openapi.yaml",
    "is_user_authenticated": false
  },
  "logo_url": "http://localhost:5003/logo.png",
  "contact_email": "legal@example.com",
  "legal_info_url": "http://example.com/legal"
}

This file contains really important information on where ChatGPT can find your API, what the name of the Plugin is, a description and much more. Make sure to change these values before releasing your ChatGPT plugin to the store.

  • openapi.yaml: This file is the API specification according to the OpenAPI standard. This will help ChatGPT understand what your API is capable of. The beauty of this is that ChatGPT literally can grasp when to query your API. You don’t need to worry about when your API should get triggered. For that particular reason it’s REALLY important that you fill out the details in ai-plugin.json with very descriptive values. Keep prompt use-cases in mind.
openapi: 3.0.1
info:
  title: TODO Plugin
  description: A plugin that allows the user to create and manage a TODO list using ChatGPT. If you do not know the user's username, ask them first before making queries to the plugin. Otherwise, use the username "global".
  version: 'v1'
servers:
  - url: http://localhost:5003
paths:
  /todos/{username}:
    get:
      operationId: getTodos
      summary: Get the list of todos
      parameters:
        - in: path
          name: username
          schema:
            type: string
          required: true
          description: The name of the user.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/getTodosResponse'
...

If you’ve worked with Swagger or the OpenAPI specification before then this shouldn’t be anything new for you.

In an ideal world this would be autogenerated based on annotations. I’m planning to build this out a bit over the next couple of weeks.

Deployment

When you’re ready to deploy your ChatGPT plugin, make sure to adjust all server URL values in ai-plugin.json and openapi.yaml.

Future Plans

I’m planning to extend this boilerplate with Swagger and an automatically generated OpenAPI specification. This will make it even easier to create and document APIs for your ChatGPT plugins.

Also, I’m currently working on another boilerplate starter kit for TypeScript. Stay tuned for updates on that!

Wrapping Up

I hope you find this ExpressJS starter kit for ChatGPT plugins useful. It’s designed to help you get up and running quickly with creating your own plugins. Happy coding!

Published inChatGPTEntrepreneurshipProgramming

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *