Added a loading indicator in the menu when sending a prompt.
Added a new default prompt that uses the placeholders and allows replying to an email thread. It requires selecting the text of the first email to identify which is the one to reply to and the others in the thread [#150].
+
+
Version 2.2.2 - 15/10/2024
+
+
APIs error handling improved.
+
[OpenAI Comp API] Added an option to remove the v1 segment in the API calls path [#161].
Version 2.2.1 - 11/10/2024
diff --git a/_locales/de/messages.json b/_locales/de/messages.json
index b13cd98a..80043635 100644
--- a/_locales/de/messages.json
+++ b/_locales/de/messages.json
@@ -507,6 +507,10 @@
"message": "Anfrage an die Ollama API fehlgeschlagen.",
"description": ""
},
+ "chatgpt_api_request_failed": {
+ "message": "Anfrage an die OpenAI ChatGPT API fehlgeschlagen",
+ "description": ""
+ },
"WaitingServerReponse": {
"message": "Warten auf die Serverantwort.",
"description": ""
@@ -677,6 +681,16 @@
},
"prefs_OptionText_btnManagePrompts_infoline": {
"message": "Sie können jetzt zusätzliche Datenplatzhalter verwenden!",
+ "prefs_OptionText_openai_comp_use_v1": {
+ "message": "\"v1\"-Kompatibilität beibehalten",
+ "description": ""
+ },
+ "prefs_OptionText_openai_comp_use_v1_info": {
+ "message": "Wenn aktiviert, wird das \"v1\"-Segment im Pfad der API-Aufrufe beibehalten, z.B. \"http://localhost:1234/v1/chat/completions\".",
+ "description": ""
+ },
+ "prefs_OptionText_owl_warning": {
+ "message": "Es scheint, dass mindestens eines Ihrer Konten das Add-on Eule für Exchange verwendet. Es gibt ein bekanntes Problem zwischen Thunderbird und Eule, das derzeit behoben wird. Derzeit können Sie ThunderAI beim Verfassen von E-Mails verwenden, jedoch nicht beim Lesen.",
"description": ""
}
}
\ No newline at end of file
diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index b02fa2fe..1827b126 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -507,6 +507,10 @@
"message": "Ollama API request failed",
"description": ""
},
+ "chatgpt_api_request_failed": {
+ "message": "OpenAI ChatGPT API request failed",
+ "description": ""
+ },
"WaitingServerReponse": {
"message": "Waiting for the server response",
"description": ""
@@ -677,6 +681,16 @@
},
"prefs_OptionText_btnManagePrompts_infoline": {
"message": "You can now use additional data placeholders!",
+ "prefs_OptionText_openai_comp_use_v1" : {
+ "message": "Keep the \"v1\" compatibility",
+ "description": ""
+ },
+ "prefs_OptionText_openai_comp_use_v1_info": {
+ "message": "If checked, the \"v1\" segment in the path of API calls will be kept, like \"http://localhost:1234/v1/chat/completions\".",
+ "description": ""
+ },
+ "prefs_OptionText_owl_warning": {
+ "message": "It appears that at least one of your accounts is using the Owl for Exchange add-on. There is a known issue between Thunderbird and Owl, which is currently being addressed. At this time, you can use ThunderAI while composing emails, but not when reading them.",
"description": ""
}
}
\ No newline at end of file
diff --git a/_locales/fr/messages.json b/_locales/fr/messages.json
index cddba217..23f27344 100644
--- a/_locales/fr/messages.json
+++ b/_locales/fr/messages.json
@@ -507,6 +507,10 @@
"message": "La demande d'API Ollama a échoué",
"description": ""
},
+ "chatgpt_api_request_failed": {
+ "message": "La demande d'API OpenAI ChatGPT a échoué",
+ "description": ""
+ },
"WaitingServerReponse": {
"message": "En attente de la réponse du serveur",
"description": ""
@@ -677,6 +681,16 @@
},
"prefs_OptionText_btnManagePrompts_infoline": {
"message": "Vous pouvez maintenant utiliser des espaces réservés de données supplémentaires !",
+ "prefs_OptionText_openai_comp_use_v1": {
+ "message": "Conserver la compatibilité \"v1\"",
+ "description": ""
+ },
+ "prefs_OptionText_openai_comp_use_v1_info": {
+ "message": "Si coché, le segment \"v1\" dans le chemin des appels API sera conservé, comme \"http://localhost:1234/v1/chat/completions\".",
+ "description": ""
+ },
+ "prefs_OptionText_owl_warning": {
+ "message": "Il semble qu'au moins un de vos comptes utilise le module complémentaire Chouette pour Exchange. Il existe un problème connu entre Thunderbird et Chouette, qui est en cours de résolution. Pour le moment, vous pouvez utiliser ThunderAI lors de la rédaction d'e-mails, mais pas lors de leur lecture.",
"description": ""
}
}
\ No newline at end of file
diff --git a/_locales/it/messages.json b/_locales/it/messages.json
index fff7b61f..5f3f48c9 100644
--- a/_locales/it/messages.json
+++ b/_locales/it/messages.json
@@ -543,6 +543,10 @@
"message": "Richiesta all'API compatibile con OpenAI fallita",
"description": ""
},
+ "chatgpt_api_request_failed": {
+ "message": "Richiesta all'API compatibile con OpenAI ChatGPT fallita",
+ "description": ""
+ },
"prefs_OpenAIComp_ChatName": {
"message": "Nome della chat",
"description": ""
@@ -677,6 +681,16 @@
},
"prefs_OptionText_btnManagePrompts_infoline": {
"message": "Ora puoi utilizzare segnaposti per i dati aggiuntivi!",
+ "prefs_OptionText_openai_comp_use_v1": {
+ "message": "Mantieni la compatibilità con \"v1\"",
+ "description": ""
+ },
+ "prefs_OptionText_openai_comp_use_v1_info": {
+ "message": "Se selezionato, il segmento \"v1\" nel percorso delle chiamate API verrà mantenuto, ad esempio \"http://localhost:1234/v1/chat/completions\".",
+ "description": ""
+ },
+ "prefs_OptionText_owl_warning": {
+ "message": "Sembra che almeno uno dei tuoi account stia utilizzando il componente aggiuntivo Gufo per Exchange. Esiste un problema noto tra Thunderbird e Gufo, che è attualmente in fase di risoluzione. Al momento, puoi utilizzare ThunderAI durante la composizione delle email, ma non durante la loro lettura.",
"description": ""
}
}
\ No newline at end of file
diff --git a/_locales/pt-br/messages.json b/_locales/pt-br/messages.json
index 0e12e249..b9d7e210 100644
--- a/_locales/pt-br/messages.json
+++ b/_locales/pt-br/messages.json
@@ -507,6 +507,10 @@
"message": "A solicitação da API do Ollama falhou",
"description": ""
},
+ "chatgpt_api_request_failed": {
+ "message": "A solicitação da API do OpenAI ChatGPT falhou",
+ "description": ""
+ },
"WaitingServerReponse": {
"message": "Aguardando a resposta do servidor",
"description": ""
@@ -677,6 +681,16 @@
},
"prefs_OptionText_btnManagePrompts_infoline": {
"message": "Agora você pode usar marcadores de posição adicionais!",
+ "prefs_OptionText_openai_comp_use_v1": {
+ "message": "Manter a compatibilidade com \"v1\"",
+ "description": ""
+ },
+ "prefs_OptionText_openai_comp_use_v1_info": {
+ "message": "Se marcado, o segmento \"v1\" no caminho das chamadas de API será mantido, como em \"http://localhost:1234/v1/chat/completions\".",
+ "description": ""
+ },
+ "prefs_OptionText_owl_warning": {
+ "message": "Parece que pelo menos uma das suas contas está usando o complemento Coruja para Exchange. Existe um problema conhecido entre Thunderbird e Coruja, que está sendo resolvido no momento. Por enquanto, você pode usar o ThunderAI ao redigir e-mails, mas não ao lê-los.",
"description": ""
}
}
\ No newline at end of file
diff --git a/api_webchat/controller.js b/api_webchat/controller.js
index c14e0403..e904871a 100644
--- a/api_webchat/controller.js
+++ b/api_webchat/controller.js
@@ -83,13 +83,13 @@ switch (llm) {
break;
}
case "openai_comp_api": {
- let prefs_api = await browser.storage.sync.get({openai_comp_host: '', openai_comp_model: '', openai_comp_api_key: '', openai_comp_chat_name: '', do_debug: false});
+ let prefs_api = await browser.storage.sync.get({openai_comp_host: '', openai_comp_model: '', openai_comp_api_key: '', openai_comp_use_v1: true, openai_comp_chat_name: '', do_debug: false});
let i18nStrings = {};
i18nStrings["OpenAIComp_api_request_failed"] = browser.i18n.getMessage('OpenAIComp_api_request_failed');
i18nStrings["error_connection_interrupted"] = browser.i18n.getMessage('error_connection_interrupted');
messageInput.setModel(prefs_api.openai_comp_model);
messagesArea.setLLMName(prefs_api.openai_comp_chat_name);
- worker.postMessage({ type: 'init', openai_comp_host: prefs_api.openai_comp_host, openai_comp_model: prefs_api.openai_comp_model, openai_comp_api_key: prefs_api.openai_comp_api_key, do_debug: prefs_api.do_debug, i18nStrings: i18nStrings});
+ worker.postMessage({ type: 'init', openai_comp_host: prefs_api.openai_comp_host, openai_comp_model: prefs_api.openai_comp_model, openai_comp_api_key: prefs_api.openai_comp_api_key, openai_comp_use_v1: prefs_api.openai_comp_use_v1, do_debug: prefs_api.do_debug, i18nStrings: i18nStrings});
messagesArea.appendUserMessage(browser.i18n.getMessage("OpenAIComp_api_connecting") + " \"" + prefs_api.openai_comp_host + "\" " +browser.i18n.getMessage("AndModel") + " \"" + prefs_api.openai_comp_model + "\"...", "info");
browser.runtime.sendMessage({command: "openai_comp_api_ready_" + call_id, window_id: (await browser.windows.getCurrent()).id});
break;
diff --git a/api_webchat/model-worker-ollama.js b/api_webchat/model-worker-ollama.js
index 9b4485ed..98354fae 100644
--- a/api_webchat/model-worker-ollama.js
+++ b/api_webchat/model-worker-ollama.js
@@ -57,13 +57,17 @@ self.onmessage = async function(event) {
if(response.is_exception === true){
error_message = response.error;
}else{
- const errorJSON = await response.json();
- errorDetail = JSON.stringify(errorJSON);
- error_message = errorJSON.error;
- taLog.log("errorJSON.error.message: " + JSON.stringify(errorJSON.error.message));
+ try{
+ const errorJSON = await response.json();
+ errorDetail = JSON.stringify(errorJSON);
+ error_message = errorJSON.error.message;
+ }catch(e){
+ error_message = response.statusText;
+ }
+ taLog.log("error_message: " + JSON.stringify(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);
+ postMessage({ type: 'error', payload: i18nStrings["ollama_api_request_failed"] + ": " + response.status + " " + response.statusText + ", Detail: " + error_message + " " + errorDetail });
+ throw new Error("[ThunderAI] Ollama API request failed: " + response.status + " " + response.statusText + ", Detail: " + error_message + " " + errorDetail);
}
const reader = response.body.getReader();
diff --git a/api_webchat/model-worker-openai.js b/api_webchat/model-worker-openai.js
index c23c0436..173a3499 100644
--- a/api_webchat/model-worker-openai.js
+++ b/api_webchat/model-worker-openai.js
@@ -52,13 +52,17 @@ self.onmessage = async function(event) {
if(response.is_exception === true){
error_message = response.error;
}else{
- const errorJSON = await response.json();
- errorDetail = JSON.stringify(errorJSON);
- error_message = errorJSON.error.message;
- taLog.error("errorJSON.error.message: " + JSON.stringify(errorJSON.error.message));
+ try{
+ const errorJSON = await response.json();
+ errorDetail = JSON.stringify(errorJSON);
+ error_message = errorJSON.error.message;
+ }catch(e){
+ error_message = response.statusText;
+ }
+ taLog.log("error_message: " + JSON.stringify(error_message));
}
- postMessage({ type: 'error', payload: error_message });
- throw new Error("[ThunderAI] OpenAI API request failed: " + response.status + " " + response.statusText + ", Detail: " + errorDetail);
+ postMessage({ type: 'error', payload: i18nStrings["chatgpt_api_request_failed"] + ": " + response.status + " " + response.statusText + ", Detail: " + error_message + " " + errorDetail });
+ throw new Error("[ThunderAI] OpenAI ChatGPT API request failed: " + response.status + " " + response.statusText + ", Detail: " + error_message + " " + errorDetail);
}
const reader = response.body.getReader();
diff --git a/api_webchat/model-worker-openai_comp.js b/api_webchat/model-worker-openai_comp.js
index 5af68da8..b63de5d7 100644
--- a/api_webchat/model-worker-openai_comp.js
+++ b/api_webchat/model-worker-openai_comp.js
@@ -26,6 +26,7 @@ import { taLogger } from '../js/mzta-logger.js';
let openai_comp_host = null;
let openai_comp_model = '';
let openai_comp_api_key = '';
+let openai_comp_use_v1 = true;
let openai_comp = null;
let stopStreaming = false;
let i18nStrings = null;
@@ -40,7 +41,8 @@ self.onmessage = async function(event) {
openai_comp_host = event.data.openai_comp_host;
openai_comp_model = event.data.openai_comp_model;
openai_comp_api_key = event.data.openai_comp_api_key;
- openai_comp = new OpenAIComp(openai_comp_host, openai_comp_model, openai_comp_api_key, true);
+ openai_comp_use_v1 = event.data.openai_comp_use_v1;
+ openai_comp = new OpenAIComp(openai_comp_host, openai_comp_model, openai_comp_api_key, true, openai_comp_use_v1);
do_debug = event.data.do_debug;
i18nStrings = event.data.i18nStrings;
taLog = new taLogger('model-worker-openai_comp', do_debug);
@@ -56,13 +58,17 @@ self.onmessage = async function(event) {
if(response.is_exception === true){
error_message = response.error;
}else{
- const errorJSON = await response.json();
- errorDetail = JSON.stringify(errorJSON);
- error_message = errorJSON.error.message;
- taLog.log("errorJSON.error.message: " + JSON.stringify(errorJSON.error.message));
+ try{
+ const errorJSON = await response.json();
+ errorDetail = JSON.stringify(errorJSON);
+ error_message = errorJSON.error.message;
+ }catch(e){
+ error_message = response.statusText;
+ }
+ taLog.log("error_message: " + JSON.stringify(error_message));
}
- postMessage({ type: 'error', payload: i18nStrings["OpenAIComp_api_request_failed"] + ": " + error_message });
- throw new Error("[ThunderAI] OpenAI Comp API request failed: " + response.status + " " + response.statusText + ", Detail: " + errorDetail);
+ postMessage({ type: 'error', payload: i18nStrings["OpenAIComp_api_request_failed"] + ": " + response.status + " " + response.statusText + ", Detail: " + error_message + " " + errorDetail });
+ throw new Error("[ThunderAI] OpenAI Comp API request failed: " + response.status + " " + response.statusText + ", Detail: " + error_message + " " + errorDetail);
}
const reader = response.body.getReader();
diff --git a/js/api/ollama.js b/js/api/ollama.js
index 2ad59032..68506afd 100644
--- a/js/api/ollama.js
+++ b/js/api/ollama.js
@@ -29,31 +29,40 @@ export class Ollama {
}
fetchModels = async () => {
- const response = await fetch(this.host + "/api/tags", {
- method: "GET",
- headers: {
- "Content-Type": "application/json"
- },
- });
+ try{
+ const response = await fetch(this.host + "/api/tags", {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json"
+ },
+ });
- if (!response.ok) {
- const errorDetail = await response.text();
- let err_msg = "[ThunderAI] Ollama API request failed: " + response.status + " " + response.statusText + ", Detail: " + errorDetail;
- console.error(err_msg);
- let output = {};
- output.ok = false;
- output.error = errorDetail;
- return output;
+ if (!response.ok) {
+ const errorDetail = await response.text();
+ let err_msg = "[ThunderAI] Ollama API request failed: " + response.status + " " + response.statusText + ", Detail: " + errorDetail;
+ console.error(err_msg);
+ let output = {};
+ output.ok = false;
+ output.error = errorDetail;
+ return output;
+ }
+
+ let output = {};
+ output.ok = true;
+ let output_response = await response.json();
+ output.response = output_response;
+
+ //console.log(">>>>>>>>>> output_response: " + JSON.stringify(output_response));
+
+ return output;
+ }catch (error) {
+ console.error("[ThunderAI] Ollama API request failed: " + error);
+ let output = {};
+ output.is_exception = true;
+ output.ok = false;
+ output.error = "Ollama API request failed: " + error;
+ return output;
}
-
- let output = {};
- output.ok = true;
- let output_response = await response.json();
- output.response = output_response;
-
- //console.log(">>>>>>>>>> output_response: " + JSON.stringify(output_response));
-
- return output;
}
diff --git a/js/api/openai.js b/js/api/openai.js
index 9eb21fda..11d4398d 100644
--- a/js/api/openai.js
+++ b/js/api/openai.js
@@ -33,30 +33,39 @@ export class OpenAI {
fetchModels = async () => {
- const response = await fetch("https://api.openai.com/v1/models", {
- method: "GET",
- headers: {
- "Content-Type": "application/json",
- Authorization: "Bearer "+ this.apiKey
- },
- });
+ try{
+ const response = await fetch("https://api.openai.com/v1/models", {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: "Bearer "+ this.apiKey
+ },
+ });
- if (!response.ok) {
- const errorDetail = await response.text();
- let err_msg = "[ThunderAI] OpenAI API request failed: " + response.status + " " + response.statusText + ", Detail: " + errorDetail;
- console.error(err_msg);
- let output = {};
- output.ok = false;
- output.error = errorDetail;
- return output;
+ if (!response.ok) {
+ const errorDetail = await response.text();
+ let err_msg = "[ThunderAI] OpenAI API request failed: " + response.status + " " + response.statusText + ", Detail: " + errorDetail;
+ console.error(err_msg);
+ let output = {};
+ output.ok = false;
+ output.error = errorDetail;
+ return output;
+ }
+
+ let output = {};
+ output.ok = true;
+ let output_response = await response.json();
+ output.response = output_response.data.filter(item => item.id.startsWith('gpt-')).sort((a, b) => b.id.localeCompare(a.id));
+
+ return output;
+ }catch (error) {
+ console.error("[ThunderAI] OpenAI API request failed: " + error);
+ let output = {};
+ output.is_exception = true;
+ output.ok = false;
+ output.error = "OpenAI API request failed: " + error;
+ return output;
}
-
- let output = {};
- output.ok = true;
- let output_response = await response.json();
- output.response = output_response.data.filter(item => item.id.startsWith('gpt-')).sort((a, b) => b.id.localeCompare(a.id));
-
- return output;
}
fetchResponse = async (messages, maxTokens = 0) => {
diff --git a/js/api/openai_comp.js b/js/api/openai_comp.js
index 0b5fefe2..fd901cbc 100644
--- a/js/api/openai_comp.js
+++ b/js/api/openai_comp.js
@@ -24,13 +24,15 @@ export class OpenAIComp {
host = '';
model = '';
apiKey = '';
+ use_v1 = true;
stream = false;
- constructor(host, model, apiKey = '', stream = false) {
+ constructor(host, model, apiKey = '', stream = false, use_v1 = true) {
this.host = host.trim().replace(/\/+$/, "");
this.model = model;
this.stream = stream;
this.apiKey = apiKey;
+ this.use_v1 = use_v1;
}
@@ -40,7 +42,7 @@ export class OpenAIComp {
};
if(this.apiKey !== '') curr_headers["Authorization"] = "Bearer "+ this.apiKey;
- const response = await fetch(this.host + "/v1/models", {
+ const response = await fetch(this.host + (this.use_v1 ? "/v1" : "") + "/models", {
method: "GET",
headers: curr_headers,
});
@@ -64,23 +66,32 @@ export class OpenAIComp {
}
fetchResponse = async (messages, maxTokens = 0) => {
- const curr_headers = {
- "Content-Type": "application/json",
- };
- if(this.apiKey !== '') curr_headers["Authorization"] = "Bearer "+ this.apiKey;
+ try{
+ const curr_headers = {
+ "Content-Type": "application/json",
+ };
+ if(this.apiKey !== '') curr_headers["Authorization"] = "Bearer "+ this.apiKey;
- try {
- const response = await fetch(this.host + "/v1/chat/completions", {
- method: "POST",
- headers: curr_headers,
- body: JSON.stringify({
- model: this.model,
- messages: messages,
- stream: this.stream,
- ...(maxTokens > 0 ? { 'max_tokens': parseInt(maxTokens) } : {})
- }),
- });
- return response;
+ try {
+ const response = await fetch(this.host + (this.use_v1 ? "/v1" : "") + "/chat/completions", {
+ method: "POST",
+ headers: curr_headers,
+ body: JSON.stringify({
+ model: this.model,
+ messages: messages,
+ stream: this.stream,
+ ...(maxTokens > 0 ? { 'max_tokens': parseInt(maxTokens) } : {})
+ }),
+ });
+ return response;
+ }catch (error) {
+ console.error("[ThunderAI] OpenAI API Comp request failed: " + error);
+ let output = {};
+ output.is_exception = true;
+ output.ok = false;
+ output.error = "OpenAI API Comp request failed: " + error;
+ return output;
+ }
}catch (error) {
console.error("[ThunderAI] OpenAI API Comp request failed: " + error);
let output = {};
diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js
index f49f83af..b2f29484 100644
--- a/options/mzta-options-default.js
+++ b/options/mzta-options-default.js
@@ -31,6 +31,7 @@ export const prefs_default = {
openai_comp_host: '', // For OpenAI Compatible API as LM-Studio
openai_comp_model: '',
openai_comp_api_key: '',
+ openai_comp_use_v1: true,
openai_comp_chat_name: 'OpenAI Comp',
dynamic_menu_force_enter: false,
dynamic_menu_order_alphabet: true,
diff --git a/options/mzta-options.css b/options/mzta-options.css
index d3bc9368..9c0305c1 100644
--- a/options/mzta-options.css
+++ b/options/mzta-options.css
@@ -146,6 +146,26 @@ input.option-input[type="text"]{
font-style: italic;
}
+#owl_warning{
+ display: none;
+}
+
+#owl_warning div{
+ color: white;
+ font-style: italic;
+ background-color: red;
+ border-radius: 4px;
+ padding: 3px;
+ font-weight: bold;
+ margin-bottom: 5px;
+}
+
+#owl_warning div a{
+ background-color: white;
+ padding:0px 3px;
+ border-radius: 4px;
+}
+
@media (prefers-color-scheme: dark) {
body {
background-color: rgb(35, 34, 43);
diff --git a/options/mzta-options.html b/options/mzta-options.html
index 8139b410..4a878c04 100644
--- a/options/mzta-options.html
+++ b/options/mzta-options.html
@@ -8,6 +8,9 @@