From 14a8b0ee4eecdbe6141d52c281251cd8b4eed51e Mon Sep 17 00:00:00 2001 From: w1gs Date: Fri, 11 Oct 2024 12:52:12 -0400 Subject: [PATCH] fixed merge conflicts --- extensions/void/src/common/sendLLMMessage.ts | 75 ++++++++++++++++++-- 1 file changed, 69 insertions(+), 6 deletions(-) diff --git a/extensions/void/src/common/sendLLMMessage.ts b/extensions/void/src/common/sendLLMMessage.ts index a1d85228..6c74b0d6 100644 --- a/extensions/void/src/common/sendLLMMessage.ts +++ b/extensions/void/src/common/sendLLMMessage.ts @@ -8,11 +8,11 @@ export type ApiConfig = { apikey: string; model: string; maxTokens: string; - }; + }, openai: { apikey: string; model: string; - }; + }, greptile: { apikey: string; githubPAT: string; @@ -20,14 +20,19 @@ export type ApiConfig = { remote: string; // e.g. 'github' repository: string; // e.g. 'voideditor/void' branch: string; // e.g. 'main' - }; - }; + } + }, ollama: { endpoint: string; model: string; - }; + }, + openaicompatible: { + endpoint: string, + model: string, + apikey: string + } whichApi: string; -}; +} type OnText = (newText: string, fullText: string) => void; @@ -199,6 +204,56 @@ const sendOpenAIMsg: SendLLMMessageFnTypeInternal = ({ return { abort }; }; +// OpenAI Compatible +const sendOpenAICompatibleMsg: SendLLMMessageFnTypeInternal = ({ messages, onText, onFinalMessage, onError, apiConfig }) => { + + let didAbort = false + let fullText = '' + + // if abort is called, onFinalMessage is NOT called, and no later onTexts are called either + let abort: () => void = () => { + didAbort = true; + }; + + const openai = new OpenAI({ apiKey: apiConfig.openaicompatible.apikey, baseURL: apiConfig.openaicompatible.endpoint, dangerouslyAllowBrowser: true }); + + openai.chat.completions.create({ + model: apiConfig.openaicompatible.model, + messages: messages, + stream: true, + }) + .then(async response => { + abort = () => { + response.controller.abort() + didAbort = true; + } + // when receive text + try { + for await (const chunk of response) { + if (didAbort) return; + const newText = chunk.choices[0]?.delta?.content || ''; + fullText += newText; + onText(newText, fullText); + } + onFinalMessage(fullText); + } + // when error/fail + catch (error) { + onError(`Error in OpenAI stream:, ${error}`) + console.error('Error in OpenAI stream:', error); + onFinalMessage(fullText); + } + }) + .catch((responseError) => { + if (responseError.status === 401) { + onError('Unauthorized: Invalid API key'); + } else { + onError(responseError.message); + } + }); + return { abort }; +}; + // Ollama const sendOllamaMsg: SendLLMMessageFnTypeInternal = ({ messages, @@ -401,6 +456,14 @@ export const sendLLMMessage: SendLLMMessageFnTypeExternal = ({ onError, apiConfig, }); + case 'openaicompatible': + return sendOpenAICompatibleMsg({ + messages, + onText, + onFinalMessage, + onError, + apiConfig, + }); default: onError(`Error: whichApi was '${apiConfig.whichApi}', which is not recognized!`); return { abort: () => {} };