├── OpenAIApp.gs └── README.md /OpenAIApp.gs: -------------------------------------------------------------------------------- 1 | class OpenAIApp { 2 | constructor(api_key) { 3 | this.api_key = api_key; 4 | this.connect = (api_key, options) => { 5 | var url = `https://api.openai.com/v1/${options.url}`; 6 | var opt = { 7 | 'method': options.method, 8 | 'contentType': 'application/json', 9 | 'headers': { 10 | Authorization: 'Bearer ' + api_key, 11 | }, 12 | muteHttpExceptions: true 13 | }; 14 | if ((options.method == 'POST') && (!!options.payload)) { 15 | opt.payload = JSON.stringify(options.payload); 16 | } 17 | var response = UrlFetchApp.fetch(url, opt); 18 | var json = JSON.parse(response); 19 | if (json.error?.message != undefined) { 20 | throw new Error(json['error']['message']); 21 | } 22 | return json; 23 | }; 24 | } 25 | Models() { 26 | class Models { 27 | constructor(api_key, connect) { 28 | this.api_key = api_key; 29 | this.connect = connect; 30 | } 31 | ListModels() { 32 | var options = { 33 | method: 'GET', 34 | url: 'models' 35 | } 36 | return this.connect(this.api_key, options); 37 | } 38 | RetrieveModel(params = {}) { 39 | if (!!params) { 40 | if (params.model == undefined) { 41 | throw new Error('Set RetrieveModel params.model'); 42 | } 43 | var options = { 44 | method: 'GET', 45 | url: `models/${params.model}`, 46 | } 47 | return this.connect(this.api_key, options); 48 | } else { 49 | throw new Error('Set RetrieveModel params') 50 | } 51 | } 52 | } 53 | return new Models(this.api_key, this.connect); 54 | } 55 | Completions() { 56 | class Completions { 57 | constructor(api_key, connect) { 58 | this.api_key = api_key; 59 | this.connect = connect; 60 | } 61 | CreateCompletion(params = {}) { 62 | if (!!params) { 63 | if (params.model == undefined) { 64 | throw new Error('Set CreateCompletion params.model'); 65 | } 66 | var options = { 67 | method: 'POST', 68 | url: 'completions', 69 | payload: params 70 | } 71 | return this.connect(this.api_key, options); 72 | } else { 73 | throw new Error('Set CreateCompletion params') 74 | } 75 | } 76 | } 77 | return new Completions(this.api_key, this.connect); 78 | } 79 | Edits() { 80 | class Edits { 81 | constructor(api_key, connect) { 82 | this.api_key = api_key; 83 | this.connect = connect; 84 | } 85 | CreateEdit(params = {}) { 86 | if (!!params) { 87 | if (params.model == undefined) { 88 | throw new Error('Set CreateEdit params.model'); 89 | } 90 | if (params.instruction == undefined) { 91 | throw new Error('Set CreateEdit params.instruction'); 92 | } 93 | var options = { 94 | method: 'POST', 95 | url: 'completions', 96 | payload: params 97 | } 98 | return this.connect(this.api_key, options); 99 | } else { 100 | throw new Error('Set CreateEdit params') 101 | } 102 | } 103 | } 104 | return new Edits(this.api_key, this.connect); 105 | } 106 | Images() { 107 | class Images { 108 | constructor(api_key, connect) { 109 | this.api_key = api_key; 110 | this.connect = connect; 111 | } 112 | CreateImage(params = {}) { 113 | if (!!params) { 114 | if (params.prompt == undefined) { 115 | throw new Error('Set CreateImage params.prompt'); 116 | } 117 | var options = { 118 | method: 'POST', 119 | url: 'images/generations', 120 | payload: params 121 | } 122 | return this.connect(this.api_key, options); 123 | } else { 124 | throw new Error('Set CreateImage params') 125 | } 126 | } 127 | CreateImageEdit(params = {}) { 128 | if (!!params) { 129 | if (params.image == undefined) { 130 | throw new Error('Set CreateImageEdit params.image'); 131 | } 132 | if (params.prompt == undefined) { 133 | throw new Error('Set CreateImageEdit params.prompt'); 134 | } 135 | var options = { 136 | method: 'POST', 137 | url: 'images/edits', 138 | payload: params 139 | } 140 | return this.connect(this.api_key, options); 141 | } else { 142 | throw new Error('Set CreateImageEdit params') 143 | } 144 | } 145 | CreateImageVariation(params = {}) { 146 | if (!!params) { 147 | if (params.image == undefined) { 148 | throw new Error('Set CreateImageVariation params.image'); 149 | } 150 | var options = { 151 | method: 'POST', 152 | url: 'images/variations', 153 | payload: params 154 | } 155 | return this.connect(this.api_key, options); 156 | } else { 157 | throw new Error('Set CreateImageVariation params') 158 | } 159 | } 160 | } 161 | return new Images(this.api_key, this.connect); 162 | } 163 | Chat() { 164 | class Chat { 165 | constructor(api_key, connect) { 166 | this.api_key = api_key; 167 | this.connect = connect; 168 | } 169 | CreateChatCompletion(params = {}) { 170 | if (!!params) { 171 | if (params.model == undefined) { 172 | throw new Error('Set CreateChatCompletion params.model'); 173 | } 174 | if (params.messages == undefined) { 175 | throw new Error('Set CreateChatCompletion params.messages'); 176 | } 177 | var options = { 178 | method: 'POST', 179 | url: 'chat/completions', 180 | payload: params 181 | } 182 | return this.connect(this.api_key, options); 183 | } else { 184 | throw new Error('Set CreateChatCompletion params') 185 | } 186 | } 187 | } 188 | return new Chat(this.api_key, this.connect); 189 | } 190 | Moderations() { 191 | class Moderations { 192 | constructor(api_key, connect) { 193 | this.api_key = api_key; 194 | this.connect = connect; 195 | } 196 | CreateModeration(params = {}) { 197 | if (!!params) { 198 | if (params.input == undefined) { 199 | throw new Error('Set CreateModeration params.input'); 200 | } 201 | var options = { 202 | method: 'POST', 203 | url: 'moderations', 204 | payload: params 205 | } 206 | return this.connect(this.api_key, options); 207 | } else { 208 | throw new Error('Set CreateModeration params') 209 | } 210 | } 211 | } 212 | return new Moderations(this.api_key, this.connect); 213 | } 214 | Finetunes() { 215 | class Finetunes { 216 | constructor(api_key, connect) { 217 | this.api_key = api_key; 218 | this.connect = connect; 219 | } 220 | CreateFinetune(params = {}) { 221 | if (!!params) { 222 | if (params.training_file == undefined) { 223 | throw new Error('Set CreateFinetune params.training_file'); 224 | } 225 | var options = { 226 | method: 'POST', 227 | url: 'fine-tunes', 228 | payload: params 229 | } 230 | return this.connect(this.api_key, options); 231 | } else { 232 | throw new Error('Set CreateFinetune params') 233 | } 234 | } 235 | ListFinetunes() { 236 | var options = { 237 | method: 'GET', 238 | url: 'fine-tunes' 239 | } 240 | return this.connect(this.api_key, options); 241 | } 242 | RetrieveFinetune(params = { fine_tune_id: string }) { 243 | if (!!params) { 244 | if (params.training_file == undefined) { 245 | throw new Error('Set CreateFinetune params.training_file'); 246 | } 247 | var options = { 248 | method: 'GET', 249 | url: `fine-tunes/${params.fine_tune_id}` 250 | } 251 | return this.connect(this.api_key, options); 252 | } else { 253 | throw new Error('Set RetrieveFinetune params') 254 | } 255 | } 256 | CancelFinetune(params = { fine_tune_id: string }) { 257 | if (!!params) { 258 | if (params.training_file == undefined) { 259 | throw new Error('Set CreateFinetune params.training_file'); 260 | } 261 | var options = { 262 | method: 'POST', 263 | url: `fine-tunes/${params.fine_tune_id}/cancel` 264 | } 265 | return this.connect(this.api_key, options); 266 | } else { 267 | throw new Error('Set CancelFinetune params') 268 | } 269 | } 270 | ListFinetuneEvents(params = { fine_tune_id: string, payload: { stream: bool } }) { 271 | if (!!params) { 272 | if (params.fine_tune_id == undefined) { 273 | throw new Error('Set ListFinetuneEvents params.fine_tune_id'); 274 | } 275 | var options = { 276 | method: 'POST', 277 | url: `fine-tunes/${params.fine_tune_id}/events`, 278 | payload: params.payload 279 | } 280 | return this.connect(this.api_key, options); 281 | } else { 282 | throw new Error('Set ListFinetuneEvents params') 283 | } 284 | } 285 | DeleteFinetuneModel(params = { model: string }) { 286 | if (!!params) { 287 | if (params.model == undefined) { 288 | throw new Error('Set DeleteFinetuneModel params.model'); 289 | } 290 | var options = { 291 | method: 'DELETE', 292 | url: `models/${params.model}` 293 | } 294 | return this.connect(this.api_key, options); 295 | } else { 296 | throw new Error('Set DeleteFinetuneModel params') 297 | } 298 | } 299 | } 300 | return new Finetunes(this.api_key, this.connect); 301 | } 302 | Files() { 303 | class Files { 304 | constructor(api_key, connect) { 305 | this.api_key = api_key; 306 | this.connect = connect; 307 | } 308 | ListFiles() { 309 | var options = { 310 | method: 'GET', 311 | url: 'files' 312 | } 313 | return this.connect(this.api_key, options); 314 | } 315 | UploadFile(params = {}) { 316 | if (!!params) { 317 | if (params.file == undefined) { 318 | throw new Error('Set UploadFile params.file'); 319 | } 320 | if (params.purpose == undefined) { 321 | throw new Error('Set UploadFile params.purpose'); 322 | } 323 | var options = { 324 | method: 'POST', 325 | url: 'files', 326 | payload: params 327 | } 328 | return this.connect(this.api_key, options); 329 | } else { 330 | throw new Error('Set UploadFile params') 331 | } 332 | } 333 | DeleteFile(params = { file_id: string }) { 334 | if (!!params) { 335 | if (params.file_id == undefined) { 336 | throw new Error('Set DeleteFile params.file_id'); 337 | } 338 | var options = { 339 | method: 'DELETE', 340 | url: `files/${params.file_id}` 341 | } 342 | return this.connect(this.api_key, options); 343 | } else { 344 | throw new Error('Set DeleteFile params') 345 | } 346 | } 347 | RetrieveFile(params = { file_id: string }) { 348 | if (!!params) { 349 | if (params.file_id == undefined) { 350 | throw new Error('Set RetrieveFile params.file_id'); 351 | } 352 | var options = { 353 | method: 'GET', 354 | url: `files/${params.file_id}` 355 | } 356 | return this.connect(this.api_key, options); 357 | } else { 358 | throw new Error('Set RetrieveFile params') 359 | } 360 | } 361 | RetrieveFileContent(params = { file_id: string }) { 362 | if (!!params) { 363 | if (params.file_id == undefined) { 364 | throw new Error('Set RetrieveFileContent params.file_id'); 365 | } 366 | var options = { 367 | method: 'GET', 368 | url: `files/${params.file_id}/content` 369 | } 370 | return this.connect(this.api_key, options); 371 | } else { 372 | throw new Error('Set RetrieveFileContent params') 373 | } 374 | } 375 | } 376 | return new Files(this.api_key, this.connect); 377 | } 378 | Audio() { 379 | class Audio { 380 | constructor(api_key, connect) { 381 | this.api_key = api_key; 382 | this.connect = connect; 383 | } 384 | CreateTranscription(params = {}) { 385 | if (!!params) { 386 | if (params.file == undefined) { 387 | throw new Error('Set CreateTranscription params.file'); 388 | } 389 | if (params.model == undefined) { 390 | throw new Error('Set CreateTranscription params.model'); 391 | } 392 | var options = { 393 | method: 'POST', 394 | url: 'audio/transcriptions', 395 | payload: params 396 | } 397 | return this.connect(this.api_key, options); 398 | } else { 399 | throw new Error('Set CreateTranscription params') 400 | } 401 | } 402 | CreateTranslation(params = {}) { 403 | if (!!params) { 404 | if (params.file == undefined) { 405 | throw new Error('Set CreateTranslation params.file'); 406 | } 407 | if (params.model == undefined) { 408 | throw new Error('Set CreateTranslation params.model'); 409 | } 410 | var options = { 411 | method: 'POST', 412 | url: 'audio/translations', 413 | payload: params 414 | } 415 | return this.connect(this.api_key, options); 416 | } else { 417 | throw new Error('Set CreateTranslation params') 418 | } 419 | } 420 | } 421 | return new Audio(this.api_key, this.connect); 422 | } 423 | Embeddings() { 424 | class Embeddings { 425 | constructor(api_key, connect) { 426 | this.api_key = api_key; 427 | this.connect = connect; 428 | } 429 | CreateEmbeddings(params = {}) { 430 | if (!!params) { 431 | if (params.model == undefined) { 432 | throw new Error('Set CreateEmbeddings params.model'); 433 | } 434 | if (params.input == undefined) { 435 | throw new Error('Set CreateEmbeddings params.input'); 436 | } 437 | var options = { 438 | method: 'POST', 439 | url: 'embeddings', 440 | payload: params 441 | } 442 | return this.connect(this.api_key, options); 443 | } else { 444 | throw new Error('Set CreateEmbeddings params') 445 | } 446 | } 447 | } 448 | return new Embeddings(this.api_key, this.connect); 449 | } 450 | } 451 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenAIApp 2 | OpenAI API wrapper for Google Apps Scripts 3 | 4 | You can use **OpenAIApp.gs** as a part of your project. 5 | 6 | All parameters names are the same as in the official documentation - [https://platform.openai.com/docs/api-reference/introduction](https://platform.openai.com/docs/api-reference/introduction). Wrap the method parameters in a js-object and pass it to the method as only one parameter. 7 | 8 | ## Examples 9 | 10 | ### ChatGPT 11 | 12 | ```javascript 13 | var api_key = '**************************************************'; 14 | var openai = new OpenAIApp(api_key); 15 | var result = openai.Chat().CreateChatCompletion({ 16 | model: 'gpt-3.5-turbo', 17 | messages: [{ 18 | role: 'user', 19 | content: 'Tell me a joke' 20 | }] 21 | }); 22 | Logger.log(result.choices[0].message.content.replace(/^\n\n/, '')); 23 | ``` 24 | ![2023-03-05_15-07](https://user-images.githubusercontent.com/11365082/222959596-39c2b593-5de4-41e1-ab36-956bb31cb02f.png) 25 | 26 | To save the context, you can use caching in the script: 27 | 28 | ```javascript 29 | function cache_context(question) { 30 | var cache = CacheService.getScriptCache(); 31 | var cache_str = cache.get('cache'); 32 | var messages = []; 33 | if (cache_str == null) { 34 | messages = [{ 35 | "role": "user", 36 | "content": question 37 | }]; 38 | } else { 39 | messages = JSON.parse(cache_str); 40 | messages[messages.length] = { 41 | "role": "user", 42 | "content": question 43 | }; 44 | } 45 | 46 | var answer = openai.Chat().CreateChatCompletion({ 47 | model: 'gpt-3.5-turbo', 48 | messages: messages 49 | }).choices[0].message.content.replace(/^\n\n/, ''); 50 | 51 | messages[messages.length] = { 52 | "role": "assistant", 53 | "content": answer 54 | }; 55 | 56 | while (JSON.stringify(messages).length > 100000) { 57 | var todelete = messages.shift(); 58 | } 59 | 60 | cache.put('cache', JSON.stringify(messages), 300); 61 | return answer; 62 | } 63 | ``` 64 | 65 | ### Create image 66 | 67 | ```javascript 68 | var api_key = '**************************************************'; 69 | var openai = new OpenAIApp(api_key); 70 | var result = openai.Images().CreateImage({ 71 | prompt: 'Fat black cat' 72 | }) 73 | Logger.log(result.data[0].url); 74 | ``` 75 | 76 | ![2023-03-05_15-08](https://user-images.githubusercontent.com/11365082/222959857-3089b92e-fe9a-47b1-be8f-4fcde7192887.png) 77 | --------------------------------------------------------------------------------