From fed577b960f269bb1e91394650f9cd0cd1fe86f5 Mon Sep 17 00:00:00 2001 From: hiroki osame Date: Fri, 10 Mar 2023 08:25:38 -0500 Subject: [PATCH] fix: content-length miscalculation bug (#147) --- src/utils/openai.ts | 78 +++++++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 24 deletions(-) diff --git a/src/utils/openai.ts b/src/utils/openai.ts index 4e58cae..8661a3d 100644 --- a/src/utils/openai.ts +++ b/src/utils/openai.ts @@ -1,46 +1,42 @@ import https from 'https'; +import type { ClientRequest, IncomingMessage } from 'http'; import type { CreateCompletionRequest, CreateCompletionResponse } from 'openai'; import { encoding_for_model as encodingForModel } from '@dqbd/tiktoken'; import { KnownError } from './error.js'; -const createCompletion = ( - apiKey: string, - json: CreateCompletionRequest, -) => new Promise((resolve, reject) => { +const httpsPost = async ( + hostname: string, + path: string, + headers: Record, + json: unknown, +) => new Promise<{ + request: ClientRequest; + response: IncomingMessage; + data: string; +}>((resolve, reject) => { const postContent = JSON.stringify(json); const request = https.request( { port: 443, - hostname: 'api.openai.com', - path: '/v1/completions', + hostname, + path, method: 'POST', headers: { + ...headers, 'Content-Type': 'application/json', - 'Content-Length': postContent.length, - Authorization: `Bearer ${apiKey}`, + 'Content-Length': Buffer.byteLength(postContent), }, timeout: 10_000, // 10s }, (response) => { - if ( - !response.statusCode - || response.statusCode < 200 - || response.statusCode > 299 - ) { - let errorMessage = `OpenAI API Error: ${response.statusCode} - ${response.statusMessage}`; - if (response.statusCode === 500) { - errorMessage += '; Check the API status: https://status.openai.com'; - } - - return reject(new KnownError(errorMessage)); - } - const body: Buffer[] = []; response.on('data', chunk => body.push(chunk)); response.on('end', () => { - resolve( - JSON.parse(Buffer.concat(body).toString()), - ); + resolve({ + request, + response, + data: Buffer.concat(body).toString(), + }); }); }, ); @@ -54,6 +50,40 @@ const createCompletion = ( request.end(); }); +const createCompletion = async ( + apiKey: string, + json: CreateCompletionRequest, +) => { + const { response, data } = await httpsPost( + 'api.openai.com', + '/v1/completions', + { + Authorization: `Bearer ${apiKey}`, + }, + json, + ); + + if ( + !response.statusCode + || response.statusCode < 200 + || response.statusCode > 299 + ) { + let errorMessage = `OpenAI API Error: ${response.statusCode} - ${response.statusMessage}`; + + if (data) { + errorMessage += `\n\n${data}`; + } + + if (response.statusCode === 500) { + errorMessage += '\n\nCheck the API status: https://status.openai.com'; + } + + throw new KnownError(errorMessage); + } + + return JSON.parse(data) as CreateCompletionResponse; +}; + const sanitizeMessage = (message: string) => message.trim().replace(/[\n\r]/g, '').replace(/(\w)\.$/, '$1'); const deduplicateMessages = (array: string[]) => Array.from(new Set(array));