├── .gitignore ├── .well-known └── ai-plugin.json ├── README.md ├── index.js ├── logo.png ├── openapi.yaml ├── package.json └── routes ├── openai.js └── todos.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | package-lock.json -------------------------------------------------------------------------------- /.well-known/ai-plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema_version": "v1", 3 | "name_for_human": "My ChatGPT To Do Plugin", 4 | "name_for_model": "todo", 5 | "description_for_human": "Plugin for managing a To Do list. You can add, remove and view your To Dos.", 6 | "description_for_model": "Plugin for managing a To Do list. You can add, remove and view your To Dos.", 7 | "auth": { 8 | "type": "none" 9 | }, 10 | "api": { 11 | "type": "openapi", 12 | "url": "http://localhost:3000/openapi.yaml", 13 | "is_user_authenticated": false 14 | }, 15 | "logo_url": "http://localhost:3000/logo.png", 16 | "contact_email": "support@yourdomain.com", 17 | "legal_info_url": "http://www.yourdomain.com/legal" 18 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ChatGPT JS Plugin Quickstart 2 | __Brought to you by SitePoint__ 3 | 4 | Get a todo list ChatGPT plugin up and running in under 5 minutes using Node and Express. Tutorial located here: [Build your first JavaScript ChatGPT Plugin](https://www.sitepoint.com/javascript-chatgpt-plugin/). 5 | 6 | ## Setup 7 | 8 | To install the required packages for this plugin, run the following command: 9 | 10 | ```bash 11 | npm install 12 | ``` 13 | 14 | To run the plugin, enter the following command: 15 | 16 | ```bash 17 | node index.js 18 | ``` 19 | 20 | Once the local server is running: 21 | 22 | 1. Navigate to https://chat.openai.com. 23 | 2. In the Model drop down, select "Plugins" (note, if you don't see it there, you don't have access yet). 24 | 3. Select "Plugin store" 25 | 4. Select "Develop your own plugin" 26 | 5. Enter in `localhost:3000` since this is the URL the server is running on locally, then select "Find manifest file". 27 | 28 | The plugin should now be installed and enabled! You can start with a question like "What is on my todo list" and then try adding something to it as well! -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const cors = require('cors'); 3 | const todosRouter = require('./routes/todos'); 4 | const openaiRoutes = require('./routes/openai'); 5 | 6 | const app = express(); 7 | const PORT = 3000; 8 | 9 | // Setting CORS to allow chat.openapi.com is required for ChatGPT to access your plugin 10 | app.use(cors({ origin: [`http://localhost:${PORT}`, 'https://chat.openai.com'] })); 11 | app.use(express.json()); 12 | 13 | // Simple request logging to see if your plugin is being called by ChatGPT 14 | app.use((req, res, next) => { 15 | console.log(`Request received: ${req.method}: ${req.path}`) 16 | next() 17 | }) 18 | 19 | // OpenAI Required Routes 20 | app.use(openaiRoutes); 21 | 22 | // The dummy todos API 23 | app.use('/todos', todosRouter); 24 | 25 | // Proxy to an existing API 26 | const api_url = 'http://localhost'; 27 | 28 | app.all('/:path', async (req, res) => { 29 | const { path } = req.params; 30 | const url = `${api_url}/${path}`; 31 | 32 | console.log(`Forwarding call: ${req.method} ${path} -> ${url}`); 33 | 34 | const headers = { 35 | 'Content-Type': 'application/json', 36 | }; 37 | 38 | try { 39 | const response = await axios({ 40 | method: req.method, 41 | url, 42 | headers, 43 | params: req.query, 44 | data: req.body, 45 | }); 46 | 47 | res.send(response.data); 48 | } catch (error) { 49 | console.error(`Error in forwarding call: ${error}`); 50 | res.status(500).send('Error in forwarding call'); 51 | } 52 | }); 53 | 54 | app.listen(PORT, () => { 55 | console.log(`Plugin server listening on port ${PORT}`); 56 | }); -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitepoint-editors/chatgpt-plugin-quickstart-js/62c0075a968a061354ce307d35b2f7b62458489c/logo.png -------------------------------------------------------------------------------- /openapi.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.1 2 | info: 3 | title: TODO Plugin 4 | description: A plugin that allows the user to create and manage a To Do list using ChatGPT. 5 | version: 'v1' 6 | servers: 7 | - url: http://localhost:3000 8 | paths: 9 | /todos: 10 | get: 11 | operationId: getTodos 12 | summary: Get the list of todos 13 | responses: 14 | "200": 15 | description: OK 16 | content: 17 | application/json: 18 | schema: 19 | type: array 20 | items: 21 | $ref: '#/components/schemas/Todo' 22 | post: 23 | operationId: addTodo 24 | summary: Add a todo to the list 25 | requestBody: 26 | required: true 27 | content: 28 | application/json: 29 | schema: 30 | $ref: '#/components/schemas/Todo' 31 | responses: 32 | "201": 33 | description: Created 34 | content: 35 | application/json: 36 | schema: 37 | $ref: '#/components/schemas/Todo' 38 | /todos/{id}: 39 | delete: 40 | operationId: removeTodo 41 | summary: Delete a todo from the list when it is complete, or no longer required. 42 | parameters: 43 | - name: id 44 | in: path 45 | required: true 46 | schema: 47 | type: integer 48 | responses: 49 | "204": 50 | description: No Content 51 | components: 52 | schemas: 53 | Todo: 54 | type: object 55 | properties: 56 | id: 57 | type: integer 58 | format: int64 59 | task: 60 | type: string 61 | required: 62 | - id 63 | - task -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gpt-js-plugin-sitepoint-quickstart", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "start": "node index.js" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "description": "", 12 | "dependencies": { 13 | "axios": "^1.4.0", 14 | "cors": "^2.8.5", 15 | "express": "^4.18.2", 16 | "js-yaml": "^4.1.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /routes/openai.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const yaml = require('js-yaml'); 6 | 7 | router.get('/openapi.yaml', async function(req, res) { 8 | try { 9 | const yamlData = fs.readFileSync(path.join(process.cwd(), 'openapi.yaml'), 'utf8'); 10 | const jsonData = yaml.load(yamlData); 11 | res.json(jsonData); 12 | 13 | } catch(e) { 14 | console.log(e.message) 15 | res.status(500).send({ error: 'Unable to fetch manifest.' }); 16 | } 17 | }); 18 | 19 | router.get('/.well-known/ai-plugin.json', function(req, res) { 20 | res.sendFile(path.join(process.cwd(), '/.well-known/ai-plugin.json')); 21 | }); 22 | 23 | router.get('/logo.png', function(req, res) { 24 | res.sendFile(path.join(process.cwd(), 'logo.png')); 25 | }) 26 | 27 | module.exports = router; 28 | -------------------------------------------------------------------------------- /routes/todos.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | 4 | let todos = [ 5 | { id: 1, task: 'Wake up' }, 6 | { id: 2, task: 'Grab a brush'}, 7 | { id: 3, task: 'Put a little makeup'}, 8 | { id: 4, task: 'Build a Chat Plugin'} 9 | ]; // placeholder todos 10 | 11 | let currentId = 5; // to assign unique ids to new todos 12 | 13 | getTodos = async function(req, res) { 14 | res.json(todos); 15 | } 16 | 17 | addTodo = async function(req, res) { 18 | const { task } = req.body; 19 | const newTodo = { id: currentId, task }; 20 | todos.push(newTodo); 21 | currentId++; 22 | res.json(newTodo); 23 | } 24 | 25 | removeTodo = async function(req, res) { 26 | const { id } = req.params; 27 | todos = todos.filter(todo => todo.id !== Number(id)); 28 | res.json({ "message" : "Todo successfully deleted" }); 29 | } 30 | 31 | router.get('/', getTodos); 32 | router.post('/', addTodo); 33 | router.delete('/:id', removeTodo); 34 | 35 | module.exports = router; --------------------------------------------------------------------------------