From a514e41137245ef8f75f88eff764a443edf8156b Mon Sep 17 00:00:00 2001 From: mic Date: Thu, 22 Aug 2024 23:07:32 +0200 Subject: [PATCH] ollama api: showing an error when connection is interrupted. fixes #114 --- _locales/en/messages.json | 8 +++ api_webchat/controller.js | 5 +- api_webchat/model-worker-ollama.js | 80 +++++++++++++++++------------- 3 files changed, 58 insertions(+), 35 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 5e3add3b..b56452d8 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -482,5 +482,13 @@ "andModel": { "message": "and model", "description": "" + }, + "error_connection_interrupted": { + "message": "The connection to the server was unexpectedly interrupted", + "description": "" + }, + "ollama_api_request_failed": { + "message": "Ollama API request failed", + "description": "" } } \ No newline at end of file diff --git a/api_webchat/controller.js b/api_webchat/controller.js index d9b51b7d..5493143a 100644 --- a/api_webchat/controller.js +++ b/api_webchat/controller.js @@ -79,10 +79,13 @@ switch (llm) { break; case "ollama_api": { let prefs_api = await browser.storage.sync.get({ollama_host: '', ollama_model: ''}); + let i18nStrings = {}; + i18nStrings["ollama_api_request_failed"] = browser.i18n.getMessage('ollama_api_request_failed'); + i18nStrings["error_connection_interrupted"] = browser.i18n.getMessage('error_connection_interrupted'); //console.log(">>>>>>>>>>> ollama_host: " + prefs_api_key.ollama_host); messageInput.setModel(prefs_api.ollama_model); messagesArea.setLLMName("Ollama Local"); - worker.postMessage({ type: 'init', ollama_host: prefs_api.ollama_host, ollama_model: prefs_api.ollama_model}); + worker.postMessage({ type: 'init', ollama_host: prefs_api.ollama_host, ollama_model: prefs_api.ollama_model, i18nStrings: i18nStrings}); messagesArea.appendUserMessage(browser.i18n.getMessage("ollama_api_connecting") + " " + prefs_api.ollama_host + " " +browser.i18n.getMessage("AndModel") + " " + prefs_api.ollama_model + " ...", "info"); break; } diff --git a/api_webchat/model-worker-ollama.js b/api_webchat/model-worker-ollama.js index 9d66b757..def38787 100644 --- a/api_webchat/model-worker-ollama.js +++ b/api_webchat/model-worker-ollama.js @@ -26,6 +26,7 @@ let ollama_host = null; let ollama_model = ''; let ollama = null; let stopStreaming = false; +let i18nStrings = null; let conversationHistory = []; let assistantResponseAccumulator = ''; @@ -37,6 +38,7 @@ self.onmessage = async function(event) { ollama_model = event.data.ollama_model; //console.log(">>>>>>>>>>> ollama_host: " + ollama_host); ollama = new Ollama(ollama_host, ollama_model, true); + i18nStrings = event.data.i18nStrings; break; // init case 'chatMessage': conversationHistory.push({ role: 'user', content: event.data.message }); @@ -55,47 +57,57 @@ self.onmessage = async function(event) { error_message = errorJSON.error; //console.log(">>>>>>>>>>>>> errorJSON.error.message: " + JSON.stringify(errorJSON.error.message)); } - postMessage({ type: 'error', payload: "Ollama API request failed: " + error_message }); + postMessage({ type: 'error', payload: i18nStrings["ollama_api_request_failed"] + ": " + error_message }); throw new Error("[ThunderAI] Ollama API request failed: " + response.status + " " + response.statusText + ", Detail: " + errorDetail); } const reader = response.body.getReader(); const decoder = new TextDecoder("utf-8"); - - while (true) { - if (stopStreaming) { - stopStreaming = false; - reader.cancel(); - conversationHistory.push({ role: 'assistant', content: assistantResponseAccumulator }); - assistantResponseAccumulator = ''; - postMessage({ type: 'tokensDone' }); + + try { + while (true) { + if (stopStreaming) { + stopStreaming = false; + reader.cancel(); + conversationHistory.push({ role: 'assistant', content: assistantResponseAccumulator }); + assistantResponseAccumulator = ''; + postMessage({ type: 'tokensDone' }); - break; - } - const { done, value } = await reader.read(); - if (done) { - conversationHistory.push({ role: 'assistant', content: assistantResponseAccumulator }); - assistantResponseAccumulator = ''; - postMessage({ type: 'tokensDone' }); - break; - } - // lots of low-level Ollama response parsing stuff - const chunk = decoder.decode(value); - //console.log(">>>>>>>>>>>>> chunk: " + chunk); - const lines = chunk.split("\n"); - const parsedLines = lines - .map((line) => line.replace(/^chunk: /, "").trim()) // Remove the "chunk: " prefix - .filter((line) => line !== "" && line !== "[DONE]") // Remove empty lines and "[DONE]" - .map((line) => JSON.parse(line)); // Parse the JSON string - - for (const parsedLine of parsedLines) { - const { message } = parsedLine; - const { content } = message; - // Update the UI with the new content - if (content) { - assistantResponseAccumulator += content; - postMessage({ type: 'newToken', payload: { token: content } }); + break; } + const { done, value } = await reader.read(); + if (done) { + conversationHistory.push({ role: 'assistant', content: assistantResponseAccumulator }); + assistantResponseAccumulator = ''; + postMessage({ type: 'tokensDone' }); + break; + } + // lots of low-level Ollama response parsing stuff + const chunk = decoder.decode(value); + //console.log(">>>>>>>>>>>>> chunk: " + chunk); + const lines = chunk.split("\n"); + const parsedLines = lines + .map((line) => line.replace(/^chunk: /, "").trim()) // Remove the "chunk: " prefix + .filter((line) => line !== "" && line !== "[DONE]") // Remove empty lines and "[DONE]" + .map((line) => JSON.parse(line)); // Parse the JSON string + + for (const parsedLine of parsedLines) { + const { message } = parsedLine; + const { content } = message; + // Update the UI with the new content + if (content) { + assistantResponseAccumulator += content; + postMessage({ type: 'newToken', payload: { token: content } }); + } + } + } + } catch (error) { + if (error instanceof TypeError && error.message.includes('Error in input stream')) { + console.error('[ThudenderAI] The connection to the server was unexpectedly interrupted:', error); + postMessage({ type: 'error', payload: i18nStrings['error_connection_interrupted'] + ": " + error.message }); + } else { + console.error('[ThudenderAI] Ollama API request failed:', error); + postMessage({ type: 'error', payload: i18nStrings["ollama_api_request_failed"] + ": " + error.message }); } } break; //chatMessage