ollama api: showing an error when connection is interrupted. fixes #114

This commit is contained in:
mic 2024-08-22 23:07:32 +02:00
parent c66927f472
commit a514e41137
3 changed files with 58 additions and 35 deletions

View file

@ -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": ""
}
}

View file

@ -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;
}

View file

@ -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