diff --git a/package-lock.json b/package-lock.json index 68cf1ad..f07546a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "@nem035/gpt-3-encoder": "^1.1.7", "@picocss/pico": "^1.5.7", "@primer/octicons-react": "^18.2.0", + "@vespaiach/axios-fetch-adapter": "^0.3.1", "azure-openai": "^0.9.4", "countries-list": "^2.6.1", "eventsource-parser": "^0.1.0", @@ -2299,6 +2300,14 @@ "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, + "node_modules/@vespaiach/axios-fetch-adapter": { + "version": "0.3.1", + "resolved": "https://registry.npmmirror.com/@vespaiach/axios-fetch-adapter/-/axios-fetch-adapter-0.3.1.tgz", + "integrity": "sha512-+1F52VWXmQHSRFSv4/H0wtnxfvjRMPK5531e880MIjypPdUSX6QZuoDgEVeCE1vjhzDdxCVX7rOqkub7StEUwQ==", + "peerDependencies": { + "axios": ">=0.26.0" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.11.1.tgz", diff --git a/package.json b/package.json index f7c3016..085106a 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "@nem035/gpt-3-encoder": "^1.1.7", "@picocss/pico": "^1.5.7", "@primer/octicons-react": "^18.2.0", + "@vespaiach/axios-fetch-adapter": "^0.3.1", "azure-openai": "^0.9.4", "countries-list": "^2.6.1", "eventsource-parser": "^0.1.0", diff --git a/src/background/apis/azure-openai-api.mjs b/src/background/apis/azure-openai-api.mjs index c8e27f9..fd15a37 100644 --- a/src/background/apis/azure-openai-api.mjs +++ b/src/background/apis/azure-openai-api.mjs @@ -2,6 +2,7 @@ import { Configuration, OpenAIApi } from 'azure-openai' import { getUserConfig, maxResponseTokenLength } from '../../config/index.mjs' import { getChatSystemPromptBase, pushRecord, setAbortController } from './shared.mjs' import { getConversationPairs } from '../../utils/get-conversation-pairs' +import fetchAdapter from '@vespaiach/axios-fetch-adapter' /** * @param {Runtime.Port} port @@ -27,7 +28,6 @@ export async function generateAnswersWithAzureOpenaiApi(port, question, session) }), ) - let answer = '' const response = await openAiApi .createChatCompletion( { @@ -38,37 +38,50 @@ export async function generateAnswersWithAzureOpenaiApi(port, question, session) { signal: controller.signal, responseType: 'stream', + adapter: fetchAdapter, }, ) .catch((err) => { port.onMessage.removeListener(messageListener) throw err }) + + let chunkData = '' + const step = 1500 + let length = 0 for await (const chunk of response.data) { - const lines = chunk + chunkData += chunk + length += 1 + if (length % step !== 0 && !chunkData.endsWith('[DONE]')) continue + + const lines = chunkData .toString('utf8') .split('\n') .filter((line) => line.trim().startsWith('data: ')) + let answer = '' + let message = '' + let data for (const line of lines) { - const message = line.replace(/^data: /, '') - console.debug('sse message', message) - if (message === '[DONE]') { - pushRecord(session, question, answer) - console.debug('conversation history', { content: session.conversationRecords }) - port.postMessage({ answer: null, done: true, session: session }) - break - } - let data + message = line.replace(/^data: /, '') try { data = JSON.parse(message) } catch (error) { - console.debug('json error', error) continue } - answer += data.choices[0].text + if ('content' in data.choices[0].delta) answer += data.choices[0].delta.content + } + if (data) { + console.debug('sse message', data) port.postMessage({ answer: answer, done: false, session: null }) } + if (message === '[DONE]') { + console.debug('sse message', '[DONE]') + pushRecord(session, question, answer) + console.debug('conversation history', { content: session.conversationRecords }) + port.postMessage({ answer: null, done: true, session: session }) + break + } } port.onMessage.removeListener(messageListener)