[All APIs] Now it is possible to define an API and its settings for any custom prompt. This allows anyone to use different AI providers for different prompts [#102].
+
[All APIs] When using special prompts (like automatically adding tags or the spam filter) with a specific API integration, all the settings for that integration can be specific. In this way you can use different api keys for the same integration, or different system prompt or temperature [#590].
+
[All APIs] Added the temperature parameter [#561].
+
[OpenAI API] Model filtering improved when choosing a model in the options page.
+
[OpenAI API] Now using the new Responses API [#407].
+
It is now possible to define a custom placeholder with dynamic data to retrieve any header present in the current email [#527].
+
[All APIs] The configuration information reported in the webchat API has been improved for all integrations.
[ChatGPT Web] Fix: Correctly getting the job completion [#607].
@@ -50,7 +64,7 @@
[All APIs] It's now possibile to define a list of tags to be used when autotagging received emails [#436]. The tags are are now shown in the information header in the AI API chat [#289].
[All APIs] The prompt id and name are now shown in the information header in the AI API chat [#436].
Added the {%mail_attachments_info%} placeholder to retrieve the name, type and file size of the mail attachments [#446].
-
[Google Gemini API]Support for the thinkingBudget parameter has been added [#494].
+
[Google Gemini API] Support for the thinkingBudget parameter has been added [#494].
Added a better error message when there is an error fetching models.
When selecting a correct model in the options page, the field is no more highlighted in red [#100].
When using the ChatGPT API, the double quotes at the beginning and end of the response are removed [#99].
-
[ChatGPT Web]"Keep formatting" option removed.
+
[ChatGPT Web] "Keep formatting" option removed.
Version 2.0.1 - 09/08/2024
diff --git a/LANG.md b/LANG.md
index f90be903..48e6e12d 100644
--- a/LANG.md
+++ b/LANG.md
@@ -2,11 +2,13 @@ cs
de
el
en
+es
fr
hr
it
pl
pt-br
ru
+sv
zh_Hans
zh_Hant
\ No newline at end of file
diff --git a/README.md b/README.md
index b995c042..0c2500ed 100644
--- a/README.md
+++ b/README.md
@@ -90,8 +90,10 @@ Are you using this addon in your Thunderbird?
- Greek (el): [ChristosK.](https://github.com/christoskaterini)
- Italian (it): [Mic](https://github.com/micz)
- Polski (pl): [neexpl](https://github.com/neexpl), [makkacprzak](https://github.com/makkacprzak)
-- Russian (ru): [Maksim](https://hosted.weblate.org/user/law820314/)
- Português Brasileiro (pt-br): Bruno Pereira de Souza
+- Russian (ru): [Maksim](https://hosted.weblate.org/user/law820314/)
+- Spanish (es): [Gerardo Sobarzo](https://hosted.weblate.org/user/gerardo.sobarzo/), [Andrés Rendón Hernández](https://hosted.weblate.org/user/arendon/), [Erick Limon](https://hosted.weblate.org/user/ErickLimonG/)
+- Swedish (sv): [Andreas Pettersson](https://hosted.weblate.org/user/Andy_tb/)
Do you want to help translate this addon? [Find out how!](https://micz.it/thunderbird-addon-thunderai/translate/)
diff --git a/_locales/de/messages.json b/_locales/de/messages.json
index 11ae9c45..9930d5ac 100644
--- a/_locales/de/messages.json
+++ b/_locales/de/messages.json
@@ -1107,7 +1107,7 @@
"message": "Claude-API-Version"
},
"prefs_OptionText_anthropic_max_tokens": {
- "message": "Maximale Anzahl an Tokens für Claude"
+ "message": "Maximale Anzahl an Tokens"
},
"anthropic_empty_apikey": {
"message": "Sie haben keinen API-Schlüssel für die Claude-API hinzugefügt. Bitte fügen Sie einen auf der Optionsseite ein."
@@ -1311,5 +1311,32 @@
},
"Optional_Permission_Denied_Model_Fetching": {
"message": "Sie haben die optionale Berechtigung verweigert, die zum Abrufen der Modelle für diese Integration erforderlich ist."
+ },
+ "prompt_string": {
+ "message": "Prompt"
+ },
+ "placeholder_mail_headers": {
+ "message": "E-Mail-Kopfzeilen"
+ },
+ "reset": {
+ "message": "Reset"
+ },
+ "prefs_chatgpt_api_temperature_Info": {
+ "message": "Welche Sampling-Temperatur soll verwendet werden (zwischen 0 und 2)? Höhere Werte wie 0,8 machen die Ausgabe zufälliger, während niedrigere Werte wie 0,2 sie fokussierter und deterministischer machen."
+ },
+ "prefs_ollama_temperature_Info": {
+ "message": "Die Temperatur des Modells. Eine Erhöhung der Temperatur führt dazu, dass das Modell kreativer antwortet. Der Standardwert ist 0,8. Es wird empfohlen, Werte zwischen 0 und 1 zu verwenden."
+ },
+ "prefs_api_temperature": {
+ "message": "Temperatur"
+ },
+ "prefs_openai_comp_temperature_Info": {
+ "message": "Welche Sampling-Temperatur verwendet werden soll (zwischen 0 und 2). Höhere Werte wie 0,8 machen die Ausgabe zufälliger, während niedrigere Werte wie 0,2 sie fokussierter und deterministischer machen."
+ },
+ "prefs_google_gemini_temperature_Info": {
+ "message": "Dieser Parameter muss eine Zahl zwischen 0,0 und 2,0 sein. Er steuert den Zufallsgrad der Ausgabe. Der Standardwert variiert je nach Modell. Lassen Sie das Feld leer, um den Parameter im API-Aufruf nicht festzulegen."
+ },
+ "prefs_anthropic_temperature_Info": {
+ "message": "Grad der Zufälligkeit in der Antwort. Der Standardwert ist 1,0. Der Bereich liegt zwischen 0,0 und 1,0. Verwenden Sie eine Temperatur näher an 0,0 für analytische Aufgaben oder Multiple-Choice-Fragen und näher an 1,0 für kreative und generative Aufgaben. Beachten Sie, dass die Ergebnisse selbst bei einer Temperatur von 0,0 nicht vollständig deterministisch sind."
}
}
diff --git a/_locales/el/messages.json b/_locales/el/messages.json
index a4ed4972..eb6e3538 100644
--- a/_locales/el/messages.json
+++ b/_locales/el/messages.json
@@ -942,7 +942,7 @@
"message": "ΑΠΑΙΤΕΙΤΑΙ. Μην αλλάξετε αυτήν την τιμή εκτός αν γνωρίζετε τι κάνετε. Περισσότερες πληροφορίες στη διεύθυνση:"
},
"prefs_OptionText_anthropic_max_tokens": {
- "message": "Claude Μέγιστα Tokens"
+ "message": "Μέγιστα Tokens"
},
"prefs_OptionText_anthropic_max_tokens_Info": {
"message": "Ο μέγιστος αριθμός διακριτικών που θα δημιουργηθούν κατά την ολοκλήρωση. Ο αριθμός διακριτικών της προτροπής σας συν το max_tokens δεν μπορεί να υπερβαίνει το μήκος περιβάλλοντος του μοντέλου."
@@ -1277,5 +1277,32 @@
},
"Optional_Permission_Denied_Model_Fetching": {
"message": "Έχετε αρνηθεί την προαιρετική άδεια που απαιτείται για την τοποθέτηση μοντέλων για αυτήν την ενσωμάτωση."
+ },
+ "reset": {
+ "message": "Επαναφορά"
+ },
+ "prompt_string": {
+ "message": "Εντολή"
+ },
+ "placeholder_mail_headers": {
+ "message": "Κεφαλίδες αλληλογραφίας"
+ },
+ "prefs_chatgpt_api_temperature_Info": {
+ "message": "Ποια θερμοκρασία δειγματοληψίας να χρησιμοποιηθεί, μεταξύ 0 και 2. Υψηλότερες τιμές όπως 0,8 θα κάνουν την έξοδο πιο τυχαία, ενώ χαμηλότερες τιμές όπως 0,2 θα την κάνουν πιο εστιασμένη και ντετερμινιστική."
+ },
+ "prefs_ollama_temperature_Info": {
+ "message": "Η θερμοκρασία του μοντέλου. Η αύξηση της θερμοκρασίας θα κάνει το μοντέλο να απαντά πιο δημιουργικά. Η προεπιλεγμένη τιμή είναι 0,8. Συνιστάται η χρήση τιμών μεταξύ 0 και 1."
+ },
+ "prefs_api_temperature": {
+ "message": "Θερμοκρασία"
+ },
+ "prefs_openai_comp_temperature_Info": {
+ "message": "Ποια θερμοκρασία δειγματοληψίας να χρησιμοποιηθεί, μεταξύ 0 και 2. Υψηλότερες τιμές όπως 0,8 θα κάνουν την έξοδο πιο τυχαία, ενώ χαμηλότερες τιμές όπως 0,2 θα την κάνουν πιο εστιασμένη και ντετερμινιστική."
+ },
+ "prefs_google_gemini_temperature_Info": {
+ "message": "Αυτή η παράμετρος πρέπει να είναι ένας αριθμός μεταξύ 0,0 και 2,0. Ελέγχει την τυχαιότητα της εξόδου. Η προεπιλεγμένη τιμή ποικίλλει ανάλογα με το μοντέλο. Αφήστε την κενή για να αποφύγετε τον ορισμό της παραμέτρου στην κλήση API."
+ },
+ "prefs_anthropic_temperature_Info": {
+ "message": "Ποσότητα τυχαιότητας που εισάγεται στην απόκριση. Προεπιλογή 1,0. Εύρος από 0,0 έως 1,0. Χρησιμοποιήστε θερμοκρασία πιο κοντά στο 0,0 για αναλυτική ανάλυση."
}
}
diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index 904229c1..1e8b9cac 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -59,6 +59,10 @@
"message": "More info",
"description": ""
},
+ "prompt_string":{
+ "message": "Prompt",
+ "description": ""
+ },
"customPrompts_managePrompts_info_default": {
"message": "The default prompts are not editable. You can disable them, then copy the prompt text and paste it into a new one to create a modified version.",
"description": ""
@@ -619,6 +623,10 @@
"message": "Folder path",
"description": ""
},
+ "placeholder_mail_headers": {
+ "message": "Mail headers",
+ "description": ""
+ },
"placeholder_selected_text": {
"message": "Selected text",
"description": ""
@@ -855,6 +863,10 @@
"message": "Reset to default",
"description": ""
},
+ "reset": {
+ "message": "Reset",
+ "description": ""
+ },
"addtags_excl_list_infoline2": {
"message": "Add a word per line, or separated by a comma.",
"description": ""
@@ -1492,7 +1504,7 @@
"description": ""
},
"prefs_OptionText_anthropic_max_tokens": {
- "message": "Claude Max Tokens",
+ "message": "Max Tokens",
"description": ""
},
"prefs_OptionText_anthropic_max_tokens_Info": {
@@ -1569,6 +1581,14 @@
"message": "If checked, your chats will be stored by OpenAI.",
"description": ""
},
+ "prefs_chatgpt_api_temperature_Info": {
+ "message": "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.",
+ "description": ""
+ },
+ "prefs_ollama_temperature_Info": {
+ "message": "The temperature of the model. Increasing the temperature will make the model answer more creatively. The default value is 0.8. It is recommended to use values between 0 and 1.",
+ "description": ""
+ },
"prefs_ollama_think": {
"message": "Enable thinking",
"description": ""
@@ -1665,6 +1685,14 @@
"message": "Are you sure you want to clear the Models List? This action cannot be undone.",
"description": ""
},
+ "prefs_api_temperature": {
+ "message": "Temperature",
+ "description": ""
+ },
+ "prefs_openai_comp_temperature_Info": {
+ "message": "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.",
+ "description": ""
+ },
"chatgpt_click_force_completion": {
"message": "It seems that it's not possible to get if ChatGPT has finished. Click here to force the completion of the job.",
"description": ""
@@ -1681,6 +1709,10 @@
"message": "Define the number of tokens to be used for thinking. Leave this field blank if the selected model does not support thinking or if you want to use the default method. Enter 0 to disable thinking, or -1 to enable dynamic thinking.",
"description": ""
},
+ "prefs_google_gemini_temperature_Info": {
+ "message": "This parameter must be a number between 0.0 and 2.0. It controls the randomness of the output. The default value varies depending on the model. Leave it empty to avoid setting the parameter in the API call.",
+ "description": ""
+ },
"SelectAll": {
"message": "Select All",
"description": ""
@@ -1697,6 +1729,10 @@
"message": "You can improve Claude performance by using a System Prompt to give it a role. This technique, known as role prompting, is the most powerful way to use system prompts with Claude. The right role can turn Claude from a general assistant into your virtual domain expert.",
"description": ""
},
+ "prefs_anthropic_temperature_Info": {
+ "message": "Amount of randomness injected into the response. Defaults to 1.0. Ranges from 0.0 to 1.0. Use temperature closer to 0.0 for analytical / multiple choice, and closer to 1.0 for creative and generative tasks. Note that even with temperature of 0.0, the results will not be fully deterministic.",
+ "description": ""
+ },
"Optional_Permission_Denied_Model_Fetching": {
"message": "You have denied the optional permission needed to fetch models for this integration.",
"description": ""
diff --git a/_locales/es/messages.json b/_locales/es/messages.json
index 92c85674..2980618d 100644
--- a/_locales/es/messages.json
+++ b/_locales/es/messages.json
@@ -153,7 +153,7 @@
"message": "Botón de cerrar"
},
"customPrompts_do_reply": {
- "message": "Hacer respuesta"
+ "message": "Responder"
},
"customPrompts_substitute_text": {
"message": "Sustituir texto"
@@ -162,7 +162,7 @@
"message": "Trabajo en progreso..."
},
"chatgpt_win_job_completed": {
- "message": "¡Completo!"
+ "message": "¡Completado!"
},
"chatgpt_win_job_completed_select": {
"message": "Selecciona el texto que deseas utilizar y haz clic en el botón."
@@ -187,5 +187,1122 @@
},
"chatgpt_win_model_warning": {
"message": "Por alguna razón, no es posible verificar si el modelo correcto está cargado. Por ahora, puedes pulsar el botón azul para continuar."
+ },
+ "chatgpt_win_send": {
+ "message": "Enviar"
+ },
+ "chatgpt_force_completion": {
+ "message": "forzar completado"
+ },
+ "chatgpt_force_completion_title": {
+ "message": "Haz clic aquí para mostrar el botón “Usar última respuesta” si ChatGPT ha terminado su trabajo pero el botón no ha aparecido."
+ },
+ "msg_prompt_too_long": {
+ "message": "El texto que proporcionaste es demasiado largo. Necesitas reducirlo."
+ },
+ "prefs_OptionText_release_notes": {
+ "message": "Notas de lanzamiento"
+ },
+ "prefs_status_page": {
+ "message": "estado del servicio"
+ },
+ "prefs_OptionText_chatgpt_win_text": {
+ "message": "dimensiones de la ventana de chat de IA"
+ },
+ "prefs_OptionText_chatgpt_win_height": {
+ "message": "Altura"
+ },
+ "prefs_OptionText_chatgpt_win_width": {
+ "message": "Ancho"
+ },
+ "prefs_OptionText_default_sign_name": {
+ "message": "Nombre de firma predeterminado"
+ },
+ "prefs_OptionText_default_chatgpt_lang": {
+ "message": "Idioma predeterminado para las respuestas"
+ },
+ "prefs_OptionText_reply_all": {
+ "message": "Responder a todos"
+ },
+ "prefs_OptionText_reply_sender": {
+ "message": "Responder al remitente"
+ },
+ "prefs_OptionText_reply_type": {
+ "message": "Tipo de respuesta"
+ },
+ "prefs_OptionText_reply_type_Info": {
+ "message": "Este es el tipo de respuesta predeterminado que se utilizará al responder a un correo electrónico. Puedes elegir el otro más tarde en el cuadro de diálogo de respuesta."
+ },
+ "prefs_OptionText_btnManagePrompts": {
+ "message": "Administrar tus prompts"
+ },
+ "prefs_OptionText_btnManageCustomDataPH": {
+ "message": "Administrar los marcadores de posición de datos"
+ },
+ "prefsInfoTitle": {
+ "message": "Información importante"
+ },
+ "prefsInfoDesc_1": {
+ "message": "Podría suceder que la interfaz web de ChatGPT cambie de una manera que interrumpa el funcionamiento del complemento. Consulta la página de \"Estado del servicio\" vinculada al final de esta página. Además, recuerda que la primera vez que uses ThunderAI, debes iniciar sesión en ChatGPT."
+ },
+ "prefsInfoDesc_2": {
+ "message": "Para usar la API de ChatGPT, necesitas una clave API de OpenAI ChatGPT y debes elegir un modelo."
+ },
+ "prefsInfoDesc_3": {
+ "message": "Para usar la integración con Ollama, necesitas configurar un servidor local de Ollama. Una vez que el servidor esté en funcionamiento, ingresa su dirección en el campo designado dentro de la aplicación. Para garantizar una comunicación adecuada entre ThunderAI y el servidor Ollama, recuerda establecer OLLAMA_ORIGINS=moz-extension://*."
+ },
+ "prefsInfoDesc_4": {
+ "message": "Para usar esta integración, necesitas configurar un servidor local compatible con la API de OpenAI, como LM Studio. Una vez que el servidor esté en funcionamiento, ingresa su dirección en el campo designado dentro de la aplicación. Para garantizar una comunicación adecuada entre ThunderAI y el servidor local, recuerda configurar correctamente los ajustes CORS."
+ },
+ "prefsInfoDesc_5": {
+ "message": "Recuerda que puedes abrir el menú de ThunderAI usando el atajo de teclado CTRL+ALT+A."
+ },
+ "prefsInfoDesc_6": {
+ "message": "Puedes cambiar el atajo haciendo clic en el ícono de engranaje en la parte superior derecha de esta página y seleccionando \"Administrar atajo de la extensión\"."
+ },
+ "prefsDonation_1": {
+ "message": "¿Te gusta este complemento?"
+ },
+ "prefsDonation_2": {
+ "message": "¡Considera hacer una donación!"
+ },
+ "backToOptionsText": {
+ "message": "Opciones"
+ },
+ "TranslateText": {
+ "message": "¿Quieres ayudar a traducir este complemento?"
+ },
+ "TranslateLink": {
+ "message": "¡Descubre cómo!"
+ },
+ "customPrompts_ExportAll": {
+ "message": "Exportar todos los prompts"
+ },
+ "customPrompts_Import": {
+ "message": "Importar nuevos prompts"
+ },
+ "importPrompts_confirmText": {
+ "message": "Estás a punto de importar nuevos prompts."
+ },
+ "customPrompts_start_import": {
+ "message": "Iniciando la importación de prompts personalizados..."
+ },
+ "customPrompts_import_completed": {
+ "message": "¡Importación de prompts personalizados completada! Necesitas hacer clic en el botón “Guardar todo” para guardar tus cambios."
+ },
+ "importPrompts_invalidFile": {
+ "message": "El archivo que estás intentando importar no es un archivo de prompts personalizados válido."
+ },
+ "importPrompts_invalidPrompts": {
+ "message": "El archivo que estás intentando importar no contiene ningún prompt válido."
+ },
+ "currently_used_prompt": {
+ "message": "Nombre del prompt usado actualmente"
+ },
+ "customprompts_form_label_define_response_lang": {
+ "message": "Define el idioma de respuesta en el prompt"
+ },
+ "prefs_Connection_type": {
+ "message": "Tipo de conexión"
+ },
+ "prefs_Connection_type_ChatGPT_Web": {
+ "message": "Interfaz web de ChatGPT"
+ },
+ "prefs_Connection_type_ChatGPT_API": {
+ "message": "API de OpenAI ChatGPT"
+ },
+ "prefs_ChatGPT_API_Key": {
+ "message": "Clave API de ChatGPT"
+ },
+ "ChatGPT_Models": {
+ "message": "Modelos de ChatGPT"
+ },
+ "ChatGPT_Models_Fetch": {
+ "message": "Actualizar lista de modelos de ChatGPT"
+ },
+ "ChatGPT_Models_Error_fetching": {
+ "message": "Error al intentar obtener los modelos de ChatGPT"
+ },
+ "Loading": {
+ "message": "Cargando..."
+ },
+ "error": {
+ "message": "¡Error de ThunderAI!"
+ },
+ "chatgpt_empty_apikey": {
+ "message": "No has añadido una clave API para la API de ChatGPT. Por favor, insértala en la página de opciones."
+ },
+ "chatgpt_win_custom_text": {
+ "message": "Inserte aquí el texto adicional para el prompt."
+ },
+ "chatgpt_empty_model": {
+ "message": "No has elegido un modelo para la API de ChatGPT. Por favor, elige uno en la página de opciones."
+ },
+ "chagpt_api_send_button": {
+ "message": "Usando el modelo"
+ },
+ "Debug": {
+ "message": "Depurar"
+ },
+ "prefs_OptionText_do_debug_info": {
+ "message": "Activar el sistema de depuración"
+ },
+ "prefs_Connection_type_Ollama_API": {
+ "message": "API de Ollama (LLM local)"
+ },
+ "prefs_Connection_type_OpenAI_Comp_API": {
+ "message": "API compatible con OpenAI"
+ },
+ "prefs_API_Host": {
+ "message": "Dirección del host"
+ },
+ "Ollama_Models": {
+ "message": "Modelos de Ollama"
+ },
+ "Ollama_Models_Fetch": {
+ "message": "Actualizar lista de modelos de Ollama"
+ },
+ "Ollama_Models_Error_fetching": {
+ "message": "Error al intentar obtener los modelos de Ollama"
+ },
+ "API_Models_Error_NoModels": {
+ "message": "No se encontraron modelos"
+ },
+ "ollama_empty_host": {
+ "message": "No has añadido una dirección de host para la API de Ollama. Por favor, insértala en la página de opciones."
+ },
+ "ollama_empty_model": {
+ "message": "No has elegido un modelo para la API de Ollama. Por favor, elige uno en la página de opciones."
+ },
+ "error_connection_interrupted": {
+ "message": "La conexión al servidor se interrumpió inesperadamente"
+ },
+ "ollama_api_request_failed": {
+ "message": "Solicitud a la API de Ollama fallida"
+ },
+ "chatgpt_api_request_failed": {
+ "message": "Solicitud a la API de OpenAI ChatGPT fallida"
+ },
+ "WaitingServerResponse": {
+ "message": "Esperando la respuesta del servidor"
+ },
+ "prefs_API_Host_Info": {
+ "message": "Algo así"
+ },
+ "OpenAIComp_Models": {
+ "message": "Modelos de API compatibles con OpenAI"
+ },
+ "OpenAIComp_Models_Fetch": {
+ "message": "Actualizar lista de modelos de API compatibles con OpenAI"
+ },
+ "OpenAIComp_Models_Error_fetching": {
+ "message": "Error al intentar obtener los modelos de API compatibles con OpenAI"
+ },
+ "OpenAIComp_empty_host": {
+ "message": "No has añadido una dirección de host para la API compatible con OpenAI. Por favor, insértala en la página de opciones."
+ },
+ "OpenAIComp_empty_model": {
+ "message": "No has elegido un modelo para la API compatible con OpenAI. Por favor, elige uno en la página de opciones."
+ },
+ "OpenAIComp_api_request_failed": {
+ "message": "Solicitud a la API de OpenAI Comp fallida"
+ },
+ "prefs_OpenAIComp_ChatName": {
+ "message": "Nombre del chat"
+ },
+ "prefs_OpenAIComp_ChatName_Info": {
+ "message": "Este es el nombre que se usará en el chat de IA."
+ },
+ "StorageSpace": {
+ "message": "Espacio total de almacenamiento ocupado"
+ },
+ "SearchPrompt": {
+ "message": "Buscar prompts"
+ },
+ "prefs_OptionText_dynamic_menu_force_enter": {
+ "message": "Menú: envío inmediato de prompt"
+ },
+ "prefs_OptionText_dynamic_menu_force_enter_info": {
+ "message": "Si está marcado, usar el atajo de teclado CTRL+ALT+A envará automáticamente el prompt resaltado del menú. De lo contrario, se mostrará el nombre del prompt al usuario, requiriendo otra pulsación de la tecla Enter para enviarlo."
+ },
+ "prefs_OptionText_dynamic_menu_order_alphabet": {
+ "message": "Menú: ordenar alfabéticamente"
+ },
+ "prefs_OptionText_dynamic_menu_order_alphabet_info": {
+ "message": "Si está marcado, los prompts en el menú se ordenarán alfabéticamente."
+ },
+ "prefs_OptionText_chatgpt_win_dims_info": {
+ "message": "Establezca en 0 si no quiere especificar el tamaño de la ventana."
+ },
+ "prefs_OpenAIComp_API_Key": {
+ "message": "Clave API de OpenAI Comp"
+ },
+ "Optional": {
+ "message": "Opcional"
+ },
+ "OpenChatGPTTab": {
+ "message": "Abrir pestaña de ChatGPT"
+ },
+ "OpenChatGPTTab_Info": {
+ "message": "En caso de problemas de inicio de sesión en la ventana de ThunderAI, abre ChatGPT en una nueva pestaña usando el botón de la derecha, inicia sesión, luego cierra la pestaña y continúa usando ThunderAI."
+ },
+ "OpenChatGPTTab_Info2": {
+ "message": "Abrir ChatGPT Web desde aquí aplicará cualquier configuración establecida para el modelo, el proyecto y el Custom GPT."
+ },
+ "placeholder_mail_text_body": {
+ "message": "Cuerpo del correo"
+ },
+ "placeholder_mail_html_body": {
+ "message": "cuerpo del correo HTML"
+ },
+ "placeholder_mail_subject": {
+ "message": "Asunto del correo"
+ },
+ "placeholder_folder_name": {
+ "message": "Nombre de carpeta"
+ },
+ "placeholder_folder_path": {
+ "message": "Ruta de la carpeta"
+ },
+ "placeholder_mail_headers": {
+ "message": "Encabezados del correo"
+ },
+ "placeholder_selected_text": {
+ "message": "Texto seleccionado"
+ },
+ "placeholder_selected_html": {
+ "message": "HTML seleccionado"
+ },
+ "placeholder_additional_text": {
+ "message": "Texto adicional"
+ },
+ "placeholder_junk_score": {
+ "message": "Puntuación de spam"
+ },
+ "placeholder_recipients": {
+ "message": "Destinatarios"
+ },
+ "placeholder_cc_list": {
+ "message": "Lista CC"
+ },
+ "placeholder_author": {
+ "message": "Autor"
+ },
+ "placeholder_account_email_address": {
+ "message": "Dirección de correo electrónico de la cuenta"
+ },
+ "prefs_OptionText_placeholders_use_default_value": {
+ "message": "Marcadores de posición: usar valor predeterminado"
+ },
+ "prefs_OptionText_placeholders_use_default_value_info": {
+ "message": "Si está marcado, los marcadores de posición se rellenarán con los valores predeterminados cuando no se proporcione un valor. En caso contrario, los marcadores de posición se mantendrán en su lugar."
+ },
+ "prefs_OptionText_max_prompt_length": {
+ "message": "Longitud máxima del prompt"
+ },
+ "prefs_OptionText_max_prompt_length_Info": {
+ "message": "Este es el número máximo de caracteres que se pueden usar en un prompt. De lo contrario, se mostrará un mensaje de error. El valor no es editable para la Interfaz Web de ChatGPT. Establécelo en cero para desactivar la verificación."
+ },
+ "prefs_OptionText_chatgpt_web_model": {
+ "message": "Modelo Web de ChatGPT"
+ },
+ "prefs_OptionText_chatgpt_web_model_info": {
+ "message": "Este es el modelo que se aplicará en la interfaz web de ChatGPT. Si no se especifica ninguno o se proporciona uno incorrecto, el modelo predeterminado será establecido por ChatGPT en la página web. Esta configuración no funcionará con una cuenta gratuita de ChatGPT."
+ },
+ "prefs_OptionText_chatgpt_web_tempchat": {
+ "message": "ChatGPT Web chat temporal"
+ },
+ "prefs_OptionText_chatgpt_web_tempchat_info": {
+ "message": "Si está marcado, el chat temporal se usará en la interfaz web de ChatGPT."
+ },
+ "chatgpt_btn_model": {
+ "message": "Usar el modelo actual"
+ },
+ "SendingPrompt": {
+ "message": "Enviando solicitud..."
+ },
+ "AllowedValues": {
+ "message": "Valores permitidos"
+ },
+ "prefs_OptionText_btnManagePrompts_infoline": {
+ "message": "Puedes usar marcadores de posición de datos adicionales."
+ },
+ "prefs_OptionText_openai_comp_use_v1": {
+ "message": "Mantener la compatibilidad \"v1\""
+ },
+ "prefs_OptionText_openai_comp_use_v1_info": {
+ "message": "Si está marcado, se mantendrá el segmento \"v1\" en la ruta de las llamadas API, como \"http://localhost:1234/v1/chat/completions\"."
+ },
+ "prefs_OptionText_openai_comp_info_remote": {
+ "message": "Aquí también puedes insertar la dirección de un servidor remoto."
+ },
+ "prefs_OptionText_owl_warning": {
+ "message": "Parece que al menos una de sus cuentas está usando el complemento Owl for Exchange. Hay un problema conocido entre Thunderbird y Owl, que se está abordando actualmente. Por el momento, puede usar ThunderAI al redactar correos electrónicos, pero no al leerlos."
+ },
+ "prefs_OptionText_chatgpt_web_model_tooltip": {
+ "message": "Haz clic en un valor para establecerlo."
+ },
+ "prompt_reply_full_text": {
+ "message": "Responder al siguiente correo electrónico. Responder solo con el texto necesario y sin comentarios extra ni otro texto."
+ },
+ "prompt_reply_additional_text": {
+ "message": "No añada la línea de asunto a la respuesta."
+ },
+ "reply_same_lang": {
+ "message": "Responder en el mismo idioma."
+ },
+ "sign_msg_as": {
+ "message": "Firma el mensaje como"
+ },
+ "prompt_reply_advanced_full_text": {
+ "message": "Responder al siguiente correo electrónico \"{%selected_text%}\", considerando que este es el hilo completo de correos \"{%mail_html_body%}\". Responder solo con el texto necesario y sin comentarios extra ni otro texto."
+ },
+ "prompt_reply_custom_command_full_text": {
+ "message": "Responder al siguiente correo electrónico \"{%mail_text_body%}\". {%additional_text%}. Responder solo con el texto necesario y sin comentarios extra ni otro texto."
+ },
+ "prompt_rewrite_full_text": {
+ "message": "Reescribe el siguiente texto para que sea más cortés. Responde solo con el texto reescrito y sin comentarios adicionales ni otro texto."
+ },
+ "prompt_rewrite_formal_full_text": {
+ "message": "Reescribe el siguiente texto para que sea más formal. Responde solo con el texto reescrito y sin comentarios adicionales ni otro texto."
+ },
+ "prompt_classify_full_text": {
+ "message": "Clasifique el siguiente texto en términos de Cortesía, Calidez, Formalidad, Asertividad, Ofensividad dando un porcentaje para cada categoría. Responda solo con la categoría y la puntuación sin comentarios extra ni otro texto."
+ },
+ "prompt_summarize_this_full_text": {
+ "message": "Resume el siguiente correo electrónico en una lista de viñetas."
+ },
+ "prompt_translate_this_full_text": {
+ "message": "Traducir el siguiente correo electrónico en"
+ },
+ "prompt_this_full_text": {
+ "message": "Responder solo con el texto necesario y sin comentarios extra ni otro texto."
+ },
+ "prefs_OptionText_add_tags": {
+ "message": "Agregar etiquetas a los correos electrónicos"
+ },
+ "prefs_OptionText_add_tags_Info": {
+ "message": "Si está marcado, se incluirá un elemento en el menú para aplicar etiquetas a los correos electrónicos."
+ },
+ "prompt_add_tags": {
+ "message": "Agregar etiquetas a este correo electrónico"
+ },
+ "prompt_add_tags_full_text": {
+ "message": "Analiza el siguiente texto de correo electrónico y genera una matriz JSON de etiquetas que resuman su contenido. Utiliza temas, tópicos clave y descriptores relevantes como etiquetas. Asegúrate de que las etiquetas sean concisas y relevantes para el contenido del correo.\nTexto del correo: {%mail_text_body%}\nConsidera los siguientes detalles para el contexto:\n- Remitente: {%author%}\n- Destinatarios: {%recipients%}\n- Lista CC: {%cc_list%}\n- Asunto del correo: {%mail_subject%}\nPor favor, basa tus etiquetas en el texto y contexto del correo, ignorando información innecesaria o detalles triviales.\nGenera una respuesta solo en formato JSON. La salida debe ser únicamente una matriz JSON de etiquetas sin ningún comentario o texto adicional. Aquí tienes un ejemplo del formato JSON a usar:\n{\n\"tags\": [\"etiqueta1\", \"etiqueta2\", \"etiqueta3\", \"etiqueta4\", \"etiqueta5\"]\n}"
+ },
+ "prompt_proofread_this": {
+ "message": "Corrija este correo electrónico"
+ },
+ "prompt_proofread_this_full_text": {
+ "message": "Corrija el siguiente correo electrónico y también corrija cualquier error ortográfico o gramatical. Responda solo con el texto corregido y sin comentarios extra ni otro texto.\n\n\"{%mail_typed_text%}\""
+ },
+ "placeholder_tags_current_email": {
+ "message": "Etiquetas de correo"
+ },
+ "placeholder_tags_full_list": {
+ "message": "Etiquetas existentes"
+ },
+ "prefs_OptionText_add_tags_maxnum": {
+ "message": "Número máximo de etiquetas"
+ },
+ "prefs_OptionText_add_tags_maxnum_Info": {
+ "message": "El número máximo de etiquetas propuesto por la IA. Establezca 0 si no desea limitar el número de etiquetas."
+ },
+ "prompt_add_tags_maxnum": {
+ "message": "Limitar el número de etiquetas a"
+ },
+ "prefs_OptionText_add_tags_hide_exclusions": {
+ "message": "Ocultar etiquetas excluidas"
+ },
+ "prefs_OptionText_add_tags_hide_exclusions_Info": {
+ "message": "Si está marcado, las etiquetas que están en la lista de exclusión se ocultarán en el cuadro de diálogo de confirmación."
+ },
+ "prefs_OptionText_btnManageTagsInfo": {
+ "message": "Administrar configuración de etiquetas"
+ },
+ "AddTags_PageTitle": {
+ "message": "Administrar configuración de etiquetas"
+ },
+ "AddTags_info_default": {
+ "message": "En esta página puedes modificar el prompt predeterminado usado para agregar etiquetas a los correos electrónicos y gestionar la lista de exclusión."
+ },
+ "AddTags_prompt_text_title": {
+ "message": "Texto del prompt actual"
+ },
+ "AddTags_excl_list_title": {
+ "message": "Lista de exclusión"
+ },
+ "AddTags_excl_list_infoline": {
+ "message": "Esta es una lista de etiquetas que no se pueden añadir a los correos electrónicos."
+ },
+ "save": {
+ "message": "Guardar"
+ },
+ "addtags_info_additional_statements": {
+ "message": "Esta declaración se añadirá al final del prompt:"
+ },
+ "reset_default": {
+ "message": "Restablecer a los valores predeterminados"
+ },
+ "addtags_excl_list_infoline2": {
+ "message": "Agrega una palabra por línea, o separada por una coma."
+ },
+ "addtags_dialog_title": {
+ "message": "Agregar etiquetas al correo electrónico"
+ },
+ "addtags_exclude_tag": {
+ "message": "Excluir etiqueta"
+ },
+ "addtags_no_tags_received": {
+ "message": "No se recibieron etiquetas de la IA."
+ },
+ "addtags_no_valid_tags": {
+ "message": "No se encontraron etiquetas válidas después de filtrar con la lista de exclusión."
+ },
+ "thunderai_error_title": {
+ "message": "Error de ThunderAI"
+ },
+ "thunderai_warning_title": {
+ "message": "Advertencia de ThunderAI"
+ },
+ "prefs_OptionText_add_tags_first_uppercase": {
+ "message": "Primera letra en mayúscula"
+ },
+ "prefs_OptionText_add_tags_first_uppercase_Info": {
+ "message": "Si está marcado, la etiqueta de etiquetas se establecerá en minúsculas con solo la primera letra en mayúscula."
+ },
+ "AddTags_prompt_prefs_title": {
+ "message": "Opciones de agregar etiquetas"
+ },
+ "prefs_SurveyLinkText": {
+ "message": "Comparte tus comentarios y ayuda a mejorar ThunderAI!"
+ },
+ "prefs_SurveyLinkText2": {
+ "message": "Haz clic aquí, ¡solo toma un minuto!"
+ },
+ "prefs_OpenAIComp_ForceModel": {
+ "message": "Insertar modelo manualmente"
+ },
+ "OpenAIComp_force_model_ask": {
+ "message": "Inserte aquí el nombre del modelo que desea usar."
+ },
+ "prefs_OptionText_add_tags_force_lang": {
+ "message": "Forzar idioma"
+ },
+ "prefs_OptionText_add_tags_force_lang_Info": {
+ "message": "Si está marcado, el idioma de las etiquetas se forzará a coincidir con el idioma definido en la página de opciones de ThunderAI, si se especifica."
+ },
+ "prompt_add_tags_force_lang": {
+ "message": "Las etiquetas deben escribirse en"
+ },
+ "prefs_Connection_type_Google_Gemini_API": {
+ "message": "API de Google Gemini"
+ },
+ "prefs_GoogleGemini_API_Key": {
+ "message": "Clave API"
+ },
+ "GoogleGemini_Models": {
+ "message": "Modelos de API de Google Gemini"
+ },
+ "GoogleGemini_Models_Fetch": {
+ "message": "Actualizar la lista de modelos de Google Gemini"
+ },
+ "GoogleGemini_Models_Error_fetching": {
+ "message": "Error al intentar obtener los modelos de Google Gemini"
+ },
+ "google_gemini_api_request_failed": {
+ "message": "Error al intentar la solicitud a la API de Google Gemini"
+ },
+ "google_gemini_empty_apikey": {
+ "message": "No has agregado una clave API para la API de Google Gemini. Por favor, insértala en la página de opciones."
+ },
+ "google_gemini_empty_model": {
+ "message": "No has elegido un modelo para la API de Google Gemini. Por favor, elige uno en la página de opciones."
+ },
+ "GoogleGemini_SystemInstruction": {
+ "message": "Instrucción del sistema"
+ },
+ "GoogleGemini_SystemInstruction_Info": {
+ "message": "Cuando configuras una instrucción del sistema, le das al modelo contexto adicional para entender la tarea, ofrecer respuestas más personalizadas y cumplir con directrices específicas sobre el mensaje que se enviará."
+ },
+ "ChatGPT_Developer_Messages": {
+ "message": "Mensajes del desarrollador"
+ },
+ "ChatGPT_Developer_Messages_Info": {
+ "message": "Cuando configuras los mensajes del desarrollador, le das al modelo contexto adicional para entender la tarea, ofrecer respuestas más personalizadas y cumplir con directrices específicas sobre el mensaje que se enviará."
+ },
+ "prefs_OptionText_btnManagePrompts_infoline3": {
+ "message": "Puedes usar el marcador de posición de datos {%tags_full_list%} en el prompt para listar las etiquetas disponibles. Con un prompt adecuado, podrías entonces forzar que las etiquetas se elijan solo de la lista de las que ya existen."
+ },
+ "placeholder_mail_typed_text": {
+ "message": "Texto escrito antes del cuerpo del correo citado"
+ },
+ "placeholder_mail_quoted_text": {
+ "message": "Texto citado en el cuerpo del correo"
+ },
+ "prompt_get_calendar_event": {
+ "message": "Agregar un nuevo evento de calendario"
+ },
+ "prompt_get_calendar_event_full_text": {
+ "message": "Extrae todos los detalles relevantes necesarios para generar un evento de calendario a partir del siguiente texto. La información extraída debe incluir:\n- Título del evento\n- Fecha y hora de inicio (incluyendo zona horaria, si se especifica)\n- Fecha y hora de fin (incluyendo zona horaria, si se especifica)\n- Día completo (si se menciona)\n- Asistentes\nAsegúrate de que los datos estén formateados de manera clara y consistente para que puedan usarse directamente en la creación de un evento de calendario.\nSi hay referencias de tiempo relativas, considera que la fecha y hora del correo son \"{%mail_datetime%}\". Calcula la fecha y hora de inicio basándote en esta referencia. Si la fecha y hora de inicio calculadas son anteriores a \"{%current_datetime%}\", recalcula la fecha y hora de inicio usando \"{%current_datetime%}\" como base.\nSi la duración no se especifica, establécela en una hora.\nEstos son los asistentes: {%author%}, {%recipients%}, {%cc_list%}. Si están presentes, excluye mi dirección: {%account_email_address%}.\nSi no puedes obtener uno o más de los datos requeridos, responde con una cadena vacía.\nGenera una respuesta solo en formato JSON. No incluyas texto adicional ni explicaciones; proporciona únicamente el JSON. El formato a usar es:\n{\n\"startDate\": \"YYYYMMDDTHHMMSS\",\n\"endDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"Resumen del evento de calendario aquí\",\n\"forceAllDay\": false,\n\"attendees\": [attendee1@example.com,attendee2@example.com,attendee3@example.com]\n}\nEste es el texto:\"{%selected_text%}\""
+ },
+ "prompt_get_task": {
+ "message": "Agregar una nueva tarea"
+ },
+ "prompt_get_task_full_text": {
+ "message": "Extrae todos los detalles relevantes necesarios para generar una tarea a partir del siguiente texto. La información extraída debe incluir:\n- Fecha y hora de vencimiento (incluyendo zona horaria, si se especifica)\n- Resumen de la tarea\n- Fecha y hora inicial (incluyendo zona horaria, si se especifica)\nAsegúrate de que los datos estén formateados de manera clara y coherente para que puedan usarse directamente al crear una tarea.\nSi hay referencias de tiempo relativas, considera que la fecha y hora del correo son \"{%mail_datetime%}\". Calcula la fecha y hora de inicio basándote en esta referencia. Si la fecha y hora de inicio calculadas son anteriores a \"{%current_datetime%}\", recalcula la fecha y hora de inicio usando \"{%current_datetime%}\" como base.\nSi no puedes obtener una o más de la información requerida, responde con una cadena vacía.\nGenera una respuesta únicamente en formato JSON. No incluyas texto adicional ni explicaciones; proporciona solo el JSON. El formato a usar es:\n{\n\"InitialDate\": \"YYYYMMDDTHHMMSS\",\n\"dueDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"Resumen de la tarea aquí\"\n}\nSi no hay información sobre las fechas, elimínalas.\nAquí está el texto:\"{%selected_text%}\""
+ },
+ "prefs_OptionText_get_calendar_event": {
+ "message": "Agregar un nuevo evento de calendario a partir del texto seleccionado"
+ },
+ "prefs_OptionText_get_calendar_event_Info": {
+ "message": "Si está marcado, se incluirá un elemento en el menú para obtener información del evento de calendario a partir del texto seleccionado."
+ },
+ "get_calendar_event_prompt_prefs_title": {
+ "message": "Opciones de eventos de calendario"
+ },
+ "prefs_OptionText_get_task": {
+ "message": "Agregar una nueva tarea a partir del texto seleccionado"
+ },
+ "prefs_OptionText_get_task_Info": {
+ "message": "Si está marcado, se incluirá un elemento en el menú para obtener información de la tarea a partir del texto seleccionado."
+ },
+ "get_task_prompt_prefs_title": {
+ "message": "Opciones de tareas"
+ },
+ "Select_your_timezone": {
+ "message": "Seleccione su zona horaria"
+ },
+ "prefs_OptionText_calendar_enforce_timezone": {
+ "message": "Forzar la zona horaria especificada"
+ },
+ "prefs_OptionText_calendar_enforce_timezone_Info": {
+ "message": "Si está marcado, la zona horaria especificada se aplicará a los eventos de calendario y a las tareas."
+ },
+ "prefs_OptionText_btnManageCalendarEventInfo": {
+ "message": "Administrar configuración de eventos de calendario"
+ },
+ "GetCalendarEvent_PageTitle": {
+ "message": "Administrar configuración de eventos de calendario"
+ },
+ "GetCalendarEvent_info_default": {
+ "message": "En esta página puedes modificar el prompt predeterminado usado para obtener un evento de calendario del texto seleccionado."
+ },
+ "GetCalendarEvent_prompt_text_title": {
+ "message": "Texto del prompt actual"
+ },
+ "prefs_OptionText_AdvancedPromptResponse_infoline2": {
+ "message": "¡Puedes cambiar el prompt como desees, pero la respuesta recibida de la IA debe estar en formato JSON como se especifica en el prompt predeterminado!"
+ },
+ "prefs_OptionText_get_calendar_event_Sparks_not_present": {
+ "message": "Para usar las funciones de eventos de calendario y tareas, por favor instale el complemento ThunderAI Sparks."
+ },
+ "prefs_OptionText_get_calendar_event_Sparks_wrong_version": {
+ "message": "Para usar las funciones de eventos de calendario y tareas, por favor instale una versión actualizada del complemento ThunderAI Sparks."
+ },
+ "GetTask_PageTitle": {
+ "message": "Administrar configuración de tareas"
+ },
+ "GetTask_info_default": {
+ "message": "En esta página puedes modificar el prompt predeterminado usado para obtener una tarea del texto seleccionado."
+ },
+ "prefs_OptionText_btnManageTaskInfo": {
+ "message": "Administrar configuración de tareas"
+ },
+ "prefs_OptionText_download_now": {
+ "message": "¡Descarga ThunderAI Sparks ahora!"
+ },
+ "placeholder_mail_datetime": {
+ "message": "La fecha y hora del correo electrónico"
+ },
+ "placeholder_current_datetime": {
+ "message": "La fecha y hora actual"
+ },
+ "calendar_getting_data_error": {
+ "message": "Error al obtener datos del evento del calendario"
+ },
+ "calendar_opening_dialog_error": {
+ "message": "Error al abrir el cuadro de diálogo del evento del calendario"
+ },
+ "task_getting_data_error": {
+ "message": "Error al obtener datos de la tarea"
+ },
+ "task_opening_dialog_error": {
+ "message": "Error al abrir el cuadro de diálogo de la tarea"
+ },
+ "no_valid_data_received": {
+ "message": "No se recibieron datos válidos de la IA."
+ },
+ "prefs_OptionText_add_tags_auto": {
+ "message": "Agregar etiquetas automáticamente"
+ },
+ "prefs_OptionText_add_tags_auto_Info": {
+ "message": "Si está marcado, la IA añadirá automáticamente etiquetas a los correos electrónicos recién recibidos."
+ },
+ "prompt_string": {
+ "message": "Prompt"
+ },
+ "prefs_OptionText_add_tags_auto_Info2": {
+ "message": "Elige qué cuenta activar esta función en la parte inferior de esta página."
+ },
+ "prefs_OptionText_add_tags_auto_force_existing": {
+ "message": "Forzar etiquetas existentes"
+ },
+ "prefs_OptionText_add_tags_auto_force_existing_Info": {
+ "message": "Si está marcado, la IA solo añadirá etiquetas existentes y no creará nuevas etiquetas."
+ },
+ "prefs_OptionText_add_tags_auto_uselist": {
+ "message": "Usa solo estas etiquetas"
+ },
+ "prefs_OptionText_add_tags_auto_uselist_Info": {
+ "message": "Si está marcado, la IA solo añadirá etiquetas de la lista a continuación."
+ },
+ "prefs_OptionText_add_tags_auto_uselist_list_Info": {
+ "message": "La lista debe contener al menos una etiqueta. Añade una etiqueta por línea, o separada por una coma."
+ },
+ "prompt_add_tags_use_list": {
+ "message": "Usa solo las etiquetas de esta lista separada por comas"
+ },
+ "prefs_OptionText_add_tags_auto_only_inbox": {
+ "message": "Solo añadir etiquetas a los correos en la bandeja de entrada"
+ },
+ "prefs_OptionText_add_tags_auto_only_inbox_Info": {
+ "message": "Si está marcado, la IA solo añadirá etiquetas a los correos recibidos en la carpeta de la bandeja de entrada."
+ },
+ "prefs_OptionText_add_tags_use_specific_integration_Info": {
+ "message": "If checked, the AI will only add tags to emails received in the inbox folder."
+ },
+ "placeholder_thunderai_def_sign": {
+ "message": "Firma predeterminada según lo definido en las opciones de ThunderAI."
+ },
+ "thunderai_def_lang": {
+ "message": "Idioma predeterminado según lo definido en las opciones de ThunderAI."
+ },
+ "placeholder_mail_attachments_info": {
+ "message": "Información sobre los archivos adjuntos en el correo electrónico"
+ },
+ "empty": {
+ "message": "Este marcador de posición no añade texto, pero evita que el cuerpo del correo se añada automáticamente al final del prompt."
+ },
+ "prefs_OptionText_spamfilter": {
+ "message": "Filtro de spam automático"
+ },
+ "prefs_OptionText_spamfilter_Info": {
+ "message": "Si está marcado, ThunderAI moverá automáticamente los correos spam a la carpeta de spam."
+ },
+ "prefs_OptionText_btnManageSpamFilterInfo": {
+ "message": "Gestionar la configuración del filtro de spam"
+ },
+ "SpamFilter_PageTitle": {
+ "message": "Gestionar la configuración del filtro de spam"
+ },
+ "SpamFilter_info_default": {
+ "message": "En esta página puedes modificar el prompt predeterminado utilizado para detectar correos spam."
+ },
+ "SpamFilter_prompt_text_title": {
+ "message": "Texto actual del prompt"
+ },
+ "prompt_spamfilter": {
+ "message": "Detectar correos spam"
+ },
+ "prompt_spamfilter_full_text": {
+ "message": "Analiza el siguiente correo electrónico y determina si es spam o no. Considera factores como palabras clave sospechosas, lenguaje promocional excesivo, líneas de asunto engañosas, solicitudes de información personal y direcciones de remitente inusuales. \nProporciona un valor de 0 (no es spam) a 100 (spam) y una explicación de no más de 10 palabras. \nEn caso de que falten datos del mensaje, establece el valor en 0 (no es spam) y da la razón. \nGenera una respuesta únicamente en formato JSON. No incluyas texto adicional ni explicación; proporciona solo el JSON. El formato a usar es: \n{\n\"spamValue\": ,\n\"explanation\": \"Breve explicación de tu razonamiento\"\n} \nAquí está la información del correo: \nRemitente: \"{%author%}\" \nAsunto: \"{%mail_subject%}\" \nCuerpo HTML: \"{%mail_html_body%}\""
+ },
+ "SpamFilter_prompt_prefs_title": {
+ "message": "Opciones del filtro de spam"
+ },
+ "prefs_OptionText_use_specific_integration": {
+ "message": "Usar modelo y API específicos"
+ },
+ "prefs_OptionText_spamfilter_use_specific_integration_Info": {
+ "message": "Si está marcado, el Modelo y la API especificados a continuación se usarán para el filtro de spam, sin importar el que se haya elegido en la página de opciones de ThunderAI."
+ },
+ "prefs_OptionText_spamfilter_threshold": {
+ "message": "Umbral de spam"
+ },
+ "prefs_OptionText_spamfilter_threshold_Info": {
+ "message": "Si el valor devuelto por la IA supera este umbral, el correo se moverá a la carpeta de spam."
+ },
+ "spamfilter_threshold_too_low": {
+ "message": "¡El umbral de spam es demasiado bajo! ¡Probablemente marcarás demasiados correos como spam!"
+ },
+ "spamfilter_threshold_zero": {
+ "message": "¡El umbral de spam es cero! ¡Marcarás todos los correos como spam!"
+ },
+ "spamfilter_no_reports": {
+ "message": "No hay mensajes filtrados como spam todavía. Aquí encontrarás una lista de los últimos 100 informes de spam solo para la sesión actual."
+ },
+ "SpamReport_Title": {
+ "message": "Informes del filtro de spam"
+ },
+ "Date": {
+ "message": "Fecha"
+ },
+ "From": {
+ "message": "De"
+ },
+ "Subject": {
+ "message": "Asunto"
+ },
+ "Spam_Value": {
+ "message": "Valor de spam"
+ },
+ "Moved_to_Spam": {
+ "message": "Movido a Spam"
+ },
+ "Explanation": {
+ "message": "Explicación"
+ },
+ "Report_Date": {
+ "message": "Fecha del informe"
+ },
+ "spamfilter_moved": {
+ "message": "Si"
+ },
+ "spamfilter_not_moved": {
+ "message": "No"
+ },
+ "context_menu_mzta-add-tags": {
+ "message": "Añadir etiquetas"
+ },
+ "context_menu_mzta-spamfilter": {
+ "message": "Analizar el spam"
+ },
+ "prefs_OptionText_add_tags_context_menu": {
+ "message": "Mostrar el elemento del menú contextual “Añadir etiquetas”"
+ },
+ "prefs_OptionText_add_tags_context_menu_Info": {
+ "message": "Si está marcado, el elemento del menú contextual “Añadir etiquetas” se mostrará al hacer clic derecho en un correo electrónico de la lista de mensajes."
+ },
+ "prefs_OptionText_spamfilter_context_menu": {
+ "message": "Mostrar el elemento del menú contextual “Analizar el spam”"
+ },
+ "prefs_OptionText_spamfilter_context_menu_Info": {
+ "message": "Si está marcado, el elemento del menú contextual “Analizar el spam” se mostrará al hacer clic derecho en un correo electrónico de la lista de mensajes."
+ },
+ "noActiveCalendar": {
+ "message": "¡No se encontró un calendario editable!"
+ },
+ "btn_show_differences": {
+ "message": "Mostrar diferencias"
+ },
+ "chatgpt_win_diff_title": {
+ "message": "Diferencias entre el texto original y el modificado"
+ },
+ "apiwebchat_you": {
+ "message": "Tu"
+ },
+ "apiwebchat_info": {
+ "message": "Información"
+ },
+ "apiwebchat_error": {
+ "message": "Error"
+ },
+ "apiwebchat_use_this_answer": {
+ "message": "Usa esta respuesta"
+ },
+ "apiwebchat_stopping": {
+ "message": "Deteniendo"
+ },
+ "apiwebchat_receiving_data": {
+ "message": "Recibiendo datos"
+ },
+ "hyprland_warning": {
+ "message": "Si tienes problemas para abrir la ventana de chat de IA, intenta establecer los valores de altura y anchura en 0. Este problema puede ocurrir en Linux en ciertos entornos, por ejemplo, al usar Hyprland."
+ },
+ "remember_CORS": {
+ "message": "¡Recuerda, debes configurar los ajustes CORS en el servidor!"
+ },
+ "maybe_CORS_openai_comp": {
+ "message": "Usar la API compatible con OpenAI puede requerir configurar los ajustes CORS en el servidor."
+ },
+ "CORS_alternative_1": {
+ "message": "¿Problemas al configurar CORS?"
+ },
+ "CORS_alternative_2": {
+ "message": "Presiona el botón a continuación para otorgar el permiso y evitar cualquier problema de CORS."
+ },
+ "CORS_give_allurls_perm": {
+ "message": "Otorgar permiso “all URLs”"
+ },
+ "prefs_OptionText_composing_plain_text": {
+ "message": "Redactando en texto plano"
+ },
+ "prefs_OptionText_composing_plain_text_Info": {
+ "message": "Marca esta opción si estás redactando los correos electrónicos en formato de texto plano."
+ },
+ "Replace_No_Selected_Text": {
+ "message": "¿Ningún texto seleccionado, deseas insertar la respuesta de la IA al inicio del correo electrónico?"
+ },
+ "prefs_ollama_num_ctx": {
+ "message": "Número de tokens de contexto"
+ },
+ "prefs_ollama_num_ctx_Info": {
+ "message": "El número de tokens de contexto que se usarán para la API de Ollama. Establece 0 si no deseas pasarlo como parámetro al servidor."
+ },
+ "ask_chatgptweb_permission_1": {
+ "message": "Para usar la integración de ChatGPT Web, necesitas otorgar el permiso requerido."
+ },
+ "ask_anthropic_api_permission_1": {
+ "message": "Para usar la integración de la API de Claude, necesitas otorgar el permiso requerido."
+ },
+ "ask_openai_api_permission_1": {
+ "message": "Para usar la integración de la API de OpenAI, necesitas otorgar el permiso requerido."
+ },
+ "ask_integration_permission_2_popup": {
+ "message": "Haz clic aquí para abrir una nueva pestaña y seguir las instrucciones."
+ },
+ "ask_integration_permission_2": {
+ "message": "Haz clic aquí para continuar."
+ },
+ "ask_integration_permission_ok": {
+ "message": "Permiso concedido. Puedes hacer clic aquí para cerrar esta pestaña y volver a la ventana principal."
+ },
+ "AccountSelector_AutoTags": {
+ "message": "Elige las cuentas donde el etiquetado automático está habilitado"
+ },
+ "AccountSelector_AutoTags_infoline": {
+ "message": "Cada cambio se guarda inmediatamente."
+ },
+ "AccountSelector_Spamfilter": {
+ "message": "Elige las cuentas donde el filtro de spam está habilitado"
+ },
+ "prefs_OptionText_chatgpt_web_project": {
+ "message": "Proyecto ChatGPT Web"
+ },
+ "prefs_OptionText_chatgpt_web_project_info": {
+ "message": "Este es el proyecto que se aplicará para la interfaz web de ChatGPT."
+ },
+ "prefs_OptionText_chatgpt_web_custom_gpt": {
+ "message": "ChatGPT Web GPT personalizado"
+ },
+ "prefs_OptionText_chatgpt_web_custom_gpt_info": {
+ "message": "Este es el GPT personalizado que se aplicará para la interfaz web de ChatGPT."
+ },
+ "prefs_OptionText_chatgpt_web_custom_data_info": {
+ "message": "Esto debe estar en el siguiente formato:"
+ },
+ "prefs_OptionText_chatgpt_web_custom_data_info2": {
+ "message": "Puedes encontrar el valor correcto en el campo de URL del navegador al abrir la página de ChatGPT correspondiente."
+ },
+ "customPrompts_Properties": {
+ "message": "Propiedades"
+ },
+ "customPrompts_show_additional_info": {
+ "message": "Mostrar propiedades adicionales"
+ },
+ "customPrompts_hide_additional_info": {
+ "message": "Ocultar propiedades adicionales"
+ },
+ "customPrompts_show_additional_info_show": {
+ "message": "Propiedades adicionales"
+ },
+ "prefs_OptionText_CustomGPT_Warn": {
+ "message": "Si se especifica un proyecto en las opciones o en un prompt, sobrescribirá la configuración del GPT personalizado."
+ },
+ "prefs_OptionText_Project_No_temporary_chat_warn": {
+ "message": "Si se especifica un proyecto en las opciones o en un prompt, no se usará el chat temporal."
+ },
+ "prefs_Anthropic_API_Key": {
+ "message": "Clave API de Claude"
+ },
+ "prefs_Connection_type_Anthropic_API": {
+ "message": "API de Claude"
+ },
+ "Anthropic_Models": {
+ "message": "Modelos Claude"
+ },
+ "Anthropic_Models_Fetch": {
+ "message": "Actualizar lista de modelos de Claude"
+ },
+ "Anthropic_Models_Error_fetching": {
+ "message": "Error al intentar obtener los modelos de Claude"
+ },
+ "Anthropic_Version": {
+ "message": "Versión de la API de Claude"
+ },
+ "Anthropic_Version_Info": {
+ "message": "REQUERIDO. No cambies este valor a menos que sepas lo que estás haciendo. Más información en:"
+ },
+ "prefs_OptionText_anthropic_max_tokens": {
+ "message": "Tokens máximos"
+ },
+ "prefs_OptionText_anthropic_max_tokens_Info": {
+ "message": "El número máximo de tokens a generar en la completación. El recuento de tokens de tu prompt más max_tokens no puede exceder la longitud del contexto del modelo."
+ },
+ "anthropic_empty_apikey": {
+ "message": "No has añadido una clave API para la API de Claude. Por favor, inserta una en la página de opciones."
+ },
+ "anthropic_empty_model": {
+ "message": "No has seleccionado un modelo para la API de Claude. Por favor, elige uno en la página de opciones."
+ },
+ "anthropic_empty_version": {
+ "message": "No has añadido una cadena de versión para la API de Claude. Por favor, insértala en la página de opciones."
+ },
+ "anthropic_api_request_failed": {
+ "message": "Solicitud a la API de Claude falló"
+ },
+ "_api_connecting": {
+ "message": "Intentando conectar a $api_string$ usando la siguiente configuración...",
+ "placeholders": {
+ "api_string": {
+ "content": "$1"
+ }
+ }
+ },
+ "_api_connecting_model": {
+ "message": "Modelo"
+ },
+ "_api_connecting_host": {
+ "message": "Host"
+ },
+ "_api_connecting_version": {
+ "message": "Versión"
+ },
+ "prefs_OpenAIComp_AvailableServices": {
+ "message": "Servicios disponibles"
+ },
+ "prefs_OpenAIComp_AvailableServices_Info": {
+ "message": "Elige uno de los servicios disponibles para la API compatible con OpenAI o insértalo manualmente."
+ },
+ "Custom": {
+ "message": "Personalizado"
+ },
+ "OpenAIComp_Configs_ConfirmApply": {
+ "message": "¿Estás seguro de que deseas aplicar la configuración \"$config_name$\"?",
+ "placeholders": {
+ "config_name": {
+ "content": "$1"
+ }
+ }
+ },
+ "apiwebchat_selection_info": {
+ "message": "Si seleccionas texto, solo esa parte será considerada."
+ },
+ "ChatGPT_chatgpt_api_store": {
+ "message": "Usar almacenamiento"
+ },
+ "ChatGPT_chatgpt_api_store_info": {
+ "message": "Si está marcado, tus chats serán almacenados por OpenAI."
+ },
+ "prefs_chatgpt_api_temperature_Info": {
+ "message": "Qué temperatura de muestreo usar, entre 0 y 2. Valores más altos como 0.8 harán que la salida sea más aleatoria, mientras que valores más bajos como 0.2 la harán más enfocada y determinista."
+ },
+ "prefs_ollama_temperature_Info": {
+ "message": "La temperatura del modelo. Incrementar la temperatura hará que el modelo responda de forma más creativa. El valor predeterminado es 0.8. Se recomienda usar valores entre 0 y 1."
+ },
+ "prefs_ollama_think": {
+ "message": "Activar el pensamiento"
+ },
+ "prefs_ollama_think_Info": {
+ "message": "Si está marcado, el modelo pensará antes de responder. Esta opción solo funciona con modelos que admiten la función «think»."
+ },
+ "chatgpt_win_change_reply_type": {
+ "message": "Haz clic para cambiar el tipo de respuesta"
+ },
+ "prefs_OptionText_add_tags_exclusions_exact_match": {
+ "message": "Coincidencia exacta de exclusiones"
+ },
+ "prefs_OptionText_add_tags_exclusions_exact_match_Info": {
+ "message": "Si está marcado, las palabras de la lista de exclusión se compararán exactamente con las etiquetas. De lo contrario, también coincidirán si están incluidas dentro de la etiqueta."
+ },
+ "customDataPH_manageDataPH": {
+ "message": "Administrar marcadores de datos"
+ },
+ "customDataPH_manageDataPH_info_default_3": {
+ "message": "También puedes usar los marcadores de datos predeterminados con autocompletar, como cuando se escriben prompts personalizados."
+ },
+ "customDataPH_manageDataPH_info_default": {
+ "message": "En esta página, es posible definir marcadores de datos personalizados para usarlos en tus prompts personalizados."
+ },
+ "customDataPH_manageDataPH_info_default_2": {
+ "message": "Los marcadores de datos existentes con el mismo ID se sobrescribirán. Los marcadores con IDs nuevos se añadirán."
+ },
+ "customDataPH_ExportAll": {
+ "message": "Exportar todos los marcadores de datos personalizados"
+ },
+ "customDataPH_Import": {
+ "message": "Importar nuevos marcadores de datos"
+ },
+ "customDataPH_form_label_Text": {
+ "message": "Texto del marcador de datos"
+ },
+ "customDataPH_saving_custom": {
+ "message": "Guardando marcadores de datos personalizados..."
+ },
+ "customDataPH_saved": {
+ "message": "¡Marcadores de datos personalizados guardados!"
+ },
+ "customDataPH_btnAddNewCommit": {
+ "message": "Agregar el marcador de datos"
+ },
+ "importCustomDataPH_confirmText": {
+ "message": "Estás a punto de importar nuevos marcadores de datos personalizados."
+ },
+ "importCustomDataPH_start_import": {
+ "message": "Iniciando la importación de marcadores de datos personalizados..."
+ },
+ "importCustomDataPH_import_completed": {
+ "message": "¡Importación de marcadores de datos personalizados completada! Necesitas hacer clic en el botón 'Guardar todo' para guardar tus cambios."
+ },
+ "importCustomDataPH_invalidFile": {
+ "message": "El archivo que estás intentando importar no es un archivo válido de marcadores de datos personalizados."
+ },
+ "importCustomDataPH_invalidDataPHs": {
+ "message": "El archivo que estás intentando importar no contiene ningún marcador de datos personalizado válido."
+ },
+ "customDataPH_add_to_menu": {
+ "message": "Utilizable en los prompts añadidos al menú"
+ },
+ "prefs_OptionText_chatgpt_web_br_replace_info": {
+ "message": "Tenga en cuenta que cualquier etiqueta en la respuesta de la IA será reemplazada por saltos de línea."
+ },
+ "prefs_OpenAIComp_ClearModelsList": {
+ "message": "Borrar lista de modelos"
+ },
+ "OpenAIComp_ClearModelsList_Confirm": {
+ "message": "¿Estás seguro de que deseas borrar la lista de modelos? Esta acción no se puede deshacer."
+ },
+ "prefs_api_temperature": {
+ "message": "Temperatura"
+ },
+ "prefs_openai_comp_temperature_Info": {
+ "message": "Qué temperatura de muestreo usar, entre 0 y 2. Valores más altos como 0.8 harán que la salida sea más aleatoria, mientras que valores más bajos como 0.2 la harán más enfocada y determinista."
+ },
+ "chatgpt_click_force_completion": {
+ "message": "Parece que no es posible saber si ChatGPT ha terminado. Haz clic aquí para forzar la finalización del trabajo."
+ },
+ "warn_API_needed": {
+ "message": "Para usar esta función, necesitas una integración de API en lugar de la integración de ChatGPT Web. Puedes definir una API específica en la página de configuración de la función marcando primero la casilla de verificación arriba y luego haciendo clic en el botón de la izquierda."
+ },
+ "prefs_google_gemini_thinking_budget": {
+ "message": "Presupuesto de pensamiento"
+ },
+ "prefs_google_gemini_thinking_budget_Info": {
+ "message": "Define el número de tokens a usar para pensar. Deja este campo vacío si el modelo seleccionado no admite el pensamiento o si deseas usar el método predeterminado. Introduce 0 para desactivar el pensamiento, o -1 para habilitar el pensamiento dinámico."
+ },
+ "prefs_google_gemini_temperature_Info": {
+ "message": "Este parámetro debe ser un número entre 0.0 y 2.0. Controla la aleatoriedad de la salida. El valor predeterminado varía según el modelo. Déjalo vacío para evitar establecer el parámetro en la llamada a la API."
+ },
+ "SelectAll": {
+ "message": "Seleccionar todo"
+ },
+ "DeselectAll": {
+ "message": "Deseleccionar todo"
+ },
+ "Optional_Permission_Denied_Model_Fetching": {
+ "message": "Has denegado el permiso opcional necesario para obtener los modelos de esta integración."
+ },
+ "prefs_anthropic_temperature_Info": {
+ "message": "Cantidad de aleatoriedad inyectada en la respuesta. Por defecto es 1.0. Varía de 0.0 a 1.0. Usa una temperatura más cercana a 0.0 para tareas analíticas / de opción múltiple, y más cercana a 1.0 para tareas creativas y generativas. Ten en cuenta que incluso con una temperatura de 0.0, los resultados no serán completamente determinísticos."
+ },
+ "Anthropic_System_Prompt_Info": {
+ "message": "Puedes mejorar el rendimiento de Claude usando un Prompt del Sistema para asignarle un rol. Esta técnica, conocida como prompting de rol, es la forma más poderosa de usar prompts del sistema con Claude. El rol adecuado puede convertir a Claude de un asistente general en tu experto virtual en el dominio."
+ },
+ "Anthropic_System_Prompt": {
+ "message": "Prompt del sistema"
+ },
+ "reset": {
+ "message": "Reiniciar"
}
}
diff --git a/_locales/fr/messages.json b/_locales/fr/messages.json
index 2b3f8a52..e8081aab 100644
--- a/_locales/fr/messages.json
+++ b/_locales/fr/messages.json
@@ -1107,7 +1107,7 @@
"message": "Version de l’API Claude"
},
"prefs_OptionText_anthropic_max_tokens": {
- "message": "Nombre maximum de jetons Claude"
+ "message": "Nombre maximum de jetons"
},
"anthropic_api_request_failed": {
"message": "Échec de la requête à l'API Claude"
@@ -1311,5 +1311,32 @@
},
"Optional_Permission_Denied_Model_Fetching": {
"message": "Vous avez refusé l’autorisation facultative nécessaire pour récupérer les modèles pour cette intégration."
+ },
+ "prompt_string": {
+ "message": "Prompt"
+ },
+ "placeholder_mail_headers": {
+ "message": "En-têtes d'e-mail"
+ },
+ "prefs_chatgpt_api_temperature_Info": {
+ "message": "Quelle température d'échantillonnage utiliser, entre 0 et 2. Des valeurs plus élevées comme 0,8 rendront le résultat plus aléatoire, tandis que des valeurs plus basses comme 0,2 le rendront plus ciblé et déterministe."
+ },
+ "prefs_ollama_temperature_Info": {
+ "message": "La température du modèle. Augmenter la température rendra les réponses du modèle plus créatives. La valeur par défaut est 0,8. Il est recommandé d'utiliser des valeurs comprises entre 0 et 1."
+ },
+ "prefs_api_temperature": {
+ "message": "Température"
+ },
+ "prefs_openai_comp_temperature_Info": {
+ "message": "Quelle température d'échantillonnage utiliser, entre 0 et 2. Des valeurs plus élevées, comme 0,8, rendront le résultat plus aléatoire, tandis que des valeurs plus basses, comme 0,2, le rendront plus ciblé et déterministe."
+ },
+ "prefs_google_gemini_temperature_Info": {
+ "message": "Ce paramètre doit être un nombre compris entre 0,0 et 2,0. Il contrôle le caractère aléatoire du résultat. La valeur par défaut varie selon le modèle. Laissez ce champ vide pour ne pas définir le paramètre dans l'appel d'API."
+ },
+ "prefs_anthropic_temperature_Info": {
+ "message": "Degré d'aléa injecté dans la réponse. La valeur par défaut est 1,0. La plage de valeurs s'étend di 0,0 à 1,0. Utilisez une température proche de 0,0 pour des tâches analytiques ou des choix multiples, et proche de 1,0 pour des tâches créatives et génératives. Notez que même avec une température de 0,0, les résultats ne seront pas totalement déterministes."
+ },
+ "reset": {
+ "message": "Réinitialiser"
}
}
diff --git a/_locales/it/messages.json b/_locales/it/messages.json
index ae811d3f..69840ade 100644
--- a/_locales/it/messages.json
+++ b/_locales/it/messages.json
@@ -1111,7 +1111,7 @@
"message": "Scegli uno dei servizi disponibili per l'API compatibile con OpenAI oppure inseriscine uno manualmente."
},
"prefs_OptionText_anthropic_max_tokens": {
- "message": "Numero massimo di token di Claude"
+ "message": "Numero massimo di token"
},
"prefs_OptionText_anthropic_max_tokens_Info": {
"message": "Il numero massimo di token da generare nell'elaborazione. Il conteggio dei token del tuo prompt, sommato a max_tokens, non può superare la lunghezza di contesto del modello."
@@ -1314,5 +1314,32 @@
},
"Optional_Permission_Denied_Model_Fetching": {
"message": "Hai negato l’autorizzazione necessaria per recuperare i modelli per questa integrazione."
+ },
+ "prompt_string": {
+ "message": "Prompt"
+ },
+ "placeholder_mail_headers": {
+ "message": "Intestazioni email"
+ },
+ "reset": {
+ "message": "Reset"
+ },
+ "prefs_chatgpt_api_temperature_Info": {
+ "message": "Quale temperatura di campionamento utilizzare, tra 0 e 2. Valori più alti come 0,8 renderanno l'output più casuale, mentre valori più bassi come 0,2 lo renderanno più focalizzato e deterministico."
+ },
+ "prefs_ollama_temperature_Info": {
+ "message": "La temperatura del modello. Aumentare la temperatura farà sì che il modello risponda in modo più creativo. Il valore predefinito è 0,8. Si consiglia di utilizzare valori compresi tra 0 e 1."
+ },
+ "prefs_api_temperature": {
+ "message": "Temperatura"
+ },
+ "prefs_openai_comp_temperature_Info": {
+ "message": "Quale temperatura di campionamento utilizzare, tra 0 e 2. Valori più alti come 0,8 renderanno l'output più casuale, mentre valori più bassi come 0,2 lo renderanno più focalizzato e deterministico."
+ },
+ "prefs_google_gemini_temperature_Info": {
+ "message": "Questo parametro deve essere un numero compreso tra 0.0 e 2.0. Questo valore controlla la casualità dell'output. Il valore predefinito varia a seconda del modello. Lascialo vuoto per evitare di impostare il parametro nella chiamata API."
+ },
+ "prefs_anthropic_temperature_Info": {
+ "message": "Quantità di casualità iniettata nella risposta. Il valore predefinito è 1,0. L'intervallo va da 0,0 a 1,0. Utilizza una temperatura più vicina a 0,0 per compiti analitici o a scelta multipla, e più vicina a 1,0 per compiti creativi e generativi. Nota che, anche con una temperatura di 0,0, i risultati non saranno completamente deterministici."
}
}
diff --git a/_locales/nb_NO/messages.json b/_locales/nb_NO/messages.json
new file mode 100644
index 00000000..0967ef42
--- /dev/null
+++ b/_locales/nb_NO/messages.json
@@ -0,0 +1 @@
+{}
diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json
new file mode 100644
index 00000000..c9e95c21
--- /dev/null
+++ b/_locales/sv/messages.json
@@ -0,0 +1,1308 @@
+{
+ "extensionDescription": {
+ "message": "Använd ChatGPT, Google Gemini, Claude eller Ollama för att förbättra dina e-postmeddelanden!"
+ },
+ "menu_title": {
+ "message": "AI"
+ },
+ "customPrompts_btnEdit": {
+ "message": "Redigera"
+ },
+ "customPrompts_btnCancel": {
+ "message": "Avbryt"
+ },
+ "customPrompts_btnOK": {
+ "message": "Ok"
+ },
+ "customPrompts_btnDelete": {
+ "message": "Ta bort"
+ },
+ "customPrompts_btnDelete_confirmText": {
+ "message": "Är du säker på att du vill ta bort det här objektet?"
+ },
+ "customPrompts_unsaved_changes": {
+ "message": "Det finns osparade ändringar!"
+ },
+ "btnSaveAll_string": {
+ "message": "Spara alla"
+ },
+ "chatgpt_win_close": {
+ "message": "Stäng"
+ },
+ "customPrompts_add_to_menu_always": {
+ "message": "Alltid"
+ },
+ "Date": {
+ "message": "Datum"
+ },
+ "prompt_selection_needed": {
+ "message": "För att fortsätta måste du markera lite text!"
+ },
+ "customPrompts_form_label_Name": {
+ "message": "Namn"
+ },
+ "customPrompts_form_label_Action": {
+ "message": "Åtgärd"
+ },
+ "customPrompts_form_label_enabled": {
+ "message": "Aktiverad"
+ },
+ "btnNew_string": {
+ "message": "Lägg till ny"
+ },
+ "chatgpt_btn_retry": {
+ "message": "Försöka igen"
+ },
+ "placeholder_selected_html": {
+ "message": "Markerad HTML"
+ },
+ "placeholder_additional_text": {
+ "message": "Ytterligare text"
+ },
+ "chatgpt_win_send": {
+ "message": "Skicka"
+ },
+ "prefs_OptionText_chatgpt_win_height": {
+ "message": "Höjd"
+ },
+ "prefs_OptionText_chatgpt_win_width": {
+ "message": "Bredd"
+ },
+ "prompt_summarize_this": {
+ "message": "Sammanfatta detta"
+ },
+ "prompt_translate_this": {
+ "message": "Översätt detta"
+ },
+ "more_info_string": {
+ "message": "Mer information"
+ },
+ "prompt_classify": {
+ "message": "Klassificera"
+ },
+ "customPrompts_reloading_menus": {
+ "message": "Laddar om menyer..."
+ },
+ "customPrompts_form_required_fields": {
+ "message": "Obligatoriska fält"
+ },
+ "customPrompts_add_to_menu_reading": {
+ "message": "Läser ett e-postmeddelande"
+ },
+ "customPrompts_add_to_menu_composing": {
+ "message": "Skriver ett e-postmeddelande"
+ },
+ "chatgpt_win_working": {
+ "message": "Arbete pågår..."
+ },
+ "chatgpt_win_job_completed": {
+ "message": "Färdigt!"
+ },
+ "chatgpt_win_job_completed_select": {
+ "message": "Markera den text du vill använda och klicka på knappen."
+ },
+ "chatgpt_win_get_answer": {
+ "message": "Använd det valda svaret"
+ },
+ "prefs_OptionText_release_notes": {
+ "message": "Versionsinformation"
+ },
+ "prefsInfoTitle": {
+ "message": "Viktig information"
+ },
+ "placeholder_tags_current_email": {
+ "message": "E-posttaggar"
+ },
+ "placeholder_tags_full_list": {
+ "message": "Befintliga taggar"
+ },
+ "prefs_OptionText_add_tags_maxnum": {
+ "message": "Maximalt antal taggar"
+ },
+ "prefs_OptionText_add_tags_maxnum_Info": {
+ "message": "Det maximala antalet taggar som föreslås av AI:n. Ställ den på 0 om du inte vill begränsa antalet taggar."
+ },
+ "prompt_add_tags_maxnum": {
+ "message": "Begränsa antalet taggar till"
+ },
+ "prefs_OptionText_add_tags_hide_exclusions": {
+ "message": "Dölj uteslutna taggar"
+ },
+ "prefs_OptionText_add_tags_hide_exclusions_Info": {
+ "message": "Om markerad kommer taggarna som finns i undantagslistan att döljas i bekräftelsedialogrutan."
+ },
+ "prefs_OptionText_btnManageTagsInfo": {
+ "message": "Hantera tagginställningar"
+ },
+ "AddTags_PageTitle": {
+ "message": "Hantera tagginställningar"
+ },
+ "AddTags_excl_list_title": {
+ "message": "Undantagslista"
+ },
+ "AddTags_excl_list_infoline": {
+ "message": "Detta är en lista över taggar som inte får läggas till i e-postmeddelanden."
+ },
+ "save": {
+ "message": "Spara"
+ },
+ "reset_default": {
+ "message": "Återställ till standard"
+ },
+ "reset": {
+ "message": "Återställ"
+ },
+ "addtags_excl_list_infoline2": {
+ "message": "Lägg till ett ord per rad, eller separera med kommatecken."
+ },
+ "addtags_dialog_title": {
+ "message": "Lägg till taggar i e-postmeddelandet"
+ },
+ "addtags_exclude_tag": {
+ "message": "Uteslut tagg"
+ },
+ "addtags_no_tags_received": {
+ "message": "Inga taggar mottagna från AI:n."
+ },
+ "addtags_no_valid_tags": {
+ "message": "Inga giltiga taggar hittades efter filtrering med undantagslistan."
+ },
+ "thunderai_error_title": {
+ "message": "ThunderAI-fel"
+ },
+ "thunderai_warning_title": {
+ "message": "ThunderAI-varning"
+ },
+ "prefs_OptionText_add_tags_first_uppercase_Info": {
+ "message": "Om markerad kommer taggarna att ställas in på gemener med endast den första bokstaven som versal."
+ },
+ "prefs_OptionText_add_tags_first_uppercase": {
+ "message": "Första bokstaven som versal"
+ },
+ "prompt_reply": {
+ "message": "Svara på detta e-postmeddelande"
+ },
+ "prompt_reply_advanced": {
+ "message": "Svara på denna tråd"
+ },
+ "prompt_reply_custom_command": {
+ "message": "Svara med kommando"
+ },
+ "prompt_rewrite_polite": {
+ "message": "Skriv om artigt"
+ },
+ "prompt_rewrite_formal": {
+ "message": "Skriv om formellt"
+ },
+ "customPrompts_managePrompts": {
+ "message": "Hantera promptar"
+ },
+ "prompt_lang": {
+ "message": "Svara på"
+ },
+ "customPrompts_start_saving": {
+ "message": "Sparar promptar..."
+ },
+ "customPrompts_reindexing_list": {
+ "message": "Omindexerar listan..."
+ },
+ "customPrompts_filtering_prompts": {
+ "message": "Filtrerar promptar..."
+ },
+ "customPrompts_saving_default_prompts": {
+ "message": "Sparar standardpromptar..."
+ },
+ "customPrompts_saving_custom_prompts": {
+ "message": "Sparar anpassade promptar..."
+ },
+ "customPrompts_saved": {
+ "message": "Promptar sparade!"
+ },
+ "customPrompts_form_label_ID": {
+ "message": "Id"
+ },
+ "customPrompts_form_label_ID_rules": {
+ "message": "Måste vara unikt, med gemener och utan mellanslag"
+ },
+ "customPrompts_form_label_Text": {
+ "message": "Prompttext"
+ },
+ "customPrompts_form_label_need_selected": {
+ "message": "Textval behövs"
+ },
+ "customPrompts_form_label_need_signature": {
+ "message": "Lägg alltid till signaturen"
+ },
+ "customPrompts_form_label_need_custom_text": {
+ "message": "Be om ytterligare text"
+ },
+ "customPrompts_form_label_use_diff_viewer": {
+ "message": "Aktivera visaren för textjämförelse"
+ },
+ "customPrompts_form_label_use_diff_viewer_title": {
+ "message": "Textjämförelsevisaren kan väljas när åtgärden är inställd på \"Ersätt text\"."
+ },
+ "customPrompts_btnAddNewCommit": {
+ "message": "Lägg till prompten"
+ },
+ "customPrompts_add_to_menu": {
+ "message": "Lägg till i meny"
+ },
+ "customPrompts_close_button": {
+ "message": "Stäng-knapp"
+ },
+ "customPrompts_do_reply": {
+ "message": "Svara"
+ },
+ "customPrompts_substitute_text": {
+ "message": "Ersätt text"
+ },
+ "chatgpt_textarea_not_found_error": {
+ "message": "Det verkar som att ChatGPT-sidan tar för lång tid att ladda. Om den är klar klickar du på knappen till höger. Om problemet kvarstår kontrollerar du tjänstens status."
+ },
+ "chatgpt_sendbutton_not_found_error": {
+ "message": "Klicka på skicka-knappen för att skicka in prompten."
+ },
+ "chatgpt_user_not_logged_in": {
+ "message": "Du är inte inloggad på ChatGPT. Logga in med dina inloggningsuppgifter, stäng ChatGPT-fönstret och upprepa sedan åtgärden du försökte göra. Du kommer att förbli inloggad efteråt."
+ },
+ "chatgpt_win_model_warning": {
+ "message": "Av någon anledning är det inte möjligt att verifiera om rätt modell är laddad. För tillfället kan du trycka på den blå knappen för att fortsätta."
+ },
+ "chatgpt_win_custom_text": {
+ "message": "Infoga här den ytterligare texten för prompten."
+ },
+ "chatgpt_force_completion": {
+ "message": "tvinga slutförande"
+ },
+ "prompt_this": {
+ "message": "Prompt detta"
+ },
+ "prompt_string": {
+ "message": "Prompt"
+ },
+ "customPrompts_managePrompts_info_default": {
+ "message": "Standardpromptar kan inte redigeras. Du kan inaktivera dem och sedan kopiera prompttexten och klistra in den i en ny för att skapa en modifierad version."
+ },
+ "customPrompts_managePrompts_info_default_2": {
+ "message": "Du kan importera och exportera promptar. Befintliga promptar med samma ID kommer att skrivas över. Promptar med nya ID:n kommer att läggas till."
+ },
+ "customPrompts_managePrompts_info_default_3": {
+ "message": "Om allt är korrekt, klicka på knappen \"Spara alla\" efter importen."
+ },
+ "chatgpt_force_completion_title": {
+ "message": "Klicka här för att visa knappen \"Använd senaste svar\" om ChatGPT har slutfört sitt arbete men knappen inte har visats."
+ },
+ "msg_prompt_too_long": {
+ "message": "Texten du angav är för lång. Du måste förkorta den."
+ },
+ "prefs_status_page": {
+ "message": "tjänstestatus"
+ },
+ "prefs_OptionText_chatgpt_win_text": {
+ "message": "AI-chattfönstrets dimensioner"
+ },
+ "prefs_OptionText_default_sign_name": {
+ "message": "Standardsignaturnamn"
+ },
+ "prefs_OptionText_default_chatgpt_lang": {
+ "message": "Standardspråk för svaren"
+ },
+ "prefs_OptionText_reply_all": {
+ "message": "Svara alla"
+ },
+ "prefs_OptionText_reply_sender": {
+ "message": "Svara till avsändaren"
+ },
+ "prefs_OptionText_reply_type": {
+ "message": "Svarstyp"
+ },
+ "prefs_OptionText_reply_type_Info": {
+ "message": "Detta är standardsvarstypen som används när du svarar på ett e-postmeddelande. Du kan välja den andra typen senare i svarsdialogrutan."
+ },
+ "prefs_OptionText_btnManagePrompts": {
+ "message": "Hantera dina promptar"
+ },
+ "prefs_OptionText_btnManageCustomDataPH": {
+ "message": "Hantera dina dataplatshållare"
+ },
+ "prefsInfoDesc_1": {
+ "message": "Det kan hända att ChatGPT:s webbgränssnitt ändras på ett sätt som stör hur tillägget fungerar. Kontrollera sidan \"Tjänststatus\" som är länkad längst ner på den här sidan. Kom också ihåg att första gången du använder ThunderAI måste du logga in på ChatGPT."
+ },
+ "prefsInfoDesc_2": {
+ "message": "För att använda ChatGPT API behöver du en OpenAI ChatGPT API-nyckel och måste välja en modell."
+ },
+ "prefsInfoDesc_3": {
+ "message": "För att använda integrationen med Ollama måste du konfigurera en lokal Ollama-server. När servern är igång anger du dess adress i det angivna fältet i applikationen. För att säkerställa korrekt kommunikation mellan ThunderAI och Ollama-servern, kom ihåg att ange OLLAMA_ORIGINS=moz-extension://*."
+ },
+ "prefsInfoDesc_4": {
+ "message": "För att använda den här integrationen behöver du konfigurera en lokal server som är kompatibel med OpenAI API, som LM Studio. När servern är igång anger du dess adress i det angivna fältet i applikationen. För att säkerställa korrekt kommunikation mellan ThunderAI och den lokala servern, kom ihåg att ställa in CORS-inställningarna korrekt."
+ },
+ "prefsInfoDesc_5": {
+ "message": "Kom ihåg att du kan öppna ThunderAI-menyn med kortkommandot CTRL+ALT+A."
+ },
+ "prefsInfoDesc_6": {
+ "message": "Du kan ändra genvägen genom att klicka på kugghjulsikonen längst upp till höger på den här sidan och välja \"Hantera genväg för tillägg\"."
+ },
+ "prefsDonation_1": {
+ "message": "Gillar du det här tillägget?"
+ },
+ "prefsDonation_2": {
+ "message": "Överväg att göra en donation!"
+ },
+ "backToOptionsText": {
+ "message": "Alternativ"
+ },
+ "TranslateText": {
+ "message": "Vill du hjälpa till att översätta det här tillägget?"
+ },
+ "TranslateLink": {
+ "message": "Ta reda på hur!"
+ },
+ "customPrompts_ExportAll": {
+ "message": "Exportera alla promptar"
+ },
+ "customPrompts_Import": {
+ "message": "Importera nya promptar"
+ },
+ "importPrompts_confirmText": {
+ "message": "Du håller på att importera nya promptar."
+ },
+ "customPrompts_start_import": {
+ "message": "Startar import av anpassade promptar..."
+ },
+ "customPrompts_import_completed": {
+ "message": "Import av anpassade promptar är klar! Du måste klicka på knappen \"Spara alla\" för att spara dina ändringar."
+ },
+ "importPrompts_invalidFile": {
+ "message": "Filen du försöker importera är inte en giltig fil med anpassade promptar."
+ },
+ "importPrompts_invalidPrompts": {
+ "message": "Filen du försöker importera innehåller inga giltiga promptar."
+ },
+ "currently_used_prompt": {
+ "message": "För närvarande använt promptnamn"
+ },
+ "customprompts_form_label_define_response_lang": {
+ "message": "Definiera svarsspråket i prompten"
+ },
+ "prefs_Connection_type": {
+ "message": "Anslutningstyp"
+ },
+ "prefs_Connection_type_ChatGPT_Web": {
+ "message": "ChatGPT-webbgränssnitt"
+ },
+ "prefs_Connection_type_ChatGPT_API": {
+ "message": "ChatGPT OpenAI API"
+ },
+ "prefs_ChatGPT_API_Key": {
+ "message": "ChatGPT API-nyckel"
+ },
+ "ChatGPT_Models": {
+ "message": "ChatGPT-modeller"
+ },
+ "ChatGPT_Models_Fetch": {
+ "message": "Uppdatera listan över ChatGPT-modeller"
+ },
+ "ChatGPT_Models_Error_fetching": {
+ "message": "Fel vid försök att hämta ChatGPT-modeller"
+ },
+ "Loading": {
+ "message": "Laddar..."
+ },
+ "error": {
+ "message": "ThunderAI-fel!"
+ },
+ "chatgpt_empty_apikey": {
+ "message": "Du har inte lagt till en API-nyckel för ChatGPT API. Vänligen ange en på alternativsidan."
+ },
+ "chatgpt_empty_model": {
+ "message": "Du har inte valt någon modell för ChatGPT API. Välj en på alternativsidan."
+ },
+ "chagpt_api_send_button": {
+ "message": "Använda modell"
+ },
+ "Debug": {
+ "message": "Felsök"
+ },
+ "prefs_OptionText_do_debug_info": {
+ "message": "Aktivera felsökningssystemet"
+ },
+ "prefs_Connection_type_Ollama_API": {
+ "message": "Ollama API (Lokal LLM)"
+ },
+ "prefs_Connection_type_OpenAI_Comp_API": {
+ "message": "OpenAI-kompatibelt API"
+ },
+ "prefs_API_Host": {
+ "message": "Värdadress"
+ },
+ "Ollama_Models": {
+ "message": "Ollama-modeller"
+ },
+ "Ollama_Models_Fetch": {
+ "message": "Uppdatera listan över Ollama-modeller"
+ },
+ "Ollama_Models_Error_fetching": {
+ "message": "Fel vid försök att hämta Ollama-modeller"
+ },
+ "API_Models_Error_NoModels": {
+ "message": "Inga modeller hittades"
+ },
+ "ollama_empty_host": {
+ "message": "Du har inte lagt till en värdadress för Ollama API. Vänligen ange en på alternativsidan."
+ },
+ "ollama_empty_model": {
+ "message": "Du har inte valt någon modell för Ollama API. Välj en på alternativsidan."
+ },
+ "error_connection_interrupted": {
+ "message": "Anslutningen till servern avbröts oväntat"
+ },
+ "ollama_api_request_failed": {
+ "message": "Ollama API-begäran misslyckades"
+ },
+ "chatgpt_api_request_failed": {
+ "message": "OpenAI ChatGPT API-begäran misslyckades"
+ },
+ "WaitingServerResponse": {
+ "message": "Väntar på serversvar"
+ },
+ "prefs_API_Host_Info": {
+ "message": "Något liknande"
+ },
+ "OpenAIComp_Models": {
+ "message": "OpenAI-kompatibla API-modeller"
+ },
+ "OpenAIComp_Models_Fetch": {
+ "message": "Uppdatera listan över OpenAI-kompatibla API-modeller"
+ },
+ "OpenAIComp_Models_Error_fetching": {
+ "message": "Fel vid försök att hämta OpenAI-kompatibla API-modeller"
+ },
+ "OpenAIComp_empty_host": {
+ "message": "Du har inte lagt till en värdadress för OpenAI-kompatibla API:et. Vänligen ange en på alternativsidan."
+ },
+ "OpenAIComp_empty_model": {
+ "message": "Du har inte valt en modell för OpenAI-kompatibelt API. Välj en på alternativsidan."
+ },
+ "OpenAIComp_api_request_failed": {
+ "message": "OpenAI Comp API-begäran misslyckades"
+ },
+ "prefs_OpenAIComp_ChatName": {
+ "message": "Chattnamn"
+ },
+ "prefs_OpenAIComp_ChatName_Info": {
+ "message": "Detta är namnet som kommer att användas i AI-chatten."
+ },
+ "StorageSpace": {
+ "message": "Totalt upptaget lagringsutrymme"
+ },
+ "SearchPrompt": {
+ "message": "Sök promptar"
+ },
+ "prefs_OptionText_dynamic_menu_force_enter_info": {
+ "message": "Om markerat, skickas den markerade prompten från menyn automatiskt genom att använda kortkommandot CTRL+ALT+A. Annars visas promptnamnet för användaren, vilket kräver ytterligare ett tryck på Enter-tangenten för att skicka den."
+ },
+ "prefs_OptionText_dynamic_menu_force_enter": {
+ "message": "Meny: skicka omedelbart prompt"
+ },
+ "prefs_OptionText_dynamic_menu_order_alphabet": {
+ "message": "Meny: ordna alfabetiskt"
+ },
+ "prefs_OptionText_dynamic_menu_order_alphabet_info": {
+ "message": "Om markerat kommer promptar i menyn att ordnas alfabetiskt."
+ },
+ "prefs_OptionText_chatgpt_win_dims_info": {
+ "message": "Ställ in värdet till 0 om du inte vill ange fönsterstorleken."
+ },
+ "prefs_OpenAIComp_API_Key": {
+ "message": "OpenAI Comp API-nyckel"
+ },
+ "Optional": {
+ "message": "Valfri"
+ },
+ "OpenChatGPTTab": {
+ "message": "Öppna fliken ChatGPT"
+ },
+ "OpenChatGPTTab_Info": {
+ "message": "Vid inloggningsproblem i ThunderAI-fönstret, öppna ChatGPT i en ny flik med knappen till höger, logga in, stäng sedan fliken och fortsätt använda ThunderAI."
+ },
+ "OpenChatGPTTab_Info2": {
+ "message": "Om du öppnar ChatGPT webbgränssnitt härifrån tillämpas alla konfigurerade inställningar för modellen, projektet och den anpassade GPT:n."
+ },
+ "placeholder_mail_text_body": {
+ "message": "Mejltext"
+ },
+ "placeholder_mail_html_body": {
+ "message": "HTML-mejltext"
+ },
+ "placeholder_mail_subject": {
+ "message": "Ämne för e-postmeddelande"
+ },
+ "placeholder_folder_name": {
+ "message": "Mappnamn"
+ },
+ "placeholder_folder_path": {
+ "message": "Mappsökväg"
+ },
+ "placeholder_mail_headers": {
+ "message": "E-postrubriker"
+ },
+ "placeholder_selected_text": {
+ "message": "Makerad text"
+ },
+ "placeholder_junk_score": {
+ "message": "Skräppoäng"
+ },
+ "placeholder_recipients": {
+ "message": "Mottagare"
+ },
+ "placeholder_cc_list": {
+ "message": "CC-lista"
+ },
+ "placeholder_author": {
+ "message": "Författare"
+ },
+ "placeholder_account_email_address": {
+ "message": "Kontots e-postadress"
+ },
+ "prefs_OptionText_placeholders_use_default_value": {
+ "message": "Platshållare: använd standardvärde"
+ },
+ "prefs_OptionText_placeholders_use_default_value_info": {
+ "message": "Om markerat kommer platshållarna att fyllas med standardvärdena när inget värde anges. Annars kommer platshållarna att behållas."
+ },
+ "prefs_OptionText_max_prompt_length": {
+ "message": "Max promptlängd"
+ },
+ "prefs_OptionText_max_prompt_length_Info": {
+ "message": "Detta är det maximala antalet tecken som kan användas i en prompt. Annars visas ett felmeddelande. Värdet kan inte redigeras för ChatGPT-webbgränssnittet. Ställ in det på 0 för att inaktivera kontrollen."
+ },
+ "prefs_OptionText_chatgpt_web_model": {
+ "message": "ChatGPT webbmodell"
+ },
+ "prefs_OptionText_chatgpt_web_model_info": {
+ "message": "Det här är modellen som kommer att tillämpas för ChatGPT:s webbgränssnitt. Om ingen modell anges eller om en felaktig modell anges, kommer standardmodellen att ställas in av ChatGPT på webbsidan. Den här inställningen fungerar inte med ett gratis ChatGPT-konto."
+ },
+ "prefs_OptionText_chatgpt_web_tempchat": {
+ "message": "ChatGPT webbgränssnitt tillfällig chatt"
+ },
+ "prefs_OptionText_chatgpt_web_tempchat_info": {
+ "message": "Om markerad kommer den tillfälliga chatten att användas i ChatGPT:s webbgränssnitt."
+ },
+ "chatgpt_btn_model": {
+ "message": "Använd den nuvarande modellen"
+ },
+ "SendingPrompt": {
+ "message": "Skickar prompt..."
+ },
+ "AllowedValues": {
+ "message": "Tillåtna värden"
+ },
+ "prefs_OptionText_btnManagePrompts_infoline": {
+ "message": "Du kan använda ytterligare dataplatshållare."
+ },
+ "prefs_OptionText_openai_comp_use_v1": {
+ "message": "Behåll \"v1\"-kompatibiliteten"
+ },
+ "prefs_OptionText_openai_comp_use_v1_info": {
+ "message": "Om markerat kommer segmentet \"v1\" i sökvägen för API-anrop att behållas, som \"http://localhost:1234/v1/chat/completions\"."
+ },
+ "prefs_OptionText_openai_comp_info_remote": {
+ "message": "Här kan du även ange en fjärrserveradress."
+ },
+ "prefs_OptionText_owl_warning": {
+ "message": "Det verkar som att minst ett av dina konton använder tillägget Owl for Exchange. Det finns ett känt problem mellan Thunderbird och Owl, vilket för närvarande åtgärdas. För närvarande kan du använda ThunderAI när du skriver e-postmeddelanden, men inte när du läser dem."
+ },
+ "prefs_OptionText_chatgpt_web_model_tooltip": {
+ "message": "Klicka på ett värde för att ställa in det."
+ },
+ "prompt_reply_full_text": {
+ "message": "Svara på följande e-postmeddelande. Svara endast med den text som behövs och utan extra kommentarer eller annan text."
+ },
+ "prompt_reply_additional_text": {
+ "message": "Lägg inte till ämnesraden i svaret."
+ },
+ "reply_same_lang": {
+ "message": "Svara på samma språk."
+ },
+ "sign_msg_as": {
+ "message": "Signera meddelandet som"
+ },
+ "prompt_reply_advanced_full_text": {
+ "message": "Svara på följande e-postmeddelande \"{%selected_text%}\", med tanke på att detta är hela tråden med e-postmeddelanden \"{%mail_html_body%}\". Svara endast med den text som behövs och utan extra kommentarer eller annan text."
+ },
+ "prompt_reply_custom_command_full_text": {
+ "message": "Svara på följande e-postmeddelande \"{%mail_text_body%}\". {%additional_text%}. Svara endast med den text som behövs och utan extra kommentarer eller annan text."
+ },
+ "prompt_rewrite_full_text": {
+ "message": "Skriv om följande text för att vara mer artig. Svara endast med den omskrivna texten och utan extra kommentarer eller annan text."
+ },
+ "prompt_rewrite_formal_full_text": {
+ "message": "Skriv om följande text för att göra den mer formell. Svara endast med den omskrivna texten och utan extra kommentarer eller annan text."
+ },
+ "prompt_summarize_this_full_text": {
+ "message": "Sammanfatta följande e-postmeddelande i en punktlista."
+ },
+ "prompt_translate_this_full_text": {
+ "message": "Översätt följande e-postmeddelande till"
+ },
+ "prompt_this_full_text": {
+ "message": "Svara endast med den text som behövs och utan extra kommentarer eller annan text."
+ },
+ "prefs_OptionText_add_tags": {
+ "message": "Lägg till taggar i e-postmeddelanden"
+ },
+ "prefs_OptionText_add_tags_Info": {
+ "message": "Om markerat kommer ett alternativ att inkluderas i menyn för att tillämpa taggar på e-postmeddelanden."
+ },
+ "prompt_add_tags": {
+ "message": "Lägg till taggar i det här e-postmeddelandet"
+ },
+ "prompt_proofread_this": {
+ "message": "Korrekturläs detta e-postmeddelande"
+ },
+ "prompt_proofread_this_full_text": {
+ "message": "Korrekturläs följande e-postmeddelande och korrigera eventuella stavfel eller grammatikfel. Svara endast med den korrigerade texten och utan extra kommentarer eller annan text.\n\n\"{%mail_typed_text%}\""
+ },
+ "AddTags_info_default": {
+ "message": "På den här sidan kan du ändra standardprompten som används för att lägga till taggar i e-postmeddelanden och hantera undantagslistan."
+ },
+ "AddTags_prompt_text_title": {
+ "message": "Aktuell prompttext"
+ },
+ "prefs_SurveyLinkText": {
+ "message": "Dela din feedback och hjälp till att förbättra ThunderAI!"
+ },
+ "prefs_SurveyLinkText2": {
+ "message": "Klicka här, det tar bara en minut!"
+ },
+ "prefs_OpenAIComp_ForceModel": {
+ "message": "Infoga modell manuellt"
+ },
+ "OpenAIComp_force_model_ask": {
+ "message": "Ange här modellnamnet du vill använda."
+ },
+ "prefs_OptionText_add_tags_force_lang": {
+ "message": "Tvinga språk"
+ },
+ "prefs_OptionText_add_tags_force_lang_Info": {
+ "message": "Om markerat kommer taggarnas språk att tvingas matcha språket som definierats på ThunderAI-inställningssidan, om det anges."
+ },
+ "prompt_add_tags_force_lang": {
+ "message": "Taggarna måste vara skrivna på"
+ },
+ "prefs_Connection_type_Google_Gemini_API": {
+ "message": "Google Gemini API"
+ },
+ "prefs_GoogleGemini_API_Key": {
+ "message": "API-nyckel"
+ },
+ "GoogleGemini_Models": {
+ "message": "Google Gemini API-modeller"
+ },
+ "GoogleGemini_Models_Fetch": {
+ "message": "Uppdatera listan över Google Gemini-modeller"
+ },
+ "GoogleGemini_Models_Error_fetching": {
+ "message": "Fel vid försök att hämta Google Gemini-modeller"
+ },
+ "google_gemini_api_request_failed": {
+ "message": "Google Gemini API-begäran misslyckades"
+ },
+ "google_gemini_empty_apikey": {
+ "message": "Du har inte lagt till en API-nyckel för Google Gemini API. Vänligen ange en på alternativsidan."
+ },
+ "google_gemini_empty_model": {
+ "message": "Du har inte valt någon modell för Google Gemini API. Välj en på alternativsidan."
+ },
+ "GoogleGemini_SystemInstruction": {
+ "message": "Systeminstruktion"
+ },
+ "GoogleGemini_SystemInstruction_Info": {
+ "message": "När du anger en systeminstruktion ger du modellen ytterligare kontext för att förstå uppgiften, ge mer anpassade svar och följa specifika riktlinjer för den prompt som skickas."
+ },
+ "ChatGPT_Developer_Messages": {
+ "message": "Utvecklarmeddelanden"
+ },
+ "ChatGPT_Developer_Messages_Info": {
+ "message": "När du anger utvecklarmeddelandena ger du modellen ytterligare kontext för att förstå uppgiften, ge mer anpassade svar och följa specifika riktlinjer för den prompt som skickas."
+ },
+ "prefs_OptionText_btnManagePrompts_infoline3": {
+ "message": "Du kan använda dataplatshållaren {%tags_full_list%} i prompten för att lista tillgängliga taggar. Med en lämplig prompt kan du sedan tvinga taggarna att endast väljas från listan över de som redan finns."
+ },
+ "prefs_OptionText_get_calendar_event": {
+ "message": "Lägg till en ny kalenderhändelse från markerad text"
+ },
+ "thunderai_def_lang": {
+ "message": "Standardspråk som definierat i ThunderAI-alternativ."
+ },
+ "placeholder_mail_attachments_info": {
+ "message": "Information om bilagorna i e-postmeddelandet"
+ },
+ "prefs_OptionText_spamfilter": {
+ "message": "Automatiskt skräppostfilter"
+ },
+ "prefs_OptionText_spamfilter_Info": {
+ "message": "Om markerat kommer ThunderAI automatiskt att flytta skräppostmeddelanden till skräppostmappen."
+ },
+ "prefs_OptionText_btnManageSpamFilterInfo": {
+ "message": "Hantera inställningar för skräppostfilter"
+ },
+ "SpamFilter_PageTitle": {
+ "message": "Hantera inställningar för skräppostfilter"
+ },
+ "SpamFilter_info_default": {
+ "message": "På den här sidan kan du ändra standardprompten som används för att upptäcka skräppost."
+ },
+ "SpamFilter_prompt_text_title": {
+ "message": "Aktuell prompttext"
+ },
+ "prompt_spamfilter": {
+ "message": "Upptäck skräppostmeddelanden"
+ },
+ "SpamFilter_prompt_prefs_title": {
+ "message": "Alternativ för skräppostfilter"
+ },
+ "prefs_OptionText_use_specific_integration": {
+ "message": "Använd specifik modell och API"
+ },
+ "prefs_OptionText_spamfilter_use_specific_integration_Info": {
+ "message": "Om markerat kommer modellen och API:et som anges nedan att användas för spamfiltret, oavsett vilket som valts på ThunderAI-alternativsidan."
+ },
+ "prefs_OptionText_spamfilter_threshold_Info": {
+ "message": "Om värdet som returneras av AI:n överstiger detta tröskelvärde flyttas e-postmeddelandet till skräppostmappen."
+ },
+ "spamfilter_threshold_too_low": {
+ "message": "Tröskeln för skräppost är för låg! Du kommer troligtvis att markera för många e-postmeddelanden som skräppost!"
+ },
+ "spamfilter_threshold_zero": {
+ "message": "Tröskeln för skräppost är noll! Du kommer att markera alla e-postmeddelanden som skräppost!"
+ },
+ "Subject": {
+ "message": "Ämne"
+ },
+ "From": {
+ "message": "Från"
+ },
+ "Spam_Value": {
+ "message": "Skräppostvärde"
+ },
+ "Moved_to_Spam": {
+ "message": "Flyttad till skräppost"
+ },
+ "Explanation": {
+ "message": "Förklaring"
+ },
+ "Report_Date": {
+ "message": "Rapportdatum"
+ },
+ "spamfilter_moved": {
+ "message": "Ja"
+ },
+ "spamfilter_not_moved": {
+ "message": "Nej"
+ },
+ "context_menu_mzta-add-tags": {
+ "message": "Lägg till taggar"
+ },
+ "context_menu_mzta-spamfilter": {
+ "message": "Analysera för skräppost"
+ },
+ "prefs_OptionText_add_tags_context_menu": {
+ "message": "Visa snabbmenyn \"Lägg till taggar\""
+ },
+ "prefs_OptionText_add_tags_context_menu_Info": {
+ "message": "Om markerat visas snabbmenyn \"Lägg till taggar\" när du högerklickar på ett e-postmeddelande i meddelandelistan."
+ },
+ "prefs_OptionText_spamfilter_context_menu": {
+ "message": "Visa snabbmenyalternativet \"Analysera för skräppost\""
+ },
+ "prefs_OptionText_spamfilter_context_menu_Info": {
+ "message": "Om markerat visas snabbmenyn \"Analysera för skräppost\" när du högerklickar på ett e-postmeddelande i meddelandelistan."
+ },
+ "noActiveCalendar": {
+ "message": "Ingen redigerbar kalender hittades!"
+ },
+ "btn_show_differences": {
+ "message": "Visa skillnader"
+ },
+ "chatgpt_win_diff_title": {
+ "message": "Skillnader mellan originaltexten och den modifierade texten"
+ },
+ "apiwebchat_you": {
+ "message": "Du"
+ },
+ "apiwebchat_info": {
+ "message": "Information"
+ },
+ "apiwebchat_error": {
+ "message": "Fel"
+ },
+ "apiwebchat_use_this_answer": {
+ "message": "Använd detta svar"
+ },
+ "apiwebchat_stopping": {
+ "message": "Stoppar"
+ },
+ "apiwebchat_receiving_data": {
+ "message": "Mottar data"
+ },
+ "hyprland_warning": {
+ "message": "Om du har problem med att öppna AI-chattfönstret kan du prova att ställa in höjd- och breddvärdena till 0. Det här problemet kan uppstå i vissa Linux-miljöer, till exempel när du använder Hyprland."
+ },
+ "remember_CORS": {
+ "message": "Kom ihåg att du måste konfigurera CORS-inställningarna på servern!"
+ },
+ "maybe_CORS_openai_comp": {
+ "message": "Att använda OpenAI-kompatibelt API kan kräva att CORS-inställningar konfigureras på servern."
+ },
+ "CORS_alternative_1": {
+ "message": "Problem med att ställa in CORS?"
+ },
+ "CORS_alternative_2": {
+ "message": "Tryck på knappen nedan för att ge behörighet för att undvika eventuella CORS-problem."
+ },
+ "customPrompts_Properties": {
+ "message": "Egenskaper"
+ },
+ "customPrompts_show_additional_info": {
+ "message": "Visa ytterligare egenskaper"
+ },
+ "customPrompts_hide_additional_info": {
+ "message": "Dölj ytterligare egenskaper"
+ },
+ "customPrompts_show_additional_info_show": {
+ "message": "Ytterligare egenskaper"
+ },
+ "prefs_OptionText_CustomGPT_Warn": {
+ "message": "Om ett projekt anges i alternativen eller i en prompt kommer det att åsidosätta inställningen för anpassad GPT."
+ },
+ "prefs_OptionText_Project_No_temporary_chat_warn": {
+ "message": "Om ett projekt anges i alternativen eller i en prompt kommer den tillfälliga chatten inte att användas."
+ },
+ "prefs_Anthropic_API_Key": {
+ "message": "Claude API-nyckel"
+ },
+ "prefs_Connection_type_Anthropic_API": {
+ "message": "Claude API"
+ },
+ "Anthropic_Models": {
+ "message": "Claude-modeller"
+ },
+ "Anthropic_Models_Fetch": {
+ "message": "Uppdatera listan med Claude-modeller"
+ },
+ "Anthropic_Models_Error_fetching": {
+ "message": "Fel vid försök att hämta Claude-modeller"
+ },
+ "Anthropic_Version": {
+ "message": "Claude API-version"
+ },
+ "Anthropic_Version_Info": {
+ "message": "KRÄVS. Ändra inte detta värde om du inte vet vad du gör. Mer information finns på:"
+ },
+ "prefs_OptionText_anthropic_max_tokens": {
+ "message": "Max antal tokens"
+ },
+ "prefs_OptionText_anthropic_max_tokens_Info": {
+ "message": "Det maximala antalet tokens som ska genereras i slutförandet. Antalet tokens för din prompt plus max_tokens får inte överstiga modellens kontextlängd."
+ },
+ "anthropic_empty_apikey": {
+ "message": "Du har inte lagt till en API-nyckel för Claude API. Vänligen ange en på alternativsidan."
+ },
+ "anthropic_empty_model": {
+ "message": "Du har inte valt någon modell för Claude API. Välj en på alternativsidan."
+ },
+ "anthropic_empty_version": {
+ "message": "Du har inte lagt till en versionssträng för Claude API. Vänligen infoga en på alternativsidan."
+ },
+ "anthropic_api_request_failed": {
+ "message": "Claude API-begäran misslyckades"
+ },
+ "_api_connecting": {
+ "message": "Försöker ansluta till $api_string$ med följande konfiguration...",
+ "placeholders": {
+ "api_string": {
+ "content": "$1"
+ }
+ }
+ },
+ "_api_connecting_model": {
+ "message": "Modell"
+ },
+ "_api_connecting_host": {
+ "message": "Värd"
+ },
+ "_api_connecting_version": {
+ "message": "Version"
+ },
+ "prefs_OpenAIComp_AvailableServices": {
+ "message": "Tillgängliga tjänster"
+ },
+ "prefs_OpenAIComp_AvailableServices_Info": {
+ "message": "Välj en av tjänsterna som är tillgängliga för OpenAI Compatible API eller infoga en manuellt."
+ },
+ "Custom": {
+ "message": "Anpassad"
+ },
+ "OpenAIComp_Configs_ConfirmApply": {
+ "message": "Är du säker på att du vill använda konfigurationen \"$config_name$\"?",
+ "placeholders": {
+ "config_name": {
+ "content": "$1"
+ }
+ }
+ },
+ "apiwebchat_selection_info": {
+ "message": "Om du väljer text kommer endast den delen att beaktas."
+ },
+ "ChatGPT_chatgpt_api_store": {
+ "message": "Använd lagring"
+ },
+ "ChatGPT_chatgpt_api_store_info": {
+ "message": "Om markerat kommer dina chattar att lagras av OpenAI."
+ },
+ "prefs_chatgpt_api_temperature_Info": {
+ "message": "Vilken samplingstemperatur som ska användas, mellan 0 och 2. Högre värden som 0,8 gör utdata mer slumpmässig, medan lägre värden som 0,2 gör den mer fokuserad och deterministisk."
+ },
+ "prefs_ollama_temperature_Info": {
+ "message": "Modellens temperatur. Att öka temperaturen gör att modellen svarar mer kreativt. Standardvärdet är 0,8. Det rekommenderas att använda värden mellan 0 och 1."
+ },
+ "prefs_ollama_think": {
+ "message": "Aktivera tänkande"
+ },
+ "prefs_ollama_think_Info": {
+ "message": "Om markerat kommer modellen att tänka innan den svarar. Det här alternativet fungerar bara med modeller som stöder funktionen \"tänk\"."
+ },
+ "chatgpt_win_change_reply_type": {
+ "message": "Klicka för att ändra svarstypen"
+ },
+ "SelectAll": {
+ "message": "Markera alla"
+ },
+ "DeselectAll": {
+ "message": "Avmarkera alla"
+ },
+ "Anthropic_System_Prompt": {
+ "message": "Systemprompt"
+ },
+ "Anthropic_System_Prompt_Info": {
+ "message": "Du kan förbättra Claudes prestanda genom att använda en systemprompt för att ge den en roll. Denna teknik, känd som rollprompt, är det mest kraftfulla sättet att använda systempromptar med Claude. Rätt roll kan förvandla Claude från en allmän assistent till din virtuella domänexpert."
+ },
+ "Optional_Permission_Denied_Model_Fetching": {
+ "message": "Du har nekat den valfria behörighet som krävs för att hämta modeller för den här integrationen."
+ },
+ "Select_your_timezone": {
+ "message": "Välj din tidszon"
+ },
+ "prefs_OptionText_calendar_enforce_timezone": {
+ "message": "Tvinga fram den angivna tidszonen"
+ },
+ "prefs_OptionText_calendar_enforce_timezone_Info": {
+ "message": "Om markerad kommer den angivna tidszonen att tillämpas för kalenderhändelser och uppgifter."
+ },
+ "prefs_OptionText_btnManageCalendarEventInfo": {
+ "message": "Hantera inställningar för kalenderhändelser"
+ },
+ "GetCalendarEvent_PageTitle": {
+ "message": "Hantera inställningar för kalenderhändelser"
+ },
+ "GetCalendarEvent_info_default": {
+ "message": "På den här sidan kan du ändra standardprompten som används för att hämta en kalenderhändelse från markerad text."
+ },
+ "GetCalendarEvent_prompt_text_title": {
+ "message": "Aktuell prompttext"
+ },
+ "prefs_OptionText_AdvancedPromptResponse_infoline2": {
+ "message": "Du kan ändra prompten som du vill, men svaret som tas emot från AI:n måste vara i JSON-format enligt standardprompten!"
+ },
+ "prefs_OptionText_get_calendar_event_Sparks_not_present": {
+ "message": "För att använda kalenderhändelser och uppgifter, installera ThunderAI Sparks-tillägget."
+ },
+ "prefs_OptionText_get_calendar_event_Sparks_wrong_version": {
+ "message": "För att använda kalenderhändelser och uppgifter, installera en uppdaterad version av ThunderAI Sparks-tillägget."
+ },
+ "GetTask_PageTitle": {
+ "message": "Hantera inställningar för uppgifter"
+ },
+ "GetTask_info_default": {
+ "message": "På den här sidan kan du ändra standardprompten som används för att hämta en uppgift från markerad text."
+ },
+ "prefs_OptionText_btnManageTaskInfo": {
+ "message": "Hantera inställningar för uppgifter"
+ },
+ "prefs_OptionText_download_now": {
+ "message": "Ladda ner ThunderAI Sparks nu!"
+ },
+ "placeholder_mail_datetime": {
+ "message": "Datum och tid för e-postmeddelandet"
+ },
+ "placeholder_current_datetime": {
+ "message": "Aktuellt datum och tid"
+ },
+ "calendar_getting_data_error": {
+ "message": "Fel vid hämtning av kalenderhändelsedata"
+ },
+ "calendar_opening_dialog_error": {
+ "message": "Fel vid öppning av dialogrutan för kalenderhändelse"
+ },
+ "task_getting_data_error": {
+ "message": "Fel vid hämtning av uppgiftsdata"
+ },
+ "task_opening_dialog_error": {
+ "message": "Fel vid öppning av uppgiftsdialogrutan"
+ },
+ "no_valid_data_received": {
+ "message": "Inga giltiga data mottagna från AI:n."
+ },
+ "prefs_OptionText_add_tags_auto": {
+ "message": "Lägg till taggar automatiskt"
+ },
+ "prefs_OptionText_add_tags_auto_Info": {
+ "message": "Om markerat kommer AI:n automatiskt att lägga till taggar till nyligen mottagna e-postmeddelanden."
+ },
+ "prefs_OptionText_add_tags_auto_Info2": {
+ "message": "Välj vilket konto du vill aktivera den här funktionen för längst ner på sidan."
+ },
+ "prefs_OptionText_add_tags_auto_force_existing": {
+ "message": "Tvinga fram befintliga taggar"
+ },
+ "prefs_OptionText_add_tags_auto_force_existing_Info": {
+ "message": "Om markerat kommer AI:n endast att lägga till befintliga taggar och inte skapa nya taggar."
+ },
+ "prefs_OptionText_add_tags_auto_uselist": {
+ "message": "Använd endast dessa taggar"
+ },
+ "prefs_OptionText_add_tags_auto_uselist_Info": {
+ "message": "Om markerat kommer AI:n endast att lägga till taggar från listan nedan."
+ },
+ "prefs_OptionText_add_tags_auto_uselist_list_Info": {
+ "message": "Listan måste innehålla minst en tagg. Lägg till en tagg per rad, eller separera med ett kommatecken."
+ },
+ "prompt_add_tags_use_list": {
+ "message": "Använd endast taggarna i den här kommaseparerade listan"
+ },
+ "prefs_OptionText_add_tags_auto_only_inbox": {
+ "message": "Lägg bara till taggar i e-postmeddelanden i inkorgen"
+ },
+ "prefs_OptionText_add_tags_auto_only_inbox_Info": {
+ "message": "Om markerat kommer AI:n bara att lägga till taggar till e-postmeddelanden som tas emot i inkorgen."
+ },
+ "prefs_OptionText_add_tags_use_specific_integration_Info": {
+ "message": "Om markerat kommer modellen och API:et som anges nedan att användas för att lägga till taggar i e-postmeddelanden, oavsett vilket som valts på ThunderAI-alternativsidan."
+ },
+ "placeholder_thunderai_def_sign": {
+ "message": "Standardsignatur som definierad i ThunderAI-alternativ."
+ },
+ "empty": {
+ "message": "Den här platshållaren lägger inte till någon text, men den förhindrar att e-postmeddelandets brödtext läggs till automatiskt i slutet av prompten."
+ },
+ "prefs_OptionText_spamfilter_threshold": {
+ "message": "Tröskel skräppost"
+ },
+ "spamfilter_no_reports": {
+ "message": "Inga meddelanden har ännu granskats för skräppost. Här hittar du en lista över de senaste 100 skräppostrapporterna för den aktuella sessionen."
+ },
+ "SpamReport_Title": {
+ "message": "Rapporter om skräppostfilter"
+ },
+ "customDataPH_ExportAll": {
+ "message": "Exportera alla anpassade dataplatshållare"
+ },
+ "customDataPH_Import": {
+ "message": "Importera nya dataplatshållare"
+ },
+ "customDataPH_form_label_Text": {
+ "message": "Dataplatshållartext"
+ },
+ "customDataPH_saving_custom": {
+ "message": "Sparar anpassade dataplatshållare..."
+ },
+ "customDataPH_saved": {
+ "message": "Anpassade dataplatshållare sparade!"
+ },
+ "customDataPH_btnAddNewCommit": {
+ "message": "Lägg till dataplatshållaren"
+ },
+ "importCustomDataPH_confirmText": {
+ "message": "Du håller på att importera nya anpassade dataplatshållare."
+ },
+ "importCustomDataPH_start_import": {
+ "message": "Startar import av anpassade dataplatshållare..."
+ },
+ "importCustomDataPH_import_completed": {
+ "message": "Import av anpassade dataplatshållare är klar! Du måste klicka på knappen \"Spara alla\" för att spara dina ändringar."
+ },
+ "importCustomDataPH_invalidFile": {
+ "message": "Filen du försöker importera är inte en giltig anpassad dataplatshållarfil."
+ },
+ "importCustomDataPH_invalidDataPHs": {
+ "message": "Filen du försöker importera innehåller inga giltiga anpassade dataplatshållare."
+ },
+ "customDataPH_add_to_menu": {
+ "message": "Kan användas i promptar som lagts till i menyn"
+ },
+ "prefs_OptionText_chatgpt_web_br_replace_info": {
+ "message": "Observera att alla -taggar i AI:ns svar kommer att ersättas med radbrytningar."
+ },
+ "prefs_OpenAIComp_ClearModelsList": {
+ "message": "Rensa modelllistan"
+ },
+ "OpenAIComp_ClearModelsList_Confirm": {
+ "message": "Är du säker på att du vill rensa modellistan? Den här åtgärden kan inte ångras."
+ },
+ "prefs_api_temperature": {
+ "message": "Temperatur"
+ },
+ "prefs_openai_comp_temperature_Info": {
+ "message": "Vilken samplingstemperatur som ska användas, mellan 0 och 2. Högre värden som 0,8 gör utdata mer slumpmässig, medan lägre värden som 0,2 gör den mer fokuserad och deterministisk."
+ },
+ "chatgpt_click_force_completion": {
+ "message": "Det verkar som att det inte går att få tag på det om inte ChatGPT är klar. Klicka här för att tvinga fram slutförandet av jobbet."
+ },
+ "warn_API_needed": {
+ "message": "För att använda den här funktionen behöver du en API-integration snarare än ChatGPT-webbintegrationen. Du kan definiera ett specifikt API på sidan med funktionsinställningar genom att först markera kryssrutan ovan och sedan klicka på knappen till vänster."
+ },
+ "prompt_classify_full_text": {
+ "message": "Klassificera följande text i termer av artighet, värme, formalitet, självsäkerhet och anstötlighet. Ange en procentandel för varje kategori. Svara endast med kategorin och poängsätt utan extra kommentarer eller annan text."
+ },
+ "prompt_get_calendar_event": {
+ "message": "Lägg till en ny kalenderhändelse"
+ },
+ "prompt_get_task": {
+ "message": "Lägg till en ny uppgift"
+ },
+ "prefs_OptionText_get_calendar_event_Info": {
+ "message": "Om markerat kommer ett alternativ att inkluderas i menyn för att hämta information om kalenderhändelser från markerad text."
+ },
+ "get_calendar_event_prompt_prefs_title": {
+ "message": "Alternativ för kalenderhändelser"
+ },
+ "prefs_OptionText_get_task": {
+ "message": "Lägg till en ny uppgift från markerad text"
+ },
+ "prefs_OptionText_get_task_Info": {
+ "message": "Om markerat kommer ett alternativ att inkluderas i menyn för att hämta uppgiftsinformation från markerad text."
+ },
+ "get_task_prompt_prefs_title": {
+ "message": "Uppgiftsalternativ"
+ },
+ "prefs_OptionText_composing_plain_text": {
+ "message": "Skriva i oformaterad text"
+ },
+ "prefs_OptionText_composing_plain_text_Info": {
+ "message": "Markera det här alternativet om du skriver e-postmeddelandena i oformaterad text."
+ },
+ "Replace_No_Selected_Text": {
+ "message": "Ingen text vald, vill du infoga AI:ns svar i början av e-postmeddelandet?"
+ },
+ "prefs_ollama_num_ctx": {
+ "message": "Antal kontexttokens"
+ },
+ "prefs_ollama_num_ctx_Info": {
+ "message": "Antalet kontexttokens som ska användas för Ollama API. Ställ in på 0 om du inte vill skicka den som en parameter till servern."
+ },
+ "ask_chatgptweb_permission_1": {
+ "message": "För att använda ChatGPT-webbintegrationen måste du ge nödvändig behörighet."
+ },
+ "ask_anthropic_api_permission_1": {
+ "message": "För att använda Claude API-integrationen måste du ge nödvändig behörighet."
+ },
+ "ask_openai_api_permission_1": {
+ "message": "För att använda OpenAI API-integrationen måste du ge nödvändig behörighet."
+ },
+ "ask_integration_permission_2_popup": {
+ "message": "Klicka här för att öppna en ny flik och följ instruktionerna."
+ },
+ "ask_integration_permission_2": {
+ "message": "Klicka här för att fortsätta."
+ },
+ "ask_integration_permission_ok": {
+ "message": "Tillstånd beviljat. Du kan klicka här för att stänga den här fliken och återgå till huvudfönstret."
+ },
+ "AccountSelector_AutoTags": {
+ "message": "Välj de konton där automatisk taggning är aktiverad"
+ },
+ "AccountSelector_AutoTags_infoline": {
+ "message": "Varje ändring sparas omedelbart."
+ },
+ "AccountSelector_Spamfilter": {
+ "message": "Välj de konton där skräppostfiltret är aktiverat"
+ },
+ "prefs_OptionText_chatgpt_web_project": {
+ "message": "ChatGPT webbprojekt"
+ },
+ "prefs_OptionText_chatgpt_web_project_info": {
+ "message": "Detta är projektet som kommer att tillämpas för ChatGPT-webbgränssnittet."
+ },
+ "prefs_OptionText_chatgpt_web_custom_gpt": {
+ "message": "ChatGPT webbanpassad GPT"
+ },
+ "prefs_OptionText_chatgpt_web_custom_gpt_info": {
+ "message": "Detta är den anpassade GPT som kommer att tillämpas för ChatGPT-webbgränssnittet."
+ },
+ "prefs_OptionText_chatgpt_web_custom_data_info": {
+ "message": "Detta måste vara i följande form:"
+ },
+ "prefs_OptionText_chatgpt_web_custom_data_info2": {
+ "message": "Du hittar rätt värde i webbläsarens URL-fält när du öppnar den relaterade ChatGPT-sidan."
+ },
+ "prefs_OptionText_add_tags_exclusions_exact_match_Info": {
+ "message": "Om markerat kommer orden i undantagslistan att matchas exakt med taggarna. Annars kommer de också att matcha om de ingår i taggen."
+ },
+ "prefs_OptionText_add_tags_exclusions_exact_match": {
+ "message": "Exakt matchning för undantag"
+ },
+ "customDataPH_manageDataPH": {
+ "message": "Hantera dataplatshållare"
+ },
+ "customDataPH_manageDataPH_info_default_3": {
+ "message": "Du kan också använda standarddataplatshållarna med autokomplettering, precis som när du skriver anpassade promptar."
+ },
+ "customDataPH_manageDataPH_info_default": {
+ "message": "På den här sidan är det möjligt att definiera anpassade dataplatshållare som ska användas i dina anpassade promptar."
+ },
+ "customDataPH_manageDataPH_info_default_2": {
+ "message": "Befintliga dataplatshållare med samma ID kommer att skrivas över. Platshållare med nya ID:n kommer att läggas till."
+ },
+ "prefs_google_gemini_thinking_budget": {
+ "message": "Tänkande budget"
+ },
+ "prefs_google_gemini_thinking_budget_Info": {
+ "message": "Definiera antalet tokens som ska användas för tänkande. Lämna det här fältet tomt om den valda modellen inte stöder tänkande eller om du vill använda standardmetoden. Ange 0 för att inaktivera tänkande eller -1 för att aktivera dynamiskt tänkande."
+ },
+ "prefs_google_gemini_temperature_Info": {
+ "message": "Denna parameter måste vara ett tal mellan 0,0 och 2,0. Den styr utdatas slumpmässighet. Standardvärdet varierar beroende på modell. Lämna det tomt för att undvika att parametern anges i API-anropet."
+ },
+ "prefs_anthropic_temperature_Info": {
+ "message": "Mängd slumpmässighet som injiceras i svaret. Standardvärdet är 1,0. Varierar från 0,0 till 1,0. Använd en temperatur närmare 0,0 för analytiska/flervalsfrågor och närmare 1,0 för kreativa och generativa uppgifter. Observera att även med en temperatur på 0,0 kommer resultaten inte att vara helt deterministiska."
+ },
+ "prompt_add_tags_full_text": {
+ "message": "Analysera följande e-posttext och generera en JSON-matris med taggar som sammanfattar innehållet. Använd teman, nyckelämnen och relevanta beskrivningar som taggar. Se till att taggarna är koncisa och relevanta för e-postmeddelandets innehåll.\nE-posttext: {%mail_text_body%}\nTänk på följande detaljer för kontext:\n- Avsändare: {%author%}\n- Mottagare: {%recipients%}\n- CC-lista: {%cc_list%}\n- E-postämne: {%mail_subject%}\nBasera dina taggar på e-postmeddelandets text och kontext och ignorera onödig information eller triviala detaljer.\nGenerera ett svar endast i JSON-format. Utdata ska endast vara en JSON-matris med taggar utan ytterligare kommentarer eller text. Här är ett exempel på JSON-formatet som ska användas:\n{\n\"tags\": [\"tag1\", \"tag2\", \"tag3\", \"tag4\", \"tag5\"]\n}"
+ },
+ "addtags_info_additional_statements": {
+ "message": "Detta uttryck kommer att läggas till i slutet av prompten:"
+ },
+ "AddTags_prompt_prefs_title": {
+ "message": "Lägga till taggar alternativ"
+ },
+ "placeholder_mail_typed_text": {
+ "message": "Skriven text före citatbrevets brödtext"
+ },
+ "placeholder_mail_quoted_text": {
+ "message": "Citerad text i meddelandets brödtext"
+ },
+ "prompt_get_calendar_event_full_text": {
+ "message": "Extrahera all relevant information som krävs för att generera en kalenderhändelse från följande text. Den extraherade informationen bör innehålla:\n- Händelsetitel\n- Startdatum och tid (inklusive tidszon, om angiven)\n- Slutdatum och tid (inklusive tidszon, om angiven)\n- Heldag (om angiven)\n- Deltagare\nSe till att informationen är tydligt och konsekvent formaterad så att den kan användas direkt för att skapa en kalenderhändelse.\nOm det finns relativa tidsreferenser, tänk på att datum och tid för e-postmeddelandet är \"{%mail_datetime%}\". Beräkna startdatum och tid baserat på denna referens. Om det beräknade startdatumet och tiden är tidigare än \"{%current_datetime%}\", beräkna om startdatumet och tiden med \"{%current_datetime%}\" som bas.\nOm varaktigheten inte anges, sätt den till en timme.\nDessa är deltagarna: {%author%}, {%recipients%}, {%cc_list%}. Om det finns, exkludera min adress: {%account_email_address%}.\nOm du inte kan få en eller flera av de obligatoriska uppgifterna, vänligen svara med en tom sträng.\nGenerera ett svar endast i JSON-format. Inkludera inte ytterligare text eller förklaringar; ange endast JSON. Här är formatet som ska användas:\n{\n\"startDate\": \"ÅÅÅÅMMDDTHHMMSS\",\n\"endDate\": \"ÅÅÅÅMMDDTHHMMSS\",\n\"summary\": \"Sammanfattning av kalenderhändelse här\",\n\"forceAllDay\": false,\n\"attendees\": [attendee1@example.com,attendee2@example.com,attendee3@example.com]\n}\nHär är texten: \"{%selected_text%}\""
+ },
+ "prompt_get_task_full_text": {
+ "message": "Extrahera alla relevanta detaljer som krävs för att generera en uppgift från följande text. Den extraherade informationen bör innehålla:\n- Förfallodatum och tid (inklusive tidszon, om angiven)\n- Uppgiftssammanfattning\n- Initialt datum och tid (inklusive tidszon, om angiven)\nSe till att informationen är tydligt och konsekvent formaterad så att den kan användas direkt för att skapa en uppgift.\nOm det finns relativa tidsreferenser, tänk på att datum och tid för e-postmeddelandet är \"{%mail_datetime%}\". Beräkna startdatum och tid baserat på denna referens. Om det beräknade startdatumet och tiden är tidigare än \"{%current_datetime%}\", beräkna om startdatumet och tiden med \"{%current_datetime%}\" som bas.\nOm du inte kan få en eller flera av de obligatoriska uppgifterna, vänligen svara med en tom sträng.\nGenerera ett svar endast i JSON-format. Inkludera inte ytterligare text eller förklaringar; ange endast JSON. Här är formatet som ska användas:\n{\n\"InitialDate\": \"ÅÅÅÅMMDDTHHMMSS\",\n\"dueDate\": \"ÅÅÅÅMMDDTHHMMSS\",\n\"summary\": \"Uppgiftssammanfattning här\"\n}\nOm det inte finns någon information om datumen, ta bort dem.\nHär är texten: \"{%selected_text%}\""
+ },
+ "prompt_spamfilter_full_text": {
+ "message": "Analysera följande e-postmeddelande och avgör om det är skräppost eller inte. Tänk på faktorer som misstänkta sökord, överdrivet reklamspråk, vilseledande ämnesrader, förfrågningar om personlig information och ovanliga avsändaradresser.\nAnge ett värde från 0 (inte skräppost) till 100 (skräppost) och en förklaring på högst 10 ord.\nOm meddelandedata saknas, sätt värdet till 0 (inte skräppost) och ange orsaken.\nGenerera ett svar endast i JSON-format. Inkludera inte ytterligare text eller förklaring; ange endast JSON. Här är formatet som ska användas:\n{\n\"spamValue\": ,\n\"explanation\": \"Kort förklaring av ditt resonemang\"\n}\nHär är e-postinformationen:\nAvsändare: \"{%author%}\"\nÄmne: \"{%mail_subject%}\"\nHtml-text: \"{%mail_html_body%}\""
+ },
+ "CORS_give_allurls_perm": {
+ "message": "Ge behörighet för \"alla webbadresser\""
+ }
+}
diff --git a/api_webchat/controller.js b/api_webchat/controller.js
index d4a9cc52..6dec60df 100644
--- a/api_webchat/controller.js
+++ b/api_webchat/controller.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,9 +20,10 @@
* The original code has been released under the Apache License, Version 2.0.
*/
-import { prefs_default } from '../options/mzta-options-default.js';
+import { prefs_default, integration_options_config } from '../options/mzta-options-default.js';
import { placeholdersUtils } from '../js/mzta-placeholders.js';
import { getAPIsInitMessageString, convertNewlinesToBr } from '../js/mzta-utils.js';
+import { loadPrompt } from '../js/mzta-prompts.js';
// Get the LLM to be used
const urlParams = new URLSearchParams(window.location.search);
@@ -46,224 +47,177 @@ const messagesArea = document.querySelector('messages-area');
// The controller wires up all the components and workers together,
// managing the dependencies. A kind of "DI" class.
let worker = null;
+const integration = llm.replace('_api', '');
+const worker_path_map = {
+ chatgpt: '../js/workers/model-worker-openai_responses.js',
+ google_gemini: '../js/workers/model-worker-google_gemini.js',
+ ollama: '../js/workers/model-worker-ollama.js',
+ openai_comp: '../js/workers/model-worker-openai_comp.js',
+ anthropic: '../js/workers/model-worker-anthropic.js',
+};
-switch (llm) {
- case "chatgpt_api":
- worker = new Worker('../js/workers/model-worker-openai.js', { type: 'module' });
- break;
- case "google_gemini_api":
- worker = new Worker('../js/workers/model-worker-google_gemini.js', { type: 'module' });
- break;
- case "ollama_api":
- worker = new Worker('../js/workers/model-worker-ollama.js', { type: 'module' });
- break;
- case "openai_comp_api":
- worker = new Worker('../js/workers/model-worker-openai_comp.js', { type: 'module' });
- break;
- case "anthropic_api":
- worker = new Worker('../js/workers/model-worker-anthropic.js', { type: 'module' });
- break;
- default:
- console.error('[ThunderAI] API WebChat Unknown LLM type:', llm);
- break;
+const worker_path = worker_path_map[integration];
+
+if (worker_path) {
+ worker = new Worker(worker_path, { type: 'module' });
+} else {
+ console.error('[ThunderAI] API WebChat Unknown LLM type:', llm);
}
-messagesArea.init(worker);
+if (worker) {
+ messagesArea.init(worker);
+ messageInput.init(worker);
+ messageInput.setMessagesArea(messagesArea);
-// Initialize the messageInput component and pass the worker to it
-messageInput.init(worker);
-messageInput.setMessagesArea(messagesArea);
+ if (integration_options_config[integration]) {
+ const integration_prefix = integration;
+ const options_config = integration_options_config[integration];
+
+ let prefsToGet = { do_debug: prefs_default.do_debug };
+ for (const key in options_config) {
+ prefsToGet[`${integration_prefix}_${key}`] = prefs_default[`${integration_prefix}_${key}`];
+ }
+ if (integration === 'openai_comp') {
+ prefsToGet.openai_comp_chat_name = prefs_default.openai_comp_chat_name;
+ }
-switch (llm) {
- case "chatgpt_api": {
- let prefs_api = await browser.storage.sync.get({
- chatgpt_api_key: prefs_default.chatgpt_api_key,
- chatgpt_model: prefs_default.chatgpt_model,
- chatgpt_developer_messages: prefs_default.chatgpt_developer_messages,
- chatgpt_api_store: prefs_default.chatgpt_api_store,
- do_debug: prefs_default.do_debug,
- });
- let i18nStrings = {};
- i18nStrings["chatgpt_api_request_failed"] = browser.i18n.getMessage('chatgpt_api_request_failed');
- i18nStrings["error_connection_interrupted"] = browser.i18n.getMessage('error_connection_interrupted');
- messageInput.setModel(prefs_api.chatgpt_model);
- messagesArea.setLLMName("ChatGPT");
- worker.postMessage({
- type: 'init',
- chatgpt_api_key: prefs_api.chatgpt_api_key,
- chatgpt_model: prefs_api.chatgpt_model,
- chatgpt_developer_messages: prefs_api.chatgpt_developer_messages,
- chatgpt_api_store: prefs_api.chatgpt_api_store,
- do_debug: prefs_api.do_debug,
- i18nStrings: i18nStrings,
- });
- let additional_text_elements = [];
- additional_text_elements.push({label: 'OpenAI Store', value: (prefs_api.chatgpt_api_store ? 'Yes' : 'No')});
- if(prefs_api.chatgpt_developer_messages && prefs_api.chatgpt_developer_messages.length > 0) {
- additional_text_elements.push({label: browser.i18n.getMessage("ChatGPT_Developer_Messages"), value: prefs_api.chatgpt_developer_messages});
+ let prefs_api = await browser.storage.sync.get(prefsToGet);
+
+ if (prompt_id) {
+ try {
+ const prompt = await loadPrompt(prompt_id);
+ if (prompt && prompt.api_type === llm) {
+ for (const key in options_config) {
+ const prefKey = `${integration_prefix}_${key}`;
+ if (prompt[prefKey] !== undefined) {
+ prefs_api[prefKey] = prompt[prefKey];
+ }
+ }
+ }
+ } catch (e) {
+ console.error("[ThunderAI] Error loading prompt settings:", e);
+ }
}
- additional_text_elements.push({label: "Prompt", value: '[' + prompt_id + '] ' + decodeURIComponent(prompt_name)});
- messagesArea.appendUserMessage(getAPIsInitMessageString({
- api_string: "ChatGPT API",
- model_string: prefs_api.chatgpt_model,
- additional_messages: additional_text_elements
- }), "info");
- browser.runtime.sendMessage({
- command: "openai_api_ready_" + call_id,
- window_id: (await browser.windows.getCurrent()).id
- });
- break;
- }
- case "google_gemini_api": {
- let prefs_api = await browser.storage.sync.get({
- google_gemini_api_key: prefs_default.google_gemini_api_key,
- google_gemini_model: prefs_default.google_gemini_model,
- google_gemini_system_instruction: prefs_default.google_gemini_system_instruction,
- google_gemini_thinking_budget: prefs_default.google_gemini_thinking_budget,
- do_debug: prefs_default.do_debug,
- });
+
let i18nStrings = {};
- i18nStrings["google_gemini_api_request_failed"] = browser.i18n.getMessage('google_gemini_api_request_failed');
+ const i18n_msg_key = integration === 'openai_comp' ? 'OpenAIComp_api_request_failed' : `${integration}_api_request_failed`;
+ i18nStrings[i18n_msg_key] = browser.i18n.getMessage(i18n_msg_key);
i18nStrings["error_connection_interrupted"] = browser.i18n.getMessage('error_connection_interrupted');
- messageInput.setModel(prefs_api.google_gemini_model);
- messagesArea.setLLMName("Google Gemini");
- let additional_text_elements = [];
- if(prefs_api.google_gemini_system_instruction && prefs_api.google_gemini_system_instruction.length > 0) {
- additional_text_elements.push({label: browser.i18n.getMessage("GoogleGemini_SystemInstruction"), value: prefs_api.google_gemini_system_instruction});
+
+ messageInput.setModel(prefs_api[`${integration_prefix}_model`]);
+
+ let llmName = "API";
+ switch(integration) {
+ case 'chatgpt': llmName = "ChatGPT"; break;
+ case 'google_gemini': llmName = "Google Gemini"; break;
+ case 'ollama': llmName = "Ollama Local"; break;
+ case 'openai_comp': llmName = prefs_api.openai_comp_chat_name || "OpenAI Comp"; break;
+ case 'anthropic': llmName = "Claude"; break;
}
- additional_text_elements.push({label: 'Thinking Budget', value: prefs_api.google_gemini_thinking_budget});
- additional_text_elements.push({label: "Prompt", value: '[' + prompt_id + '] ' + decodeURIComponent(prompt_name)});
- worker.postMessage({
+ messagesArea.setLLMName(llmName);
+
+ let workerInitMessage = {
type: 'init',
- google_gemini_api_key: prefs_api.google_gemini_api_key,
- google_gemini_model: prefs_api.google_gemini_model,
- google_gemini_system_instruction: prefs_api.google_gemini_system_instruction,
- google_gemini_thinking_budget: prefs_api.google_gemini_thinking_budget,
do_debug: prefs_api.do_debug,
i18nStrings: i18nStrings,
- });
- messagesArea.appendUserMessage(getAPIsInitMessageString({
- api_string: "Google Gemini API",
- model_string: prefs_api.google_gemini_model,
- additional_messages: additional_text_elements
- }), "info");
- browser.runtime.sendMessage({
- command: "google_gemini_api_ready_" + call_id,
- window_id: (await browser.windows.getCurrent()).id
- });
- break;
- }
- case "ollama_api": {
- let prefs_api = await browser.storage.sync.get({
- ollama_host: prefs_default.ollama_host,
- ollama_model: prefs_default.ollama_model,
- ollama_num_ctx: prefs_default.ollama_num_ctx,
- ollama_think: prefs_default.ollama_think,
- do_debug: prefs_default.do_debug,
- });
- let i18nStrings = {};
- i18nStrings["ollama_api_request_failed"] = browser.i18n.getMessage('ollama_api_request_failed');
- i18nStrings["error_connection_interrupted"] = browser.i18n.getMessage('error_connection_interrupted');
- 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,
- ollama_num_ctx: prefs_api.ollama_num_ctx,
- ollama_think: prefs_api.ollama_think,
- do_debug: prefs_api.do_debug,
- i18nStrings: i18nStrings
- });
- browser.runtime.sendMessage({
- command: "ollama_api_ready_" + call_id,
- window_id: (await browser.windows.getCurrent()).id
- });
+ };
+
+ for (const key in options_config) {
+ const prefKey = `${integration_prefix}_${key}`;
+ workerInitMessage[prefKey] = prefs_api[prefKey];
+ }
+
+ worker.postMessage(workerInitMessage);
+
+ const additional_messages_config = {
+ chatgpt: [
+ { key: 'store', labelKey: 'ChatGPT_chatgpt_api_store', type: 'boolean' },
+ { key: 'developer_messages', labelKey: 'ChatGPT_Developer_Messages', type: 'string' },
+ { key: 'temperature', labelKey: 'prefs_api_temperature', type: 'string' }
+ ],
+ google_gemini: [
+ { key: 'system_instruction', labelKey: 'GoogleGemini_SystemInstruction', type: 'string' },
+ { key: 'temperature', labelKey: 'prefs_api_temperature', type: 'string' },
+ { key: 'thinking_budget', labelKey: 'prefs_google_gemini_thinking_budget', type: 'string' }
+ ],
+ ollama: [
+ { key: 'think', labelKey: 'prefs_ollama_think', type: 'boolean' },
+ { key: 'temperature', labelKey: 'prefs_api_temperature', type: 'string' },
+ { key: 'num_ctx', labelKey: 'prefs_ollama_num_ctx', type: 'number_gt_zero' }
+ ],
+ openai_comp: [
+ { key: 'temperature', labelKey: 'prefs_api_temperature', type: 'string' }
+ ],
+ anthropic: [
+ { key: 'system_prompt', labelKey: 'Anthropic_System_Prompt', type: 'string' },
+ { key: 'max_tokens', labelKey: 'prefs_OptionText_anthropic_max_tokens', type: 'number_gt_zero' },
+ { key: 'temperature', labelKey: 'prefs_api_temperature', type: 'string' }
+ ]
+ };
+
+ const getAdditionalMessages = (integration, prefs) => {
+ const messages = [];
+ const config = additional_messages_config[integration];
+ if (!config) return messages;
+
+ for (const item of config) {
+ const prefKey = `${integration}_${item.key}`;
+ const value = prefs[prefKey];
+
+ if (value !== undefined && value !== null && value !== '') {
+ let displayValue;
+ let shouldAdd = false;
+
+ switch (item.type) {
+ case 'boolean':
+ displayValue = value ? 'Yes' : 'No';
+ shouldAdd = true;
+ break;
+ case 'string':
+ if (value.length > 0) {
+ displayValue = value;
+ shouldAdd = true;
+ }
+ break;
+ case 'number_gt_zero':
+ if (value > 0) {
+ displayValue = value;
+ shouldAdd = true;
+ }
+ break;
+ }
+ if (shouldAdd) {
+ messages.push({ label: browser.i18n.getMessage(item.labelKey), value: displayValue });
+ }
+ }
+ }
+ return messages;
+ };
+
let additional_text_elements = [];
- additional_text_elements.push({label: "Prompt", value: '[' + prompt_id + '] ' + decodeURIComponent(prompt_name)});
+ additional_text_elements.push({label: browser.i18n.getMessage("prompt_string"), value: '[' + prompt_id + '] ' + decodeURIComponent(prompt_name)});
+ additional_text_elements.push(...getAdditionalMessages(integration, prefs_api));
+
+ const api_strings = {
+ chatgpt: "ChatGPT API",
+ google_gemini: "Google Gemini API",
+ ollama: "Ollama API",
+ openai_comp: "OpenAI Compatible API",
+ anthropic: "Claude API"
+ };
+
messagesArea.appendUserMessage(getAPIsInitMessageString({
- api_string: "Ollama API",
- model_string: prefs_api.ollama_model,
- host_string: prefs_api.ollama_host,
- additional_messages: additional_text_elements
- }), "info");
- break;
- }
- case "openai_comp_api": {
- let prefs_api = await browser.storage.sync.get({
- openai_comp_host: prefs_default.openai_comp_host,
- openai_comp_model: prefs_default.openai_comp_model,
- openai_comp_api_key: prefs_default.openai_comp_api_key,
- openai_comp_use_v1: prefs_default.openai_comp_use_v1,
- openai_comp_chat_name: prefs_default.openai_comp_chat_name,
- do_debug: prefs_default.do_debug,
- });
- 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,
- openai_comp_use_v1: prefs_api.openai_comp_use_v1,
- do_debug: prefs_api.do_debug,
- i18nStrings: i18nStrings,
- });
- let additional_text_elements = [];
- additional_text_elements.push({label: "Prompt", value: '[' + prompt_id + '] ' + decodeURIComponent(prompt_name)});
- messagesArea.appendUserMessage(getAPIsInitMessageString({
- api_string: "OpenAI Compatible API",
- model_string: prefs_api.openai_comp_model,
- host_string: prefs_api.openai_comp_host,
+ api_string: api_strings[integration],
+ model_string: prefs_api[`${integration_prefix}_model`],
+ host_string: prefs_api[`${integration_prefix}_host`],
+ version_string: prefs_api[`${integration_prefix}_version`],
additional_messages: additional_text_elements
}), "info");
+
browser.runtime.sendMessage({
- command: "openai_comp_api_ready_" + call_id,
+ command: `${llm}_ready_${call_id}`,
window_id: (await browser.windows.getCurrent()).id
});
- break;
- }
- case "anthropic_api": {
- let prefs_api = await browser.storage.sync.get({
- anthropic_api_key: prefs_default.anthropic_api_key,
- anthropic_model: prefs_default.anthropic_model,
- anthropic_system_prompt: prefs_default.anthropic_system_prompt,
- anthropic_version: prefs_default.anthropic_version,
- anthropic_max_tokens: prefs_default.anthropic_max_tokens,
- do_debug: prefs_default.do_debug,
- });
- let i18nStrings = {};
- i18nStrings["anthropic_api_request_failed"] = browser.i18n.getMessage('anthropic_api_request_failed');
- i18nStrings["error_connection_interrupted"] = browser.i18n.getMessage('error_connection_interrupted');
- messageInput.setModel(prefs_api.anthropic_model);
- messagesArea.setLLMName("Claude");
- worker.postMessage({
- type: 'init',
- anthropic_api_key: prefs_api.anthropic_api_key,
- anthropic_model: prefs_api.anthropic_model,
- anthropic_system_prompt: prefs_api.anthropic_system_prompt,
- anthropic_version: prefs_api.anthropic_version,
- anthropic_max_tokens: prefs_api.anthropic_max_tokens,
- do_debug: prefs_api.do_debug,
- i18nStrings: i18nStrings,
- });
- let additional_text_elements = [];
- additional_text_elements.push({label: "Prompt", value: '[' + prompt_id + '] ' + decodeURIComponent(prompt_name)});
- additional_text_elements.push({label: "System Prompt", value: prefs_api.anthropic_system_prompt});
- messagesArea.appendUserMessage(getAPIsInitMessageString({
- api_string: "Claude API",
- model_string: prefs_api.anthropic_model,
- version_string: prefs_api.anthropic_version,
- additional_messages: additional_text_elements
- }), "info");
- browser.runtime.sendMessage({
- command: "anthropic_api_ready_" + call_id,
- window_id: (await browser.windows.getCurrent()).id
- });
- break;
}
}
diff --git a/api_webchat/messageInput.js b/api_webchat/messageInput.js
index aba7c272..b5b2a6b0 100644
--- a/api_webchat/messageInput.js
+++ b/api_webchat/messageInput.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/api_webchat/messagesArea.js b/api_webchat/messagesArea.js
index 3696dbe2..7036c30f 100644
--- a/api_webchat/messagesArea.js
+++ b/api_webchat/messagesArea.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/js/api/anthropic.js b/js/api/anthropic.js
index e1bb27a5..9d44a99e 100644
--- a/js/api/anthropic.js
+++ b/js/api/anthropic.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@ export class Anthropic {
version = '';
model = '';
system_prompt = '';
+ temperature = '';
max_tokens = 4096;
stream = false;
@@ -33,6 +34,7 @@ export class Anthropic {
version = '',
model = '',
system_prompt = '',
+ temperature = '',
max_tokens = 4096,
stream = false,
} = {}) {
@@ -40,6 +42,7 @@ export class Anthropic {
this.version = version;
this.model = model;
this.system_prompt = system_prompt;
+ this.temperature = temperature;
this.max_tokens = max_tokens > 0 ? max_tokens : 4096;
this.stream = stream;
}
@@ -84,9 +87,22 @@ export class Anthropic {
fetchResponse = async (messages) => {
- // console.log(">>>>>>>>>>> Anthropic API request: " + JSON.stringify(messages));
-
try {
+
+ let claude_body = {
+ model: this.model,
+ max_tokens: parseInt(this.max_tokens),
+ system: this.system_prompt,
+ messages: messages,
+ stream: this.stream,
+ };
+
+ const tempFloat = parseFloat(this.temperature);
+
+ if(this.temperature != '' && !Number.isNaN(tempFloat)) claude_body.temperature = tempFloat;
+
+ // console.log(">>>>>>>>>>>>>>>>> [ThunderAI] Anthropic API request: " + JSON.stringify(claude_body));
+
const response = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: {
@@ -95,13 +111,7 @@ export class Anthropic {
"anthropic-version": this.version,
"anthropic-dangerous-direct-browser-access": "true",
},
- body: JSON.stringify({
- model: this.model,
- max_tokens: this.max_tokens,
- system: this.system_prompt,
- messages: messages,
- stream: this.stream,
- }),
+ body: JSON.stringify(claude_body),
});
return response;
}catch (error) {
diff --git a/js/api/google_gemini.js b/js/api/google_gemini.js
index f2e2eb67..91e764bb 100644
--- a/js/api/google_gemini.js
+++ b/js/api/google_gemini.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@ export class GoogleGemini {
system_instruction = '';
stream = false;
thinking_budget = ''; // Model default
+ temperature = ''; // no temperature defined
constructor({
apiKey = '',
@@ -32,12 +33,14 @@ export class GoogleGemini {
system_instruction = '',
stream = false,
thinking_budget = '',
+ temperature = '',
} = {}) {
this.apiKey = apiKey;
this.model = model;
this.system_instruction = system_instruction;
this.stream = stream;
this.thinking_budget = String(thinking_budget ?? '').trim();
+ this.temperature = String(temperature ?? '').trim();
/* Info from: https://ai.google.dev/gemini-api/docs/thinking?#set-budget
# Turn on thinking with a specific token limit: "thinking_budget": 1024
# Thinking off: "thinking_budget": 0
@@ -87,7 +90,8 @@ export class GoogleGemini {
try {
let google_gemini_body = {
- contents:messages
+ contents: messages,
+ generationConfig: {},
};
// console.log("[ThunderAI] Google Gemini API system_instruction: " + JSON.stringify(this.system_instruction));
@@ -101,14 +105,18 @@ export class GoogleGemini {
}
if(this.thinking_budget !== '') {
- google_gemini_body.generationConfig = {
- thinkingConfig: {
+ google_gemini_body.generationConfig.thinkingConfig = {
thinking_budget: this.thinking_budget,
- }
};
}
- // console.log("[ThunderAI] Google Gemini API request: " + JSON.stringify(google_gemini_body));
+ const tempFloat = parseFloat(this.temperature);
+
+ if(this.temperature != '' && !Number.isNaN(tempFloat)) {
+ google_gemini_body.generationConfig.temperature = tempFloat;
+ }
+
+ // console.log(">>>>>>>>>>>>>>>>> [ThunderAI] Google Gemini API request: " + JSON.stringify(google_gemini_body));
const response = await fetch("https://generativelanguage.googleapis.com/v1beta/models/" + this.model + ":" + (this.stream ? 'streamGenerateContent?alt=sse&' : 'generateContent?') + "key=" + this.apiKey, {
method: "POST",
diff --git a/js/api/ollama.js b/js/api/ollama.js
index 9a4be836..07d5a066 100644
--- a/js/api/ollama.js
+++ b/js/api/ollama.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,6 +22,7 @@ export class Ollama {
model = '';
stream = false;
num_ctx = 0;
+ temperature = '';
think = false;
constructor({
@@ -29,12 +30,14 @@ export class Ollama {
model = '',
stream = false,
num_ctx = 0,
+ temperature = '',
think = false,
} = {}) {
this.host = (host || '').trim().replace(/\/+$/, "");
this.model = model;
this.stream = stream;
this.num_ctx = num_ctx;
+ this.temperature = temperature;
this.think = think;
}
@@ -78,6 +81,7 @@ export class Ollama {
fetchResponse = async (messages) => {
try {
+ const tempFloat = parseFloat(this.temperature);
//console.log(">>>>>>>>>> messages: " +JSON.stringify(messages));
const response = await fetch(this.host + "/api/chat", {
method: "POST",
@@ -90,6 +94,7 @@ export class Ollama {
stream: this.stream,
think: this.think,
...(this.num_ctx > 0 ? { options: { num_ctx: parseInt(this.num_ctx) } } : {}),
+ ...(this.temperature != '' && !Number.isNaN(tempFloat) ? { options: { temperature: tempFloat } } : {}),
}),
});
return response;
@@ -103,30 +108,4 @@ export class Ollama {
}
}
-
- // fetchResponse = async (messages) => {
- // try {
- // let sending = messages.join(' ');
- // console.log(">>>>>>>>>> sending: " + sending);
- // const response = await fetch(this.host + "/api/generate", {
- // method: "POST",
- // headers: {
- // "Content-Type": "application/json",
- // },
- // body: JSON.stringify({
- // model: this.model,
- // prompt: sending,
- // stream: this.stream,
- // }),
- // });
- // return response;
- // }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;
- // }
- // }
}
diff --git a/js/api/openai_comp.js b/js/api/openai_comp.js
index 3e975b62..19d1d2cf 100644
--- a/js/api/openai_comp.js
+++ b/js/api/openai_comp.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,6 +26,7 @@ export class OpenAIComp {
apiKey = '';
use_v1 = true;
stream = false;
+ temperature = '';
constructor({
host = '',
@@ -33,12 +34,14 @@ export class OpenAIComp {
apiKey = '',
stream = false,
use_v1 = true,
+ temperature = '',
} = {}) {
this.host = (host || '').trim().replace(/\/+$/, "");
this.model = model;
this.stream = stream;
this.apiKey = apiKey;
this.use_v1 = use_v1;
+ this.temperature = temperature;
}
@@ -78,6 +81,7 @@ export class OpenAIComp {
fetchResponse = async (messages, maxTokens = 0) => {
try{
+ const tempFloat = parseFloat(this.temperature);
const curr_headers = {
"Content-Type": "application/json",
};
@@ -91,7 +95,8 @@ export class OpenAIComp {
model: this.model,
messages: messages,
stream: this.stream,
- ...(maxTokens > 0 ? { 'max_tokens': parseInt(maxTokens) } : {})
+ ...(maxTokens > 0 ? { 'max_tokens': parseInt(maxTokens) } : {}),
+ ...(this.temperature != '' && !Number.isNaN(tempFloat) ? { 'temperature': tempFloat } : {})
}),
});
return response;
diff --git a/js/api/openai_comp_configs.js b/js/api/openai_comp_configs.js
index 35ce9cd9..4eb7bbd4 100644
--- a/js/api/openai_comp_configs.js
+++ b/js/api/openai_comp_configs.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/js/api/openai.js b/js/api/openai_responses.js
similarity index 70%
rename from js/api/openai.js
rename to js/api/openai_responses.js
index 6d589c4c..229cc0c4 100644
--- a/js/api/openai.js
+++ b/js/api/openai_responses.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,6 +24,7 @@ export class OpenAI {
apiKey = '';
model = '';
developer_messages = '';
+ temperature = '';
stream = false;
store = false;
@@ -31,12 +32,14 @@ export class OpenAI {
apiKey = '',
model = '',
developer_messages = '',
+ temperature = '',
stream = false,
store = false
} = {}) {
this.apiKey = apiKey;
this.model = model;
this.developer_messages = developer_messages;
+ this.temperature = temperature;
this.stream = stream;
this.store = store;
}
@@ -65,7 +68,7 @@ export class OpenAI {
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));
+ output.response = output_response.data.filter(item => item.id.startsWith('gpt-') || item.id.startsWith('o1-') || item.id.startsWith('o4-') || item.id.startsWith('o3-')).sort((a, b) => b.id.localeCompare(a.id));
return output;
}catch (error) {
@@ -78,52 +81,49 @@ export class OpenAI {
}
}
- fetchResponse = async (messages, maxTokens = 0) => {
+ fetchResponse = async (messages, maxTokens = 0, previous_response_id = null) => {
+
+ const input = messages.map(msg => ({
+ role: msg.role,
+ content: [{ type: "input_text", text: msg.content }]
+ }));
+
+ const tempFloat = parseFloat(this.temperature);
+
+ let request_body = {
+ model: this.model,
+ input: input,
+ stream: this.stream,
+ store: this.store,
+ ...(this.temperature != '' && !Number.isNaN(tempFloat) ? { 'temperature': tempFloat } : {}),
+ ...(maxTokens > 0 ? { 'max_output_tokens': parseInt(maxTokens) } : {}),
+ ...(previous_response_id && this.store ? { 'previous_response_id': previous_response_id } : {})
+ }
if(this.developer_messages !== ''){
- messages.push({role: "developer", content: [{"type": "text", "text": this.developer_messages}]});
+ request_body.instructions = this.developer_messages;
}
// console.log(">>>>>>>>>>> OpenAI API request: " + JSON.stringify(messages));
try {
- const response = await fetch("https://api.openai.com/v1/chat/completions", {
+ const response = await fetch("https://api.openai.com/v1/responses", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer "+ this.apiKey
},
- body: JSON.stringify({
- model: this.model,
- messages: messages,
- stream: this.stream,
- store: this.store,
- ...(maxTokens > 0 ? { 'max_tokens': parseInt(maxTokens) } : {})
- }),
+ body: JSON.stringify(request_body),
});
return response;
}catch (error) {
- console.error("[ThunderAI] OpenAI API request failed: " + error);
+ console.error("[ThunderAI] OpenAI Responses API request failed: " + error);
let output = {};
output.is_exception = true;
output.ok = false;
- output.error = "OpenAI API request failed: " + error;
+ output.error = "OpenAI Responses API request failed: " + error;
return output;
}
}
- async countTokensUsingAPI(model, text) {
- const response = await fetch('https://api.openai.com/v1/engines/'+model+'/tokenizer', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'Authorization': 'Bearer ' + this.apiKey
- },
- body: JSON.stringify({ text })
- });
-
- const data = await response.json();
- return data.token_count;
- }
-
-}
+}
\ No newline at end of file
diff --git a/js/mzta-addatags-exclusion-list.js b/js/mzta-addatags-exclusion-list.js
index 47e35ece..1b04b645 100644
--- a/js/mzta-addatags-exclusion-list.js
+++ b/js/mzta-addatags-exclusion-list.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/js/mzta-chatgpt-loader.js b/js/mzta-chatgpt-loader.js
index 0e3685df..28bb8272 100644
--- a/js/mzta-chatgpt-loader.js
+++ b/js/mzta-chatgpt-loader.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/js/mzta-chatgpt.js b/js/mzta-chatgpt.js
index 9b7087d3..eeda649e 100644
--- a/js/mzta-chatgpt.js
+++ b/js/mzta-chatgpt.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/js/mzta-compose-script.js b/js/mzta-compose-script.js
index 6d11c492..972a32de 100644
--- a/js/mzta-compose-script.js
+++ b/js/mzta-compose-script.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/js/mzta-logger.js b/js/mzta-logger.js
index be7292fc..eb68ec66 100644
--- a/js/mzta-logger.js
+++ b/js/mzta-logger.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/js/mzta-menus.js b/js/mzta-menus.js
index 241daebe..b164bae1 100644
--- a/js/mzta-menus.js
+++ b/js/mzta-menus.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,7 +19,10 @@
// Some original methods are derived from https://github.com/ali-raheem/Aify/blob/cfadf52f576b7be3720b5b73af7c8d3129c054da/plugin/html/actions.js
import { getPrompts } from './mzta-prompts.js';
-import { prefs_default } from '../options/mzta-options-default.js';
+import {
+ prefs_default,
+ getDynamicSettingsDefaults
+} from '../options/mzta-options-default.js';
import {
getLanguageDisplayName,
getMenuContextCompose,
@@ -203,7 +206,7 @@ export class mzta_Menus {
default_chatgpt_lang: prefs_default.default_chatgpt_lang,
do_debug: prefs_default.do_debug,
});
- let def_conntype = getConnectionType(prefs_at.connection_type, curr_prompt);
+ let def_conntype = getConnectionType(prefs_at, curr_prompt, 'add_tags');
if((def_conntype === '')||(def_conntype === null)||(def_conntype === undefined)||(def_conntype === 'chatgpt_web')){
console.error("[ThunderAI | AddTags] Invalid connection type: " + def_conntype);
taWorkingStatus.stopWorking();
@@ -222,7 +225,8 @@ export class mzta_Menus {
prompt: fullPrompt,
llm: def_conntype,
custom_model: curr_prompt.model ? curr_prompt.model : '',
- do_debug: prefs_at.do_debug
+ do_debug: prefs_at.do_debug,
+ config: curr_prompt
});
await cmd_addTags.initWorker();
try{
@@ -258,9 +262,11 @@ export class mzta_Menus {
connection_type: prefs_default.connection_type,
calendar_enforce_timezone: prefs_default.calendar_enforce_timezone,
calendar_timezone: prefs_default.calendar_timezone,
+ ...getDynamicSettingsDefaults(['use_specific_integration', 'connection_type'])
});
- if((prefs_at.connection_type === '')||(prefs_at.connection_type === null)||(prefs_at.connection_type === undefined)||(prefs_at.connection_type === 'chatgpt_web')){
- console.error("[ThunderAI | GetCalendarEvent] Invalid connection type: " + prefs_at.connection_type);
+ let def_conntype = getConnectionType(prefs_at, curr_prompt, 'get_calendar_event');
+ if((def_conntype === '')||(def_conntype === null)||(def_conntype === undefined)||(def_conntype === 'chatgpt_web')){
+ console.error("[ThunderAI | GetCalendarEvent] Invalid connection type: " + def_conntype);
taWorkingStatus.stopWorking();
return {ok:'0'};
}
@@ -277,8 +283,9 @@ export class mzta_Menus {
this.logger.log("fullPrompt: " + fullPrompt);
let cmd_GetCalendarEvent = new mzta_specialCommand({
prompt: fullPrompt,
- llm: prefs_at.connection_type,
- do_debug: true
+ llm: def_conntype,
+ do_debug: true,
+ config: curr_prompt
});
await cmd_GetCalendarEvent.initWorker();
try{
@@ -333,9 +340,14 @@ export class mzta_Menus {
}
case 'prompt_get_task': { // Get a task info
let task_data = '';
- let prefs_at = await browser.storage.sync.get({connection_type: '', calendar_enforce_timezone: false, calendar_timezone: '',});
- if((prefs_at.connection_type === '')||(prefs_at.connection_type === null)||(prefs_at.connection_type === undefined)||(prefs_at.connection_type === 'chatgpt_web')){
- console.error("[ThunderAI | GetTask] Invalid connection type: " + prefs_at.connection_type);
+ let prefs_at = await browser.storage.sync.get({
+ connection_type: '',
+ calendar_enforce_timezone: false,
+ calendar_timezone: '',
+ ...getDynamicSettingsDefaults(['use_specific_integration', 'connection_type'])});
+ let def_conntype = getConnectionType(prefs_at, curr_prompt, 'get_task');
+ if((def_conntype === '')||(def_conntype === null)||(def_conntype === undefined)||(def_conntype === 'chatgpt_web')){
+ console.error("[ThunderAI | GetTask] Invalid connection type: " + def_conntype);
taWorkingStatus.stopWorking();
return {ok:'0'};
}
@@ -349,8 +361,9 @@ export class mzta_Menus {
this.logger.log("fullPrompt: " + fullPrompt);
let cmd_GetTask = new mzta_specialCommand({
prompt: fullPrompt,
- llm: prefs_at.connection_type,
- do_debug: true
+ llm: def_conntype,
+ do_debug: true,
+ config: curr_prompt
});
await cmd_GetTask.initWorker();
try{
@@ -417,7 +430,13 @@ export class mzta_Menus {
}
}else{ // Classic prompts for the API webchat
this.logger.log("fullPrompt: " + fullPrompt);
- this.logger.log("curr_prompt: " + JSON.stringify(curr_prompt));
+ this.logger.log("curr_prompt: " + JSON.stringify(curr_prompt, (key, value) => {
+ if (typeof key === 'string' && key.endsWith('_api_key')) {
+ return '****************';
+ }
+ return value;
+ })
+ );
this.openChatGPT(fullPrompt, curr_prompt.action, tabs[0].id, curr_prompt.name, curr_prompt.need_custom_text, curr_prompt);
taWorkingStatus.stopWorking();
return {ok:'1'};
diff --git a/js/mzta-placeholders-autocomplete.js b/js/mzta-placeholders-autocomplete.js
index 3bf1463b..ecfd7028 100644
--- a/js/mzta-placeholders-autocomplete.js
+++ b/js/mzta-placeholders-autocomplete.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,7 +34,7 @@ export function textareaAutocomplete(textarea, suggestions, type_value = -1) {
type = tr.querySelector('.type_output').value
}
// console.log(">>>>>>>>> type: " + type);
- // console.log(">>>>>>>>> suggestions: " + JSON.stringify(suggestions));
+ // console.log(">>>>>>>>> suggestions: " + JSON.stringify(suggestions));
// console.log(">>>>>>>>> lastWord: " + lastWord);
const matches = suggestions.filter(s => s.command.startsWith(lastWord) && (String(s.type) == String(type) || String(s.type) == '0' )).map(s => s.command);
// console.log(">>>>>>>>> matches: " + JSON.stringify(matches));
@@ -106,6 +106,7 @@ export function textareaAutocomplete(textarea, suggestions, type_value = -1) {
}
function insertAutocomplete(suggestion, textarea) {
+ // console.log(">>>>>>>>> insertAutocomplete suggestion: " + JSON.stringify(suggestion));
const cursorPosition = textarea.selectionStart;
const textBefore = textarea.value.substring(0, cursorPosition);
const textAfter = textarea.value.substring(cursorPosition);
@@ -115,7 +116,7 @@ export function textareaAutocomplete(textarea, suggestions, type_value = -1) {
const completion = suggestion.substring(lastWord.length);
const newText = textBefore + completion + textAfter;
textarea.value = newText;
- const newCursorPosition = cursorPosition + completion.length;
+ const newCursorPosition = cursorPosition + completion.length - (suggestion.endsWith(':%}') ? 2 : 0);
textarea.setSelectionRange(newCursorPosition, newCursorPosition);
}
}
diff --git a/js/mzta-placeholders.js b/js/mzta-placeholders.js
index 0eb6f926..bfb841c7 100644
--- a/js/mzta-placeholders.js
+++ b/js/mzta-placeholders.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,6 +17,7 @@
*/
import { prefs_default } from '../options/mzta-options-default.js';
+import { getMailHeader } from './mzta-utils.js';
/* ================= PLACEHOLDERS PROPERTIES ========================================
@@ -35,6 +36,10 @@ import { prefs_default } from '../options/mzta-options-default.js';
0: Custom placeholder
1: Default placeholder (not editable, cannot be deleted)
+ is_dynamic attribute:
+ 0: it's a fixed placeholder
+ 1: it's a dynamic placehoder (it means that it will have a : and then a value, like {%my_placeholder:test_value%})
+
================ USER PROPERTIES
enabled attribute:
0: Disabled
@@ -53,6 +58,7 @@ const defaultPlaceholders = [
default_value: "",
type: 0,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -61,6 +67,7 @@ const defaultPlaceholders = [
default_value: "",
type: 0,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -69,6 +76,7 @@ const defaultPlaceholders = [
default_value: "",
type: 2,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -77,6 +85,7 @@ const defaultPlaceholders = [
default_value: "",
type: 2,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -85,6 +94,7 @@ const defaultPlaceholders = [
default_value: "",
type: 0,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -93,6 +103,7 @@ const defaultPlaceholders = [
default_value: "",
type: 1,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -101,6 +112,16 @@ const defaultPlaceholders = [
default_value: "",
type: 1,
is_default: "1",
+ is_dynamic: "0",
+ enabled: 1,
+ },
+ {
+ id: 'mail_headers',
+ name: "__MSG_placeholder_mail_headers__",
+ default_value: "",
+ type: 1,
+ is_default: "1",
+ is_dynamic: "1",
enabled: 1,
},
{
@@ -109,6 +130,7 @@ const defaultPlaceholders = [
default_value: "",
type: 0,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -117,6 +139,7 @@ const defaultPlaceholders = [
default_value: "",
type: 0,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -125,6 +148,7 @@ const defaultPlaceholders = [
default_value: "",
type: 0,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -133,6 +157,7 @@ const defaultPlaceholders = [
default_value: "0",
type: 1,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -141,6 +166,7 @@ const defaultPlaceholders = [
default_value: "",
type: 0,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -149,6 +175,7 @@ const defaultPlaceholders = [
default_value: "",
type: 0,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -157,6 +184,7 @@ const defaultPlaceholders = [
default_value: "",
type: 0,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -165,6 +193,7 @@ const defaultPlaceholders = [
default_value: "",
type: 1,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -173,6 +202,7 @@ const defaultPlaceholders = [
default_value: "",
type: 0,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -181,6 +211,7 @@ const defaultPlaceholders = [
default_value: "",
type: 0,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -189,6 +220,7 @@ const defaultPlaceholders = [
default_value: "",
type: 0,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -197,6 +229,7 @@ const defaultPlaceholders = [
default_value: "",
type: 0,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -205,6 +238,7 @@ const defaultPlaceholders = [
default_value: "",
type: 0,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -213,6 +247,7 @@ const defaultPlaceholders = [
default_value: "",
type: 0,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -221,6 +256,7 @@ const defaultPlaceholders = [
default_value: "",
type: 0,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
},
{
@@ -229,6 +265,7 @@ const defaultPlaceholders = [
default_value: "",
type: 1,
is_default: "1",
+ is_dynamic: "0",
enabled: 1,
}
];
@@ -269,6 +306,7 @@ export async function setCustomPlaceholders(placeholders) {
placeholders.forEach(ph => {
ph.id = placeholdersUtils.validateCustomDataPH_ID(ph.id);
ph.is_default = "0";
+ ph.is_dynamic = "0";
});
await browser.storage.local.set({_custom_placeholder: placeholders});
}
@@ -301,6 +339,14 @@ export async function prepareCustomDataPHsForImport(placeholders){
return output;
}
+export function mapPlaceholderToSuggestion(p) {
+ // console.log(">>>>>>>>>> mapPlaceholderToSuggestion p" + JSON.stringify(p));
+ return {
+ command: '{%' + p.id + (p.is_dynamic == 1 ? ':' : '') + '%}',
+ type: p.type,
+ is_dynamic: p.is_dynamic,
+ };
+}
export const placeholdersUtils = {
@@ -330,10 +376,21 @@ export const placeholdersUtils = {
// Use exec to find all matches
while ((match = regex.exec(text)) !== null) {
- const foundPH = activePHs.find(ph => ph.id === match[1].trim());
- if (foundPH) {
- matches.push(foundPH);
- }
+ // console.log(">>>>>>>>>> extractPlaceholders match: " + JSON.stringify(match));
+ const foundPH = activePHs.find(ph => ph.id === match[1].trim() || (ph.is_dynamic == 1 && match[1].startsWith(ph.id + ':')));
+ if (foundPH) {
+ if (foundPH.is_dynamic == 1 && match[1].includes(':')) {
+ const [id, custom_value] = match[1].split(':', 2);
+ const dynamicPH = { ...foundPH }; // Create a copy to avoid modifying the original
+ dynamicPH.id = id.trim();
+ dynamicPH.custom_value = custom_value.trim();
+ matches.push(dynamicPH);
+ // console.log(">>>>>>>>>> extractPlaceholders dynamicPH: " + JSON.stringify(dynamicPH));
+ } else {
+ matches.push(foundPH);
+ // console.log(">>>>>>>>>> extractPlaceholders foundPH: " + JSON.stringify(foundPH));
+ }
+ }
}
return matches;
@@ -346,13 +403,17 @@ export const placeholdersUtils = {
use_default_value = false,
skip_additional_text = false
} = args || {};
+ // console.log(">>>>>>>>>> replacePlaceholders replacements: " + JSON.stringify(replacements));
// Regular expression to match patterns like {%...%}
return text.replace(/{%\s*(.*?)\s*%}/g, function(match, p1) {
+ // console.log(">>>>>>>>>> replacePlaceholders match: " + JSON.stringify(match));
+ // console.log(">>>>>>>>>> replacePlaceholders p1: " + JSON.stringify(p1));
// p1 contains the key inside {% %}
if (skip_additional_text && (p1 === 'additional_text')) {
return match;
}
- const currPlaceholder = defaultPlaceholders.find(ph => ph.id === p1);
+ const currPlaceholder = defaultPlaceholders.find(ph => (ph.id === p1) || (ph.is_dynamic == 1 && p1.startsWith(ph.id + ':')));
+ // console.log(">>>>>>>>>> replacePlaceholders currPlaceholder: " + JSON.stringify(currPlaceholder));
if (!currPlaceholder) {
return match;
}
@@ -424,6 +485,7 @@ export const placeholdersUtils = {
// console.log(">>>>>>>>>> curr_message: " + JSON.stringify(curr_message));
let finalSubs = {};
for(let currPH of currPHs){
+ // console.log(">>>>>>>>>> currPH: " + JSON.stringify(currPH));
switch(currPH.id){
case 'mail_text_body':
finalSubs['mail_text_body'] = placeholdersUtils.failSafePlaceholders(body_text);
@@ -446,6 +508,9 @@ export const placeholdersUtils = {
case 'mail_folder_path':
finalSubs['mail_folder_path'] = placeholdersUtils.failSafePlaceholders(curr_message.folder?.path);
break;
+ case 'mail_headers':
+ finalSubs['mail_headers:' + currPH.custom_value] = placeholdersUtils.failSafePlaceholders(await getMailHeader(curr_message, currPH.custom_value));
+ break;
case 'selected_text':
finalSubs['selected_text'] = placeholdersUtils.failSafePlaceholders(selection_text);
break;
@@ -506,7 +571,7 @@ export const placeholdersUtils = {
break;
}
}
-
+ // console.log(">>>>>>>>>> finalSubs: " + JSON.stringify(finalSubs));
return finalSubs;
},
@@ -516,6 +581,6 @@ export const placeholdersUtils = {
return '';
}
return element;
- }
+ },
-}
+}
\ No newline at end of file
diff --git a/js/mzta-prompts.js b/js/mzta-prompts.js
index b6db041a..b598cbce 100644
--- a/js/mzta-prompts.js
+++ b/js/mzta-prompts.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -75,11 +75,11 @@
API Connection Type
: api type
- API Model
- : api model
-
+ << All the API settings defined in the default options, with the same IDs. >>
*/
+import { integration_options_config } from "../../options/mzta-options-default.js";
+
const defaultPrompts = [
{
id: 'prompt_reply',
@@ -96,7 +96,6 @@ const defaultPrompts = [
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
api_type: '',
- api_model: '',
is_default: "1",
is_special: "0",
},
@@ -115,7 +114,6 @@ const defaultPrompts = [
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
api_type: '',
- api_model: '',
is_default: "1",
is_special: "0",
},
@@ -134,7 +132,6 @@ const defaultPrompts = [
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
api_type: '',
- api_model: '',
is_default: "1",
is_special: "0",
},
@@ -153,7 +150,6 @@ const defaultPrompts = [
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
api_type: '',
- api_model: '',
is_default: "1",
is_special: "0",
},
@@ -172,7 +168,6 @@ const defaultPrompts = [
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
api_type: '',
- api_model: '',
is_default: "1",
is_special: "0",
},
@@ -191,7 +186,6 @@ const defaultPrompts = [
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
api_type: '',
- api_model: '',
is_default: "1",
is_special: "0",
},
@@ -210,7 +204,6 @@ const defaultPrompts = [
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
api_type: '',
- api_model: '',
is_default: "1",
is_special: "0",
},
@@ -229,7 +222,6 @@ const defaultPrompts = [
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
api_type: '',
- api_model: '',
is_default: "1",
is_special: "0",
},
@@ -248,7 +240,6 @@ const defaultPrompts = [
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
api_type: '',
- api_model: '',
is_default: "1",
is_special: "0",
},
@@ -267,7 +258,6 @@ const defaultPrompts = [
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
api_type: '',
- api_model: '',
is_default: "1",
is_special: "0",
},
@@ -286,7 +276,6 @@ const specialPrompts = [
define_response_lang: "0",
use_diff_viewer: "0",
api_type: '',
- api_model: '',
is_default: "1",
is_special: "1",
},
@@ -302,7 +291,6 @@ const specialPrompts = [
define_response_lang: "0",
use_diff_viewer: "0",
api_type: '',
- api_model: '',
is_default: "1",
is_special: "1",
},
@@ -318,7 +306,6 @@ const specialPrompts = [
define_response_lang: "0",
use_diff_viewer: "0",
api_type: '',
- api_model: '',
is_default: "1",
is_special: "1",
},
@@ -334,7 +321,6 @@ const specialPrompts = [
define_response_lang: "0",
use_diff_viewer: "0",
api_type: '',
- api_model: '',
is_default: "1",
is_special: "1",
},
@@ -440,7 +426,6 @@ async function getDefaultPrompts_withProps() {
prompt.chatgpt_web_project = prefs._default_prompts_properties[prompt.id].chatgpt_web_project;
prompt.chatgpt_web_custom_gpt = (prefs._default_prompts_properties[prompt.id]?.chatgpt_web_custom_gpt || '').trim();
prompt.api_type = (prefs._default_prompts_properties[prompt.id]?.api_type || '').trim();
- prompt.api_model = (prefs._default_prompts_properties[prompt.id]?.api_model || '').trim();
}else{
prompt.position_display = pos;
prompt.position_compose = pos;
@@ -450,6 +435,7 @@ async function getDefaultPrompts_withProps() {
})
// console.log('>>>>>>>>>>>> getDefaultPrompts_withProps [prop saved] defaultPrompts_prop: ' + JSON.stringify(defaultPrompts_prop));
}
+ // console.log('>>>>>>>>>>>> getDefaultPrompts_withProps [final] defaultPrompts_prop: ' + JSON.stringify(defaultPrompts_prop));
return defaultPrompts_prop;
}
@@ -475,9 +461,6 @@ async function getCustomPrompts() {
if(prompt.api_type === undefined){
prompt.api_type = "";
}
- if(prompt.api_model === undefined){
- prompt.api_model = "";
- }
});
return prefs._custom_prompt;
}
@@ -495,7 +478,6 @@ export async function setDefaultPromptsProperties(prompts) {
chatgpt_web_project: (prompt.chatgpt_web_project === undefined || prompt.chatgpt_web_project === "undefined") ? "" : prompt.chatgpt_web_project,
chatgpt_web_custom_gpt: (prompt.chatgpt_web_custom_gpt === undefined || prompt.chatgpt_web_custom_gpt === "undefined") ? "" : prompt.chatgpt_web_custom_gpt,
api_type: (prompt.api_type === undefined || prompt.api_type === "undefined") ? "" : prompt.api_type,
- api_model: (prompt.api_model === undefined || prompt.api_model === "undefined") ? "" : prompt.api_model
};
});
//console.log('>>>>>>>>>>>>>> default_prompts_properties: ' + JSON.stringify(default_prompts_properties));
@@ -503,6 +485,7 @@ export async function setDefaultPromptsProperties(prompts) {
}
export async function setCustomPrompts(prompts) {
+ // console.log(">>>>>>>>>>>> setCustomPrompts prompts: " + JSON.stringify(prompts));
await browser.storage.local.set({_custom_prompt: prompts});
}
@@ -555,7 +538,7 @@ export async function savePrompt(prompt) {
throw new Error("Invalid prompt: " + JSON.stringify(prompt));
}
// Special Prompt
- if (prompt.is_special === "1") {
+ if ((prompt.is_special === "1")||(prompt.is_special === 1)) {
let specialPrompts = await getSpecialPrompts();
let index = specialPrompts.findIndex(p => p.id === prompt.id);
if (index === -1) {
@@ -567,7 +550,7 @@ export async function savePrompt(prompt) {
return;
}
// Custom Prompt
- if (prompt.is_default === "0") {
+ if ((prompt.is_default === "0")||(prompt.is_default === 0)) {
let customPrompts = await getCustomPrompts();
let index = customPrompts.findIndex(p => p.id === prompt.id);
if (index === -1) {
@@ -575,9 +558,10 @@ export async function savePrompt(prompt) {
} else {
customPrompts[index] = prompt;
}
+ // console.log(">>>>>>>>>>>> savePrompt customPrompts: " + JSON.stringify(customPrompts));
await setCustomPrompts(customPrompts);
} else { // Default Prompt
- let defaultPrompts = getDefaultPrompts_withProps();
+ let defaultPrompts = await getDefaultPrompts_withProps();
let index = defaultPrompts.findIndex(p => p.id === prompt.id);
if (index === -1) {
defaultPrompts.push(prompt);
@@ -590,7 +574,17 @@ export async function savePrompt(prompt) {
export async function clearPromptAPI(id){
let _prompt = await loadPrompt(id);
- _prompt.api = "";
- _prompt.model = "";
+ // console.log(">>>>>>>>>>>>> clearPromptAPI _prompt BEFORE: " + JSON.stringify(_prompt));
+ _prompt.api_type = "";
+ // Reset all integration-specific settings to their default values
+ for (const [integration, options] of Object.entries(integration_options_config)) {
+ for (const key of Object.keys(options)) {
+ const propName = `${integration}_${key}`;
+ if (_prompt.hasOwnProperty(propName)) {
+ _prompt[propName] = '';
+ }
+ }
+ }
+ // console.log(">>>>>>>>>>>>> clearPromptAPI _prompt AFTER: " + JSON.stringify(_prompt));
await savePrompt(_prompt);
}
\ No newline at end of file
diff --git a/js/mzta-spamreport.js b/js/mzta-spamreport.js
index abfaae83..99b4efc5 100644
--- a/js/mzta-spamreport.js
+++ b/js/mzta-spamreport.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/js/mzta-special-commands.js b/js/mzta-special-commands.js
index 0bbab812..716b232e 100644
--- a/js/mzta-special-commands.js
+++ b/js/mzta-special-commands.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,7 +17,10 @@
*/
// Call the API to use a special prompt
- import { prefs_default } from "../options/mzta-options-default.js";
+ import {
+ prefs_default,
+ integration_options_config
+ } from "../options/mzta-options-default.js";
import { taLogger } from './mzta-logger.js';
export class mzta_specialCommand {
@@ -25,135 +28,96 @@
prompt = "";
worker = null;
llm = "";
- custom_model = "";
full_message = "";
logger = null;
do_debug = false;
+ config = {};
constructor(args = {}) {
let {
prompt = '',
llm = '',
- custom_model = '',
- do_debug = false
+ do_debug = false,
+ config = {}
} = args;
this.prompt = prompt;
this.llm = llm;
- this.custom_model = custom_model;
- this.logger = new taLogger('mzta_specialCommand', do_debug);
+ this.config = config;
this.do_debug = do_debug;
- switch (this.llm) {
- case "chatgpt_api":
- this.worker = new Worker(new URL('./workers/model-worker-openai.js', import.meta.url), { type: 'module' });
- break;
- case "google_gemini_api":
- this.worker = new Worker(new URL('./workers/model-worker-google_gemini.js', import.meta.url), { type: 'module' });
- break;
- case "ollama_api":
- this.worker = new Worker(new URL('./workers/model-worker-ollama.js', import.meta.url), { type: 'module' });
- break;
- case "openai_comp_api":
- this.worker = new Worker(new URL('./workers/model-worker-openai_comp.js', import.meta.url), { type: 'module' });
- break;
- case "anthropic_api":
- this.worker = new Worker(new URL('./workers/model-worker-anthropic.js', import.meta.url), { type: 'module' });
- break;
- default:
- this.logger.log("Invalid LLM type: " + this.llm);
- throw new Error("Invalid LLM type: " + this.llm);
+ this.logger = new taLogger('mzta_specialCommand', do_debug);
+
+ const worker_path_map = {
+ chatgpt_api: './workers/model-worker-openai_responses.js',
+ google_gemini_api: './workers/model-worker-google_gemini.js',
+ ollama_api: './workers/model-worker-ollama.js',
+ openai_comp_api: './workers/model-worker-openai_comp.js',
+ anthropic_api: './workers/model-worker-anthropic.js',
+ };
+
+ const worker_path = worker_path_map[this.llm];
+ if (worker_path) {
+ this.worker = new Worker(new URL(worker_path, import.meta.url), { type: 'module' });
+ } else {
+ this.logger.log("Invalid LLM type: " + this.llm);
+ throw new Error("Invalid LLM type: " + this.llm);
}
}
async initWorker() {
- // console.log((">>>>>>>>>>>> this.custom_model: " + this.custom_model));
- switch (this.llm) {
- case "chatgpt_api": {
- let prefs_api = await browser.storage.sync.get({
- chatgpt_api_key: prefs_default.chatgpt_api_key,
- chatgpt_model: prefs_default.chatgpt_model,
- chatgpt_developer_messages: prefs_default.chatgpt_developer_messages,
- });
- this.worker.postMessage({
- type: 'init',
- chatgpt_api_key: prefs_api.chatgpt_api_key,
- chatgpt_model: this.custom_model != '' ? this.custom_model : prefs_api.chatgpt_model,
- chatgpt_developer_messages: prefs_api.chatgpt_developer_messages,
- do_debug: this.do_debug,
- i18nStrings: ''
- });
- break;
- }
- case "google_gemini_api": {
- let prefs_api = await browser.storage.sync.get({
- google_gemini_api_key: prefs_default.google_gemini_api_key,
- google_gemini_model: prefs_default.google_gemini_model,
- google_gemini_system_instruction: prefs_default.google_gemini_system_instruction,
- google_gemini_thinking_budget: prefs_default.google_gemini_thinking_budget,
- });
- this.worker.postMessage({
- type: 'init',
- google_gemini_api_key: prefs_api.google_gemini_api_key,
- google_gemini_model: this.custom_model != '' ? this.custom_model : prefs_api.google_gemini_model,
- google_gemini_system_instruction: prefs_api.google_gemini_system_instruction,
- google_gemini_thinking_budget: prefs_api.google_gemini_thinking_budget,
- do_debug: this.do_debug,
- i18nStrings: ''
- });
- break;
- }
- case "ollama_api": {
- let prefs_api = await browser.storage.sync.get({
- ollama_host: prefs_default.ollama_host,
- ollama_model: prefs_default.ollama_model,
- });
- this.worker.postMessage({
- type: 'init',
- ollama_host: prefs_api.ollama_host,
- ollama_model: this.custom_model != '' ? this.custom_model : prefs_api.ollama_model,
- do_debug: this.do_debug,
- i18nStrings: ''
- });
- break;
- }
- case "openai_comp_api": {
- let prefs_api = await browser.storage.sync.get({
- openai_comp_host: prefs_default.openai_comp_host,
- openai_comp_model: prefs_default.openai_comp_model,
- openai_comp_api_key: prefs_default.openai_comp_api_key,
- openai_comp_use_v1: prefs_default.openai_comp_use_v1,
- openai_comp_chat_name: prefs_default.openai_comp_chat_name,
- do_debug: prefs_default.do_debug,
- });
- this.worker.postMessage({
- type: 'init',
- openai_comp_host: prefs_api.openai_comp_host,
- openai_comp_model: this.custom_model != '' ? this.custom_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: this.do_debug,
- i18nStrings: ''
- });
- break;
- }
- case "anthropic_api": {
- let prefs_api = await browser.storage.sync.get({
- anthropic_api_key: prefs_default.anthropic_api_key,
- anthropic_model: prefs_default.anthropic_model,
- anthropic_version: prefs_default.anthropic_version,
- anthropic_max_tokens: prefs_default.anthropic_max_tokens,
- });
- this.worker.postMessage({
- type: 'init',
- anthropic_api_key: prefs_api.anthropic_api_key,
- anthropic_model: this.custom_model != '' ? this.custom_model : prefs_api.anthropic_model,
- anthropic_version: prefs_api.anthropic_version,
- anthropic_max_tokens: prefs_api.anthropic_max_tokens,
- do_debug: this.do_debug,
- i18nStrings: ''
- });
- break;
- }
+ let integration = this.llm.replace('_api', '');
+ let use_specific_api = false;
+
+ this.logger.log("integration: " + integration);
+
+ if (this.config.api_type && this.config.api_type !== '') {
+ integration = this.config.api_type.replace('_api', '');
+ use_specific_api = true;
+ this.logger.log("use_specific_api: " + use_specific_api);
+ this.logger.log("specific integration: " + integration);
}
+ const options_config = integration_options_config[integration];
+
+ if (!options_config) {
+ this.logger.error("Invalid integration type: " + integration);
+ throw new Error("Invalid integration type: " + integration);
+ }
+
+ const prefsToGet = {};
+ const configKeys = Object.keys(options_config);
+
+ for (const key of configKeys) {
+ const prefKey = `${integration}_${key}`;
+ prefsToGet[prefKey] = prefs_default[prefKey];
+ }
+
+ const prefs_api = await browser.storage.sync.get(prefsToGet);
+
+ let workerInitMessage = {
+ type: 'init',
+ do_debug: this.do_debug,
+ i18nStrings: ''
+ };
+
+ for (const key of configKeys) {
+ const prefKey = `${integration}_${key}`;
+ let value = prefs_api[prefKey];
+
+ if(use_specific_api){
+ const configValue = this.config[prefKey];
+
+ if (configValue !== undefined) {
+ if (typeof options_config[key] === 'boolean') {
+ value = (configValue === true || configValue === 'true' || configValue === 1);
+ } else {
+ value = configValue;
+ }
+ }
+ }
+
+ workerInitMessage[prefKey] = value;
+ }
+
+ this.worker.postMessage(workerInitMessage);
}
sendPrompt(){
diff --git a/js/mzta-store.js b/js/mzta-store.js
index 1b4e3f6c..5729aa4e 100644
--- a/js/mzta-store.js
+++ b/js/mzta-store.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/js/mzta-utils-prompt.js b/js/mzta-utils-prompt.js
index 896f6406..c19499f8 100644
--- a/js/mzta-utils-prompt.js
+++ b/js/mzta-utils-prompt.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -50,7 +50,9 @@ export const taPromptUtils = {
if(!placeholdersUtils.hasPlaceholder(curr_prompt.text)){
// no placeholders, do as usual
- fullPrompt = curr_prompt.text + (String(curr_prompt.need_signature) == "1" ? " " + await taPromptUtils.getDefaultSignature():"") + " " + chatgpt_lang + " \"" + (selection_text=='' ? body_text : selection_text) + "\" ";
+ const signature = String(curr_prompt.need_signature) === "1" ? await taPromptUtils.getDefaultSignature() : "";
+ const content = selection_text || body_text;
+ fullPrompt = [curr_prompt.text, signature, chatgpt_lang, content ? `"${content}"` : ""].filter(Boolean).join(" ");
}else{
// we have at least a placeholder, do the magic!
// check if we have custom placeholders
diff --git a/js/mzta-utils.js b/js/mzta-utils.js
index 24cb954c..67ce0823 100644
--- a/js/mzta-utils.js
+++ b/js/mzta-utils.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
* along with this program. If not, see .
*/
-import { prefs_default } from '../options/mzta-options-default.js';
+import { prefs_default, getDynamicSettingValue } from '../options/mzta-options-default.js';
const sparks_min = '1.2.0'; // Minimum version of ThunderAI-Sparks required for the add-on to work
export const ChatGPTWeb_models = ['gpt-5','gpt-5-instant','gpt-5-t-mini','gpt-5-thinking']; // List of models available in ChatGPT Web
@@ -189,6 +189,17 @@ export async function replaceBody(tabId, replyHtml) {
await messenger.compose.setComposeDetails(tabId, {body: fullBody});
}
+export async function getMailHeader(curr_message, mail_header_id) {
+ let mail_header_value = "";
+ let full_message = await browser.messages.getFull(curr_message.id);
+ // console.log(">>>>>>>>>>>> getMailHeader full_message: " + JSON.stringify(full_message));
+ if(full_message.hasOwnProperty("headers") && Object.keys(full_message.headers).some(header => header.toLowerCase() === mail_header_id.toLowerCase())){
+ mail_header_value = full_message.headers[Object.keys(full_message.headers).find(header => header.toLowerCase() === mail_header_id.toLowerCase())];
+ }
+ // console.log(">>>>>>>>>>>> getMailHeader mail_header_value: " + mail_header_value)
+ return mail_header_value;
+}
+
export function sanitizeHtml(input) {
// Keep only tags and remove all other HTML tags
return input.replace(/<(?!br\s*\/?)[^>]+>/gi, '');
@@ -397,10 +408,11 @@ export async function createTag(tag) {
let prefs_tag = await browser.storage.sync.get({ add_tags_first_uppercase: prefs_default.add_tags_first_uppercase });
if(prefs_tag.add_tags_first_uppercase) tag = tag.toLowerCase().charAt(0).toUpperCase() + tag.toLowerCase().slice(1);
try {
+ const tagKey = '$ta-' + generateCallID(16) + '-' + sanitizeString(tag); // Ensure uniqueness with a longer random ID
if(await isThunderbird128OrGreater()) {
- return browser.messages.tags.create('$ta-'+sanitizeString(tag), tag, generateHexColorForTag());
+ return browser.messages.tags.create(tagKey, tag, generateHexColorForTag());
}else{
- return browser.messages.createTag('$ta-'+sanitizeString(tag), tag, generateHexColorForTag());
+ return browser.messages.createTag(tagKey, tag, generateHexColorForTag());
}
} catch (error) {
console.error('[ThunderAI] Error creating tag:', error);
@@ -612,19 +624,28 @@ export function extractJsonObject(inputString) {
}
export function isAPIKeyValue(id){
- return id=="chatgpt_api_key" || id=="openai_comp_api_key" || id=="google_gemini_api_key" || id=="anthropic_api_key";
+ return id.endsWith('_api_key');
}
-export function getConnectionType(conntype, prompt, use_promptspecific_api = true) {
- if(!use_promptspecific_api) {
- return conntype;
- }
- // console.log(">>>>>>>>>>> getConnectionType conntype: " + conntype + " prompt: " + JSON.stringify(prompt));
- if (prompt?.api != null && prompt.api !== '') {
- return prompt.api;
- } else {
- return conntype;
- }
+export function getConnectionType(prefs, prompt, prefix = null) {
+ let defaultType = '';
+ let specificType = '';
+
+ if (prefs !== null) {
+ defaultType = prefs.connection_type;
+ if (typeof prefix === 'string' && prefix) {
+ const useSpecific = getDynamicSettingValue(prefs, prefix, 'use_specific_integration');
+ if (useSpecific) {
+ specificType = getDynamicSettingValue(prefs, prefix, 'connection_type');
+ }
+ }
+ }
+
+ if (specificType && specificType !== '') return specificType;
+ if (prompt) {
+ if (prompt.api_type && prompt.api_type !== '') return prompt.api_type;
+ }
+ return defaultType;
}
export async function checkSparksPresence() {
diff --git a/js/mzta-working-status.js b/js/mzta-working-status.js
index 9f220d0f..81f2cb76 100644
--- a/js/mzta-working-status.js
+++ b/js/mzta-working-status.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/js/tb115_segmenter/tb115_loader.js b/js/tb115_segmenter/tb115_loader.js
index 0c2fc7da..df476c7c 100644
--- a/js/tb115_segmenter/tb115_loader.js
+++ b/js/tb115_segmenter/tb115_loader.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/js/tb115_segmenter/tb115_polyfill.js b/js/tb115_segmenter/tb115_polyfill.js
index ae06b97a..6760cd9a 100644
--- a/js/tb115_segmenter/tb115_polyfill.js
+++ b/js/tb115_segmenter/tb115_polyfill.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/js/workers/model-worker-anthropic.js b/js/workers/model-worker-anthropic.js
index f750e5c8..21452ca4 100644
--- a/js/workers/model-worker-anthropic.js
+++ b/js/workers/model-worker-anthropic.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,8 +23,6 @@
import { Anthropic } from '../api/anthropic.js';
import { taLogger } from '../mzta-logger.js';
-let anthropic_api_key = null;
-let anthropic_model = '';
let anthropic = null;
let stopStreaming = false;
let i18nStrings = null;
@@ -37,16 +35,15 @@ let assistantResponseAccumulator = '';
self.onmessage = async function(event) {
if (event.data.type === 'init') {
// console.log(">>>>>>>>>>>>>> event.data: " + JSON.stringify(event.data));
- anthropic_api_key = event.data.anthropic_api_key;
- anthropic_model = event.data.anthropic_model;
- anthropic = new Anthropic({
- apiKey: anthropic_api_key,
- version: event.data.anthropic_version,
- model: anthropic_model,
- system_prompt: event.data.anthropic_system_prompt,
- max_tokens: event.data.anthropic_max_tokens,
- stream: true
- });
+ let config = { stream: true };
+ for (const key in event.data) {
+ if (key.startsWith('anthropic_')) {
+ let newKey = key.replace('anthropic_', '');
+ if (newKey === 'api_key') newKey = 'apiKey';
+ config[newKey] = event.data[key];
+ }
+ }
+ anthropic = new Anthropic(config);
do_debug = event.data.do_debug;
i18nStrings = event.data.i18nStrings;
taLog = new taLogger('model-worker-anthropic', do_debug);
diff --git a/js/workers/model-worker-google_gemini.js b/js/workers/model-worker-google_gemini.js
index cce3cf8b..efd1b9c7 100644
--- a/js/workers/model-worker-google_gemini.js
+++ b/js/workers/model-worker-google_gemini.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,8 +23,6 @@
import { GoogleGemini } from '../api/google_gemini.js';
import { taLogger } from '../mzta-logger.js';
-let google_gemini_api_key = null;
-let google_gemini_model = '';
let google_gemini = null;
let stopStreaming = false;
let i18nStrings = null;
@@ -36,15 +34,15 @@ let assistantResponseAccumulator = '';
self.onmessage = async function(event) {
if (event.data.type === 'init') {
- google_gemini_api_key = event.data.google_gemini_api_key;
- google_gemini_model = event.data.google_gemini_model;
- google_gemini = new GoogleGemini({
- apiKey: google_gemini_api_key,
- model: google_gemini_model,
- system_instruction: event.data.google_gemini_system_instruction,
- thinking_budget: event.data.google_gemini_thinking_budget,
- stream: true
- });
+ let config = { stream: true };
+ for (const key in event.data) {
+ if (key.startsWith('google_gemini_')) {
+ let newKey = key.replace('google_gemini_', '');
+ if (newKey === 'api_key') newKey = 'apiKey';
+ config[newKey] = event.data[key];
+ }
+ }
+ google_gemini = new GoogleGemini(config);
do_debug = event.data.do_debug;
i18nStrings = event.data.i18nStrings;
taLog = new taLogger('model-worker-google_gemini', do_debug);
diff --git a/js/workers/model-worker-ollama.js b/js/workers/model-worker-ollama.js
index d099cf2a..6a8d1310 100644
--- a/js/workers/model-worker-ollama.js
+++ b/js/workers/model-worker-ollama.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,9 +23,6 @@
import { Ollama } from '../api/ollama.js';
import { taLogger } from '../mzta-logger.js';
-let ollama_host = null;
-let ollama_model = '';
-let ollama_num_ctx = 0;
let ollama = null;
let stopStreaming = false;
let i18nStrings = null;
@@ -38,16 +35,14 @@ let assistantResponseAccumulator = '';
self.onmessage = async function(event) {
switch (event.data.type) {
case 'init':
- ollama_host = event.data.ollama_host;
- ollama_model = event.data.ollama_model;
- ollama_num_ctx = event.data.ollama_num_ctx;
- //console.log(">>>>>>>>>>> ollama_host: " + ollama_host);
- ollama = new Ollama({
- host: ollama_host,
- model: ollama_model,
- stream: true,
- num_ctx: ollama_num_ctx
- });
+ let config = { stream: true };
+ for (const key in event.data) {
+ if (key.startsWith('ollama_')) {
+ let newKey = key.replace('ollama_', '');
+ config[newKey] = event.data[key];
+ }
+ }
+ ollama = new Ollama(config);
do_debug = event.data.do_debug;
i18nStrings = event.data.i18nStrings;
taLog = new taLogger('model-worker-ollama', do_debug);
diff --git a/js/workers/model-worker-openai_comp.js b/js/workers/model-worker-openai_comp.js
index 333ce148..d2685500 100644
--- a/js/workers/model-worker-openai_comp.js
+++ b/js/workers/model-worker-openai_comp.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,10 +23,6 @@
import { OpenAIComp } from '../api/openai_comp.js';
import { taLogger } from '../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;
@@ -38,17 +34,15 @@ let assistantResponseAccumulator = '';
self.onmessage = async function(event) {
if (event.data.type === 'init') {
- 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_use_v1 = event.data.openai_comp_use_v1;
- openai_comp = new OpenAIComp({
- host: openai_comp_host,
- model: openai_comp_model,
- apiKey: openai_comp_api_key,
- stream: true,
- use_v1: openai_comp_use_v1
- });
+ let config = { stream: true };
+ for (const key in event.data) {
+ if (key.startsWith('openai_comp_')) {
+ let newKey = key.replace('openai_comp_', '');
+ if (newKey === 'api_key') newKey = 'apiKey';
+ config[newKey] = event.data[key];
+ }
+ }
+ openai_comp = new OpenAIComp(config);
do_debug = event.data.do_debug;
i18nStrings = event.data.i18nStrings;
taLog = new taLogger('model-worker-openai_comp', do_debug);
diff --git a/js/workers/model-worker-openai.js b/js/workers/model-worker-openai_responses.js
similarity index 72%
rename from js/workers/model-worker-openai.js
rename to js/workers/model-worker-openai_responses.js
index 1cd9055b..8f3189ee 100644
--- a/js/workers/model-worker-openai.js
+++ b/js/workers/model-worker-openai_responses.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,11 +20,9 @@
* The original code has been released under the Apache License, Version 2.0.
*/
-import { OpenAI } from '../api/openai.js';
+import { OpenAI } from '../api/openai_responses.js';
import { taLogger } from '../mzta-logger.js';
-let chatgpt_api_key = null;
-let chatgpt_model = '';
let openai = null;
let stopStreaming = false;
let i18nStrings = null;
@@ -33,25 +31,36 @@ let taLog = null;
let conversationHistory = [];
let assistantResponseAccumulator = '';
+let previous_response_id = null;
self.onmessage = async function(event) {
if (event.data.type === 'init') {
- chatgpt_api_key = event.data.chatgpt_api_key;
- chatgpt_model = event.data.chatgpt_model;
- openai = new OpenAI({
- apiKey: chatgpt_api_key,
- model: chatgpt_model,
- developer_messages: event.data.chatgpt_developer_messages,
- stream: true,
- store: event.data.chatgpt_api_store
- });
+ let config = { stream: true };
+ for (const key in event.data) {
+ if (key.startsWith('chatgpt_')) {
+ if (key.startsWith('chatgpt_web_')) continue; // Exclude chatgpt_web_ prefixed keys
+ let newKey = key.replace('chatgpt_', '');
+ if (newKey === 'api_key') newKey = 'apiKey';
+ config[newKey] = event.data[key];
+ }
+ }
+ openai = new OpenAI(config);
do_debug = event.data.do_debug;
i18nStrings = event.data.i18nStrings;
- taLog = new taLogger('model-worker-openai', do_debug);
+ taLog = new taLogger('model-worker-openai_responses', do_debug);
+ previous_response_id = null;
} else if (event.data.type === 'chatMessage') {
conversationHistory.push({ role: 'user', content: event.data.message });
- const response = await openai.fetchResponse(conversationHistory); //4096);
+ let messagesToSend = conversationHistory;
+ if (previous_response_id) {
+ messagesToSend = [conversationHistory[conversationHistory.length - 1]];
+ taLog.log("previous_response_id: " + previous_response_id);
+ } else {
+ taLog.log("no previous_response_id");
+ }
+
+ const response = await openai.fetchResponse(messagesToSend, 0, previous_response_id);
postMessage({ type: 'messageSent' });
if (!response.ok) {
@@ -102,9 +111,10 @@ self.onmessage = async function(event) {
let parsedLines = [];
try{
parsedLines = lines
+ .map((line) => line.trim())
+ .filter((line) => line.startsWith("data:"))
.map((line) => line.replace(/^data: /, "").trim()) // Remove the "data: " prefix
.filter((line) => line !== "" && line !== "[DONE]") // Remove empty lines and "[DONE]"
- // .map((line) => JSON.parse(line)); // Parse the JSON string
.map((line) => {
try {
taLog.log("line: " + JSON.stringify(line));
@@ -120,13 +130,13 @@ self.onmessage = async function(event) {
}
for (const parsedLine of parsedLines) {
- const { choices } = parsedLine;
- const { delta } = choices[0];
- const { content } = delta;
- // Update the UI with the new content
- if (content) {
- assistantResponseAccumulator += content;
- postMessage({ type: 'newToken', payload: { token: content } });
+ if (parsedLine.type === 'response.created' && parsedLine.response && parsedLine.response.id){
+ previous_response_id = parsedLine.response.id;
+ } else if (parsedLine.type === 'response.output_text.delta' && parsedLine.delta) {
+ assistantResponseAccumulator += parsedLine.delta;
+ postMessage({ type: 'newToken', payload: { token: parsedLine.delta } });
+ // } else if (parsedLine.type === 'response.completed' && parsedLine.response && parsedLine.response.id) {
+ // previous_response_id = parsedLine.response.id;
}
}
}
diff --git a/manifest.json b/manifest.json
index 4985fbf3..5128f779 100644
--- a/manifest.json
+++ b/manifest.json
@@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "ThunderAI",
"description": "__MSG_extensionDescription__",
- "version": "3.7.9",
+ "version": "3.8.0pre4",
"author": "Mic (m@micz.it)",
"homepage_url": "https://micz.it/thunderbird-addon-thunderai/",
"browser_specific_settings": {
diff --git a/mzta-background.js b/mzta-background.js
index e1d63747..e2161b66 100644
--- a/mzta-background.js
+++ b/mzta-background.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,7 +17,11 @@
*/
import { mzta_script } from './js/mzta-chatgpt.js';
-import { prefs_default } from './options/mzta-options-default.js';
+import {
+ prefs_default,
+ getDynamicSettingValue,
+ getDynamicSettingsDefaults
+} from './options/mzta-options-default.js';
import { mzta_Menus } from './js/mzta-menus.js';
import { taLogger } from './js/mzta-logger.js';
import {
@@ -367,6 +371,9 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_
prefs = checkScreenDimensions(prefs);
//console.log(">>>>>>>>>>>>>>>> prefs: " + JSON.stringify(prefs));
// console.log(">>>>>>>>>>>>>>>> prompt_info: " + JSON.stringify(prompt_info));
+
+ prefs.connection_type = getConnectionType(prefs, prompt_info);
+
taLog.log("Prompt length: " + promptText.length);
let _max_prompt_length = prefs.max_prompt_length;
if(prefs.connection_type == 'chatgpt_web'){
@@ -799,10 +806,7 @@ async function reload_pref_init(){
dynamic_menu_force_enter: prefs_default.dynamic_menu_force_enter,
add_tags_context_menu: prefs_default.add_tags_context_menu,
spamfilter_context_menu: prefs_default.spamfilter_context_menu,
- add_tags_use_specific_integration: prefs_default.add_tags_use_specific_integration,
- add_tags_connection_type: prefs_default.add_tags_connection_type,
- spamfilter_use_specific_integration: prefs_default.spamfilter_use_specific_integration,
- spamfilter_connection_type: prefs_default.spamfilter_connection_type
+ ...getDynamicSettingsDefaults(['use_specific_integration', 'connection_type'])
});
_process_incoming = prefs_init.add_tags_auto || prefs_init.spamfilter;
_sparks_presence = await checkSparksPresence();
@@ -1034,11 +1038,10 @@ async function processEmails(messages, addTagsAuto, spamFilter) {
add_tags_auto_uselist: prefs_default.add_tags_auto_uselist,
add_tags_auto_uselist_list: prefs_default.add_tags_auto_uselist_list,
spamfilter_enabled_accounts: prefs_default.spamfilter_enabled_accounts,
- add_tags_use_specific_integration: prefs_default.add_tags_use_specific_integration,
- spamfilter_use_specific_integration: prefs_default.spamfilter_use_specific_integration,
+ ...getDynamicSettingsDefaults(['use_specific_integration', 'connection_type']),
do_debug: prefs_default.do_debug,
});
-
+ // console.log(">>>>>>>>>>>>>>>> prefs_aats: " + JSON.stringify(prefs_aats));
for await (let message of messages) {
let curr_fullMessage = null;
let msg_text = null;
@@ -1080,11 +1083,13 @@ async function processEmails(messages, addTagsAuto, spamFilter) {
specialFullPrompt_add_tags = taPromptUtils.finalizePrompt_add_tags(specialFullPrompt_add_tags, prefs_aats.add_tags_maxnum, prefs_aats.add_tags_force_lang, prefs_aats.default_chatgpt_lang, prefs_aats.add_tags_auto_uselist, prefs_aats.add_tags_auto_uselist_list);
taLog.log("Special prompt: " + specialFullPrompt_add_tags);
// console.log(">>>>>>>>>> curr_prompt_add_tags.model: " + curr_prompt_add_tags.model);
+ // console.log(">>>>>>>>>>>>>>>>> getConnectionType add_tags:" + JSON.stringify(getConnectionType(prefs_aats, curr_prompt_add_tags, 'add_tags')));
let cmd_addTags = new mzta_specialCommand({
prompt: specialFullPrompt_add_tags,
- llm: getConnectionType(prefs_aats.connection_type, curr_prompt_add_tags, prefs_aats.add_tags_use_specific_integration),
+ llm: getConnectionType(prefs_aats, curr_prompt_add_tags, 'add_tags'),
custom_model: curr_prompt_add_tags.model ? curr_prompt_add_tags.model : '',
- do_debug: prefs_aats.do_debug
+ do_debug: prefs_aats.do_debug,
+ config: curr_prompt_add_tags
});
await cmd_addTags.initWorker();
let tags_current_email = [];
@@ -1121,9 +1126,10 @@ async function processEmails(messages, addTagsAuto, spamFilter) {
// console.log(">>>>>>>> Special prompt for spamfilter: " + specialFullPrompt_spamfilter);
let cmd_spamfilter = new mzta_specialCommand({
prompt: specialFullPrompt_spamfilter,
- llm: getConnectionType(prefs_aats.connection_type, curr_prompt_spamfilter, prefs_aats.spamfilter_use_specific_integration),
+ llm: getConnectionType(prefs_aats, curr_prompt_spamfilter, 'spamfilter'),
custom_model: curr_prompt_spamfilter.model ? curr_prompt_spamfilter.model : '',
- do_debug: prefs_aats.do_debug
+ do_debug: prefs_aats.do_debug,
+ config: curr_prompt_spamfilter
});
await cmd_spamfilter.initWorker();
let spamfilter_result = '';
diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js
index 6405c1a0..66b24890 100644
--- a/options/mzta-options-default.js
+++ b/options/mzta-options-default.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,86 @@
* along with this program. If not, see .
*/
+const special_prompts_with_integration = ['add_tags', 'spamfilter'];
+
+export const integration_options_config = {
+ chatgpt: {
+ api_key: '',
+ model: '',
+ developer_messages: '',
+ temperature: '',
+ store: false
+ },
+ ollama: {
+ host: '',
+ model: '',
+ num_ctx: 0,
+ temperature: '',
+ think: false
+ },
+ openai_comp: {
+ host: '',
+ model: '',
+ api_key: '',
+ use_v1: true,
+ chat_name: 'OpenAI Comp',
+ temperature: ''
+ },
+ google_gemini: {
+ api_key: '',
+ model: '',
+ system_instruction: '',
+ thinking_budget: '',
+ temperature: ''
+ },
+ anthropic: {
+ api_key: '',
+ model: '',
+ version: '2023-06-01',
+ max_tokens: 4096,
+ system_prompt: '',
+ temperature: ''
+ }
+};
+
+const integration_settings_template = {
+ use_specific_integration: false,
+ connection_type: 'chatgpt_api',
+};
+
+const global_integration_settings = { ...integration_settings_template };
+
+for (const [integration, options] of Object.entries(integration_options_config)) {
+ for (const [key, value] of Object.entries(options)) {
+ global_integration_settings[`${integration}_${key}`] = value;
+ }
+}
+
+let generated_prefs = {};
+
+special_prompts_with_integration.forEach(prompt_prefix => {
+ for (const [key, value] of Object.entries(integration_settings_template)) {
+ generated_prefs[`${prompt_prefix}_${key}`] = value;
+ }
+});
+
+export function getDynamicSettingsDefaults(keysFilter = []) {
+ let defaults = {};
+ special_prompts_with_integration.forEach(prefix => {
+ const keys = keysFilter.length > 0 ? keysFilter : Object.keys(integration_settings_template);
+ keys.forEach(key => {
+ defaults[`${prefix}_${key}`] = prefs_default[`${prefix}_${key}`];
+ });
+ });
+ return defaults;
+}
+
+export function getDynamicSettingValue(prefs, prefix, settingName) {
+ return prefs[`${prefix}_${settingName}`];
+}
+
export const prefs_default = {
+ ...global_integration_settings,
do_debug: false,
chatgpt_win_height: 800,
chatgpt_win_width: 700,
@@ -29,28 +108,6 @@ export const prefs_default = {
chatgpt_web_tempchat: false,
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
- chatgpt_api_key: '',
- chatgpt_api_store: false,
- chatgpt_model: '',
- chatgpt_developer_messages: '',
- ollama_host: '',
- ollama_model: '',
- ollama_num_ctx: 0,
- ollama_think: false,
- 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',
- google_gemini_api_key: '',
- google_gemini_model: '',
- google_gemini_system_instruction: '',
- google_gemini_thinking_budget: '',
- anthropic_api_key: '',
- anthropic_model: '',
- anthropic_version: '2023-06-01',
- anthropic_max_tokens: 4096,
- anthropic_system_prompt: '',
dynamic_menu_force_enter: false,
dynamic_menu_order_alphabet: true,
placeholders_use_default_value: false,
@@ -68,13 +125,6 @@ export const prefs_default = {
add_tags_auto_uselist_list: '',
add_tags_context_menu: true,
add_tags_enabled_accounts: [],
- add_tags_use_specific_integration: false,
- add_tags_connection_type: 'chatgpt_api',
- add_tags_chatgpt_model: '',
- add_tags_ollama_model: '',
- add_tags_openai_comp_model: '',
- add_tags_google_gemini_model: '',
- add_tags_anthropic_model: '',
get_calendar_event: true,
get_task: true,
calendar_enforce_timezone: false,
@@ -83,11 +133,5 @@ export const prefs_default = {
spamfilter_threshold: 70,
spamfilter_context_menu: true,
spamfilter_enabled_accounts: [],
- spamfilter_use_specific_integration: false,
- spamfilter_connection_type: 'chatgpt_api',
- spamfilter_chatgpt_model: '',
- spamfilter_ollama_model: '',
- spamfilter_openai_comp_model: '',
- spamfilter_google_gemini_model: '',
- spamfilter_anthropic_model: '',
+ ...generated_prefs
}
diff --git a/options/mzta-options.css b/options/mzta-options.css
index f0c21d66..86d168d1 100644
--- a/options/mzta-options.css
+++ b/options/mzta-options.css
@@ -163,6 +163,10 @@ div#miczTranslate{
color: #292929;
}
+label:has(input[type="checkbox"]) {
+ cursor: pointer;
+}
+
@media (prefers-color-scheme: dark) {
body {
background-color: rgb(35, 34, 43);
diff --git a/options/mzta-options.js b/options/mzta-options.js
index 92d2989a..16b130fd 100644
--- a/options/mzta-options.js
+++ b/options/mzta-options.js
@@ -1,6 +1,6 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
- * Copyright (C) 2024 - 2025 Mic (m@micz.it)
+ * Copyright (C) 2024 - 2026 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
* along with this program. If not, see .
*/
-import { prefs_default } from './mzta-options-default.js';
+import { prefs_default, getDynamicSettingsDefaults } from './mzta-options-default.js';
import { taLogger } from '../js/mzta-logger.js';
import {
ChatGPTWeb_models,
@@ -127,7 +127,11 @@ function disable_MaxPromptLength(){
function disable_AddTags(prefs_opt){
let add_tags = document.getElementById('add_tags');
let conntype_select = document.getElementById("connection_type");
- let add_tags_disabled = (getConnectionType(conntype_select.value, {api: prefs_opt.add_tags_use_specific_integration ? prefs_opt.add_tags_connection_type : ''}) === "chatgpt_web");
+ const tempPrefs = {
+ connection_type: conntype_select.value,
+ ...prefs_opt
+ };
+ let add_tags_disabled = (getConnectionType(tempPrefs, null, 'add_tags') === "chatgpt_web");
// console.log('>>>>>>>>>>>>> add_tags_disabled: ' + add_tags_disabled);
add_tags.checked = add_tags_disabled ? false : add_tags.checked;
let add_tags_checked_original = add_tags.checked;
@@ -145,7 +149,11 @@ function disable_AddTags(prefs_opt){
function disable_SpamFilter(prefs_opt){
let spamfilter = document.getElementById('spamfilter');
let conntype_select = document.getElementById("connection_type");
- let spamfilter_disabled = (getConnectionType(conntype_select.value, {api: prefs_opt.spamfilter_use_specific_integration ? prefs_opt.spamfilter_connection_type : ''}) === "chatgpt_web");;
+ const tempPrefs = {
+ connection_type: conntype_select.value,
+ ...prefs_opt
+ };
+ let spamfilter_disabled = (getConnectionType(tempPrefs, null, 'spamfilter') === "chatgpt_web");
let spamfilter_checked_original = spamfilter.checked;
spamfilter.checked = spamfilter_disabled ? false : spamfilter.checked;
if(!spamfilter.checked){
@@ -302,10 +310,7 @@ document.addEventListener('DOMContentLoaded', async () => {
});
let prefs_opt = await browser.storage.sync.get({
- add_tags_use_specific_integration: prefs_default.add_tags_use_specific_integration,
- add_tags_connection_type: prefs_default.add_tags_connection_type,
- spamfilter_use_specific_integration: prefs_default.spamfilter_use_specific_integration,
- spamfilter_connection_type: prefs_default.spamfilter_connection_type,
+ ...getDynamicSettingsDefaults(['use_specific_integration', 'connection_type'])
});
let conntype_select = document.getElementById("connection_type");
diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html
index 11f7418b..77dbbf75 100644
--- a/options/mzta-release-notes.html
+++ b/options/mzta-release-notes.html
@@ -7,6 +7,20 @@
[All APIs] Now it is possible to define an API and its settings for any custom prompt. This allows anyone to use different AI providers for different prompts [#102].
+
[All APIs] When using special prompts (like automatically adding tags or the spam filter) with a specific API integration, all the settings for that integration can be specific. In this way you can use different api keys for the same integration, or different system prompt or temperature [#590].
+
[All APIs] Added the temperature parameter [#561].
+
[OpenAI API] Model filtering improved when choosing a model in the options page.
+
[OpenAI API] Now using the new Responses API [#407].
+
It is now possible to define a custom placeholder with dynamic data to retrieve any header present in the current email [#527].
+
[All APIs] The configuration information reported in the webchat API has been improved for all integrations.
[ChatGPT Web] Fix: Correctly getting the job completion [#607].
@@ -53,7 +67,7 @@
[All APIs] It's now possibile to define a list of tags to be used when autotagging received emails [#436]. The tags are are now shown in the information header in the AI API chat [#289].
[All APIs] The prompt id and name are now shown in the information header in the AI API chat [#436].
Added the {%mail_attachments_info%} placeholder to retrieve the name, type and file size of the mail attachments [#446].
-
[Google Gemini API]Support for the thinkingBudget parameter has been added [#494].
+
[Google Gemini API] Support for the thinkingBudget parameter has been added [#494].