├── .gitattributes ├── package.json ├── scraper.js ├── .gitignore └── index.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "devDependencies": { 4 | "openai": "^3.3.0" 5 | }, 6 | "dependencies": { 7 | "puppeteer-core": "^21.0.3" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /scraper.js: -------------------------------------------------------------------------------- 1 | import puppeteer from 'puppeteer-core'; 2 | const SBR_WS_ENDPOINT = 'wss://your-endpoint'; 3 | 4 | async function main(keyword) { 5 | console.log('Connecting to Scraping Browser...'); 6 | const browser = await puppeteer.connect({ 7 | browserWSEndpoint: SBR_WS_ENDPOINT, 8 | }); 9 | try { 10 | console.log('Connected! Navigating to Goodreads search results...'); 11 | const page = await browser.newPage(); 12 | page.setDefaultNavigationTimeout(2*60*1000); 13 | await page.goto(`https://www.goodreads.com/search?q=${keyword}`); 14 | console.log('Navigated! Scraping book titles...'); 15 | 16 | const books = await page.$$eval('.bookTitle', nodes => nodes.map(node => node.innerText)); 17 | 18 | console.log(`Books with "${keyword}" in the title:`); 19 | let returnStatement = "" 20 | books.forEach((book, index) => { 21 | // console.log(`${index + 1}. ${book}`); 22 | returnStatement += `${index + 1}. ${book}\n` 23 | }); 24 | 25 | return returnStatement 26 | 27 | } finally { 28 | await browser.close(); 29 | } 30 | } 31 | 32 | export default main; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Serverless directories 108 | .serverless/ 109 | 110 | # FuseBox cache 111 | .fusebox/ 112 | 113 | # DynamoDB Local files 114 | .dynamodb/ 115 | 116 | # TernJS port file 117 | .tern-port 118 | 119 | # Stores VSCode versions used for testing VSCode extensions 120 | .vscode-test 121 | 122 | # yarn v2 123 | .yarn/cache 124 | .yarn/unplugged 125 | .yarn/build-state.yml 126 | .yarn/install-state.gz 127 | .pnp.* 128 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import { Configuration, OpenAIApi } from 'openai'; 2 | import scraper from './scraper.js'; 3 | const configuration = new Configuration({ 4 | organization: "org-yourorg", 5 | apiKey: "sk-yourapikey", 6 | }); 7 | 8 | const openai = new OpenAIApi(configuration); 9 | 10 | // Define your function 11 | function helloWorld(appendString){ 12 | let hello = "Hello World! " + appendString 13 | return hello 14 | } 15 | 16 | // Get the current time of day 17 | function getTimeOfDay(){ 18 | let date = new Date() 19 | let hours = date.getHours() 20 | let minutes = date.getMinutes() 21 | let seconds = date.getSeconds() 22 | let timeOfDay = "AM" 23 | if(hours > 12){ 24 | hours = hours - 12 25 | timeOfDay = "PM" 26 | } 27 | return hours + ":" + minutes + ":" + seconds + " " + timeOfDay 28 | } 29 | 30 | // Define your ChatGPT Function 31 | async function callChatGPTWithFunctions(appendString){ 32 | let messages = [{ 33 | role: "system", 34 | content: "Perform function requests for the user", 35 | },{ 36 | role: "user", 37 | content: "Hello, I am a user, I would like to get 5 book recommendations with the keyword 'ChatGPT'", 38 | }]; 39 | // Step 1: Call ChatGPT with the function name 40 | let chat = await openai.createChatCompletion({ 41 | model: "gpt-3.5-turbo-0613", 42 | messages, 43 | functions: [{ 44 | name: "helloWorld", 45 | description: "Prints hello world with the string passed to it", 46 | parameters: { 47 | type: "object", 48 | properties: { 49 | appendString: { 50 | type: "string", 51 | description: "The string to append to the hello world message", 52 | }, 53 | }, 54 | require: ["appendString"], 55 | } 56 | },{ 57 | name: "scraper", 58 | description: "Scraps the book website goodreads for books with the keyword passed to it", 59 | parameters: { 60 | type: "object", 61 | properties: { 62 | keyword: { 63 | type: "string", 64 | description: "The keyword to search for", 65 | }, 66 | }, 67 | require: ["keyword"], 68 | } 69 | }, 70 | { 71 | name: "getTimeOfDay", 72 | description: "Get the time of day.", 73 | parameters: { 74 | type: "object", 75 | properties: { 76 | }, 77 | require: [], 78 | } 79 | }], 80 | function_call: "auto", 81 | }) 82 | 83 | let wantsToUseFunction = chat.data.choices[0].finish_reason == "function_call" 84 | 85 | let content = "" 86 | // Step 2: Check if ChatGPT wants to use a function 87 | if(wantsToUseFunction){ 88 | // Step 3: Use ChatGPT arguments to call your function 89 | if(chat.data.choices[0].message.function_call.name == "helloWorld"){ 90 | let argumentObj = JSON.parse(chat.data.choices[0].message.function_call.arguments) 91 | content = helloWorld(argumentObj.appendString) 92 | messages.push(chat.data.choices[0].message) 93 | messages.push({ 94 | role: "function", 95 | name: "helloWorld", 96 | content, 97 | }) 98 | } 99 | if(chat.data.choices[0].message.function_call.name == "scraper"){ 100 | let argumentObj = JSON.parse(chat.data.choices[0].message.function_call.arguments) 101 | content = await scraper(argumentObj.keyword) 102 | messages.push(chat.data.choices[0].message) 103 | messages.push({ 104 | role: "function", 105 | name: "scraper", 106 | content, 107 | }) 108 | } 109 | if(chat.data.choices[0].message.function_call.name == "getTimeOfDay"){ 110 | content = getTimeOfDay() 111 | messages.push(chat.data.choices[0].message) 112 | messages.push({ 113 | role: "function", 114 | name: "getTimeOfDay", 115 | content, 116 | }) 117 | } 118 | } 119 | 120 | 121 | // Step 4: Call ChatGPT again with the function response 122 | let step4response = await openai.createChatCompletion({ 123 | model: "gpt-3.5-turbo-0613", 124 | messages, 125 | }); 126 | console.log(step4response.data.choices[0]) 127 | 128 | } 129 | 130 | callChatGPTWithFunctions() --------------------------------------------------------------------------------