├── .env ├── .gitignore ├── AWS Cloud Week - DIA 2.pdf ├── package.json ├── README.md └── index.js /.env: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY="" 2 | API_ENDPOINT='' -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | function.zip 3 | websocket.zip -------------------------------------------------------------------------------- /AWS Cloud Week - DIA 2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cassiano-dio/chatgpt-nodejs-api/HEAD/AWS Cloud Week - DIA 2.pdf -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chatgpt-nodejs", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "async": "^3.2.4", 14 | "dotenv": "^16.0.3", 15 | "express": "^4.18.2", 16 | "openai": "^3.1.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # API para chat serverless integrado com API do OpenAI ChatGPT para a AWS Cloud Week 2 | 3 | ## Passos para o projeto 4 | 5 | - Clonar o repositório 6 | - Instalar as dependências com o comando ```npm install``` 7 | - Atualizar o arquivo ```.env``` com a sua chave do OpenAI 8 | - Compactar o conteúdo do projeto em um arquivo ```.zip``` 9 | 10 | ## Na AWS 11 | 12 | - Acessar o console da AWS 13 | - Criar uma função no serviço AWS Lambda 14 | - Fazer o upload do conteúdo do arquivo ```.zip``` no código da função 15 | - Acessar o serviço AWS API Gateway 16 | - Criar uma API Websocket 17 | - Criar os endpoints (obs: os três primeiros endpoints marcados com ```$``` são padrão de uma API Websocket do API Gateway): 18 | - ```$connect``` 19 | - ```$disconnect``` 20 | - ```$default``` 21 | - ```setName``` 22 | - ```sendPublic``` 23 | - ```sendPrivate``` 24 | - ```sendBot``` 25 | 26 | ## Testando o Websocket 27 | 28 | - Baixar a dependência ```wscat``` através do comando ```npm i -g wscat```. 29 | - Utilizar o parâmetro ```-g``` para instalar de forma global no sistema operacional, podendo chamá-la de fora do projeto. 30 | 31 | ### Utilizando o wscat 32 | 33 | - ```wscat -c url_de_conexao_do_websocket``` 34 | - Exemplo de chamada ```{"action":"sendPublic", "message":"Hello World!"}``` -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const AWS = require('aws-sdk') 2 | 3 | const ENDPOINT = process.env.API_ENDPOINT 4 | const client = new AWS.ApiGatewayManagementApi({endpoint: ENDPOINT}) 5 | const names = {}; 6 | 7 | const { Configuration, OpenAIApi } = require("openai"); 8 | require('dotenv').config() 9 | 10 | const configuration = new Configuration({ 11 | apiKey: process.env.OPENAI_API_KEY, 12 | }); 13 | const openai = new OpenAIApi(configuration); 14 | 15 | async function runCompletion(message) { 16 | 17 | const completion = await openai.createCompletion({ 18 | model: "text-davinci-003", 19 | prompt: message, 20 | temperature: 0.5, 21 | max_tokens: 3500, 22 | top_p: 1, 23 | frequency_penalty: 0, 24 | presence_penalty: 0, 25 | }); 26 | 27 | console.log(completion.data.choices[0].text) 28 | 29 | return completion.data.choices[0].text 30 | } 31 | 32 | const sendToBot = async (ids, mess) => { 33 | 34 | let res = await runCompletion(mess); 35 | 36 | let message = {publicMessage: `Bot : ${res}`} 37 | const all = ids.map(i => sendToOne(i, message)); 38 | 39 | return Promise.all(all); 40 | }; 41 | 42 | const sendToOne = async (id, body) => { 43 | try { 44 | await client.postToConnection({ 45 | 'ConnectionId': id, 46 | 'Data':Buffer.from(JSON.stringify(body)) 47 | }).promise(); 48 | } catch (e) { 49 | console.log(e); 50 | } 51 | }; 52 | 53 | const sendToAll = async (ids, body) => { 54 | console.log("BODY:", body) 55 | const all = ids.map(i => sendToOne(i, body)); 56 | return Promise.all(all); 57 | }; 58 | 59 | exports.handler = async(event) => { 60 | 61 | if(event.requestContext){ 62 | const connectionId = event.requestContext.connectionId; 63 | const routeKey = event.requestContext.routeKey; 64 | 65 | let body = {}; 66 | try{ 67 | if(event.body){ 68 | body = JSON.parse(event.body); 69 | } 70 | }catch (err){ 71 | console.log(err); 72 | } 73 | 74 | switch(routeKey){ 75 | case '$connect': 76 | break; 77 | case '$disconnect': 78 | await sendToAll(Object.keys(names), {systemMessage: `${names[connectionId]} acabou de sair.`}); 79 | delete names[connectionId]; 80 | await sendToAll(Object.keys(names), {members:Object.values(names)}); 81 | break; 82 | case '$default': 83 | break; 84 | case 'setName': 85 | names[connectionId] = body.name; 86 | await sendToAll(Object.keys(names), {members:Object.values(names)}); 87 | await sendToAll(Object.keys(names), {systemMessage: `${names[connectionId]} acabou de entrar.`}); 88 | break; 89 | case 'sendPublic': 90 | await sendToAll(Object.keys(names),{publicMessage: `${names[connectionId]} : ${body.message}`}); 91 | break; 92 | case 'sendBot': 93 | await sendToAll(Object.keys(names),{publicMessage: `${names[connectionId]} : ${body.message}`}); 94 | await sendToBot(Object.keys(names), body.message); 95 | break; 96 | case 'sendPrivate': 97 | const to = Object.keys(names).find(key => names[key] === body.to); 98 | await sendToOne(to,{privateMessage: `${names[connectionId]} : ${body.message}`}); 99 | break; 100 | default: 101 | } 102 | } 103 | 104 | 105 | 106 | // TODO implement 107 | const response = { 108 | statusCode: 200, 109 | body: JSON.stringify('Hello from Lambda!'), 110 | }; 111 | return response; 112 | }; 113 | --------------------------------------------------------------------------------