├── .DS_Store ├── .gitignore ├── LICENSE ├── README.md ├── chatgpt-n4m.maxpat ├── index.js ├── media └── screenshot.png ├── package-lock.json └── package.json /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tmhglnd/chatgpt-n4m/14db3d63c8fe41313ca71a45984ca658b9ce8a64/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore .env 2 | .env 3 | 4 | # ignore node_modules 5 | node_modules/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Timo Hoogland 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ChatGPT with Node4Max 2 | 3 | An example using OpenAI's GPT API with NodeJS in MaxMSP 4 | 5 | #### [More visuals and code!](http://gumroad.com/tmhglnd) 6 | 7 | #### [Become a Patron!](https://www.patreon.com/bePatron?u=9649817) 8 | 9 | # About 10 | 11 | Provide a prompt as a string/symbol via the `[textedit]` object (or by creating your own messages) and wait for the response. You can adjust parameters such as the `temperature`, the `role` and the `max_tokens` for the generated output. 12 | 13 | **You will need your own `API_KEY` from OpenAI to be able to work with the API.** 14 | 15 | ![Screenshot of the patcher](/media/screenshot.png) 16 | 17 | # Install 18 | 19 | Download zip 20 | 21 | ``` 22 | 1. download zip 23 | 2. unzip 24 | ``` 25 | 26 | or git clone 27 | 28 | ``` 29 | 1. $ cd ~/Documents/Max\ 8/Library 30 | 2. $ git clone https://github.com/tmhglnd/chatgpt-n4m.git 31 | ``` 32 | 33 | Go to the directory and run 34 | 35 | ``` 36 | $ npm install 37 | ``` 38 | 39 | Create a `.env` file and save your `API_KEY` as follows: 40 | 41 | ``` 42 | OPENAI_API_KEY=****************************************** 43 | ``` 44 | 45 | Open `chatgpt-n4m.maxpat`, if the script hasn't started click `start` 46 | 47 | # Dependencies 48 | 49 | This project requires node packages: 50 | 51 | - [openai](https://www.npmjs.com/package/openai) 52 | - [dotenv](https://www.npmjs.com/package/dotenv) 53 | 54 | # Licenses 55 | 56 | The MIT License 57 | 58 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /chatgpt-n4m.maxpat: -------------------------------------------------------------------------------- 1 | { 2 | "patcher" : { 3 | "fileversion" : 1, 4 | "appversion" : { 5 | "major" : 8, 6 | "minor" : 5, 7 | "revision" : 4, 8 | "architecture" : "x64", 9 | "modernui" : 1 10 | } 11 | , 12 | "classnamespace" : "box", 13 | "rect" : [ 34.0, 96.0, 1033.0, 837.0 ], 14 | "bglocked" : 0, 15 | "openinpresentation" : 0, 16 | "default_fontsize" : 12.0, 17 | "default_fontface" : 0, 18 | "default_fontname" : "Arial", 19 | "gridonopen" : 1, 20 | "gridsize" : [ 15.0, 15.0 ], 21 | "gridsnaponopen" : 1, 22 | "objectsnaponopen" : 1, 23 | "statusbarvisible" : 2, 24 | "toolbarvisible" : 1, 25 | "lefttoolbarpinned" : 0, 26 | "toptoolbarpinned" : 0, 27 | "righttoolbarpinned" : 0, 28 | "bottomtoolbarpinned" : 0, 29 | "toolbars_unpinned_last_save" : 0, 30 | "tallnewobj" : 0, 31 | "boxanimatetime" : 200, 32 | "enablehscroll" : 1, 33 | "enablevscroll" : 1, 34 | "devicewidth" : 0.0, 35 | "description" : "", 36 | "digest" : "", 37 | "tags" : "", 38 | "style" : "", 39 | "subpatcher_template" : "", 40 | "assistshowspatchername" : 0, 41 | "boxes" : [ { 42 | "box" : { 43 | "id" : "obj-50", 44 | "linecount" : 2, 45 | "maxclass" : "comment", 46 | "numinlets" : 1, 47 | "numoutlets" : 0, 48 | "patching_rect" : [ 575.0, 375.0, 82.0, 33.0 ], 49 | "text" : "clear the chat history" 50 | } 51 | 52 | } 53 | , { 54 | "box" : { 55 | "id" : "obj-48", 56 | "maxclass" : "message", 57 | "numinlets" : 2, 58 | "numoutlets" : 1, 59 | "outlettype" : [ "" ], 60 | "patching_rect" : [ 575.0, 410.0, 35.0, 22.0 ], 61 | "text" : "clear" 62 | } 63 | 64 | } 65 | , { 66 | "box" : { 67 | "id" : "obj-45", 68 | "linecount" : 2, 69 | "maxclass" : "comment", 70 | "numinlets" : 1, 71 | "numoutlets" : 0, 72 | "patching_rect" : [ 575.0, 450.0, 88.0, 33.0 ], 73 | "text" : "output the current history" 74 | } 75 | 76 | } 77 | , { 78 | "box" : { 79 | "id" : "obj-41", 80 | "maxclass" : "comment", 81 | "numinlets" : 1, 82 | "numoutlets" : 0, 83 | "patching_rect" : [ 121.0, 504.0, 119.0, 20.0 ], 84 | "text" : "write the chat history" 85 | } 86 | 87 | } 88 | , { 89 | "box" : { 90 | "id" : "obj-36", 91 | "linecount" : 2, 92 | "maxclass" : "comment", 93 | "numinlets" : 1, 94 | "numoutlets" : 0, 95 | "patching_rect" : [ 755.0, 375.0, 150.0, 33.0 ], 96 | "text" : "read a stored history json file back into the script" 97 | } 98 | 99 | } 100 | , { 101 | "box" : { 102 | "id" : "obj-29", 103 | "maxclass" : "message", 104 | "numinlets" : 2, 105 | "numoutlets" : 1, 106 | "outlettype" : [ "" ], 107 | "patching_rect" : [ 575.0, 485.0, 44.0, 22.0 ], 108 | "text" : "history" 109 | } 110 | 111 | } 112 | , { 113 | "box" : { 114 | "id" : "obj-26", 115 | "maxclass" : "newobj", 116 | "numinlets" : 1, 117 | "numoutlets" : 1, 118 | "outlettype" : [ "" ], 119 | "patching_rect" : [ 680.0, 435.0, 121.0, 22.0 ], 120 | "text" : "prepend load_history" 121 | } 122 | 123 | } 124 | , { 125 | "box" : { 126 | "id" : "obj-22", 127 | "maxclass" : "message", 128 | "numinlets" : 2, 129 | "numoutlets" : 1, 130 | "outlettype" : [ "" ], 131 | "patching_rect" : [ 680.0, 375.0, 66.0, 22.0 ], 132 | "text" : "read, bang" 133 | } 134 | 135 | } 136 | , { 137 | "box" : { 138 | "id" : "obj-18", 139 | "maxclass" : "newobj", 140 | "numinlets" : 2, 141 | "numoutlets" : 4, 142 | "outlettype" : [ "dictionary", "", "", "" ], 143 | "patching_rect" : [ 680.0, 405.0, 50.5, 22.0 ], 144 | "saved_object_attributes" : { 145 | "embed" : 0, 146 | "parameter_enable" : 0, 147 | "parameter_mappable" : 0 148 | } 149 | , 150 | "text" : "dict" 151 | } 152 | 153 | } 154 | , { 155 | "box" : { 156 | "id" : "obj-12", 157 | "maxclass" : "message", 158 | "numinlets" : 2, 159 | "numoutlets" : 1, 160 | "outlettype" : [ "" ], 161 | "patching_rect" : [ 180.0, 480.0, 34.0, 22.0 ], 162 | "text" : "write" 163 | } 164 | 165 | } 166 | , { 167 | "box" : { 168 | "id" : "obj-3", 169 | "maxclass" : "newobj", 170 | "numinlets" : 2, 171 | "numoutlets" : 4, 172 | "outlettype" : [ "dictionary", "", "", "" ], 173 | "patching_rect" : [ 121.0, 480.0, 50.5, 22.0 ], 174 | "saved_object_attributes" : { 175 | "embed" : 0, 176 | "parameter_enable" : 0, 177 | "parameter_mappable" : 0 178 | } 179 | , 180 | "text" : "dict" 181 | } 182 | 183 | } 184 | , { 185 | "box" : { 186 | "fontface" : 1, 187 | "id" : "obj-8", 188 | "maxclass" : "comment", 189 | "numinlets" : 1, 190 | "numoutlets" : 0, 191 | "patching_rect" : [ 450.0, 45.0, 323.0, 20.0 ], 192 | "text" : "!!! Make sure you add your own API key to a .env file !!!" 193 | } 194 | 195 | } 196 | , { 197 | "box" : { 198 | "id" : "obj-78", 199 | "linecount" : 3, 200 | "maxclass" : "comment", 201 | "numinlets" : 1, 202 | "numoutlets" : 0, 203 | "patching_rect" : [ 79.0, 130.0, 122.0, 47.0 ], 204 | "text" : "start script (if not automatically started or after error)" 205 | } 206 | 207 | } 208 | , { 209 | "box" : { 210 | "id" : "obj-76", 211 | "maxclass" : "comment", 212 | "numinlets" : 1, 213 | "numoutlets" : 0, 214 | "patching_rect" : [ 293.0, 248.0, 58.0, 20.0 ], 215 | "text" : "filter 'text'" 216 | } 217 | 218 | } 219 | , { 220 | "box" : { 221 | "id" : "obj-75", 222 | "maxclass" : "comment", 223 | "numinlets" : 1, 224 | "numoutlets" : 0, 225 | "patching_rect" : [ 293.0, 278.0, 106.0, 20.0 ], 226 | "text" : "filter empty strings" 227 | } 228 | 229 | } 230 | , { 231 | "box" : { 232 | "id" : "obj-69", 233 | "linecount" : 2, 234 | "maxclass" : "comment", 235 | "numinlets" : 1, 236 | "numoutlets" : 0, 237 | "patching_rect" : [ 225.0, 130.0, 210.0, 33.0 ], 238 | "text" : "The prompt(s) to generate completions for, encoded as a string" 239 | } 240 | 241 | } 242 | , { 243 | "box" : { 244 | "id" : "obj-67", 245 | "maxclass" : "newobj", 246 | "numinlets" : 2, 247 | "numoutlets" : 2, 248 | "outlettype" : [ "", "" ], 249 | "patching_rect" : [ 225.0, 278.0, 66.0, 22.0 ], 250 | "text" : "route bang" 251 | } 252 | 253 | } 254 | , { 255 | "box" : { 256 | "id" : "obj-66", 257 | "linecount" : 2, 258 | "maxclass" : "message", 259 | "numinlets" : 2, 260 | "numoutlets" : 1, 261 | "outlettype" : [ "" ], 262 | "patching_rect" : [ 450.0, 945.0, 129.0, 35.0 ], 263 | "text" : ";\rmax launchbrowser $1" 264 | } 265 | 266 | } 267 | , { 268 | "box" : { 269 | "id" : "obj-64", 270 | "maxclass" : "comment", 271 | "numinlets" : 1, 272 | "numoutlets" : 0, 273 | "patching_rect" : [ 450.0, 795.0, 70.0, 20.0 ], 274 | "text" : "References" 275 | } 276 | 277 | } 278 | , { 279 | "box" : { 280 | "id" : "obj-62", 281 | "maxclass" : "message", 282 | "numinlets" : 2, 283 | "numoutlets" : 1, 284 | "outlettype" : [ "" ], 285 | "patching_rect" : [ 450.0, 915.0, 316.0, 22.0 ], 286 | "text" : "https://platform.openai.com/docs/api-reference/models/list" 287 | } 288 | 289 | } 290 | , { 291 | "box" : { 292 | "id" : "obj-60", 293 | "maxclass" : "message", 294 | "numinlets" : 2, 295 | "numoutlets" : 1, 296 | "outlettype" : [ "" ], 297 | "patching_rect" : [ 450.0, 822.0, 219.0, 22.0 ], 298 | "text" : "https://www.npmjs.com/package/openai" 299 | } 300 | 301 | } 302 | , { 303 | "box" : { 304 | "id" : "obj-58", 305 | "maxclass" : "message", 306 | "numinlets" : 2, 307 | "numoutlets" : 1, 308 | "outlettype" : [ "" ], 309 | "patching_rect" : [ 450.0, 852.0, 319.0, 22.0 ], 310 | "text" : "https://platform.openai.com/docs/api-reference/chat/create" 311 | } 312 | 313 | } 314 | , { 315 | "box" : { 316 | "id" : "obj-56", 317 | "maxclass" : "message", 318 | "numinlets" : 2, 319 | "numoutlets" : 1, 320 | "outlettype" : [ "" ], 321 | "patching_rect" : [ 450.0, 882.0, 205.0, 22.0 ], 322 | "text" : "https://platform.openai.com/tokenizer" 323 | } 324 | 325 | } 326 | , { 327 | "box" : { 328 | "id" : "obj-54", 329 | "linecount" : 7, 330 | "maxclass" : "comment", 331 | "numinlets" : 1, 332 | "numoutlets" : 0, 333 | "patching_rect" : [ 680.0, 252.0, 307.0, 100.0 ], 334 | "text" : "The maximum number of tokens to generate in the chat completion. The GPT family of models process text using tokens, which are common sequences of characters found in text. A helpful rule of thumb is that one token generally corresponds to ~4 characters of text for common English text. This translates to roughly ¾ of a word (so 100 tokens ~= 75 words)." 335 | } 336 | 337 | } 338 | , { 339 | "box" : { 340 | "id" : "obj-52", 341 | "maxclass" : "message", 342 | "numinlets" : 2, 343 | "numoutlets" : 1, 344 | "outlettype" : [ "" ], 345 | "patching_rect" : [ 635.0, 285.0, 43.0, 22.0 ], 346 | "text" : "Infinity" 347 | } 348 | 349 | } 350 | , { 351 | "box" : { 352 | "id" : "obj-44", 353 | "maxclass" : "number", 354 | "numinlets" : 1, 355 | "numoutlets" : 2, 356 | "outlettype" : [ "", "bang" ], 357 | "parameter_enable" : 0, 358 | "patching_rect" : [ 575.0, 285.0, 50.0, 22.0 ] 359 | } 360 | 361 | } 362 | , { 363 | "box" : { 364 | "id" : "obj-42", 365 | "maxclass" : "message", 366 | "numinlets" : 2, 367 | "numoutlets" : 1, 368 | "outlettype" : [ "" ], 369 | "patching_rect" : [ 575.0, 330.0, 90.0, 22.0 ], 370 | "text" : "max_tokens $1" 371 | } 372 | 373 | } 374 | , { 375 | "box" : { 376 | "id" : "obj-40", 377 | "maxclass" : "newobj", 378 | "numinlets" : 1, 379 | "numoutlets" : 1, 380 | "outlettype" : [ "" ], 381 | "patching_rect" : [ 490.5, 345.0, 19.0, 22.0 ], 382 | "text" : "t l" 383 | } 384 | 385 | } 386 | , { 387 | "box" : { 388 | "id" : "obj-39", 389 | "maxclass" : "comment", 390 | "numinlets" : 1, 391 | "numoutlets" : 0, 392 | "patching_rect" : [ 450.0, 143.0, 184.0, 20.0 ], 393 | "text" : "The role of the messages author." 394 | } 395 | 396 | } 397 | , { 398 | "box" : { 399 | "id" : "obj-37", 400 | "maxclass" : "message", 401 | "numinlets" : 2, 402 | "numoutlets" : 1, 403 | "outlettype" : [ "" ], 404 | "patching_rect" : [ 490.5, 195.0, 45.0, 22.0 ], 405 | "text" : "role $1" 406 | } 407 | 408 | } 409 | , { 410 | "box" : { 411 | "id" : "obj-35", 412 | "items" : [ "user", ",", "assistent", ",", "system" ], 413 | "maxclass" : "umenu", 414 | "numinlets" : 1, 415 | "numoutlets" : 3, 416 | "outlettype" : [ "int", "", "" ], 417 | "parameter_enable" : 1, 418 | "patching_rect" : [ 450.0, 165.0, 100.0, 22.0 ], 419 | "saved_attribute_attributes" : { 420 | "valueof" : { 421 | "parameter_enum" : [ "user", "assistent", "system" ], 422 | "parameter_initial" : [ 0.0 ], 423 | "parameter_initial_enable" : 1, 424 | "parameter_longname" : "umenu", 425 | "parameter_mmax" : 2, 426 | "parameter_shortname" : "umenu", 427 | "parameter_type" : 2 428 | } 429 | 430 | } 431 | , 432 | "varname" : "umenu" 433 | } 434 | 435 | } 436 | , { 437 | "box" : { 438 | "id" : "obj-34", 439 | "maxclass" : "message", 440 | "numinlets" : 2, 441 | "numoutlets" : 1, 442 | "outlettype" : [ "" ], 443 | "patching_rect" : [ 575.0, 225.0, 90.0, 22.0 ], 444 | "text" : "temperature $1" 445 | } 446 | 447 | } 448 | , { 449 | "box" : { 450 | "id" : "obj-31", 451 | "linecount" : 4, 452 | "maxclass" : "comment", 453 | "numinlets" : 1, 454 | "numoutlets" : 0, 455 | "patching_rect" : [ 635.0, 157.5, 285.0, 60.0 ], 456 | "text" : "set the temperature. What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic." 457 | } 458 | 459 | } 460 | , { 461 | "box" : { 462 | "format" : 6, 463 | "id" : "obj-27", 464 | "maxclass" : "flonum", 465 | "maximum" : 2.0, 466 | "minimum" : 0.0, 467 | "numinlets" : 1, 468 | "numoutlets" : 2, 469 | "outlettype" : [ "", "bang" ], 470 | "parameter_enable" : 1, 471 | "patching_rect" : [ 575.0, 195.0, 50.0, 22.0 ], 472 | "saved_attribute_attributes" : { 473 | "valueof" : { 474 | "parameter_initial" : [ 1 ], 475 | "parameter_initial_enable" : 1, 476 | "parameter_longname" : "number", 477 | "parameter_mmax" : 2.0, 478 | "parameter_shortname" : "number", 479 | "parameter_type" : 0 480 | } 481 | 482 | } 483 | , 484 | "varname" : "number" 485 | } 486 | 487 | } 488 | , { 489 | "box" : { 490 | "id" : "obj-25", 491 | "linecount" : 2, 492 | "maxclass" : "comment", 493 | "numinlets" : 1, 494 | "numoutlets" : 0, 495 | "patching_rect" : [ 79.0, 210.5, 117.0, 33.0 ], 496 | "text" : "install the packages (only needed once)" 497 | } 498 | 499 | } 500 | , { 501 | "box" : { 502 | "id" : "obj-23", 503 | "maxclass" : "comment", 504 | "numinlets" : 1, 505 | "numoutlets" : 0, 506 | "patching_rect" : [ 45.0, 80.0, 311.0, 20.0 ], 507 | "text" : "written by Timo Hoogland, 2023 www.timohoogland.com" 508 | } 509 | 510 | } 511 | , { 512 | "box" : { 513 | "fontface" : 3, 514 | "fontsize" : 24.0, 515 | "id" : "obj-21", 516 | "maxclass" : "comment", 517 | "numinlets" : 1, 518 | "numoutlets" : 0, 519 | "patching_rect" : [ 45.0, 45.0, 266.0, 33.0 ], 520 | "text" : "n4m chatGPT example" 521 | } 522 | 523 | } 524 | , { 525 | "box" : { 526 | "id" : "obj-19", 527 | "maxclass" : "message", 528 | "numinlets" : 2, 529 | "numoutlets" : 1, 530 | "outlettype" : [ "" ], 531 | "patching_rect" : [ 79.0, 248.0, 66.0, 22.0 ], 532 | "text" : "npm install" 533 | } 534 | 535 | } 536 | , { 537 | "box" : { 538 | "id" : "obj-17", 539 | "maxclass" : "button", 540 | "numinlets" : 1, 541 | "numoutlets" : 1, 542 | "outlettype" : [ "bang" ], 543 | "parameter_enable" : 0, 544 | "patching_rect" : [ 83.0, 479.0, 24.0, 24.0 ] 545 | } 546 | 547 | } 548 | , { 549 | "box" : { 550 | "id" : "obj-15", 551 | "maxclass" : "button", 552 | "numinlets" : 1, 553 | "numoutlets" : 1, 554 | "outlettype" : [ "bang" ], 555 | "parameter_enable" : 0, 556 | "patching_rect" : [ 45.0, 479.0, 24.0, 24.0 ] 557 | } 558 | 559 | } 560 | , { 561 | "box" : { 562 | "id" : "obj-13", 563 | "maxclass" : "newobj", 564 | "numinlets" : 4, 565 | "numoutlets" : 4, 566 | "outlettype" : [ "", "", "", "" ], 567 | "patching_rect" : [ 45.0, 438.0, 133.0, 22.0 ], 568 | "text" : "route error done history" 569 | } 570 | 571 | } 572 | , { 573 | "box" : { 574 | "id" : "obj-10", 575 | "maxclass" : "newobj", 576 | "numinlets" : 2, 577 | "numoutlets" : 2, 578 | "outlettype" : [ "", "" ], 579 | "patching_rect" : [ 225.0, 248.0, 59.0, 22.0 ], 580 | "text" : "route text" 581 | } 582 | 583 | } 584 | , { 585 | "box" : { 586 | "id" : "obj-9", 587 | "linecount" : 32, 588 | "maxclass" : "message", 589 | "numinlets" : 2, 590 | "numoutlets" : 1, 591 | "outlettype" : [ "" ], 592 | "patching_rect" : [ 45.0, 540.0, 377.0, 437.0 ], 593 | "text" : "\"Max/MSP is a visual programming language and development environment for creating interactive and multimedia applications. It was developed by Cycling '74 and is widely used for sound synthesis, music composition, and real-time audio processing.\n\nMax/MSP allows users to build audio and multimedia applications by connecting various modules called \\\"objects\\\" through a graphical user interface. Objects can represent audio generators, filters, effects, MIDI controllers, visual components, and more. Users can connect these objects by drawing lines between them to define the signal flow and data processing.\n\nOne of the noteworthy features of Max/MSP is its ability to support real-time interactions and live improvisation. Users can modify and manipulate their projects in real-time, making it a popular choice for live performances, installations, and interactive audiovisual experiences.\n\nMax/MSP provides a wide range of pre-built objects and libraries, allowing users to create complex audio and multimedia applications without writing code. However, for those with programming experience, Max/MSP also provides an advanced mode called \\\"Max for Live\\\" that allows the integration of custom code written in languages like Max's own Max Object Language (MOL), JavaScript, and C/C++.\n\nMax/MSP is a versatile tool used by musicians, artists, designers, and developers for various purposes, including live music performances, interactive installations, sound design, and music composition. It offers a flexible and intuitive interface that allows both beginners and advanced users to explore the possibilities of audio and multimedia programming.\"" 594 | } 595 | 596 | } 597 | , { 598 | "box" : { 599 | "id" : "obj-7", 600 | "maxclass" : "message", 601 | "numinlets" : 2, 602 | "numoutlets" : 1, 603 | "outlettype" : [ "" ], 604 | "patching_rect" : [ 225.0, 315.0, 63.0, 22.0 ], 605 | "text" : "prompt $1" 606 | } 607 | 608 | } 609 | , { 610 | "box" : { 611 | "id" : "obj-6", 612 | "maxclass" : "textedit", 613 | "numinlets" : 1, 614 | "numoutlets" : 4, 615 | "outlettype" : [ "", "int", "", "" ], 616 | "outputmode" : 1, 617 | "parameter_enable" : 0, 618 | "patching_rect" : [ 225.0, 165.0, 210.0, 75.0 ], 619 | "text" : "What is Max/MSP?" 620 | } 621 | 622 | } 623 | , { 624 | "box" : { 625 | "id" : "obj-5", 626 | "maxclass" : "newobj", 627 | "numinlets" : 1, 628 | "numoutlets" : 1, 629 | "outlettype" : [ "" ], 630 | "patching_rect" : [ 45.0, 315.0, 85.0, 22.0 ], 631 | "text" : "prepend script" 632 | } 633 | 634 | } 635 | , { 636 | "box" : { 637 | "id" : "obj-4", 638 | "maxclass" : "message", 639 | "numinlets" : 2, 640 | "numoutlets" : 1, 641 | "outlettype" : [ "" ], 642 | "patching_rect" : [ 45.0, 130.0, 32.0, 22.0 ], 643 | "text" : "start" 644 | } 645 | 646 | } 647 | , { 648 | "box" : { 649 | "bgmode" : 0, 650 | "border" : 0, 651 | "clickthrough" : 0, 652 | "enablehscroll" : 0, 653 | "enablevscroll" : 0, 654 | "id" : "obj-2", 655 | "lockeddragscroll" : 0, 656 | "lockedsize" : 0, 657 | "maxclass" : "bpatcher", 658 | "name" : "n4m.monitor.maxpat", 659 | "numinlets" : 1, 660 | "numoutlets" : 1, 661 | "offset" : [ 0.0, 0.0 ], 662 | "outlettype" : [ "bang" ], 663 | "patching_rect" : [ 450.0, 540.0, 400.0, 220.0 ], 664 | "viewvisibility" : 1 665 | } 666 | 667 | } 668 | , { 669 | "box" : { 670 | "id" : "obj-1", 671 | "maxclass" : "newobj", 672 | "numinlets" : 1, 673 | "numoutlets" : 2, 674 | "outlettype" : [ "", "" ], 675 | "patching_rect" : [ 45.0, 393.0, 240.0, 22.0 ], 676 | "saved_object_attributes" : { 677 | "autostart" : 1, 678 | "defer" : 0, 679 | "node_bin_path" : "", 680 | "npm_bin_path" : "", 681 | "watch" : 1 682 | } 683 | , 684 | "text" : "node.script index.js @autostart 1 @watch 1" 685 | } 686 | 687 | } 688 | ], 689 | "lines" : [ { 690 | "patchline" : { 691 | "destination" : [ "obj-13", 0 ], 692 | "source" : [ "obj-1", 0 ] 693 | } 694 | 695 | } 696 | , { 697 | "patchline" : { 698 | "destination" : [ "obj-2", 0 ], 699 | "source" : [ "obj-1", 1 ] 700 | } 701 | 702 | } 703 | , { 704 | "patchline" : { 705 | "destination" : [ "obj-67", 0 ], 706 | "source" : [ "obj-10", 0 ] 707 | } 708 | 709 | } 710 | , { 711 | "patchline" : { 712 | "destination" : [ "obj-3", 0 ], 713 | "source" : [ "obj-12", 0 ] 714 | } 715 | 716 | } 717 | , { 718 | "patchline" : { 719 | "destination" : [ "obj-15", 0 ], 720 | "source" : [ "obj-13", 0 ] 721 | } 722 | 723 | } 724 | , { 725 | "patchline" : { 726 | "destination" : [ "obj-17", 0 ], 727 | "source" : [ "obj-13", 1 ] 728 | } 729 | 730 | } 731 | , { 732 | "patchline" : { 733 | "destination" : [ "obj-3", 0 ], 734 | "source" : [ "obj-13", 2 ] 735 | } 736 | 737 | } 738 | , { 739 | "patchline" : { 740 | "destination" : [ "obj-9", 1 ], 741 | "source" : [ "obj-13", 3 ] 742 | } 743 | 744 | } 745 | , { 746 | "patchline" : { 747 | "destination" : [ "obj-26", 0 ], 748 | "source" : [ "obj-18", 0 ] 749 | } 750 | 751 | } 752 | , { 753 | "patchline" : { 754 | "destination" : [ "obj-5", 0 ], 755 | "source" : [ "obj-19", 0 ] 756 | } 757 | 758 | } 759 | , { 760 | "patchline" : { 761 | "destination" : [ "obj-18", 0 ], 762 | "source" : [ "obj-22", 0 ] 763 | } 764 | 765 | } 766 | , { 767 | "patchline" : { 768 | "destination" : [ "obj-40", 0 ], 769 | "source" : [ "obj-26", 0 ] 770 | } 771 | 772 | } 773 | , { 774 | "patchline" : { 775 | "destination" : [ "obj-34", 0 ], 776 | "source" : [ "obj-27", 0 ] 777 | } 778 | 779 | } 780 | , { 781 | "patchline" : { 782 | "destination" : [ "obj-40", 0 ], 783 | "source" : [ "obj-29", 0 ] 784 | } 785 | 786 | } 787 | , { 788 | "patchline" : { 789 | "destination" : [ "obj-40", 0 ], 790 | "source" : [ "obj-34", 0 ] 791 | } 792 | 793 | } 794 | , { 795 | "patchline" : { 796 | "destination" : [ "obj-37", 0 ], 797 | "source" : [ "obj-35", 1 ] 798 | } 799 | 800 | } 801 | , { 802 | "patchline" : { 803 | "destination" : [ "obj-40", 0 ], 804 | "source" : [ "obj-37", 0 ] 805 | } 806 | 807 | } 808 | , { 809 | "patchline" : { 810 | "destination" : [ "obj-5", 0 ], 811 | "source" : [ "obj-4", 0 ] 812 | } 813 | 814 | } 815 | , { 816 | "patchline" : { 817 | "destination" : [ "obj-1", 0 ], 818 | "source" : [ "obj-40", 0 ] 819 | } 820 | 821 | } 822 | , { 823 | "patchline" : { 824 | "destination" : [ "obj-40", 0 ], 825 | "source" : [ "obj-42", 0 ] 826 | } 827 | 828 | } 829 | , { 830 | "patchline" : { 831 | "destination" : [ "obj-42", 0 ], 832 | "source" : [ "obj-44", 0 ] 833 | } 834 | 835 | } 836 | , { 837 | "patchline" : { 838 | "destination" : [ "obj-40", 0 ], 839 | "source" : [ "obj-48", 0 ] 840 | } 841 | 842 | } 843 | , { 844 | "patchline" : { 845 | "destination" : [ "obj-1", 0 ], 846 | "source" : [ "obj-5", 0 ] 847 | } 848 | 849 | } 850 | , { 851 | "patchline" : { 852 | "destination" : [ "obj-42", 0 ], 853 | "source" : [ "obj-52", 0 ] 854 | } 855 | 856 | } 857 | , { 858 | "patchline" : { 859 | "destination" : [ "obj-66", 0 ], 860 | "source" : [ "obj-56", 0 ] 861 | } 862 | 863 | } 864 | , { 865 | "patchline" : { 866 | "destination" : [ "obj-66", 0 ], 867 | "source" : [ "obj-58", 0 ] 868 | } 869 | 870 | } 871 | , { 872 | "patchline" : { 873 | "destination" : [ "obj-10", 0 ], 874 | "source" : [ "obj-6", 0 ] 875 | } 876 | 877 | } 878 | , { 879 | "patchline" : { 880 | "destination" : [ "obj-66", 0 ], 881 | "source" : [ "obj-60", 0 ] 882 | } 883 | 884 | } 885 | , { 886 | "patchline" : { 887 | "destination" : [ "obj-66", 0 ], 888 | "source" : [ "obj-62", 0 ] 889 | } 890 | 891 | } 892 | , { 893 | "patchline" : { 894 | "destination" : [ "obj-7", 0 ], 895 | "source" : [ "obj-67", 1 ] 896 | } 897 | 898 | } 899 | , { 900 | "patchline" : { 901 | "destination" : [ "obj-40", 0 ], 902 | "source" : [ "obj-7", 0 ] 903 | } 904 | 905 | } 906 | ], 907 | "parameters" : { 908 | "obj-27" : [ "number", "number", 0 ], 909 | "obj-35" : [ "umenu", "umenu", 0 ], 910 | "parameterbanks" : { 911 | "0" : { 912 | "index" : 0, 913 | "name" : "", 914 | "parameters" : [ "-", "-", "-", "-", "-", "-", "-", "-" ] 915 | } 916 | 917 | } 918 | , 919 | "inherited_shortname" : 1 920 | } 921 | , 922 | "dependency_cache" : [ { 923 | "name" : "fit_jweb_to_bounds.js", 924 | "bootpath" : "C74:/packages/Node for Max/patchers/debug-monitor", 925 | "type" : "TEXT", 926 | "implicit" : 1 927 | } 928 | , { 929 | "name" : "index.js", 930 | "bootpath" : "~/Drive/work/code/max/major_projects/chatgpt-n4m", 931 | "patcherrelativepath" : ".", 932 | "type" : "TEXT", 933 | "implicit" : 1 934 | } 935 | , { 936 | "name" : "n4m.monitor.maxpat", 937 | "bootpath" : "C74:/packages/Node for Max/patchers/debug-monitor", 938 | "type" : "JSON", 939 | "implicit" : 1 940 | } 941 | , { 942 | "name" : "resize_n4m_monitor_patcher.js", 943 | "bootpath" : "C74:/packages/Node for Max/patchers/debug-monitor", 944 | "type" : "TEXT", 945 | "implicit" : 1 946 | } 947 | ], 948 | "autosave" : 0 949 | } 950 | 951 | } 952 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // 2 | // ChatGPT Node4Max Example 3 | // written by Timo Hoogland 4 | // 2023, www.timohoogland.com 5 | // 6 | // MIT License 7 | // 8 | 9 | // updated for openai node library 4.0.0+ and gpt4 model 10 | // @un1crom aka #worksonbecoming www.worksonbecoming.com 11 | 12 | require('dotenv').config(); 13 | 14 | const max = require('max-api'); 15 | // Import OpenAI package 16 | const { OpenAI } = require("openai"); 17 | 18 | 19 | const openai = new OpenAI({ 20 | apiKey: process.env.OPENAI_API_KEY 21 | }); 22 | 23 | // Settings 24 | let ROLE = 'user'; 25 | let TEMPERATURE = 1; 26 | let MAX_TOKENS = Infinity; 27 | 28 | // Chat history array 29 | let HISTORY = []; 30 | 31 | // The prompt send to OpenAI API with error handling 32 | // Returns the result and a message 'done' 33 | // Else returns a message 'error' 34 | // 35 | async function prompt(p){ 36 | try { 37 | // add prompt to chat history 38 | HISTORY.push({ role: ROLE, content: p }); 39 | 40 | // await chat completion with settings and chat history 41 | const chat = await openai.chat.completions.create({ 42 | model: "gpt-4-1106-preview", // Replace with your desired model 43 | messages: HISTORY, 44 | temperature: TEMPERATURE, 45 | max_tokens: MAX_TOKENS 46 | }); 47 | // add response to chat history 48 | HISTORY.push(chat.choices[0].message); 49 | // output response to max patch 50 | max.outlet(chat.choices[0].message.content); 51 | // output history (for storage and saving in dictionary) 52 | max.outlet('history', { history: HISTORY }); 53 | max.outlet('done'); 54 | } catch (error) { 55 | if (error.response){ 56 | max.post(error.response.status); 57 | max.post(error.response.data); 58 | } else { 59 | max.post(error.message); 60 | } 61 | max.outlet('error'); 62 | } 63 | } 64 | 65 | // Messages send from Max to node.script 66 | // 67 | max.addHandlers({ 68 | 'prompt' : (p) => { 69 | // if prompt is an array join into one string 70 | p = Array.isArray(p) ? p.join(" ") : p; 71 | prompt(p); 72 | }, 73 | // set the temperature 74 | 'temperature' : (t) => { 75 | if (isNaN(t)){ 76 | max.post(`Error: temperature ${t} is not a number`); 77 | return; 78 | } 79 | // temperature is a value between 0 and 2 80 | TEMPERATURE = Math.max(0, Math.min(2, t)); 81 | max.post(`temperature: ${TEMPERATURE}`); 82 | }, 83 | // set the max tokens 84 | 'max_tokens' : (t) => { 85 | if (isNaN(t)){ 86 | max.post(`Error: max_tokens ${t} is not a number`); 87 | return; 88 | } else { 89 | // max tokens is an integer or Infinity 90 | MAX_TOKENS = Math.max(1, Math.floor(t)); 91 | } 92 | max.post(`max_tokens: ${MAX_TOKENS}`); 93 | }, 94 | // set the role 95 | 'role' : (r) => { 96 | if (String(r).match(/(user|assistent|system)/)){ 97 | ROLE = r; 98 | max.post(`role: ${ROLE}`); 99 | } else { 100 | max.post(`Error: role ${r} is not user, assistent or system`); 101 | } 102 | }, 103 | // clear the chat history 104 | 'clear' : () => { 105 | HISTORY = []; 106 | }, 107 | // output the current history 108 | 'history' : () => { 109 | max.outlet('history', { history: HISTORY }); 110 | }, 111 | // load the history of a chat from a dictionary 112 | 'load_history' : (dict) => { 113 | HISTORY = dict.history ? dict.history : []; 114 | } 115 | }); 116 | -------------------------------------------------------------------------------- /media/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tmhglnd/chatgpt-n4m/14db3d63c8fe41313ca71a45984ca658b9ce8a64/media/screenshot.png -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chatgpt-n4m", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "version": "1.0.0", 9 | "license": "ISC", 10 | "dependencies": { 11 | "dotenv": "^16.3.1", 12 | "openai": "^3.3.0" 13 | } 14 | }, 15 | "node_modules/asynckit": { 16 | "version": "0.4.0", 17 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 18 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" 19 | }, 20 | "node_modules/axios": { 21 | "version": "0.26.1", 22 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", 23 | "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", 24 | "dependencies": { 25 | "follow-redirects": "^1.14.8" 26 | } 27 | }, 28 | "node_modules/combined-stream": { 29 | "version": "1.0.8", 30 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 31 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 32 | "dependencies": { 33 | "delayed-stream": "~1.0.0" 34 | }, 35 | "engines": { 36 | "node": ">= 0.8" 37 | } 38 | }, 39 | "node_modules/delayed-stream": { 40 | "version": "1.0.0", 41 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 42 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 43 | "engines": { 44 | "node": ">=0.4.0" 45 | } 46 | }, 47 | "node_modules/dotenv": { 48 | "version": "16.3.1", 49 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", 50 | "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", 51 | "engines": { 52 | "node": ">=12" 53 | }, 54 | "funding": { 55 | "url": "https://github.com/motdotla/dotenv?sponsor=1" 56 | } 57 | }, 58 | "node_modules/follow-redirects": { 59 | "version": "1.15.2", 60 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", 61 | "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", 62 | "funding": [ 63 | { 64 | "type": "individual", 65 | "url": "https://github.com/sponsors/RubenVerborgh" 66 | } 67 | ], 68 | "engines": { 69 | "node": ">=4.0" 70 | }, 71 | "peerDependenciesMeta": { 72 | "debug": { 73 | "optional": true 74 | } 75 | } 76 | }, 77 | "node_modules/form-data": { 78 | "version": "4.0.0", 79 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", 80 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", 81 | "dependencies": { 82 | "asynckit": "^0.4.0", 83 | "combined-stream": "^1.0.8", 84 | "mime-types": "^2.1.12" 85 | }, 86 | "engines": { 87 | "node": ">= 6" 88 | } 89 | }, 90 | "node_modules/mime-db": { 91 | "version": "1.52.0", 92 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 93 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 94 | "engines": { 95 | "node": ">= 0.6" 96 | } 97 | }, 98 | "node_modules/mime-types": { 99 | "version": "2.1.35", 100 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 101 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 102 | "dependencies": { 103 | "mime-db": "1.52.0" 104 | }, 105 | "engines": { 106 | "node": ">= 0.6" 107 | } 108 | }, 109 | "node_modules/openai": { 110 | "version": "3.3.0", 111 | "resolved": "https://registry.npmjs.org/openai/-/openai-3.3.0.tgz", 112 | "integrity": "sha512-uqxI/Au+aPRnsaQRe8CojU0eCR7I0mBiKjD3sNMzY6DaC1ZVrc85u98mtJW6voDug8fgGN+DIZmTDxTthxb7dQ==", 113 | "dependencies": { 114 | "axios": "^0.26.0", 115 | "form-data": "^4.0.0" 116 | } 117 | } 118 | }, 119 | "dependencies": { 120 | "asynckit": { 121 | "version": "0.4.0", 122 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 123 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" 124 | }, 125 | "axios": { 126 | "version": "0.26.1", 127 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", 128 | "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", 129 | "requires": { 130 | "follow-redirects": "^1.14.8" 131 | } 132 | }, 133 | "combined-stream": { 134 | "version": "1.0.8", 135 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 136 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 137 | "requires": { 138 | "delayed-stream": "~1.0.0" 139 | } 140 | }, 141 | "delayed-stream": { 142 | "version": "1.0.0", 143 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 144 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" 145 | }, 146 | "dotenv": { 147 | "version": "16.3.1", 148 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", 149 | "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==" 150 | }, 151 | "follow-redirects": { 152 | "version": "1.15.2", 153 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", 154 | "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" 155 | }, 156 | "form-data": { 157 | "version": "4.0.0", 158 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", 159 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", 160 | "requires": { 161 | "asynckit": "^0.4.0", 162 | "combined-stream": "^1.0.8", 163 | "mime-types": "^2.1.12" 164 | } 165 | }, 166 | "mime-db": { 167 | "version": "1.52.0", 168 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 169 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" 170 | }, 171 | "mime-types": { 172 | "version": "2.1.35", 173 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 174 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 175 | "requires": { 176 | "mime-db": "1.52.0" 177 | } 178 | }, 179 | "openai": { 180 | "version": "3.3.0", 181 | "resolved": "https://registry.npmjs.org/openai/-/openai-3.3.0.tgz", 182 | "integrity": "sha512-uqxI/Au+aPRnsaQRe8CojU0eCR7I0mBiKjD3sNMzY6DaC1ZVrc85u98mtJW6voDug8fgGN+DIZmTDxTthxb7dQ==", 183 | "requires": { 184 | "axios": "^0.26.0", 185 | "form-data": "^4.0.0" 186 | } 187 | } 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chatgpt-n4m", 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 | "dotenv": "^16.3.1", 14 | "openai": "^4.0.0" 15 | } 16 | } 17 | --------------------------------------------------------------------------------