Merge branch 'main' into v2.3.0

This commit is contained in:
Mic 2024-10-23 22:33:34 +02:00 committed by GitHub
commit 863ce095f8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 276 additions and 91 deletions

View file

@ -55,6 +55,7 @@ body:
- ChatGPT Web Interface
- OpenAI ChatGPT API
- Ollama API
- OpenAI Compatible API
- type: markdown
attributes:
value: |

View file

@ -18,6 +18,11 @@
<li>A few typos fixed [<a href="https://github.com/micz/ThunderAI/issues/170">#170</a>].</li>
<li>Added a loading indicator in the menu when sending a prompt.</li>
<li>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 [<a href="https://github.com/micz/ThunderAI/issues/150">#150</a>].</li>
</ul>
<h2>Version 2.2.2 - 15/10/2024</h2>
<ul>
<li>APIs error handling improved.</li>
<li><i>[OpenAI Comp API]</i> Added an option to remove the <i>v1</i> segment in the API calls path [<a href="https://github.com/micz/ThunderAI/issues/161">#161</a>].</li>
</ul>
<h2>Version 2.2.1 - 11/10/2024</h2>
<ul>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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();

View file

@ -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();

View file

@ -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();

View file

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

View file

@ -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) => {

View file

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

View file

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

View file

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

View file

@ -8,6 +8,9 @@
<div id="miczRelNotes"><a href="mzta-release-notes.html">__MSG_prefs_OptionText_release_notes__</a></div>
<div id="miczStatusPage" class="conntype_chatgpt_web"><a href="https://micz.it/thunderbird-addon-thunderai/status/">__MSG_prefs_status_page__</a></div>
<table id="miczPrefs">
<tr id="owl_warning">
<td colspan="2"><div>__MSG_prefs_OptionText_owl_warning__ <a href="https://micz.it/thunderbird-addon-thunderai/owl/">__MSG_customPrompts_managePrompts_help__</a></div></td>
</tr>
<tr>
<td><span>__MSG_prefs_OptionText_chatgpt_win_text__</span></td>
<td>
@ -204,6 +207,17 @@
</label>
</td>
</tr>
<tr class="conntype_openai_comp_api">
<td><label>
<span>__MSG_prefs_OptionText_openai_comp_use_v1__</span>
</label></td>
<td>
<label>
<input type="checkbox" id="openai_comp_use_v1" name="openai_comp_use_v1" class="option-input" />
&nbsp;<span>__MSG_prefs_OptionText_openai_comp_use_v1_info__</span>
</label>
</td>
</tr>
<tr class="conntype_openai_comp_api">
<td><label>
<span>__MSG_prefs_OpenAIComp_API_Key__</span>

View file

@ -214,6 +214,14 @@ function disable_MaxPromptLength(){
document.addEventListener('DOMContentLoaded', async () => {
await restoreOptions();
// show Owl warning
const accountList = await messenger.accounts.list(false);
if(accountList.some(account => account.type.toLowerCase().includes('owl'))) {
taLog.log('OWL detected, displaying the warning.');
document.getElementById('owl_warning').style.display = 'table-row';
}
i18n.updateDocument();
document.querySelectorAll(".option-input").forEach(element => {
element.addEventListener("change", saveOptions);
@ -256,10 +264,16 @@ document.addEventListener('DOMContentLoaded', async () => {
let openai = new OpenAI(document.getElementById("chatgpt_api_key").value, '', true);
openai.fetchModels().then((data) => {
if(!data.ok){
let errorDetail = JSON.parse(data.error);
let errorDetail;
try {
errorDetail = JSON.parse(data.error);
errorDetail = errorDetail.error.message;
} catch (e) {
errorDetail = data.error;
}
document.getElementById('chatgpt_model_fetch_loading').style.display = 'none';
console.error("[ThunderAI] " + browser.i18n.getMessage("ChatGPT_Models_Error_fetching"));
alert(browser.i18n.getMessage("ChatGPT_Models_Error_fetching")+": " + errorDetail.error.message);
alert(browser.i18n.getMessage("ChatGPT_Models_Error_fetching")+": " + errorDetail);
return;
}
taLog.log("ChatGPT models: " + JSON.stringify(data));
@ -297,10 +311,16 @@ select_ollama_model.addEventListener("change", warn_Ollama_HostEmpty);
return;
}
if(!data.ok){
let errorDetail = JSON.parse(data.error);
let errorDetail;
try {
errorDetail = JSON.parse(data.error);
errorDetail = errorDetail.error.message;
} catch (e) {
errorDetail = data.error;
}
document.getElementById('ollama_model_fetch_loading').style.display = 'none';
console.error("[ThunderAI] " + browser.i18n.getMessage("Ollama_Models_Error_fetching"));
alert(browser.i18n.getMessage("Ollama_Models_Error_fetching")+": " + errorDetail.error.message);
alert(browser.i18n.getMessage("Ollama_Models_Error_fetching")+": " + errorDetail);
return;
}
if(data.response.models.length == 0){
@ -339,13 +359,19 @@ select_openai_comp_model.addEventListener("change", warn_OpenAIComp_HostEmpty);
document.getElementById('btnUpdateOpenAICompModels').addEventListener('click', async () => {
document.getElementById('openai_comp_model_fetch_loading').style.display = 'inline';
let openai_comp = new OpenAIComp(document.getElementById("openai_comp_host").value , null, document.getElementById("openai_comp_api_key").value, true);
let openai_comp = new OpenAIComp(document.getElementById("openai_comp_host").value , null, document.getElementById("openai_comp_api_key").value, true, document.getElementById("openai_comp_use_v1").checked);
openai_comp.fetchModels().then((data) => {
if(!data.ok){
let errorDetail = JSON.parse(data.error);
let errorDetail;
try {
errorDetail = JSON.parse(data.error);
errorDetail = errorDetail.error.message;
} catch (e) {
errorDetail = data.error;
}
document.getElementById('openai_comp_model_fetch_loading').style.display = 'none';
console.error("[ThunderAI] " + browser.i18n.getMessage("OpenAIComp_Models_Error_fetching"));
alert(browser.i18n.getMessage("OpenAIComp_Models_Error_fetching")+": " + errorDetail.error.message);
alert(browser.i18n.getMessage("OpenAIComp_Models_Error_fetching")+": " + errorDetail);
return;
}
taLog.log("OpenAIComp models: " + JSON.stringify(data));

View file

@ -21,6 +21,11 @@
<li>Added a loading indicator in the menu when sending a prompt.</li>
<li>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 [<a href="https://github.com/micz/ThunderAI/issues/150">#150</a>].</li>
</ul>
<h2>Version 2.2.2 - 15/10/2024</h2>
<ul>
<li>APIs error handling improved.</li>
<li><i>[OpenAI Comp API]</i> Added an option to remove the <i>v1</i> segment in the API calls path [<a href="https://github.com/micz/ThunderAI/issues/161">#161</a>].</li>
</ul>
<h2>Version 2.2.1 - 11/10/2024</h2>
<ul>
<li><i>[ChatGPT Web]</i> Added a workaround to login in ChatGPT. See the new button in the options page.</li>