Merge branch 'v4.0.0' into main
This commit is contained in:
commit
feaaac5e01
59 changed files with 7310 additions and 761 deletions
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
|
@ -36,7 +36,7 @@ body:
|
|||
attributes:
|
||||
label: Which version of Thunderbird are you using?
|
||||
description: >
|
||||
Thunderbird version like 115.14.0 or 128.1.
|
||||
Thunderbird version like 140.0 or 147.0.1.
|
||||
- type: input
|
||||
id: version
|
||||
validations:
|
||||
|
|
|
|||
|
|
@ -4,13 +4,17 @@ on:
|
|||
release:
|
||||
types: [published, edited]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
comment-milestone-issues:
|
||||
# consenti il run manuale per test; in produzione resta solo prerelease
|
||||
# allow manual run for testing; in production, only prerelease
|
||||
if: ${{ github.event.release.prerelease == true }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
|
|
|||
37
CHANGELOG.md
37
CHANGELOG.md
|
|
@ -4,7 +4,32 @@
|
|||
|
||||
|
||||
|
||||
<h2>Version 3.8.0 - ??/??/2026</h2>
|
||||
<h2>Version 4.0.0 - ??/??/2026</h2>
|
||||
<ul>
|
||||
<li>ThunderAI is now compatible only with Thunderbird 140 and later [<a href="https://github.com/micz/ThunderAI/issues/616">#616</a>].</li>
|
||||
<li><i>[All APIs]</i> It's now possibile to define a specific API integration for calendar and task recognition [<a href="https://github.com/micz/ThunderAI/issues/498">#498</a>].</li>
|
||||
<li>Added a new model selector with a search functionality to dynamically filter the list [<a href="https://github.com/micz/ThunderAI/issues/603">#603</a>].</li>
|
||||
<li><i>[All APIs]</i> Added a special prompt to summarize one or more emails, using a context menu command [<a href="https://github.com/micz/ThunderAI/issues/615">#615</a>]. Thanks to <a href="https://github.com/gdkrmr">Guido Kraemer</a> for his great work on this feature.</li>
|
||||
<li><i>[All APIs]</i> "Analyze for spam" and "Add tags" context menu items are always shown when the corresponding feature is enabled [<a href="https://github.com/micz/ThunderAI/issues/609">#609</a>].</li>
|
||||
<li><i>[OpenAI Comp API][Ollama API]</i> Asking for the single host for permission to avoid CORS errors, instead of <i>all_urls</i>, as requested by the Thunderbird Review Team [<a href="https://github.com/micz/ThunderAI/issues/524">#524</a>].</li>
|
||||
<li>Fix: Using also the mail folder owner to search for the right identity to use when composing a reply [<a href="https://github.com/micz/ThunderAI/issues/627">#627</a>].</li>
|
||||
<li>Context menu items are always ordered alfabetically [<a href="https://github.com/micz/ThunderAI/issues/630">#630</a>].</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
<h2>Version 3.8.3 - 22/01/2026</h2>
|
||||
<ul>
|
||||
<li>Fix: Correctly saving the API settings in new custom prompts [<a href="https://github.com/micz/ThunderAI/issues/623">#623</a>].</li>
|
||||
<li>Japanese (ja) translation added, thanks to <a href="https://hosted.weblate.org/user/watya1/">Taichi Ito</a>.</li>
|
||||
</ul>
|
||||
<h2>Version 3.8.2 - 20/01/2026</h2>
|
||||
<ul>
|
||||
<li>Fix: Correctly saving the enabled status in custom prompts [<a href="https://github.com/micz/ThunderAI/issues/621">#621</a>].</li>
|
||||
</ul>
|
||||
<h2>Version 3.8.1 - 20/01/2026</h2>
|
||||
<ul>
|
||||
<li><i>[OpenAI API]</i> Fix: Correctly sending the prompt after opening the chat window [<a href="https://github.com/micz/ThunderAI/issues/620">#620</a>].</li>
|
||||
</ul>
|
||||
<h2>Version 3.8.0 - 16/01/2026</h2>
|
||||
<ul>
|
||||
<li><i>[All APIs]</i> 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 [<a href="https://github.com/micz/ThunderAI/pull/102">#102</a>].</li>
|
||||
<li><i>[All APIs]</i> 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 [<a href="https://github.com/micz/ThunderAI/pull/590">#590</a>].</li>
|
||||
|
|
@ -16,7 +41,10 @@
|
|||
<li>Spanish (es) translation added, thanks to <a href="https://hosted.weblate.org/user/gerardo.sobarzo/">Gerardo Sobarzo</a>, <a href="https://hosted.weblate.org/user/arendon/">Andrés Rendón Hernández</a>, <a href="https://hosted.weblate.org/user/ErickLimonG/">Erick Limon</a>.</li>
|
||||
<li>Swedish (sv) translation added, thanks to <a href="https://hosted.weblate.org/user/Andy_tb/">Andreas Pettersson</a>.</li>
|
||||
<li>Various fixes.</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
<h2>Version 3.7.9 - 06/01/2026</h2>
|
||||
<ul>
|
||||
<li><i>[ChatGPT Web]</i> Fix: Correctly getting the job completion [<a href="https://github.com/micz/ThunderAI/issues/607">#607</a>].</li>
|
||||
</ul>
|
||||
<h2>Version 3.7.8 - 18/12/2025</h2>
|
||||
<ul>
|
||||
|
|
@ -59,8 +87,9 @@
|
|||
<ul>
|
||||
<li><i>[All APIs]</i> It's now possibile to define a list of tags to be used when autotagging received emails [<a href="https://github.com/micz/ThunderAI/issues/436">#436</a>]. The tags are are now shown in the information header in the AI API chat [<a href="https://github.com/micz/ThunderAI/issues/289">#289</a>].</li>
|
||||
<li><i>[All APIs]</i> The prompt id and name are now shown in the information header in the AI API chat [<a href="https://github.com/micz/ThunderAI/issues/436">#436</a>].</li>
|
||||
<li><i>[All APIs]</i> It's now possibile to define a specific API integration for spamfilter and auto tagging [<a href="https://github.com/micz/ThunderAI/issues/438">#438</a>].</li>
|
||||
<li>Added the <i>{%mail_attachments_info%}</i> placeholder to retrieve the name, type and file size of the mail attachments [<a href="https://github.com/micz/ThunderAI/issues/446">#446</a>].</li>
|
||||
<li><i>[Google Gemini API]</i>Support for the thinkingBudget parameter has been added [<a href="https://github.com/micz/ThunderAI/issues/494">#494</a>].</li>
|
||||
<li><i>[Google Gemini API]</i> Support for the thinkingBudget parameter has been added [<a href="https://github.com/micz/ThunderAI/issues/494">#494</a>].</li>
|
||||
<li><i>[OpenAI Comp API]</i> Added DeepSeek configuration [<a href="https://github.com/micz/ThunderAI/issues/486">#486</a>].</li>
|
||||
<li><i>[ChatGPT Web]</i> Added a message to explain to click on "Force completion" if the ChatGPT job is not done after 7 seconds [<a href="https://github.com/micz/ThunderAI/issues/419">#419</a>].</li>
|
||||
<li>Anthropic API renamed to Claude API [<a href="https://github.com/micz/ThunderAI/issues/510">#510</a>].</li>
|
||||
|
|
@ -394,7 +423,7 @@
|
|||
<li>Added a better error message when there is an error fetching models.</li>
|
||||
<li>When selecting a correct model in the options page, the field is no more highlighted in red [<a href="https://github.com/micz/ThunderAI/issues/100">#100</a>].</li>
|
||||
<li>When using the ChatGPT API, the double quotes at the beginning and end of the response are removed [<a href="https://github.com/micz/ThunderAI/issues/99">#99</a>].</li>
|
||||
<li><i>[ChatGPT Web]</i>"Keep formatting" option removed.</li>
|
||||
<li><i>[ChatGPT Web]</i> "Keep formatting" option removed.</li>
|
||||
</ul>
|
||||
<h2>Version 2.0.1 - 09/08/2024</h2>
|
||||
<ul>
|
||||
|
|
|
|||
36
GEMINI.md
Normal file
36
GEMINI.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# ThunderAI Project Agent Context
|
||||
|
||||
## Project Overview
|
||||
ThunderAI is a Mozilla Thunderbird add-on that integrates Large Language Models (LLMs) such as ChatGPT, Gemini, Claude, and Ollama for advanced email management. It allows users to analyze, draft, correct, tag, and create calendar events directly from the email client.
|
||||
|
||||
## Technical Stack
|
||||
- **Languages:** JavaScript (ES6+), HTML5, CSS3.
|
||||
- **Environment:** Thunderbird MailExtension API (based on WebExtensions).
|
||||
- **Core Logic:** Primarily located in `background.js` and UI-specific scripts.
|
||||
- **API Integrations:** Specific logic is contained within dedicated API provider files (e.g., `api_openai.js`, `api_google_gemini.js`).
|
||||
|
||||
## Development Rules & Style Guide
|
||||
- **Code Style:** Use modern JavaScript. Prefer `async/await` over chained Promises.
|
||||
- **Naming Conventions:** Use `camelCase` for variables and functions.
|
||||
- **Security:** - Never hardcode API keys in the source code.
|
||||
- Use `messenger.storage.local` for data persistence.
|
||||
- Strictly adhere to CORS policies for external API calls.
|
||||
- **i18n:**
|
||||
- The project supports multiple languages via `_locales/`. When adding UI strings, always use `messenger.i18n.getMessage()`.
|
||||
- When you need to modify language file, modify only the english version.
|
||||
|
||||
## Files & Directories Structure
|
||||
- `manifest.json`: Extension entry point and permission definitions.
|
||||
- `api_*.js`: Modules for integration with different AI providers.
|
||||
- `options/`: Configuration and settings pages.
|
||||
- `_locales/`: Translation files (JSON format).
|
||||
- `graphics/`: Visual assets and icons.
|
||||
|
||||
## Important Commands & Workflow
|
||||
- **Testing:** Since this is a Thunderbird add-on, testing is performed by loading the extension as a "Temporary Add-on" via Thunderbird's `Debug Add-ons` menu.
|
||||
- **Build:** The project does not use complex build tools (no Webpack/Vite by default); it is a "pure" MailExtension.
|
||||
|
||||
## Agent Instructions
|
||||
1. **Context Awareness:** When modifying API-related files, ensure compatibility with the existing placeholder system (e.g., `{%mail_body%}`, `{%additional_text%}`).
|
||||
2. **Permission Review:** Before modifying `manifest.json`, verify that any new permissions requested are strictly necessary for the feature.
|
||||
3. **Compatibility:** Ensure code is compatible with the latest Thunderbird ESR (Extended Support Release) versions.
|
||||
1
LANG.md
1
LANG.md
|
|
@ -6,6 +6,7 @@ es
|
|||
fr
|
||||
hr
|
||||
it
|
||||
ja
|
||||
pl
|
||||
pt-br
|
||||
ru
|
||||
|
|
|
|||
|
|
@ -82,13 +82,15 @@ Are you using this addon in your Thunderbird?
|
|||
## Attributions
|
||||
|
||||
### Translations
|
||||
- Chinese (Simplified): [jeklau](https://github.com/jeklau) <img src="https://micz.it/weblate/thunderai/zh_Hans.svg">
|
||||
- Chinese (Traditional): [evez](https://github.com/evez) <img src="https://micz.it/weblate/thunderai/zh_Hant.svg">
|
||||
- Chinese (Simplified) (zh_Hans): [jeklau](https://github.com/jeklau) <img src="https://micz.it/weblate/thunderai/zh_Hans.svg">
|
||||
- Chinese (Traditional) (zh_Hant): [evez](https://github.com/evez) <img src="https://micz.it/weblate/thunderai/zh_Hant.svg">
|
||||
- Croatian (hr): Petar Jedvaj <img src="https://micz.it/weblate/thunderai/hr.svg">
|
||||
- Czech (cs): [Fjuro](https://hosted.weblate.org/user/Fjuro/), [Jaroslav Staněk](https://hosted.weblate.org/user/jaroush/) <img src="https://micz.it/weblate/thunderai/cs.svg">
|
||||
- French (fr): Generated automatically, [Noam](https://github.com/noam-sc) <img src="https://micz.it/weblate/thunderai/fr.svg">
|
||||
- German (de): Generated automatically <img src="https://micz.it/weblate/thunderai/de.svg">
|
||||
- Greek (el): [ChristosK.](https://github.com/christoskaterini) <img src="https://micz.it/weblate/thunderai/el.svg">
|
||||
- Italian (it): [Mic](https://github.com/micz) <img src="https://micz.it/weblate/thunderai/it.svg">
|
||||
- Japanese (ja): [Taichi Ito](https://github.com/watya1) <img src="https://micz.it/weblate/thunderai/ja.svg">
|
||||
- Polski (pl): [neexpl](https://github.com/neexpl), [makkacprzak](https://github.com/makkacprzak) <img src="https://micz.it/weblate/thunderai/pl.svg">
|
||||
- Português Brasileiro (pt-br): Bruno Pereira de Souza <img src="https://micz.it/weblate/thunderai/pt-br.svg">
|
||||
- Russian (ru): [Maksim](https://hosted.weblate.org/user/law820314/) <img src="https://micz.it/weblate/thunderai/ru.svg">
|
||||
|
|
@ -109,6 +111,7 @@ _The language status represents the percentage of translated strings in the late
|
|||
- [JessiGue](https://www.flaticon.com/authors/jessigue) for the show/hide icon for api key fields
|
||||
- [Iconka.com](https://www.iconarchive.com/artist/iconka.html) for the autotag context menu icon
|
||||
- [Icojam](https://www.iconarchive.com/artist/icojam.html) for the spam filter context menu icon
|
||||
- [Roundicons](https://www.flaticon.com/authors/roundicons) for the summarize context menu icon
|
||||
|
||||
|
||||
<br>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
file: pages\_lib\list.js
|
||||
source: https://raw.githubusercontent.com/javve/list.js/v2.3.1/dist/list.js
|
||||
|
||||
file: pages\_lib\tom-select.base.js
|
||||
source: https://cdn.jsdelivr.net/npm/tom-select@2.4.4/dist/js/tom-select.base.js
|
||||
|
||||
file: js\lib\diff.js
|
||||
source: https://cdnjs.cloudflare.com/ajax/libs/jsdiff/7.0.0/diff.js
|
||||
|
|
@ -296,9 +296,6 @@
|
|||
"chatgpt_empty_model": {
|
||||
"message": "Nevybrali jste model pro ChatGPT API. Vyberte jej prosím na stránce s možnostmi."
|
||||
},
|
||||
"chagpt_api_connecting": {
|
||||
"message": "Pokouším se připojit k OpenAI ChatGPT pomocí poskytnutého klíče API"
|
||||
},
|
||||
"chagpt_api_send_button": {
|
||||
"message": "Používám model"
|
||||
},
|
||||
|
|
@ -335,12 +332,6 @@
|
|||
"ollama_empty_model": {
|
||||
"message": "Nevybrali jste model pro Ollama API. Prosím, vyberte jej na stránce s nastavením."
|
||||
},
|
||||
"ollama_api_connecting": {
|
||||
"message": "Pokouším se připojit k lokálnímu serveru Ollama pomocí hostitele"
|
||||
},
|
||||
"andModel": {
|
||||
"message": "a model"
|
||||
},
|
||||
"error_connection_interrupted": {
|
||||
"message": "Spojení se serverem bylo neočekávaně přerušeno"
|
||||
},
|
||||
|
|
@ -368,9 +359,6 @@
|
|||
"OpenAIComp_empty_model": {
|
||||
"message": "Nevybrali jste model pro API kompatibilní s OpenAI. Prosím, vyberte jej na stránce s nastavením."
|
||||
},
|
||||
"OpenAIComp_api_connecting": {
|
||||
"message": "Pokouším se připojit k lokálnímu serveru API kompatibilního s OpenAI pomocí hostitele"
|
||||
},
|
||||
"OpenAIComp_api_request_failed": {
|
||||
"message": "Požadavek na OpenAI Comp API selhal"
|
||||
},
|
||||
|
|
@ -479,7 +467,7 @@
|
|||
"Spam_Value": {
|
||||
"message": "Hodnota spamu"
|
||||
},
|
||||
"spamfilter_not_moved": {
|
||||
"no_string": {
|
||||
"message": "Ne"
|
||||
},
|
||||
"prefsInfoDesc_4": {
|
||||
|
|
@ -539,7 +527,7 @@
|
|||
"Date": {
|
||||
"message": "Datum"
|
||||
},
|
||||
"spamfilter_moved": {
|
||||
"yes_string": {
|
||||
"message": "Ano"
|
||||
},
|
||||
"Report_Date": {
|
||||
|
|
@ -590,9 +578,6 @@
|
|||
"GoogleGemini_Models_Fetch": {
|
||||
"message": "Aktualizovat seznam modelů Google Gemini"
|
||||
},
|
||||
"google_gemini_api_connecting": {
|
||||
"message": "Probíhá pokus o připojení ke Google Gemini pomocí zadaného API klíče"
|
||||
},
|
||||
"google_gemini_empty_apikey": {
|
||||
"message": "Nezadali jste API klíč pro Google Gemini API. Vložte jej na stránce možností."
|
||||
},
|
||||
|
|
@ -848,9 +833,6 @@
|
|||
"calendar_opening_dialog_error": {
|
||||
"message": "Chyba při otevírání dialogu události kalendáře"
|
||||
},
|
||||
"sparks_not_installed": {
|
||||
"message": "ThunderAI Sparks není nainstalován!"
|
||||
},
|
||||
"prefs_OptionText_add_tags_auto": {
|
||||
"message": "Přidávat štítky automaticky"
|
||||
},
|
||||
|
|
@ -869,18 +851,6 @@
|
|||
"context_menu_mzta-spamfilter": {
|
||||
"message": "Analýza spamu"
|
||||
},
|
||||
"prefs_OptionText_add_tags_context_menu": {
|
||||
"message": "Zobrazit v nabídce položku „Přidat štítky“"
|
||||
},
|
||||
"prefs_OptionText_spamfilter_context_menu": {
|
||||
"message": "Zobrazit v nabídce položku „Analýza spamu“"
|
||||
},
|
||||
"prefs_OptionText_spamfilter_context_menu_Info": {
|
||||
"message": "Po zaškrtnutí bude po kliknutí pravým tlačítkem na e-mail v seznamu zpráv v kontextové nabídce zobrazena položka „Analýza spamu“."
|
||||
},
|
||||
"prefs_OptionText_add_tags_context_menu_Info": {
|
||||
"message": "Po zaškrtnutí bude po kliknutí pravým tlačítkem na e-mail v seznamu zpráv v kontextové nabídce zobrazena položka „Přidat štítky“."
|
||||
},
|
||||
"get_calendar_event_prompt_prefs_title": {
|
||||
"message": "Možnosti události kalendáře"
|
||||
},
|
||||
|
|
@ -1125,12 +1095,6 @@
|
|||
"CORS_alternative_1": {
|
||||
"message": "Problémy s nastavením CORS?"
|
||||
},
|
||||
"CORS_alternative_2": {
|
||||
"message": "Stiskněte tlačítko níže a udělte oprávnění <all_urls>, abyste se vyhnuli jakýmkoli problémům s CORS."
|
||||
},
|
||||
"CORS_give_allurls_perm": {
|
||||
"message": "Udělit oprávnění \"všechny URL\""
|
||||
},
|
||||
"maybe_CORS_openai_comp": {
|
||||
"message": "Používání API kompatibilního s OpenAI může vyžadovat nastavení CORS na serveru."
|
||||
},
|
||||
|
|
|
|||
|
|
@ -327,9 +327,6 @@
|
|||
"chagpt_api_send_button": {
|
||||
"message": "Modell wird verwendet"
|
||||
},
|
||||
"chagpt_api_connecting": {
|
||||
"message": "Versuch, eine Verbindung zu OpenAI ChatGPT mit dem bereitgestellten API-Schlüssel herzustellen"
|
||||
},
|
||||
"Debug": {
|
||||
"message": "Debuggen"
|
||||
},
|
||||
|
|
@ -363,12 +360,6 @@
|
|||
"ollama_empty_model": {
|
||||
"message": "Sie haben kein Modell für die Ollama API ausgewählt. Bitte wählen Sie eines auf der Optionsseite aus."
|
||||
},
|
||||
"ollama_api_connecting": {
|
||||
"message": "Versuch, eine Verbindung zum Ollama-Lokalserver über den Host herzustellen"
|
||||
},
|
||||
"andModel": {
|
||||
"message": "und Modell"
|
||||
},
|
||||
"error_connection_interrupted": {
|
||||
"message": "Die Verbindung zum Server wurde unerwartet unterbrochen"
|
||||
},
|
||||
|
|
@ -399,9 +390,6 @@
|
|||
"OpenAIComp_empty_model": {
|
||||
"message": "Sie haben kein Modell für die OpenAI-kompatible API ausgewählt. Bitte wählen Sie eines auf der Optionsseite aus."
|
||||
},
|
||||
"OpenAIComp_api_connecting": {
|
||||
"message": "Versuche, eine Verbindung zum OpenAI-kompatiblen lokalen API-Server über den Host herzustellen"
|
||||
},
|
||||
"OpenAIComp_api_request_failed": {
|
||||
"message": "OpenAI-kompatible API-Anfrage fehlgeschlagen"
|
||||
},
|
||||
|
|
@ -681,9 +669,6 @@
|
|||
"google_gemini_api_request_failed": {
|
||||
"message": "Google Gemini API-Anfrage fehlgeschlagen"
|
||||
},
|
||||
"google_gemini_api_connecting": {
|
||||
"message": "Versuch, eine Verbindung zu Google Gemini mit dem bereitgestellten API-Schlüssel herzustellen"
|
||||
},
|
||||
"google_gemini_empty_apikey": {
|
||||
"message": "Sie haben keinen API-Schlüssel für die Google Gemini API hinzugefügt. Bitte fügen Sie einen auf der Optionsseite ein."
|
||||
},
|
||||
|
|
@ -825,18 +810,15 @@
|
|||
"Report_Date": {
|
||||
"message": "Berichtsdatum"
|
||||
},
|
||||
"spamfilter_moved": {
|
||||
"yes_string": {
|
||||
"message": "Ja"
|
||||
},
|
||||
"spamfilter_not_moved": {
|
||||
"no_string": {
|
||||
"message": "Nein"
|
||||
},
|
||||
"spamfilter_threshold_too_low": {
|
||||
"message": "Der Spam-Schwellenwert ist zu niedrig! Sie werden wahrscheinlich zu viele E-Mails als Spam markieren!"
|
||||
},
|
||||
"sparks_not_installed": {
|
||||
"message": "ThunderAI Sparks nicht installiert!"
|
||||
},
|
||||
"prefs_OptionText_add_tags_auto_force_existing_Info": {
|
||||
"message": "Wenn aktiviert, fügt die KI nur vorhandene Tags hinzu und erstellt keine neuen Tags."
|
||||
},
|
||||
|
|
@ -855,12 +837,6 @@
|
|||
"prefs_OptionText_openai_comp_info_remote": {
|
||||
"message": "Hier können Sie auch die Adresse eines entfernten Servers eingeben."
|
||||
},
|
||||
"prefs_OptionText_add_tags_context_menu_Info": {
|
||||
"message": "Wenn aktiviert, wird beim Rechtsklick auf eine E-Mail in der Nachrichtenliste der Eintrag \"Tags hinzufügen\" angezeigt."
|
||||
},
|
||||
"prefs_OptionText_spamfilter_context_menu_Info": {
|
||||
"message": "Wenn aktiviert, wird beim Rechtsklick auf eine E-Mail in der Nachrichtenliste der Eintrag \"Auf Spam analysieren\" angezeigt."
|
||||
},
|
||||
"prefs_OptionText_calendar_enforce_timezone": {
|
||||
"message": "Erzwinge die angegebene Zeitzone"
|
||||
},
|
||||
|
|
@ -882,12 +858,6 @@
|
|||
"prefs_OptionText_calendar_enforce_timezone_Info": {
|
||||
"message": "Wenn aktiviert, wird die angegebene Zeitzone für die Kalendereinträge und Aufgaben erzwungen."
|
||||
},
|
||||
"prefs_OptionText_add_tags_context_menu": {
|
||||
"message": "\"Tags hinzufügen\" im Kontextmenü anzeigen"
|
||||
},
|
||||
"prefs_OptionText_spamfilter_context_menu": {
|
||||
"message": "\"Auf Spam analysieren\" im Kontextmenü anzeigen"
|
||||
},
|
||||
"apiwebchat_you": {
|
||||
"message": "Du"
|
||||
},
|
||||
|
|
@ -930,12 +900,6 @@
|
|||
"CORS_alternative_1": {
|
||||
"message": "Probleme beim Einrichten von CORS?"
|
||||
},
|
||||
"CORS_alternative_2": {
|
||||
"message": "Drücke den Button unten, um die Berechtigung <all_urls> zu erteilen und CORS-Probleme zu vermeiden."
|
||||
},
|
||||
"CORS_give_allurls_perm": {
|
||||
"message": "Gib die Berechtigung für \"alle URLs\""
|
||||
},
|
||||
"remember_CORS": {
|
||||
"message": "Denk daran, du musst die CORS-Einstellungen auf dem Server konfigurieren!"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -773,10 +773,10 @@
|
|||
"Report_Date": {
|
||||
"message": "Ημερομηνία αναφοράς"
|
||||
},
|
||||
"spamfilter_moved": {
|
||||
"yes_string": {
|
||||
"message": "Ναί"
|
||||
},
|
||||
"spamfilter_not_moved": {
|
||||
"no_string": {
|
||||
"message": "Οχι"
|
||||
},
|
||||
"context_menu_mzta-add-tags": {
|
||||
|
|
@ -785,18 +785,6 @@
|
|||
"context_menu_mzta-spamfilter": {
|
||||
"message": "Ανάλυση για ανεπιθύμητα μηνύματα"
|
||||
},
|
||||
"prefs_OptionText_add_tags_context_menu": {
|
||||
"message": "Εμφάνιση του στοιχείου μενού \"Προσθήκη ετικετών\""
|
||||
},
|
||||
"prefs_OptionText_add_tags_context_menu_Info": {
|
||||
"message": "Εάν είναι επιλεγμένο, το στοιχείο μενού \"Προσθήκη ετικετών\" θα εμφανίζεται όταν κάνετε δεξί κλικ σε ένα μήνυμα ηλεκτρονικού ταχυδρομείου στη λίστα μηνυμάτων."
|
||||
},
|
||||
"prefs_OptionText_spamfilter_context_menu": {
|
||||
"message": "Εμφάνιση του στοιχείου μενού \"Ανάλυση για ανεπιθύμητα μηνύματα\""
|
||||
},
|
||||
"prefs_OptionText_spamfilter_context_menu_Info": {
|
||||
"message": "Εάν είναι επιλεγμένο, το στοιχείο μενού \"Ανάλυση για ανεπιθύμητα μηνύματα\" θα εμφανίζεται όταν κάνετε δεξί κλικ σε ένα μήνυμα ηλεκτρονικού ταχυδρομείου στη λίστα μηνυμάτων."
|
||||
},
|
||||
"noActiveCalendar": {
|
||||
"message": "Δεν βρέθηκε επεξεργάσιμο ημερολόγιο!"
|
||||
},
|
||||
|
|
@ -836,12 +824,6 @@
|
|||
"CORS_alternative_1": {
|
||||
"message": "Προβλήματα με τη ρύθμιση του CORS;"
|
||||
},
|
||||
"CORS_alternative_2": {
|
||||
"message": "Πατήστε το παρακάτω κουμπί για να δώσετε στο <all_urls> την άδεια να αποφύγει οποιοδήποτε πρόβλημα CORS."
|
||||
},
|
||||
"CORS_give_allurls_perm": {
|
||||
"message": "Δώστε άδεια σε \"όλες τις διευθύνσεις URL\""
|
||||
},
|
||||
"prefs_OptionText_composing_plain_text": {
|
||||
"message": "Σύνταξη σε απλό κείμενο"
|
||||
},
|
||||
|
|
@ -942,7 +924,7 @@
|
|||
"message": "ΑΠΑΙΤΕΙΤΑΙ. Μην αλλάξετε αυτήν την τιμή εκτός αν γνωρίζετε τι κάνετε. Περισσότερες πληροφορίες στη διεύθυνση:"
|
||||
},
|
||||
"prefs_OptionText_anthropic_max_tokens": {
|
||||
"message": "Claude Μέγιστα Tokens"
|
||||
"message": "Μέγιστα Tokens"
|
||||
},
|
||||
"prefs_OptionText_anthropic_max_tokens_Info": {
|
||||
"message": "Ο μέγιστος αριθμός διακριτικών που θα δημιουργηθούν κατά την ολοκλήρωση. Ο αριθμός διακριτικών της προτροπής σας συν το max_tokens δεν μπορεί να υπερβαίνει το μήκος περιβάλλοντος του μοντέλου."
|
||||
|
|
@ -1298,5 +1280,29 @@
|
|||
},
|
||||
"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 για αναλυτική ανάλυση."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1003,6 +1003,34 @@
|
|||
"message": "Extract all relevant details required to generate a calendar event from the following text. The extracted information should include:\n- Event Title\n- Start Date and Time (including timezone, if specified)\n- End Date and Time (including timezone, if specified)\n- Full day (if mentioned)\n- Attendees\nEnsure the data is formatted clearly and consistently so that it can be directly used for creating a calendar event.\nIf there are relative time references, consider that the date and time of the email are \"{%mail_datetime%}\". Calculate the start date and time based on this reference. If the calculated start date and time are earlier than \"{%current_datetime%}\", recalculate the start date and time using \"{%current_datetime%}\" as the base.\nIf the duration is not specified, set it to one hour.\nThese are the attendees: {%author%}, {%recipients%}, {%cc_list%}. If present, exclude my address: {%account_email_address%}.\nIf you're not able to get one or more of the required information, please respond with an empty string.\nGenerate a response in JSON format only. Do not include any additional text or explanations; provide only the JSON. Here is the format to be used:\n{\n\"startDate\": \"YYYYMMDDTHHMMSS\",\n\"endDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"Calendar event summary here\",\n\"forceAllDay\": false,\n\"attendees\": [attendee1@example.com,attendee2@example.com,attendee3@example.com]\n}\nHere's the text:\"{%selected_text%}\"",
|
||||
"description": ""
|
||||
},
|
||||
"Summarize_prompt_prefs_title": {
|
||||
"message": "Add Summarization Options",
|
||||
"description": ""
|
||||
},
|
||||
"prompt_summarize": {
|
||||
"message": "Summarize this email or these emails",
|
||||
"description": ""
|
||||
},
|
||||
"prompt_summarize_full_text": {
|
||||
"message": "You are an assistant that summarizes email conversations.\n\nGiven an email thread, produce a concise, accurate summary that captures:\n\n- The main topic or purpose of the conversation\n- Key decisions, conclusions, or agreements\n- Important questions, requests, or action items\n- Who is responsible for each action item (if stated)\n\nOmit greetings, signatures, quoted text, and redundant back-and-forth.\nDo not add assumptions or information not present in the emails.\n\nWrite the summary in clear, neutral language suitable for a busy professional.",
|
||||
"description": ""
|
||||
},
|
||||
"prompt_summarize_email_template": {
|
||||
"message": "Summarize email template",
|
||||
"description": ""
|
||||
},
|
||||
"prompt_summarize_email_template_full_text": {
|
||||
"message": "From: {%author%}\nTo: {%recipients%}\nCC: {%cc_list%}\nSubject: {%mail_subject%}\nDate: {%mail_datetime%}\nAttachments:\n{%mail_attachments_info%}\n\nBody:\n{%mail_text_body%}",
|
||||
"description": ""
|
||||
},
|
||||
"prompt_summarize_email_separator": {
|
||||
"message": "Email separator",
|
||||
"description": ""
|
||||
},
|
||||
"prompt_summarize_email_separator_full_text": {
|
||||
"message": "\n\n---------- NEXT EMAIL ----------\n\n",
|
||||
"description": ""
|
||||
},
|
||||
"prompt_get_task": {
|
||||
"message": "Add a new task",
|
||||
"description": ""
|
||||
|
|
@ -1067,6 +1095,22 @@
|
|||
"message": "You can change the prompt as you wish, but the response received from the AI must be in JSON format as specified in the default prompt!",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_Summarize_infoline2": {
|
||||
"message": "You can change the prompt as you wish, the first field is the main prompt, the second field is the template for a single mail. The list of emails will be appended to the main prompt. Emails will be separated by the separator specified in the third field.",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_Summarize_main_prompt": {
|
||||
"message": "The main prompt describing the task to be performed on all selected emails:",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_Summarize_email_template": {
|
||||
"message": "The template for a single email:",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_Summarize_email_separator": {
|
||||
"message": "The separator between emails:",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_get_calendar_event_Sparks_not_present": {
|
||||
"message": "To use the calendar event and task features, please install the ThunderAI Sparks addon.",
|
||||
"description": ""
|
||||
|
|
@ -1167,6 +1211,10 @@
|
|||
"message": "If checked, the Model and API specified below will be used for adding tags to emails, regardless the one choosen in the ThunderAI options page.",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_get_calendar_event_use_specific_integration_Info": {
|
||||
"message": "If checked, the Model and API specified below will be used for creating calendar events, regardless the one choosen in the ThunderAI options page.",
|
||||
"description": ""
|
||||
},
|
||||
"placeholder_thunderai_def_sign": {
|
||||
"message": "Default signature as defined in ThunderAI options.",
|
||||
"description": ""
|
||||
|
|
@ -1195,6 +1243,22 @@
|
|||
"message": "Manage spam filter settings",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_summarize": {
|
||||
"message": "Summarize mail",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_summarize_use_specific_integration_Info": {
|
||||
"message": "If checked, the Model and API specified below will be used for summarizing email(s), regardless the one choosen in the ThunderAI options page.",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_summarize_Info": {
|
||||
"message": "If checked, adds an option to context menu to summarize mail.",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_btnManageSummarizeInfo": {
|
||||
"message": "Manage summarize settings",
|
||||
"description": ""
|
||||
},
|
||||
"SpamFilter_PageTitle": {
|
||||
"message": "Manage Spam Filter Settings",
|
||||
"description": ""
|
||||
|
|
@ -1219,6 +1283,18 @@
|
|||
"message": "Spam Filter Options",
|
||||
"description": ""
|
||||
},
|
||||
"Summarize_PageTitle": {
|
||||
"message": "Manage Summarize Settings",
|
||||
"description": ""
|
||||
},
|
||||
"Summarize_info_default": {
|
||||
"message": "In this page you can modify the default prompt used to summarize emails.",
|
||||
"description": ""
|
||||
},
|
||||
"Summarize_prompt_text_title": {
|
||||
"message": "Current prompt text",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_use_specific_integration": {
|
||||
"message": "Use specific Model and API",
|
||||
"description": ""
|
||||
|
|
@ -1279,11 +1355,11 @@
|
|||
"message": "Report Date",
|
||||
"description": ""
|
||||
},
|
||||
"spamfilter_moved": {
|
||||
"yes_string": {
|
||||
"message": "Yes",
|
||||
"description": ""
|
||||
},
|
||||
"spamfilter_not_moved": {
|
||||
"no_string": {
|
||||
"message": "No",
|
||||
"description": ""
|
||||
},
|
||||
|
|
@ -1295,20 +1371,8 @@
|
|||
"message": "Analyze for spam",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_add_tags_context_menu": {
|
||||
"message": "Show the \"Add tags\" context menu item",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_add_tags_context_menu_Info": {
|
||||
"message": "If checked, the \"Add tags\" context menu item will be shown when right-clicking on an email in the messages list.",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_spamfilter_context_menu": {
|
||||
"message": "Show the \"Analyze for spam\" context menu item",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_spamfilter_context_menu_Info": {
|
||||
"message": "If checked, the \"Analyze for spam\" context menu item will be shown when right-clicking on an email in the messages list.",
|
||||
"context_menu_mzta-summarize": {
|
||||
"message": "Summarize",
|
||||
"description": ""
|
||||
},
|
||||
"noActiveCalendar": {
|
||||
|
|
@ -1363,12 +1427,16 @@
|
|||
"message": "Problems setting CORS?",
|
||||
"description": ""
|
||||
},
|
||||
"CORS_alternative_2": {
|
||||
"message": "Press the button below to give the <all_urls> permission to avoid any CORS problem.",
|
||||
"CORS_alternative_2_new": {
|
||||
"message": "Press the button below to give the permission to the current host to avoid any CORS problem.",
|
||||
"description": ""
|
||||
},
|
||||
"CORS_give_allurls_perm": {
|
||||
"message": "Give \"all URLs\" permission",
|
||||
"CORS_give_host_perm": {
|
||||
"message": "Give permission to the current host",
|
||||
"description": ""
|
||||
},
|
||||
"CORS_localhost_warn": {
|
||||
"message": "If you are using localhost or 127.0.0.1 because the AI server is hosted on your PC, the <all_urls> permission is required.",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_composing_plain_text": {
|
||||
|
|
@ -1754,5 +1822,9 @@
|
|||
},
|
||||
"auto_summary_prompt": {
|
||||
"message": "Please provide a concise summary of the following email message. The summary should be 3-5 sentences maximum and capture the main points:\n\n"
|
||||
},
|
||||
"customPrompts_export_include_api_settings": {
|
||||
"message": "Do you want to include the API settings in the export? Be aware that also the API Key will be saved in the file!",
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
"From": {
|
||||
"message": "De"
|
||||
},
|
||||
"spamfilter_not_moved": {
|
||||
"no_string": {
|
||||
"message": "Ne"
|
||||
},
|
||||
"apiwebchat_stopping": {
|
||||
|
|
@ -122,7 +122,7 @@
|
|||
"Explanation": {
|
||||
"message": "Klarigo"
|
||||
},
|
||||
"spamfilter_moved": {
|
||||
"yes_string": {
|
||||
"message": "Jes"
|
||||
},
|
||||
"apiwebchat_you": {
|
||||
|
|
|
|||
|
|
@ -956,10 +956,10 @@
|
|||
"Report_Date": {
|
||||
"message": "Fecha del informe"
|
||||
},
|
||||
"spamfilter_moved": {
|
||||
"yes_string": {
|
||||
"message": "Si"
|
||||
},
|
||||
"spamfilter_not_moved": {
|
||||
"no_string": {
|
||||
"message": "No"
|
||||
},
|
||||
"context_menu_mzta-add-tags": {
|
||||
|
|
@ -968,18 +968,6 @@
|
|||
"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!"
|
||||
},
|
||||
|
|
@ -1019,12 +1007,6 @@
|
|||
"CORS_alternative_1": {
|
||||
"message": "¿Problemas al configurar CORS?"
|
||||
},
|
||||
"CORS_alternative_2": {
|
||||
"message": "Presiona el botón a continuación para otorgar el permiso <all_urls> 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"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -327,9 +327,6 @@
|
|||
"chagpt_api_send_button": {
|
||||
"message": "Utilisation du modèle"
|
||||
},
|
||||
"chagpt_api_connecting": {
|
||||
"message": "Tentative de connexion à OpenAI ChatGPT en utilisant la clé API fournie"
|
||||
},
|
||||
"Debug": {
|
||||
"message": "Debug"
|
||||
},
|
||||
|
|
@ -363,12 +360,6 @@
|
|||
"ollama_empty_model": {
|
||||
"message": "Vous n'avez pas choisi de modèle pour l'API Ollama. Veuillez en choisir un sur la page des options."
|
||||
},
|
||||
"ollama_api_connecting": {
|
||||
"message": "Tentative de connexion au serveur local Ollama en utilisant l'hôte"
|
||||
},
|
||||
"andModel": {
|
||||
"message": "et le modèle"
|
||||
},
|
||||
"error_connection_interrupted": {
|
||||
"message": "La connexion au serveur a été interrompue de manière inattendue"
|
||||
},
|
||||
|
|
@ -399,9 +390,6 @@
|
|||
"OpenAIComp_empty_model": {
|
||||
"message": "Vous n'avez pas choisi de modèle pour l'API compatible OpenAI. Veuillez en choisir un dans la page des options."
|
||||
},
|
||||
"OpenAIComp_api_connecting": {
|
||||
"message": "Tentative de connexion au serveur local de l'API compatible OpenAI en utilisant l'hôte"
|
||||
},
|
||||
"OpenAIComp_api_request_failed": {
|
||||
"message": "La requête de l'API compatible OpenAI a échoué"
|
||||
},
|
||||
|
|
@ -681,9 +669,6 @@
|
|||
"google_gemini_api_request_failed": {
|
||||
"message": "La requête API Google Gemini a échoué"
|
||||
},
|
||||
"google_gemini_api_connecting": {
|
||||
"message": "Tentative de connexion à Google Gemini en utilisant la clé API fournie"
|
||||
},
|
||||
"google_gemini_empty_apikey": {
|
||||
"message": "Vous n'avez pas ajouté de clé API pour l'API Google Gemini. Veuillez en insérer une dans la page des options."
|
||||
},
|
||||
|
|
@ -792,7 +777,7 @@
|
|||
"Moved_to_Spam": {
|
||||
"message": "Déplacé dans le spam"
|
||||
},
|
||||
"spamfilter_not_moved": {
|
||||
"no_string": {
|
||||
"message": "Non"
|
||||
},
|
||||
"spamfilter_no_reports": {
|
||||
|
|
@ -801,9 +786,6 @@
|
|||
"SpamFilter_PageTitle": {
|
||||
"message": "Gérer les paramètres du filtre anti-spam"
|
||||
},
|
||||
"sparks_not_installed": {
|
||||
"message": "ThunderAI Sparks non installé !"
|
||||
},
|
||||
"SpamFilter_info_default": {
|
||||
"message": "Sur cette page, vous pouvez modifier l'invite par défaut utilisée pour détecter les e-mails indésirables."
|
||||
},
|
||||
|
|
@ -816,7 +798,7 @@
|
|||
"SpamReport_Title": {
|
||||
"message": "Rapports du filtre anti-spam"
|
||||
},
|
||||
"spamfilter_moved": {
|
||||
"yes_string": {
|
||||
"message": "Oui"
|
||||
},
|
||||
"prefs_OptionText_add_tags_auto_Info": {
|
||||
|
|
@ -858,12 +840,6 @@
|
|||
"context_menu_mzta-add-tags": {
|
||||
"message": "Ajouter des étiquettes"
|
||||
},
|
||||
"prefs_OptionText_spamfilter_context_menu": {
|
||||
"message": "Afficher l'option \"Analyser comme spam\" dans le menu contextuel"
|
||||
},
|
||||
"prefs_OptionText_spamfilter_context_menu_Info": {
|
||||
"message": "Si coché, l'option \"Analyser comme spam\" apparaîtra lors d’un clic droit sur un e-mail dans la liste des messages."
|
||||
},
|
||||
"noActiveCalendar": {
|
||||
"message": "Aucun calendrier modifiable trouvé !"
|
||||
},
|
||||
|
|
@ -879,9 +855,6 @@
|
|||
"prefs_OptionText_calendar_enforce_timezone": {
|
||||
"message": "Forcer le fuseau horaire spécifié"
|
||||
},
|
||||
"prefs_OptionText_add_tags_context_menu_Info": {
|
||||
"message": "Si coché, l'option \"Ajouter des étiquettes\" apparaîtra lors d’un clic droit sur un e-mail dans la liste des messages."
|
||||
},
|
||||
"chatgpt_win_diff_title": {
|
||||
"message": "Différences entre le texte original et le texte modifié"
|
||||
},
|
||||
|
|
@ -897,9 +870,6 @@
|
|||
"apiwebchat_error": {
|
||||
"message": "Erreur"
|
||||
},
|
||||
"prefs_OptionText_add_tags_context_menu": {
|
||||
"message": "Afficher l'option \"Ajouter des étiquettes\" dans le menu contextuel"
|
||||
},
|
||||
"apiwebchat_use_this_answer": {
|
||||
"message": "Utiliser cette réponse"
|
||||
},
|
||||
|
|
@ -930,12 +900,6 @@
|
|||
"CORS_alternative_1": {
|
||||
"message": "Des problèmes pour configurer le CORS ?"
|
||||
},
|
||||
"CORS_alternative_2": {
|
||||
"message": "Appuie sur le bouton ci-dessous pour accorder la permission <all_urls> afin d'éviter tout problème lié au CORS."
|
||||
},
|
||||
"CORS_give_allurls_perm": {
|
||||
"message": "Accorde la permission \"tous les URLs\""
|
||||
},
|
||||
"remember_CORS": {
|
||||
"message": "N'oublie pas, tu dois configurer les paramètres CORS sur le serveur !"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -327,9 +327,6 @@
|
|||
"chagpt_api_send_button": {
|
||||
"message": "Korištenje modela"
|
||||
},
|
||||
"chagpt_api_connecting": {
|
||||
"message": "Pokušaj povezivanja na OpenAI ChatGPT pomoću dostavljenog API ključa"
|
||||
},
|
||||
"Debug": {
|
||||
"message": "Otklanjanje pogrešaka"
|
||||
},
|
||||
|
|
@ -363,12 +360,6 @@
|
|||
"ollama_empty_model": {
|
||||
"message": "Niste odabrali model za Ollama API. Odaberite jedan na stranici s mogućnostima."
|
||||
},
|
||||
"ollama_api_connecting": {
|
||||
"message": "Pokušaj povezivanja na Ollama lokalni poslužitelj pomoću glavnog računala"
|
||||
},
|
||||
"andModel": {
|
||||
"message": "i model"
|
||||
},
|
||||
"error_connection_interrupted": {
|
||||
"message": "Veza s poslužiteljem je neočekivano prekinuta"
|
||||
},
|
||||
|
|
@ -399,9 +390,6 @@
|
|||
"OpenAIComp_empty_model": {
|
||||
"message": "Niste odabrali model za OpenAI kompatibilan API. Odaberite jedan na stranici s opcijama."
|
||||
},
|
||||
"OpenAIComp_api_connecting": {
|
||||
"message": "Pokušaj povezivanja s OpenAI kompatibilnim API lokalnim poslužiteljem pomoću glavnog računala"
|
||||
},
|
||||
"OpenAIComp_api_request_failed": {
|
||||
"message": "OpenAI Comp API zahtjev nije uspio"
|
||||
},
|
||||
|
|
@ -681,9 +669,6 @@
|
|||
"google_gemini_api_request_failed": {
|
||||
"message": "Google Gemini API zahtjev nije uspio"
|
||||
},
|
||||
"google_gemini_api_connecting": {
|
||||
"message": "Pokušaj povezivanja na Google Gemini pomoću dostavljenog API ključa"
|
||||
},
|
||||
"google_gemini_empty_apikey": {
|
||||
"message": "Niste dodali API ključ za Google Gemini API. Unesite jedan na stranicu s mogućnostima."
|
||||
},
|
||||
|
|
@ -753,9 +738,6 @@
|
|||
"calendar_opening_dialog_error": {
|
||||
"message": "Pogreška pri otvaranju dijaloškog okvira kalendarskog događaja"
|
||||
},
|
||||
"sparks_not_installed": {
|
||||
"message": "ThunderAI Sparks nije instaliran!"
|
||||
},
|
||||
"prefs_OptionText_add_tags_auto": {
|
||||
"message": "Dodajte oznake automatski"
|
||||
},
|
||||
|
|
@ -846,10 +828,10 @@
|
|||
"Report_Date": {
|
||||
"message": "Datum izvješća"
|
||||
},
|
||||
"spamfilter_moved": {
|
||||
"yes_string": {
|
||||
"message": "Da"
|
||||
},
|
||||
"spamfilter_not_moved": {
|
||||
"no_string": {
|
||||
"message": "Ne"
|
||||
},
|
||||
"prefs_OptionText_openai_comp_info_remote": {
|
||||
|
|
|
|||
|
|
@ -327,9 +327,6 @@
|
|||
"chagpt_api_send_button": {
|
||||
"message": "Modello utilizzato"
|
||||
},
|
||||
"chagpt_api_connecting": {
|
||||
"message": "Tentativo di connessione a OpenAI ChatGPT utilizzando la chiave API fornita"
|
||||
},
|
||||
"Debug": {
|
||||
"message": "Debug"
|
||||
},
|
||||
|
|
@ -363,12 +360,6 @@
|
|||
"ollama_empty_model": {
|
||||
"message": "Non hai scelto un modello per l'API Ollama. Per favore, scegline uno nella pagina delle opzioni."
|
||||
},
|
||||
"ollama_api_connecting": {
|
||||
"message": "Tentativo di connettersi al server locale Ollama usando l'host"
|
||||
},
|
||||
"andModel": {
|
||||
"message": "e il modello"
|
||||
},
|
||||
"error_connection_interrupted": {
|
||||
"message": "La connessione al server è stata interrotta inaspettatamente"
|
||||
},
|
||||
|
|
@ -399,9 +390,6 @@
|
|||
"OpenAIComp_empty_model": {
|
||||
"message": "Non hai scelto un modello per l'API compatibile con OpenAI. Scegline uno nella pagina delle opzioni."
|
||||
},
|
||||
"OpenAIComp_api_connecting": {
|
||||
"message": "Tentativo di connessione al server locale dell'API compatibile con OpenAI utilizzando l'host"
|
||||
},
|
||||
"OpenAIComp_api_request_failed": {
|
||||
"message": "Richiesta all'API compatibile con OpenAI fallita"
|
||||
},
|
||||
|
|
@ -681,9 +669,6 @@
|
|||
"google_gemini_api_request_failed": {
|
||||
"message": "La richiesta all'API Google Gemini è fallita"
|
||||
},
|
||||
"google_gemini_api_connecting": {
|
||||
"message": "Tentativo di connessione a Google Gemini utilizzando la chiave API fornita"
|
||||
},
|
||||
"google_gemini_empty_apikey": {
|
||||
"message": "Non hai aggiunto una chiave API per l'API Google Gemini. Inseriscine una nella pagina delle opzioni."
|
||||
},
|
||||
|
|
@ -753,9 +738,6 @@
|
|||
"calendar_opening_dialog_error": {
|
||||
"message": "Errore durante l'apertura della finestra di dialogo dell'evento del calendario"
|
||||
},
|
||||
"sparks_not_installed": {
|
||||
"message": "ThunderAI Sparks non installato!"
|
||||
},
|
||||
"Subject": {
|
||||
"message": "Oggetto"
|
||||
},
|
||||
|
|
@ -789,7 +771,7 @@
|
|||
"Moved_to_Spam": {
|
||||
"message": "Spostato nello spam"
|
||||
},
|
||||
"spamfilter_not_moved": {
|
||||
"no_string": {
|
||||
"message": "No"
|
||||
},
|
||||
"From": {
|
||||
|
|
@ -798,7 +780,7 @@
|
|||
"prefs_OptionText_btnManageSpamFilterInfo": {
|
||||
"message": "Gestisci le impostazioni del filtro antispam"
|
||||
},
|
||||
"spamfilter_moved": {
|
||||
"yes_string": {
|
||||
"message": "Sì"
|
||||
},
|
||||
"SpamReport_Title": {
|
||||
|
|
@ -879,9 +861,6 @@
|
|||
"btn_show_differences": {
|
||||
"message": "Mostra le differenze"
|
||||
},
|
||||
"apiwebchat_show_differences": {
|
||||
"message": "Mostra le differenze"
|
||||
},
|
||||
"apiwebchat_error": {
|
||||
"message": "Errore"
|
||||
},
|
||||
|
|
@ -894,21 +873,9 @@
|
|||
"prefs_OptionText_calendar_enforce_timezone": {
|
||||
"message": "Forza il fuso orario specificato"
|
||||
},
|
||||
"prefs_OptionText_add_tags_context_menu_Info": {
|
||||
"message": "Se selezionato, la voce \"Aggiungi etichette\" verrà mostrata facendo clic con il pulsante destro del mouse su un'email nell'elenco dei messaggi."
|
||||
},
|
||||
"apiwebchat_use_this_answer": {
|
||||
"message": "Usa questa risposta"
|
||||
},
|
||||
"prefs_OptionText_spamfilter_context_menu_Info": {
|
||||
"message": "Se selezionato, la voce \"Analizza come spam\" verrà mostrata facendo clic con il pulsante destro del mouse su un'email nell'elenco dei messaggi."
|
||||
},
|
||||
"prefs_OptionText_spamfilter_context_menu": {
|
||||
"message": "Mostra la voce \"Analizza come spam\" nel menu contestuale"
|
||||
},
|
||||
"prefs_OptionText_add_tags_context_menu": {
|
||||
"message": "Mostra la voce \"Aggiungi etichette\" nel menu contestuale"
|
||||
},
|
||||
"apiwebchat_info": {
|
||||
"message": "Informazioni"
|
||||
},
|
||||
|
|
@ -933,12 +900,6 @@
|
|||
"CORS_alternative_1": {
|
||||
"message": "Problemi con la configurazione di CORS?"
|
||||
},
|
||||
"CORS_alternative_2": {
|
||||
"message": "Premi il pulsante qui sotto per concedere il permesso <all_urls> ed evitare qualsiasi problema legato a CORS."
|
||||
},
|
||||
"CORS_give_allurls_perm": {
|
||||
"message": "Concedi il permesso \"tutti gli URL\""
|
||||
},
|
||||
"remember_CORS": {
|
||||
"message": "Ricorda, devi configurare le impostazioni CORS sul server!"
|
||||
},
|
||||
|
|
|
|||
1290
_locales/ja/messages.json
Normal file
1290
_locales/ja/messages.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -327,9 +327,6 @@
|
|||
"chagpt_api_send_button": {
|
||||
"message": "Używając modelu"
|
||||
},
|
||||
"chagpt_api_connecting": {
|
||||
"message": "Próba połączenia z OpenAI ChatGPT przy użyciu podanego klucza API"
|
||||
},
|
||||
"Debug": {
|
||||
"message": "Debugowanie"
|
||||
},
|
||||
|
|
@ -363,12 +360,6 @@
|
|||
"ollama_empty_model": {
|
||||
"message": "Nie wybrałeś modelu dla API Ollama. Proszę wybierz jeden na stronie opcji."
|
||||
},
|
||||
"ollama_api_connecting": {
|
||||
"message": "Próba połączenia z lokalnym serwerem Ollama używając hosta"
|
||||
},
|
||||
"andModel": {
|
||||
"message": "i modelu"
|
||||
},
|
||||
"error_connection_interrupted": {
|
||||
"message": "Połączenie z serwerem zostało nieoczekiwanie przerwane"
|
||||
},
|
||||
|
|
@ -399,9 +390,6 @@
|
|||
"OpenAIComp_empty_model": {
|
||||
"message": "Nie wybrałeś modelu dla API kompatybilnego z OpenAI. Proszę wybierz jeden na stronie opcji."
|
||||
},
|
||||
"OpenAIComp_api_connecting": {
|
||||
"message": "Próba połączenia z lokalnym serwerem API kompatybilnym z OpenAI używając hosta"
|
||||
},
|
||||
"OpenAIComp_api_request_failed": {
|
||||
"message": "Zapytanie do API kompatybilnego z OpenAI nie powiodło się"
|
||||
},
|
||||
|
|
@ -672,9 +660,6 @@
|
|||
"google_gemini_api_request_failed": {
|
||||
"message": "Połączenie do interfejsu API Google Gemini nie powiodło się"
|
||||
},
|
||||
"google_gemini_api_connecting": {
|
||||
"message": "Próba połączenia z Google Gemini przy użyciu dostarczonego klucza API"
|
||||
},
|
||||
"google_gemini_empty_apikey": {
|
||||
"message": "Nie dodałeś klucza API dla API Google Gemini. Wstaw go na stronie opcji."
|
||||
},
|
||||
|
|
@ -792,15 +777,12 @@
|
|||
"Moved_to_Spam": {
|
||||
"message": "Przeniesiono do spamu"
|
||||
},
|
||||
"spamfilter_not_moved": {
|
||||
"no_string": {
|
||||
"message": "Nie"
|
||||
},
|
||||
"prefs_OptionText_add_tags_auto_force_existing_Info": {
|
||||
"message": "Jeśli zaznaczone, AI doda tylko istniejące tagi do nowo odebranych e-maili i nie utworzy nowych."
|
||||
},
|
||||
"sparks_not_installed": {
|
||||
"message": "ThunderAI Sparks nie zainstalowany!"
|
||||
},
|
||||
"SpamFilter_info_default": {
|
||||
"message": "Na tej stronie możesz edytować domyślny prompt używany do wykrywania e-maili spamowych."
|
||||
},
|
||||
|
|
@ -813,7 +795,7 @@
|
|||
"prefs_OptionText_btnManageSpamFilterInfo": {
|
||||
"message": "Zarządzaj ustawieniami filtra spamu"
|
||||
},
|
||||
"spamfilter_moved": {
|
||||
"yes_string": {
|
||||
"message": "Tak"
|
||||
},
|
||||
"prefs_OptionText_spamfilter": {
|
||||
|
|
|
|||
|
|
@ -327,9 +327,6 @@
|
|||
"chagpt_api_send_button": {
|
||||
"message": "Usando modelo"
|
||||
},
|
||||
"chagpt_api_connecting": {
|
||||
"message": "Tentando conectar ao OpenAI ChatGPT usando a chave de API fornecida"
|
||||
},
|
||||
"Debug": {
|
||||
"message": "Depurar"
|
||||
},
|
||||
|
|
@ -363,12 +360,6 @@
|
|||
"ollama_empty_model": {
|
||||
"message": "Você não escolheu um modelo para a API do Ollama. Por favor, escolha um na página de opções."
|
||||
},
|
||||
"ollama_api_connecting": {
|
||||
"message": "Tentando conectar ao servidor local do Ollama usando o host"
|
||||
},
|
||||
"andModel": {
|
||||
"message": "e modelo"
|
||||
},
|
||||
"error_connection_interrupted": {
|
||||
"message": "A conexão com o servidor foi interrompida inesperadamente"
|
||||
},
|
||||
|
|
@ -399,9 +390,6 @@
|
|||
"OpenAIComp_empty_model": {
|
||||
"message": "Você não escolheu um modelo para a API Compatível com OpenAI. Por favor, escolha um na página de opções."
|
||||
},
|
||||
"OpenAIComp_api_connecting": {
|
||||
"message": "Tentando conectar ao Servidor Local da API Compatível com OpenAI usando o host"
|
||||
},
|
||||
"OpenAIComp_api_request_failed": {
|
||||
"message": "Solicitação da API Comp do OpenAI falhou"
|
||||
},
|
||||
|
|
@ -681,9 +669,6 @@
|
|||
"google_gemini_api_request_failed": {
|
||||
"message": "A solicitação para a API Google Gemini falhou"
|
||||
},
|
||||
"google_gemini_api_connecting": {
|
||||
"message": "Tentando conectar ao Google Gemini usando a chave API fornecida"
|
||||
},
|
||||
"google_gemini_empty_apikey": {
|
||||
"message": "Você não adicionou uma chave API para a API Google Gemini. Por favor, insira uma na página de opções."
|
||||
},
|
||||
|
|
@ -795,12 +780,9 @@
|
|||
"Moved_to_Spam": {
|
||||
"message": "Movido para spam"
|
||||
},
|
||||
"spamfilter_not_moved": {
|
||||
"no_string": {
|
||||
"message": "Não"
|
||||
},
|
||||
"sparks_not_installed": {
|
||||
"message": "ThunderAI Sparks não instalado!"
|
||||
},
|
||||
"prefs_OptionText_btnManageSpamFilterInfo": {
|
||||
"message": "Gerenciar configurações do filtro de spam"
|
||||
},
|
||||
|
|
@ -810,7 +792,7 @@
|
|||
"prefs_OptionText_spamfilter_Info": {
|
||||
"message": "Se marcado, o ThunderAI moverá automaticamente e-mails de spam para a pasta de spam."
|
||||
},
|
||||
"spamfilter_moved": {
|
||||
"yes_string": {
|
||||
"message": "Sim"
|
||||
},
|
||||
"SpamReport_Title": {
|
||||
|
|
|
|||
|
|
@ -920,10 +920,10 @@
|
|||
"Report_Date": {
|
||||
"message": "Дата отчета"
|
||||
},
|
||||
"spamfilter_moved": {
|
||||
"yes_string": {
|
||||
"message": "Да"
|
||||
},
|
||||
"spamfilter_not_moved": {
|
||||
"no_string": {
|
||||
"message": "Нет"
|
||||
},
|
||||
"context_menu_mzta-add-tags": {
|
||||
|
|
@ -932,18 +932,6 @@
|
|||
"context_menu_mzta-spamfilter": {
|
||||
"message": "Анализ на предмет спама"
|
||||
},
|
||||
"prefs_OptionText_add_tags_context_menu": {
|
||||
"message": "Показать пункт меню \"Добавить теги\""
|
||||
},
|
||||
"prefs_OptionText_add_tags_context_menu_Info": {
|
||||
"message": "Если флажок установлен, пункт контекстного меню \"Добавить теги\" будет отображаться при щелчке ПКМ на письме в списке сообщений."
|
||||
},
|
||||
"prefs_OptionText_spamfilter_context_menu": {
|
||||
"message": "Показать пункт контекстного меню \"Анализировать на предмет спама\""
|
||||
},
|
||||
"prefs_OptionText_spamfilter_context_menu_Info": {
|
||||
"message": "Если флажок установлен, пункт контекстного меню \"Анализировать на спам\" будет отображаться при щелчке ПКМ на письме в списке сообщений."
|
||||
},
|
||||
"noActiveCalendar": {
|
||||
"message": "Редактируемый календарь не найден!"
|
||||
},
|
||||
|
|
@ -983,12 +971,6 @@
|
|||
"CORS_alternative_1": {
|
||||
"message": "Проблемы с настройкой CORS?"
|
||||
},
|
||||
"CORS_alternative_2": {
|
||||
"message": "Нажмите кнопку ниже, чтобы дать разрешение <all_urls> во избежание проблем с CORS."
|
||||
},
|
||||
"CORS_give_allurls_perm": {
|
||||
"message": "Дайте разрешение на \"все URL-адреса\""
|
||||
},
|
||||
"prefs_OptionText_composing_plain_text": {
|
||||
"message": "Сочинение обычного текста"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -815,10 +815,10 @@
|
|||
"Report_Date": {
|
||||
"message": "Rapportdatum"
|
||||
},
|
||||
"spamfilter_moved": {
|
||||
"yes_string": {
|
||||
"message": "Ja"
|
||||
},
|
||||
"spamfilter_not_moved": {
|
||||
"no_string": {
|
||||
"message": "Nej"
|
||||
},
|
||||
"context_menu_mzta-add-tags": {
|
||||
|
|
@ -827,18 +827,6 @@
|
|||
"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!"
|
||||
},
|
||||
|
|
@ -878,9 +866,6 @@
|
|||
"CORS_alternative_1": {
|
||||
"message": "Problem med att ställa in CORS?"
|
||||
},
|
||||
"CORS_alternative_2": {
|
||||
"message": "Tryck på knappen nedan för att ge <all_urls> behörighet för att undvika eventuella CORS-problem."
|
||||
},
|
||||
"customPrompts_Properties": {
|
||||
"message": "Egenskaper"
|
||||
},
|
||||
|
|
@ -1320,7 +1305,70 @@
|
|||
"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\": <heltal från 0 till 100>,\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\""
|
||||
"Summarize_prompt_prefs_title": {
|
||||
"message": "Lägg till sammanfattningsalternativ"
|
||||
},
|
||||
"prompt_summarize": {
|
||||
"message": "Sammanfatta det här e-postmeddelandet eller dessa e-postmeddelanden"
|
||||
},
|
||||
"prompt_summarize_full_text": {
|
||||
"message": "Du är en assistent som sammanfattar e-postkonversationer.\n\nMed tanke på en e-posttråd, skapa en kortfattad och korrekt sammanfattning som fångar:\n\n- Konversationens huvudämne eller syfte\n- Viktiga beslut, slutsatser eller överenskommelser\n- Viktiga frågor, förfrågningar eller åtgärdspunkter\n- Vem som är ansvarig för varje åtgärdspunkt (om det anges)\n\nUteslut hälsningar, signaturer, citat och överflödig fram-och-tillbaka-text.\nLägg inte till antaganden eller information som inte finns i e-postmeddelandena.\n\nSkriv sammanfattningen på ett tydligt och neutralt språk som passar en upptagen yrkesperson."
|
||||
},
|
||||
"prompt_summarize_email_template": {
|
||||
"message": "Sammanfattningsmall för e-post"
|
||||
},
|
||||
"prompt_summarize_email_template_full_text": {
|
||||
"message": "Från: {%author%}\nTill: {%recipients%}\nCC: {%cc_list%}\nÄmne: {%mail_subject%}\nDatum: {%mail_datetime%}\nBilagor:\n{%mail_attachments_info%}\n\nBrödtext:\n{%mail_text_body%}"
|
||||
},
|
||||
"prompt_summarize_email_separator": {
|
||||
"message": "E-postavgränsare"
|
||||
},
|
||||
"prompt_summarize_email_separator_full_text": {
|
||||
"message": "\n\n---------- NÄSTA E-POST ----------\n\n"
|
||||
},
|
||||
"prefs_OptionText_Summarize_infoline2": {
|
||||
"message": "Du kan ändra prompten som du vill, det första fältet är huvudprompten, det andra fältet är mallen för ett enskilt e-postmeddelande. Listan över e-postmeddelanden kommer att läggas till i huvudprompten. E-postmeddelanden kommer att separeras med avgränsaren som anges i det tredje fältet."
|
||||
},
|
||||
"prefs_OptionText_Summarize_main_prompt": {
|
||||
"message": "Huvudprompten som beskriver uppgiften som ska utföras på alla valda e-postmeddelanden:"
|
||||
},
|
||||
"prefs_OptionText_Summarize_email_template": {
|
||||
"message": "Mallen för ett enda e-postmeddelande:"
|
||||
},
|
||||
"prefs_OptionText_Summarize_email_separator": {
|
||||
"message": "Avgränsaren mellan e-postmeddelanden:"
|
||||
},
|
||||
"prefs_OptionText_summarize": {
|
||||
"message": "Sammanfatta e-postmeddelande"
|
||||
},
|
||||
"prefs_OptionText_summarize_use_specific_integration_Info": {
|
||||
"message": "Om markerat kommer modellen och API:et som anges nedan att användas för att sammanfatta e-postmeddelanden, oavsett vilket som valts på ThunderAI-alternativsidan."
|
||||
},
|
||||
"prefs_OptionText_summarize_Info": {
|
||||
"message": "Om markerad läggs ett alternativ till i snabbmenyn för att sammanfatta e-post."
|
||||
},
|
||||
"prefs_OptionText_btnManageSummarizeInfo": {
|
||||
"message": "Hantera sammanfattningsinställningar"
|
||||
},
|
||||
"Summarize_PageTitle": {
|
||||
"message": "Hantera sammanfattningsinställningar"
|
||||
},
|
||||
"Summarize_info_default": {
|
||||
"message": "På den här sidan kan du ändra standardprompten som används för att sammanfatta e-postmeddelanden."
|
||||
},
|
||||
"Summarize_prompt_text_title": {
|
||||
"message": "Aktuell prompttext"
|
||||
},
|
||||
"context_menu_mzta-summarize": {
|
||||
"message": "Sammanfatta"
|
||||
},
|
||||
"CORS_alternative_2_new": {
|
||||
"message": "Tryck på knappen nedan för att ge den aktuella värden behörighet att undvika CORS-problem."
|
||||
},
|
||||
"CORS_give_host_perm": {
|
||||
"message": "Ge behörighet till den nuvarande värden"
|
||||
},
|
||||
"CORS_localhost_warn": {
|
||||
"message": "Om du använder localhost eller 127.0.0.1 eftersom AI-servern finns på din dator krävs behörigheten <all_urls>."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
20
_locales/tr/messages.json
Normal file
20
_locales/tr/messages.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"extensionDescription": {
|
||||
"message": "E-postalarınızı geliştirmek için ChatGPT, Google Gemini, Claude veya Ollama’yı kullanın!"
|
||||
},
|
||||
"menu_title": {
|
||||
"message": "YZ"
|
||||
},
|
||||
"customPrompts_managePrompts_info_default": {
|
||||
"message": "Varsayılan promptlar düzenlenemez. Bunları devre dışı bırakabilir, ardından prompt metnini kopyalayıp yeni bir prompta yapıştırarak düzenlenmiş bir sürüm oluşturabilirsiniz."
|
||||
},
|
||||
"customPrompts_managePrompts_info_default_2": {
|
||||
"message": "Promptları içe ve dışa aktarabilirsiniz. Aynı kimliğe (ID) sahip mevcut istemlerin üzerine yazılır. Yeni kimliklere (ID) sahip promptlar eklenir."
|
||||
},
|
||||
"customPrompts_managePrompts_info_default_3": {
|
||||
"message": "Her şey doğruysa, içe aktarma işleminden sonra ‘Tümünü Kaydet’ düğmesine tıklayın."
|
||||
},
|
||||
"customPrompts_start_saving": {
|
||||
"message": "Promptlar kaydediliyor…"
|
||||
}
|
||||
}
|
||||
|
|
@ -134,10 +134,10 @@
|
|||
"SpamReport_Title": {
|
||||
"message": "垃圾邮件过滤报告"
|
||||
},
|
||||
"spamfilter_not_moved": {
|
||||
"no_string": {
|
||||
"message": "否"
|
||||
},
|
||||
"spamfilter_moved": {
|
||||
"yes_string": {
|
||||
"message": "是"
|
||||
},
|
||||
"prompt_rewrite_polite": {
|
||||
|
|
@ -236,9 +236,6 @@
|
|||
"prefs_OptionText_spamfilter_Info": {
|
||||
"message": "如果选中,ThunderAI将自动将垃圾邮件移至垃圾邮件文件夹。"
|
||||
},
|
||||
"sparks_not_installed": {
|
||||
"message": "ThunderAI Sparks 未安装!"
|
||||
},
|
||||
"chatgpt_textarea_not_found_error": {
|
||||
"message": "看起来 ChatGPT 页面加载时间太长。如果加载完成,请点击右边的按钮。如果问题仍然存在,请检查服务状态。"
|
||||
},
|
||||
|
|
@ -341,9 +338,6 @@
|
|||
"prefs_ChatGPT_API_Key": {
|
||||
"message": "ChatGPT API 密钥"
|
||||
},
|
||||
"chagpt_api_connecting": {
|
||||
"message": "尝试使用提供的 API 密钥连接到 OpenAI ChatGPT"
|
||||
},
|
||||
"prefs_OptionText_release_notes": {
|
||||
"message": "发行说明"
|
||||
},
|
||||
|
|
@ -371,9 +365,6 @@
|
|||
"OpenAIComp_empty_model": {
|
||||
"message": "您尚未选择 OpenAI Compatible API 的模型。请在选项页面中选择一个。"
|
||||
},
|
||||
"OpenAIComp_api_connecting": {
|
||||
"message": "尝试使用主机连接到 OpenAI 兼容 API 本地服务器"
|
||||
},
|
||||
"prefs_OpenAIComp_ChatName": {
|
||||
"message": "对话名称"
|
||||
},
|
||||
|
|
@ -416,9 +407,6 @@
|
|||
"importPrompts_invalidPrompts": {
|
||||
"message": "您尝试导入的文件不包含任何有效提示词。"
|
||||
},
|
||||
"andModel": {
|
||||
"message": "和模型"
|
||||
},
|
||||
"ChatGPT_Models_Error_fetching": {
|
||||
"message": "尝试获取 ChatGPT 模型时出错"
|
||||
},
|
||||
|
|
@ -581,9 +569,6 @@
|
|||
"OpenAIComp_force_model_ask": {
|
||||
"message": "在此处填入您想要使用的模型名称。"
|
||||
},
|
||||
"ollama_api_connecting": {
|
||||
"message": "尝试使用主机连接到 Ollama 本地服务器"
|
||||
},
|
||||
"ollama_api_request_failed": {
|
||||
"message": "Ollama API 请求失败"
|
||||
},
|
||||
|
|
@ -635,9 +620,6 @@
|
|||
"thunderai_warning_title": {
|
||||
"message": "ThunderAI 警告"
|
||||
},
|
||||
"google_gemini_api_connecting": {
|
||||
"message": "尝试使用提供的 API 密钥连接到 Google Gemini"
|
||||
},
|
||||
"prefs_SurveyLinkText2": {
|
||||
"message": "单击此处,只需一分钟!"
|
||||
},
|
||||
|
|
@ -854,21 +836,9 @@
|
|||
"context_menu_mzta-add-tags": {
|
||||
"message": "添加标签"
|
||||
},
|
||||
"prefs_OptionText_add_tags_context_menu": {
|
||||
"message": "显示“添加标签”上下文菜单项"
|
||||
},
|
||||
"prefs_OptionText_spamfilter_context_menu": {
|
||||
"message": "显示“分析垃圾邮件”上下文菜单项"
|
||||
},
|
||||
"prefs_OptionText_spamfilter_context_menu_Info": {
|
||||
"message": "如果选中,则在邮件列表中右键单击电子邮件时,将显示“分析垃圾邮件”上下文菜单项。"
|
||||
},
|
||||
"context_menu_mzta-spamfilter": {
|
||||
"message": "分析垃圾邮件"
|
||||
},
|
||||
"prefs_OptionText_add_tags_context_menu_Info": {
|
||||
"message": "如果选中,“添加标签”上下文菜单项将在消息列表中右键单击电子邮件时显示。"
|
||||
},
|
||||
"noActiveCalendar": {
|
||||
"message": "未找到可编辑的日历!"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -284,7 +284,7 @@
|
|||
"Spam_Value": {
|
||||
"message": "垃圾訊息評分"
|
||||
},
|
||||
"spamfilter_not_moved": {
|
||||
"no_string": {
|
||||
"message": "否"
|
||||
},
|
||||
"Report_Date": {
|
||||
|
|
@ -387,7 +387,7 @@
|
|||
"Date": {
|
||||
"message": "日期"
|
||||
},
|
||||
"spamfilter_moved": {
|
||||
"yes_string": {
|
||||
"message": "是"
|
||||
},
|
||||
"Custom": {
|
||||
|
|
@ -533,9 +533,6 @@
|
|||
"chatgpt_api_request_failed": {
|
||||
"message": "OpenAI ChatGPT API 請求失敗"
|
||||
},
|
||||
"WaitingServerReponse": {
|
||||
"message": "等待伺服器回應"
|
||||
},
|
||||
"error_connection_interrupted": {
|
||||
"message": "與伺服器的連線意外中斷"
|
||||
},
|
||||
|
|
@ -635,9 +632,6 @@
|
|||
"context_menu_mzta-spamfilter": {
|
||||
"message": "檢測垃圾郵件"
|
||||
},
|
||||
"prefs_OptionText_spamfilter_context_menu_Info": {
|
||||
"message": "如果勾選,則在訊息清單中點右鍵時,會出現「分析垃圾郵件」快顯功能選單項目。"
|
||||
},
|
||||
"apiwebchat_use_this_answer": {
|
||||
"message": "使用這個答案"
|
||||
},
|
||||
|
|
@ -802,9 +796,6 @@
|
|||
"prefs_OptionText_spamfilter_threshold_Info": {
|
||||
"message": "如果 AI 傳回的值高於此閾值,則電子郵件將被移至垃圾郵件資料夾。"
|
||||
},
|
||||
"prefs_OptionText_add_tags_context_menu": {
|
||||
"message": "顯示「新增標籤」在快顯功能選單"
|
||||
},
|
||||
"remember_CORS": {
|
||||
"message": "記住,您需要在伺服器上設定 CORS 設定!"
|
||||
},
|
||||
|
|
@ -1005,9 +996,6 @@
|
|||
"prefs_OptionText_btnManageSpamFilterInfo": {
|
||||
"message": "管理垃圾郵件設定"
|
||||
},
|
||||
"CORS_give_allurls_perm": {
|
||||
"message": "授予「所有網址」權限"
|
||||
},
|
||||
"prefs_ollama_num_ctx": {
|
||||
"message": "情境 Token 數量"
|
||||
},
|
||||
|
|
@ -1095,9 +1083,6 @@
|
|||
"prompt_get_task_full_text": {
|
||||
"message": "從以下文字中提取所有需要生成任務的相關資訊。 提取的資訊應包含:\n- 截止日期和時間(包括時區,如果指定)\n- 任務總結\n- 初始日期和時間(包括時區,如果指定)\n確保數據以清晰一致的方式格式化,以便直接用於建立任務。\n如果有相對時間參考,請考慮電子郵件的日期和時間是 「{%mail_datetime%}」。 計算基於此參考的起日期和時間。如果計算出的起日期和時間早於「{%current_datetime%}」,則使用 「{%current_datetime%}」作為基準重新計算起日期和時間。\n如果無法獲得其中一個或多個所需的資訊,請回覆一個空字串。\n請以 JSON 格式回覆,不包含任何額外的文字或說明,提供僅 JSON。 以下是將要使用的格式:\n{\n\"InitialDate\": \"YYYYMMDDTHHMMSS\",\n\"dueDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"任務總結在此\"\n}\n如果沒有日期資訊,請刪除這些資訊。\n以下是文字:「{%selected_text%}」"
|
||||
},
|
||||
"prefs_OptionText_spamfilter_context_menu": {
|
||||
"message": "顯示「分析垃圾郵件」在快顯功能選單"
|
||||
},
|
||||
"sign_msg_as": {
|
||||
"message": "簽署訊息為"
|
||||
},
|
||||
|
|
@ -1137,15 +1122,9 @@
|
|||
"prompt_rewrite_formal_full_text": {
|
||||
"message": "請將以下文字重寫得更正式一些。僅回覆重寫的文字,不要提供任何額外的註解或其他文字。"
|
||||
},
|
||||
"CORS_alternative_2": {
|
||||
"message": "點擊下方按鈕,授予「所有網址」權限,以避免任何 CORS 問題。"
|
||||
},
|
||||
"GoogleGemini_SystemInstruction_Info": {
|
||||
"message": "當您設定系統指示時,您會為模型提供額外情境來理解任務,提供更客製化的回應,並遵守將要發送的提示的特定指南。"
|
||||
},
|
||||
"prefs_OptionText_add_tags_context_menu_Info": {
|
||||
"message": "如果勾選,則右鍵單擊訊息清單中的電子郵件時將顯示「新增標籤」在快顯功能選單。"
|
||||
},
|
||||
"prefs_OptionText_chatgpt_web_custom_gpt_info": {
|
||||
"message": "這是將針對 ChatGPT 網頁介面強制執行的自訂 GPT。"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -213,6 +213,8 @@ if (worker) {
|
|||
version_string: prefs_api[`${integration_prefix}_version`],
|
||||
additional_messages: additional_text_elements
|
||||
}), "info");
|
||||
|
||||
//console.log(`>>>>>>>>>>>>> command: ${llm}_ready_${call_id}`,)
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
command: `${llm}_ready_${call_id}`,
|
||||
|
|
|
|||
BIN
images/summarize.png
Normal file
BIN
images/summarize.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -87,8 +87,6 @@ export class Anthropic {
|
|||
|
||||
fetchResponse = async (messages) => {
|
||||
|
||||
// console.log(">>>>>>>>>>> Anthropic API request: " + JSON.stringify(messages));
|
||||
|
||||
try {
|
||||
|
||||
let claude_body = {
|
||||
|
|
@ -103,6 +101,8 @@ export class Anthropic {
|
|||
|
||||
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: {
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ export class GoogleGemini {
|
|||
google_gemini_body.generationConfig.temperature = tempFloat;
|
||||
}
|
||||
|
||||
// console.log("[ThunderAI] Google Gemini API request: " + JSON.stringify(google_gemini_body));
|
||||
// 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",
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ async function chatgpt_isIdle() {
|
|||
|
||||
function chatgpt_getRegenerateButton() {
|
||||
for (const mainSVG of document.querySelectorAll('main svg.icon')) {
|
||||
if (mainSVG.querySelector('path[d^="M3.502 16.6663V13"]') || mainSVG.querySelector('path[d^="M3.06957"]') || mainSVG.querySelector('path[d^="M10.9153 1.83987L11.2942 1.88772L11.4749"]')){ // regen icon or thumb-up icon found
|
||||
if (mainSVG.querySelector('path[d^="M3.502 16.6663V13"]') || mainSVG.querySelector('path[d^="M3.06957"]') || mainSVG.querySelector('path[d^="M10.9153 1.83987L11.2942 1.88772L11.4749"]') || document.querySelector("button[data-testid=good-response-turn-action-button]")){ // regen icon or thumb-up icon found
|
||||
//console.log(">>>>>>>>>> found regen icon!");
|
||||
return mainSVG.parentNode.parentNode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -430,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'};
|
||||
|
|
|
|||
|
|
@ -324,6 +324,54 @@ const specialPrompts = [
|
|||
is_default: "1",
|
||||
is_special: "1",
|
||||
},
|
||||
{
|
||||
id: 'prompt_summarize',
|
||||
name: "__MSG_prompt_summarize__",
|
||||
text: "prompt_summarize_full_text",
|
||||
type: "1",
|
||||
action: "0",
|
||||
need_selected: "0",
|
||||
need_signature: "0",
|
||||
need_custom_text: "0",
|
||||
define_response_lang: "0",
|
||||
use_diff_viewer: "0",
|
||||
api_type: '',
|
||||
api_model: '',
|
||||
is_default: "1",
|
||||
is_special: "1",
|
||||
},
|
||||
{
|
||||
id: 'prompt_summarize_email_template',
|
||||
name: "__MSG_prompt_summarize_email_template__",
|
||||
text: "prompt_summarize_email_template_full_text",
|
||||
type: "1",
|
||||
action: "0",
|
||||
need_selected: "0",
|
||||
need_signature: "0",
|
||||
need_custom_text: "0",
|
||||
define_response_lang: "0",
|
||||
use_diff_viewer: "0",
|
||||
api_type: '',
|
||||
api_model: '',
|
||||
is_default: "1",
|
||||
is_special: "1",
|
||||
},
|
||||
{
|
||||
id: 'prompt_summarize_email_separator',
|
||||
name: "__MSG_prompt_summarize_email_separator__",
|
||||
text: "prompt_summarize_email_separator_full_text",
|
||||
type: "1",
|
||||
action: "0",
|
||||
need_selected: "0",
|
||||
need_signature: "0",
|
||||
need_custom_text: "0",
|
||||
define_response_lang: "0",
|
||||
use_diff_viewer: "0",
|
||||
api_type: '',
|
||||
api_model: '',
|
||||
is_default: "1",
|
||||
is_special: "1",
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
|
|
@ -362,18 +410,55 @@ export async function getPrompts(onlyEnabled = false, includeSpecial = [], allSp
|
|||
return output;
|
||||
}
|
||||
|
||||
export function preparePromptsForExport(prompts){
|
||||
let output = [...prompts];
|
||||
export function preparePromptsForExport(prompts, include_api_settings = false){
|
||||
let output = JSON.parse(JSON.stringify(prompts));
|
||||
output.forEach(prompt => {
|
||||
|
||||
if(!include_api_settings){
|
||||
delete prompt.api_type;
|
||||
for (const [integration, options] of Object.entries(integration_options_config)) {
|
||||
for (const key of Object.keys(options)) {
|
||||
delete prompt[`${integration}_${key}`];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(prompt.api_type && prompt.api_type !== ''){
|
||||
const activeIntegration = prompt.api_type.replace('_api', '');
|
||||
for (const [integration, options] of Object.entries(integration_options_config)) {
|
||||
if(integration !== activeIntegration){
|
||||
for (const key of Object.keys(options)) {
|
||||
delete prompt[`${integration}_${key}`];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const [integration, options] of Object.entries(integration_options_config)) {
|
||||
for (const key of Object.keys(options)) {
|
||||
delete prompt[`${integration}_${key}`];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(prompt.is_default == 1){
|
||||
let allowedKeys = ['id', 'enabled', 'position_compose', 'position_display', 'need_custom_text'];
|
||||
if(include_api_settings){
|
||||
allowedKeys.push('api_type');
|
||||
for (const [integration, options] of Object.entries(integration_options_config)) {
|
||||
for (const key of Object.keys(options)) {
|
||||
allowedKeys.push(`${integration}_${key}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
Object.keys(prompt).forEach(key => {
|
||||
if(!['id', 'enabled', 'position_compose', 'position_display', 'need_custom_text'].includes(key)){
|
||||
if(!allowedKeys.includes(key)){
|
||||
delete prompt[key];
|
||||
}
|
||||
})
|
||||
}else{
|
||||
delete prompt['idnum'];
|
||||
}
|
||||
|
||||
});
|
||||
return output;
|
||||
}
|
||||
|
|
@ -587,4 +672,4 @@ export async function clearPromptAPI(id){
|
|||
}
|
||||
// console.log(">>>>>>>>>>>>> clearPromptAPI _prompt AFTER: " + JSON.stringify(_prompt));
|
||||
await savePrompt(_prompt);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -25,9 +25,11 @@ export const getMenuContextDisplay = () => 'message_display_action_menu';
|
|||
|
||||
export const contextMenuID_AddTags = 'mzta-add-tags';
|
||||
export const contextMenuID_Spamfilter = 'mzta-spamfilter';
|
||||
export const contextMenuID_Summarize = 'mzta-summarize';
|
||||
export const contextMenuIconsPath = {
|
||||
[contextMenuID_AddTags]: 'moz-extension:images/autotags.png',
|
||||
[contextMenuID_Spamfilter]: 'moz-extension:images/spamfilter.png',
|
||||
[contextMenuID_Summarize]: 'moz-extension:images/summarize.png',
|
||||
};
|
||||
|
||||
export function getLanguageDisplayName(languageCode) {
|
||||
|
|
@ -92,6 +94,17 @@ export async function getCurrentIdentity(msgHeader, getFull = false) {
|
|||
}
|
||||
}
|
||||
|
||||
// Check the account that the folder of the message belongs to
|
||||
if (msgHeader.folder && msgHeader.folder.accountId) {
|
||||
const account = accounts.find(a => a.id === msgHeader.folder.accountId);
|
||||
if (account && account.identities && account.identities.length > 0) {
|
||||
// Just return the first identity of the account.
|
||||
const identity = account.identities[0];
|
||||
console.log(">>>>>>>>>> got from folder");
|
||||
return getFull ? { id: identity.id, email: identity.email } : identity.id;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback
|
||||
return getFull ? fallbackIdentity : fallbackIdentity?.id || null;
|
||||
}
|
||||
|
|
@ -347,17 +360,6 @@ export function i18nConditionalGet(str) {
|
|||
return str; // Return the original string if the conditions are not met
|
||||
}
|
||||
|
||||
export async function isThunderbird128OrGreater(){
|
||||
try {
|
||||
const info = await browser.runtime.getBrowserInfo();
|
||||
const version = info.version;
|
||||
return compareThunderbirdVersions(version, '128.0') >= 0;
|
||||
} catch (error) {
|
||||
console.error('[ThunderAI] Error retrieving browser information:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function compareThunderbirdVersions(v1, v2) {
|
||||
const v1parts = v1.split('.').map(Number);
|
||||
const v2parts = v2.split('.').map(Number);
|
||||
|
|
@ -383,12 +385,9 @@ export function generateCallID(length = 10) {
|
|||
|
||||
export async function getTagsList(){
|
||||
let messageTags = [];
|
||||
if(await isThunderbird128OrGreater()) {
|
||||
// without the tags related permissions, we can't get the tags list
|
||||
messageTags = await browser.messages.tags.list();
|
||||
} else {
|
||||
messageTags = await browser.messages.listTags();
|
||||
}
|
||||
// without the tags related permissions, we can't get the tags list
|
||||
messageTags = await browser.messages.tags.list();
|
||||
|
||||
const output = messageTags.map(tag => tag.tag).join(', ');
|
||||
|
||||
const output2 = messageTags.reduce((acc, messageTag) => {
|
||||
|
|
@ -409,11 +408,7 @@ export async function createTag(tag) {
|
|||
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(tagKey, tag, generateHexColorForTag());
|
||||
}else{
|
||||
return browser.messages.createTag(tagKey, tag, generateHexColorForTag());
|
||||
}
|
||||
return browser.messages.tags.create(tagKey, tag, generateHexColorForTag());
|
||||
} catch (error) {
|
||||
console.error('[ThunderAI] Error creating tag:', error);
|
||||
}
|
||||
|
|
@ -515,6 +510,10 @@ export function normalizeStringList(list, returnType = 0) {
|
|||
}
|
||||
}
|
||||
|
||||
export function prepareOriginURL(url) {
|
||||
return url.endsWith('/') ? `${url}*` : `${url}/*`;
|
||||
}
|
||||
|
||||
function generateHexColorForTag() {
|
||||
const red = Math.floor(Math.random() * 256);
|
||||
const green = Math.floor(Math.random() * 256);
|
||||
|
|
@ -535,6 +534,14 @@ export async function transformTagsLabels(labels, tags_list) {
|
|||
return output;
|
||||
}
|
||||
|
||||
export function setTomSelectBorder(el){
|
||||
if (el.getValue() === "") {
|
||||
el.control.style.border = '2px solid red';
|
||||
} else {
|
||||
el.control.style.border = '1px solid #d0d0d0';
|
||||
}
|
||||
}
|
||||
|
||||
export function getAPIsInitMessageString(args = {}) {
|
||||
const {
|
||||
api_string = '',
|
||||
|
|
@ -685,6 +692,29 @@ export function validateCustomData_ChatGPTWeb(event) {
|
|||
document.getElementById(event.target.id + '_info').style.color = is_valid ? '' : 'red';
|
||||
}
|
||||
|
||||
// From https://thunderbird.topicbox.com/groups/addons/Tafa58394231a18f8-M3e565a75287313ea4395ff5f
|
||||
// Thanks to John Bieling
|
||||
export async function requestSitePermission(url) {
|
||||
// Normalize the origin to ensure it ends with /*
|
||||
const origin = url.replace(/\/?\*?$/, '/*');
|
||||
|
||||
const hasPermission = await browser.permissions.contains({
|
||||
origins: [origin],
|
||||
});
|
||||
|
||||
if (hasPermission) {
|
||||
// Permission already granted — safe to save and use the URL.
|
||||
return true;
|
||||
}
|
||||
|
||||
const granted = await browser.permissions.request({
|
||||
origins: [origin],
|
||||
});
|
||||
|
||||
// If not granted, it's not safe to save or use the URL,
|
||||
// since the user explicitly denied access.
|
||||
return granted;
|
||||
}
|
||||
|
||||
// The following methods are a modified version derived from https://github.com/ali-raheem/Aify/blob/13ff87583bc520fb80f555ab90a90c5c9df797a7/plugin/content_scripts/compose.js
|
||||
|
||||
|
|
|
|||
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Firefox 115 and, consequently, Thunderbird 115 are not compatible with Intl.Segmenter.
|
||||
// ChatGPT is using Intl.Segmenter, so we have to do something about it or it won't work...
|
||||
|
||||
// console.log("[ThunderAI] Intl.Segmenter: " + Intl.Segmenter);
|
||||
|
||||
(function() {
|
||||
if('Segmenter' in Intl){
|
||||
// console.log('[ThunderAI] TB128+ detected. Intl.Segmenter is already supported.');
|
||||
return;
|
||||
}
|
||||
// Creates a <script> element to inject polyfill.js into the page context
|
||||
const script = document.createElement('script');
|
||||
script.src = browser.runtime.getURL('js/tb115_segmenter/tb115_polyfill.js');
|
||||
script.onload = function() {
|
||||
// Remove the script once loaded for cleanup
|
||||
this.remove();
|
||||
};
|
||||
script.onerror = function() {
|
||||
console.error('[ThunderAI] Error loading Intl.Segmenter polyfill.');
|
||||
};
|
||||
(document.head || document.documentElement).appendChild(script);
|
||||
})();
|
||||
|
||||
|
||||
|
||||
async function isThunderbird128OrGreater(){
|
||||
try {
|
||||
const info = await browser.runtime.getBrowserInfo();
|
||||
const version = info.version;
|
||||
return compareThunderbirdVersions(version, '128.0') >= 0;
|
||||
} catch (error) {
|
||||
console.error('[ThunderAI] Error retrieving browser information:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function compareThunderbirdVersions(v1, v2) {
|
||||
const v1parts = v1.split('.').map(Number);
|
||||
const v2parts = v2.split('.').map(Number);
|
||||
|
||||
for (let i = 0; i < Math.max(v1parts.length, v2parts.length); i++) {
|
||||
const v1part = v1parts[i] || 0;
|
||||
const v2part = v2parts[i] || 0;
|
||||
if (v1part > v2part) return 1;
|
||||
if (v1part < v2part) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Firefox 115 and, consequently, Thunderbird 115 are not compatible with Intl.Segmenter.
|
||||
// ChatGPT is using Intl.Segmenter, so we have to do something about it or it won't work...
|
||||
|
||||
(function() {
|
||||
if (!('Segmenter' in Intl)) {
|
||||
class Segmenter {
|
||||
constructor(locale = 'en', options = { granularity: 'grapheme' }) {
|
||||
this.locale = locale;
|
||||
this.granularity = options.granularity || 'grapheme';
|
||||
}
|
||||
|
||||
segment(text) {
|
||||
switch (this.granularity) {
|
||||
case 'word':
|
||||
return text.split(/\s+/).filter(word => word.length > 0).map(word => ({ segment: word }));
|
||||
case 'grapheme':
|
||||
return Array.from(text).map(char => ({ segment: char }));
|
||||
case 'sentence':
|
||||
return text.split(/(?<=[.!?])\s+/).map(sentence => ({ segment: sentence }));
|
||||
default:
|
||||
return [{ segment: text }];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Intl.Segmenter = Segmenter;
|
||||
// console.log('Intl.Segmenter polyfill correctly loaded.');
|
||||
}
|
||||
// else {
|
||||
// console.log('Intl.Segmenter is already supported.');
|
||||
// }
|
||||
})();
|
||||
|
|
@ -2,13 +2,13 @@
|
|||
"manifest_version": 2,
|
||||
"name": "ThunderAI",
|
||||
"description": "__MSG_extensionDescription__",
|
||||
"version": "3.8.0pre4",
|
||||
"version": "4.0.0",
|
||||
"author": "Mic (m@micz.it)",
|
||||
"homepage_url": "https://micz.it/thunderbird-addon-thunderai/",
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "thunderai@micz.it",
|
||||
"strict_min_version": "115.0"
|
||||
"strict_min_version": "140.0"
|
||||
}
|
||||
},
|
||||
"message_display_action": {
|
||||
|
|
@ -40,6 +40,8 @@
|
|||
"https://*.chatgpt.com/*",
|
||||
"https://*.openai.com/*",
|
||||
"https://*.anthropic.com/*",
|
||||
"https://*/*",
|
||||
"http://*/*",
|
||||
"<all_urls>"
|
||||
],
|
||||
"background": {
|
||||
|
|
@ -65,7 +67,7 @@
|
|||
"content_scripts": [
|
||||
{
|
||||
"matches": ["https://*.chatgpt.com/*"],
|
||||
"js": ["js/tb115_segmenter/tb115_loader.js","js/lib/diff.js"],
|
||||
"js": ["js/lib/diff.js"],
|
||||
"all_frames": true,
|
||||
"run_at": "document_start"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import {
|
|||
extractJsonObject,
|
||||
contextMenuID_AddTags,
|
||||
contextMenuID_Spamfilter,
|
||||
contextMenuID_Summarize,
|
||||
contextMenuIconsPath,
|
||||
sanitizeChatGPTModelData,
|
||||
sanitizeChatGPTWebCustomData,
|
||||
|
|
@ -57,10 +58,16 @@ import {
|
|||
} from './js/mzta-utils.js';
|
||||
import { taPromptUtils } from './js/mzta-utils-prompt.js';
|
||||
import { mzta_specialCommand } from './js/mzta-special-commands.js';
|
||||
import { getSpamFilterPrompt } from './js/mzta-prompts.js';
|
||||
import {
|
||||
getSpamFilterPrompt,
|
||||
getSpecialPrompts
|
||||
} from './js/mzta-prompts.js';
|
||||
import { taSpamReport } from './js/mzta-spamreport.js';
|
||||
import { taWorkingStatus } from './js/mzta-working-status.js';
|
||||
import { addTags_getExclusionList, checkExcludedTag } from './js/mzta-addatags-exclusion-list.js';
|
||||
import {
|
||||
addTags_getExclusionList,
|
||||
checkExcludedTag
|
||||
} from './js/mzta-addatags-exclusion-list.js';
|
||||
|
||||
browser.runtime.onInstalled.addListener(({ reason, previousVersion }) => {
|
||||
// console.log(">>>>>>>>>>> onInstalled: " + JSON.stringify(reason) + ", previousVersion: " + previousVersion);
|
||||
|
|
@ -572,7 +579,7 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_
|
|||
browser.runtime.onMessage.removeListener(listener2);
|
||||
}
|
||||
|
||||
if (message.command === "openai_api_ready_"+rand_call_id2) {
|
||||
if (message.command === "chatgpt_api_ready_"+rand_call_id2) {
|
||||
return handleChatGptApi(sender.tab);
|
||||
}
|
||||
return false;
|
||||
|
|
@ -848,10 +855,9 @@ async function reload_pref_init(){
|
|||
add_tags_auto_force_existing: prefs_default.add_tags_auto_force_existing,
|
||||
add_tags_auto_only_inbox: prefs_default.add_tags_auto_only_inbox,
|
||||
spamfilter: prefs_default.spamfilter,
|
||||
summarize: prefs_default.summarize,
|
||||
spamfilter_threshold: prefs_default.spamfilter_threshold,
|
||||
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,
|
||||
...getDynamicSettingsDefaults(['use_specific_integration', 'connection_type'])
|
||||
});
|
||||
_process_incoming = prefs_init.add_tags_auto || prefs_init.spamfilter;
|
||||
|
|
@ -922,48 +928,11 @@ function setupStorageChangeListener() {
|
|||
is_chatgpt_web: (newConnectionType === "chatgpt_web")
|
||||
});
|
||||
menus.reload(special_prompts_ids);
|
||||
}
|
||||
|
||||
if(newConnectionType === "chatgpt_web"){
|
||||
removeContextMenu(contextMenuID_AddTags);
|
||||
removeContextMenu(contextMenuID_Spamfilter);
|
||||
}
|
||||
reload_pref_init().then(() => {
|
||||
addContextMenuItems();
|
||||
}
|
||||
|
||||
// context menu changes for add_tags and spamfilter
|
||||
if (changes.add_tags_context_menu) {
|
||||
if(changes.add_tags_context_menu.newValue){
|
||||
addContextMenu(contextMenuID_AddTags);
|
||||
}else{
|
||||
removeContextMenu(contextMenuID_AddTags);
|
||||
}
|
||||
}
|
||||
if (changes.add_tags) {
|
||||
if(changes.add_tags.newValue){
|
||||
if(prefs_init.add_tags_context_menu){
|
||||
addContextMenu(contextMenuID_AddTags);
|
||||
}
|
||||
}else{
|
||||
removeContextMenu(contextMenuID_AddTags);
|
||||
}
|
||||
}
|
||||
if (changes.spamfilter_context_menu) {
|
||||
if(changes.spamfilter_context_menu.newValue){
|
||||
addContextMenu(contextMenuID_Spamfilter);
|
||||
}else{
|
||||
removeContextMenu(contextMenuID_Spamfilter);
|
||||
}
|
||||
}
|
||||
if (changes.spamfilter) {
|
||||
if(changes.spamfilter.newValue){
|
||||
if(prefs_init.spamfilter_context_menu){
|
||||
addContextMenu(contextMenuID_Spamfilter);
|
||||
}
|
||||
}else{
|
||||
removeContextMenu(contextMenuID_Spamfilter);
|
||||
}
|
||||
}
|
||||
reload_pref_init();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -1014,15 +983,38 @@ function removeContextMenu(menu_id) {
|
|||
}
|
||||
|
||||
function addContextMenuItems() {
|
||||
let itemsToAdd = [];
|
||||
|
||||
// Add Context menu: Add tags
|
||||
if(prefs_init.add_tags && prefs_init.add_tags_context_menu && checkAPIIntegration(prefs_init.connection_type, prefs_init.add_tags_use_specific_integration,prefs_init.add_tags_connection_type)){
|
||||
addContextMenu(contextMenuID_AddTags);
|
||||
if(prefs_init.add_tags && checkAPIIntegration(prefs_init.connection_type, prefs_init.add_tags_use_specific_integration,prefs_init.add_tags_connection_type)){
|
||||
itemsToAdd.push(contextMenuID_AddTags);
|
||||
} else {
|
||||
removeContextMenu(contextMenuID_AddTags);
|
||||
}
|
||||
|
||||
// Add Context menu: Spamfilter
|
||||
if(prefs_init.spamfilter && prefs_init.spamfilter_context_menu && checkAPIIntegration(prefs_init.connection_type, prefs_init.spamfilter_use_specific_integration,prefs_init.spamfilter_connection_type)){
|
||||
addContextMenu(contextMenuID_Spamfilter);
|
||||
if(prefs_init.spamfilter && checkAPIIntegration(prefs_init.connection_type, prefs_init.spamfilter_use_specific_integration,prefs_init.spamfilter_connection_type)){
|
||||
itemsToAdd.push(contextMenuID_Spamfilter);
|
||||
} else {
|
||||
removeContextMenu(contextMenuID_Spamfilter);
|
||||
}
|
||||
|
||||
// Add Context menu: Summarize
|
||||
if(prefs_init.summarize && checkAPIIntegration(prefs_init.connection_type, prefs_init.summarize_use_specific_integration, prefs_init.summarize_connection_type)) {
|
||||
itemsToAdd.push(contextMenuID_Summarize);
|
||||
} else {
|
||||
removeContextMenu(contextMenuID_Summarize);
|
||||
}
|
||||
|
||||
itemsToAdd.sort((a, b) => {
|
||||
let titleA = browser.i18n.getMessage("context_menu_" + a);
|
||||
let titleB = browser.i18n.getMessage("context_menu_" + b);
|
||||
return titleA.localeCompare(titleB);
|
||||
});
|
||||
|
||||
itemsToAdd.forEach(menu_id => {
|
||||
addContextMenu(menu_id);
|
||||
});
|
||||
}
|
||||
|
||||
addContextMenuItems();
|
||||
|
|
@ -1031,17 +1023,93 @@ addContextMenuItems();
|
|||
browser.menus.onClicked.addListener( (info, tab) => {
|
||||
let _add_tags = false
|
||||
let _spamfilter = false
|
||||
let _summarize = false;
|
||||
if(info.menuItemId === contextMenuID_AddTags){
|
||||
_add_tags = true;
|
||||
}
|
||||
if(info.menuItemId === contextMenuID_Spamfilter){
|
||||
_spamfilter = true;
|
||||
}
|
||||
if(info.menuItemId === contextMenuID_Summarize) {
|
||||
_summarize = true;
|
||||
}
|
||||
if(_add_tags || _spamfilter){
|
||||
processEmails(getMessages(info.selectedMessages), _add_tags, _spamfilter);
|
||||
}
|
||||
if(_summarize) {
|
||||
// info.selectedMessages is of type MessageList
|
||||
summarizeEmails(getMessages(info.selectedMessages));
|
||||
}
|
||||
});
|
||||
|
||||
async function summarizeEmails(messages) {
|
||||
taWorkingStatus.startWorking();
|
||||
|
||||
// we have three prompts, the actual assignment for the LLM, the email
|
||||
// template prompt, and the email separator prompt
|
||||
const specialPrompts = await getSpecialPrompts();
|
||||
const prompt = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize');
|
||||
const prompt_email = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_template');
|
||||
const prompt_email_separator = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_separator');
|
||||
|
||||
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
|
||||
const chatgpt_lang = await taPromptUtils.getDefaultLang(prompt);
|
||||
|
||||
// replace placeholders in the prompts the assignment prompt and email
|
||||
// separator prompt do not have a message as context, so there is only
|
||||
// limited things to replace
|
||||
const prompt_string = await taPromptUtils.preparePrompt({
|
||||
curr_prompt: prompt,
|
||||
chatgpt_lang: chatgpt_lang,
|
||||
});
|
||||
const prompt_email_separator_string = await taPromptUtils.preparePrompt({
|
||||
curr_prompt: prompt_email_separator,
|
||||
chatgpt_lang: chatgpt_lang,
|
||||
});
|
||||
|
||||
|
||||
// assemble all email messages into one string and add the assignment prompt
|
||||
const messages_list = [];
|
||||
for await (let curr_message of messages) {
|
||||
|
||||
// extract body of current message as text
|
||||
const curr_message_full = await browser.messages.getFull(curr_message.id);
|
||||
const curr_body_full_html = getMailBody(curr_message_full);
|
||||
const curr_body_full_text = htmlBodyToPlainText(curr_body_full_html.html);
|
||||
if( curr_body_full_text.length === 0) {
|
||||
taLog.log("No HTML found in the message body, using plain text...");
|
||||
curr_body_full_text = curr_message_full.text;
|
||||
}
|
||||
|
||||
messages_list.push(await taPromptUtils.preparePrompt({
|
||||
curr_prompt: prompt_email,
|
||||
curr_message: curr_message,
|
||||
chatgpt_lang: chatgpt_lang,
|
||||
body_text: curr_body_full_text,
|
||||
subject_text: curr_message_full.headers.subject,
|
||||
msg_text: curr_body_full_html,
|
||||
}));
|
||||
};
|
||||
const messages_string = messages_list.join(prompt_email_separator_string);
|
||||
|
||||
const full_prompt = prompt_string + prompt_email_separator_string + messages_string;
|
||||
|
||||
// console.log(full_prompt);
|
||||
|
||||
// send the prompt to the chat interface
|
||||
openChatGPT(
|
||||
full_prompt,
|
||||
prompt.action,
|
||||
tabs[0].id,
|
||||
prompt.name,
|
||||
prompt.need_custom_text,
|
||||
prompt
|
||||
)
|
||||
|
||||
taWorkingStatus.stopWorking();
|
||||
return {ok : '1'};
|
||||
}
|
||||
|
||||
|
||||
// Listening for new received emails
|
||||
const newEmailListener = (folder, messagesList) => {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const special_prompts_with_integration = ['add_tags', 'spamfilter'];
|
||||
const special_prompts_with_integration = ['add_tags', 'spamfilter', 'summarize', 'get_calendar_event', 'get_task'];
|
||||
|
||||
export const integration_options_config = {
|
||||
chatgpt: {
|
||||
|
|
@ -123,7 +123,6 @@ export const prefs_default = {
|
|||
add_tags_auto_only_inbox: true,
|
||||
add_tags_auto_uselist: false,
|
||||
add_tags_auto_uselist_list: '',
|
||||
add_tags_context_menu: true,
|
||||
add_tags_enabled_accounts: [],
|
||||
get_calendar_event: true,
|
||||
get_task: true,
|
||||
|
|
@ -131,8 +130,8 @@ export const prefs_default = {
|
|||
calendar_timezone: '',
|
||||
spamfilter: false,
|
||||
spamfilter_threshold: 70,
|
||||
spamfilter_context_menu: true,
|
||||
spamfilter_enabled_accounts: [],
|
||||
auto_summary_enabled: false, // Enable automatic AI summarization for message previews
|
||||
summarize: false,
|
||||
...generated_prefs
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,6 +158,17 @@
|
|||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="summarize_tr">
|
||||
<td><span class="opt_title">__MSG_prefs_OptionText_summarize__</span>
|
||||
<br><button id="btnManageSummarizeInfo" class="btn_small">__MSG_prefs_OptionText_btnManageSummarizeInfo__</button></td>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" id="summarize" name="summarize" class="option-input" />
|
||||
__MSG_prefs_OptionText_summarize_Info__
|
||||
<br><span class="warn_API_needed" id="summarize_warn_API_needed">__MSG_warn_API_needed__</span>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="get_calendar_event_tr">
|
||||
<td><span class="opt_title">__MSG_prefs_OptionText_get_calendar_event__</span>
|
||||
<br><button id="btnManageCalendarEventInfo" class="btn_small">__MSG_prefs_OptionText_btnManageCalendarEventInfo__</button></td>
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@ import { taLogger } from '../js/mzta-logger.js';
|
|||
import {
|
||||
ChatGPTWeb_models,
|
||||
checkSparksPresence,
|
||||
isThunderbird128OrGreater,
|
||||
openTab,
|
||||
getChatGPTWebModelsList_HTML,
|
||||
isAPIKeyValue,
|
||||
getConnectionType,
|
||||
setTomSelectBorder
|
||||
} from '../js/mzta-utils.js';
|
||||
import {
|
||||
injectConnectionUI,
|
||||
|
|
@ -35,7 +35,6 @@ import {
|
|||
} from '../pages/_lib/connection-ui.js';
|
||||
|
||||
let taLog = new taLogger("mzta-options",true);
|
||||
let _isThunderbird128OrGreater = true;
|
||||
|
||||
function saveOptions(e) {
|
||||
e.preventDefault();
|
||||
|
|
@ -77,6 +76,7 @@ function saveOptions(e) {
|
|||
async function restoreOptions() {
|
||||
function setCurrentChoice(result) {
|
||||
document.querySelectorAll(".option-input").forEach(element => {
|
||||
if(!element.id) return;
|
||||
taLog.log("Options restoring " + element.id + " = " + (isAPIKeyValue(element.id) ? "****************" : result[element.id]));
|
||||
switch (element.type) {
|
||||
case 'checkbox':
|
||||
|
|
@ -102,6 +102,10 @@ async function restoreOptions() {
|
|||
if (element.value === '') {
|
||||
element.selectedIndex = -1;
|
||||
}
|
||||
if (element.tomselect) {
|
||||
element.tomselect.setValue(element.value, true);
|
||||
setTomSelectBorder(element.tomselect);
|
||||
}
|
||||
break;
|
||||
case 'textarea':
|
||||
element.value = result[element.id];
|
||||
|
|
@ -167,6 +171,27 @@ function disable_SpamFilter(prefs_opt){
|
|||
}
|
||||
}
|
||||
|
||||
function disable_Summarize(prefs_opt){
|
||||
let summarize = document.getElementById('summarize');
|
||||
let conntype_select = document.getElementById("connection_type");
|
||||
const tempPrefs = {
|
||||
connection_type: conntype_select.value,
|
||||
...prefs_opt
|
||||
};
|
||||
let summarize_disabled = (getConnectionType(tempPrefs, null, 'summarize') === "chatgpt_web");
|
||||
let summarize_checked_original = summarize.checked;
|
||||
summarize.checked = summarize_disabled ? false : summarize.checked;
|
||||
if(!summarize.checked){
|
||||
let summarize_info_btn = document.getElementById('btnManageSummarizeInfo');
|
||||
summarize_info_btn.disabled = 'disabled';
|
||||
}
|
||||
let summarize_warn_API_needed = document.getElementById('summarize_warn_API_needed');
|
||||
summarize_warn_API_needed.style.display = (summarize_disabled) ? 'inline-block' : 'none';
|
||||
if(summarize_checked_original != summarize.checked){
|
||||
browser.storage.sync.set({summarize: summarize.checked});
|
||||
}
|
||||
}
|
||||
|
||||
async function disable_GetCalendarEvent(){
|
||||
let get_calendar_event = document.getElementById('get_calendar_event');
|
||||
let get_task = document.getElementById('get_task');
|
||||
|
|
@ -207,8 +232,6 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
|
||||
varConnectionUI.permission_all_urls = await messenger.permissions.contains({ origins: ["<all_urls>"] })
|
||||
|
||||
_isThunderbird128OrGreater = await isThunderbird128OrGreater();
|
||||
|
||||
// show Owl warning
|
||||
const accountList = await messenger.accounts.list(false);
|
||||
if(accountList.some(account => account.type.toLowerCase().includes('owl'))) {
|
||||
|
|
@ -227,11 +250,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
async function _addtags_el_change() {
|
||||
if (event.target.checked) {
|
||||
let granted = false;
|
||||
if(_isThunderbird128OrGreater){
|
||||
granted = await messenger.permissions.request({ permissions: ["messagesTags", "messagesUpdate"] });
|
||||
}else{
|
||||
granted = await messenger.permissions.request({ permissions: ["messagesTags"] });
|
||||
}
|
||||
granted = await messenger.permissions.request({ permissions: ["messagesTags", "messagesUpdate"] });
|
||||
if (!granted) {
|
||||
event.target.checked = false;
|
||||
addtags_info_btn.disabled = 'disabled';
|
||||
|
|
@ -262,6 +281,13 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
});
|
||||
spamfilter_info_btn.disabled = spamfilter_el.checked ? '' : 'disabled';
|
||||
|
||||
let summarize_el = document.getElementById('summarize');
|
||||
let summarize_info_btn = document.getElementById('btnManageSummarizeInfo');
|
||||
summarize_el.addEventListener('click', (event) => {
|
||||
summarize_info_btn.disabled = event.target.checked ? '' : 'disabled';
|
||||
});
|
||||
summarize_info_btn.disabled = summarize_el.checked ? '' : 'disabled';
|
||||
|
||||
let get_calendar_event_el = document.getElementById('get_calendar_event');
|
||||
let get_calendar_event_info_btn = document.getElementById('btnManageCalendarEventInfo');
|
||||
get_calendar_event_el.addEventListener('click', (event) => {
|
||||
|
|
@ -291,6 +317,10 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
document.getElementById('btnManageSpamFilterInfo').addEventListener('click', () => {
|
||||
openTab('/pages/spamfilter/mzta-spamfilter.html');
|
||||
});
|
||||
|
||||
document.getElementById('btnManageSummarizeInfo').addEventListener('click', () => {
|
||||
openTab('/pages/summarize/mzta-summarize.html');
|
||||
});
|
||||
|
||||
document.getElementById('btnManageCalendarEventInfo').addEventListener('click', () => {
|
||||
openTab('/pages/get-calendar-event/mzta-get-calendar-event.html');
|
||||
|
|
@ -317,19 +347,21 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
conntype_select.addEventListener("change", disable_MaxPromptLength);
|
||||
conntype_select.addEventListener("change", () => disable_AddTags(prefs_opt));
|
||||
conntype_select.addEventListener("change", () => disable_SpamFilter(prefs_opt));
|
||||
conntype_select.addEventListener("change", () => disable_Summarize(prefs_opt));
|
||||
conntype_select.addEventListener("change", disable_GetCalendarEvent);
|
||||
|
||||
showConnectionOptions(conntype_select);
|
||||
disable_MaxPromptLength();
|
||||
disable_AddTags(prefs_opt);
|
||||
disable_SpamFilter(prefs_opt);
|
||||
disable_Summarize(prefs_opt);
|
||||
disable_GetCalendarEvent();
|
||||
|
||||
document.getElementById('reset_max_prompt_length').addEventListener('click', resetMaxPromptLength);
|
||||
|
||||
browser.runtime.getPlatformInfo().then(info => {
|
||||
taLog.log("OS: " + info.os);
|
||||
if ((info.os === "linux")&&(prefs.chatgpt_win_height!=0)&&(prefs.chatgpt_win_width!=0)){
|
||||
if ((info.os === "linux")&&(prefs_opt.chatgpt_win_height!=0)&&(prefs_opt.chatgpt_win_width!=0)){
|
||||
document.getElementById('hyprland_warning').style.display = 'table-row';
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,7 +7,32 @@
|
|||
<body>
|
||||
<div id="miczBackPrefs"><a href="mzta-options.html">__MSG_backToOptionsText__</a></div>
|
||||
<div id="miczRelNotes"><h1>ThunderAI Release Notes</h1>
|
||||
<h2>Version 3.8.0 - ??/??/2026</h2>
|
||||
<h2>Version 4.0.0 - ??/??/2026</h2>
|
||||
<ul>
|
||||
<li>ThunderAI is now compatible only with Thunderbird 140 and later [<a href="https://github.com/micz/ThunderAI/issues/616">#616</a>].</li>
|
||||
<li><i>[All APIs]</i> It's now possibile to define a specific API integration for calendar and task recognition [<a href="https://github.com/micz/ThunderAI/issues/498">#498</a>].</li>
|
||||
<li>Added a new model selector with a search functionality to dynamically filter the list [<a href="https://github.com/micz/ThunderAI/issues/603">#603</a>].</li>
|
||||
<li><i>[All APIs]</i> Added a special prompt to summarize one or more emails, using a context menu command [<a href="https://github.com/micz/ThunderAI/issues/615">#615</a>]. Thanks to <a href="https://github.com/gdkrmr">Guido Kraemer</a> for his great work on this feature.</li>
|
||||
<li><i>[All APIs]</i> "Analyze for spam" and "Add tags" context menu items are always shown when the corresponding feature is enabled [<a href="https://github.com/micz/ThunderAI/issues/609">#609</a>].</li>
|
||||
<li><i>[OpenAI Comp API][Ollama API]</i> Asking for the single host for permission to avoid CORS errors, instead of <i>all_urls</i>, as requested by the Thunderbird Review Team [<a href="https://github.com/micz/ThunderAI/issues/524">#524</a>].</li>
|
||||
<li>Fix: Using also the mail folder owner to search for the right identity to use when composing a reply [<a href="https://github.com/micz/ThunderAI/issues/627">#627</a>].</li>
|
||||
<li>Context menu items are always ordered alfabetically [<a href="https://github.com/micz/ThunderAI/issues/630">#630</a>].</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
<h2>Version 3.8.3 - 22/01/2026</h2>
|
||||
<ul>
|
||||
<li>Fix: Correctly saving the API settings in new custom prompts [<a href="https://github.com/micz/ThunderAI/issues/623">#623</a>].</li>
|
||||
<li>Japanese (ja) translation added, thanks to <a href="https://hosted.weblate.org/user/watya1/">Taichi Ito</a>.</li>
|
||||
</ul>
|
||||
<h2>Version 3.8.2 - 20/01/2026</h2>
|
||||
<ul>
|
||||
<li>Fix: Correctly saving the enabled status in custom prompts [<a href="https://github.com/micz/ThunderAI/issues/621">#621</a>].</li>
|
||||
</ul>
|
||||
<h2>Version 3.8.1 - 20/01/2026</h2>
|
||||
<ul>
|
||||
<li><i>[OpenAI API]</i> Fix: Correctly sending the prompt after opening the chat window [<a href="https://github.com/micz/ThunderAI/issues/620">#620</a>].</li>
|
||||
</ul>
|
||||
<h2>Version 3.8.0 - 16/01/2026</h2>
|
||||
<ul>
|
||||
<li><i>[All APIs]</i> 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 [<a href="https://github.com/micz/ThunderAI/pull/102">#102</a>].</li>
|
||||
<li><i>[All APIs]</i> 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 [<a href="https://github.com/micz/ThunderAI/pull/590">#590</a>].</li>
|
||||
|
|
@ -19,7 +44,10 @@
|
|||
<li>Spanish (es) translation added, thanks to <a href="https://hosted.weblate.org/user/gerardo.sobarzo/">Gerardo Sobarzo</a>, <a href="https://hosted.weblate.org/user/arendon/">Andrés Rendón Hernández</a>, <a href="https://hosted.weblate.org/user/ErickLimonG/">Erick Limon</a>.</li>
|
||||
<li>Swedish (sv) translation added, thanks to <a href="https://hosted.weblate.org/user/Andy_tb/">Andreas Pettersson</a>.</li>
|
||||
<li>Various fixes.</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
<h2>Version 3.7.9 - 06/01/2026</h2>
|
||||
<ul>
|
||||
<li><i>[ChatGPT Web]</i> Fix: Correctly getting the job completion [<a href="https://github.com/micz/ThunderAI/issues/607">#607</a>].</li>
|
||||
</ul>
|
||||
<h2>Version 3.7.8 - 18/12/2025</h2>
|
||||
<ul>
|
||||
|
|
@ -62,8 +90,9 @@
|
|||
<ul>
|
||||
<li><i>[All APIs]</i> It's now possibile to define a list of tags to be used when autotagging received emails [<a href="https://github.com/micz/ThunderAI/issues/436">#436</a>]. The tags are are now shown in the information header in the AI API chat [<a href="https://github.com/micz/ThunderAI/issues/289">#289</a>].</li>
|
||||
<li><i>[All APIs]</i> The prompt id and name are now shown in the information header in the AI API chat [<a href="https://github.com/micz/ThunderAI/issues/436">#436</a>].</li>
|
||||
<li><i>[All APIs]</i> It's now possibile to define a specific API integration for spamfilter and auto tagging [<a href="https://github.com/micz/ThunderAI/issues/438">#438</a>].</li>
|
||||
<li>Added the <i>{%mail_attachments_info%}</i> placeholder to retrieve the name, type and file size of the mail attachments [<a href="https://github.com/micz/ThunderAI/issues/446">#446</a>].</li>
|
||||
<li><i>[Google Gemini API]</i>Support for the thinkingBudget parameter has been added [<a href="https://github.com/micz/ThunderAI/issues/494">#494</a>].</li>
|
||||
<li><i>[Google Gemini API]</i> Support for the thinkingBudget parameter has been added [<a href="https://github.com/micz/ThunderAI/issues/494">#494</a>].</li>
|
||||
<li><i>[OpenAI Comp API]</i> Added DeepSeek configuration [<a href="https://github.com/micz/ThunderAI/issues/486">#486</a>].</li>
|
||||
<li><i>[ChatGPT Web]</i> Added a message to explain to click on "Force completion" if the ChatGPT job is not done after 7 seconds [<a href="https://github.com/micz/ThunderAI/issues/419">#419</a>].</li>
|
||||
<li>Anthropic API renamed to Claude API [<a href="https://github.com/micz/ThunderAI/issues/510">#510</a>].</li>
|
||||
|
|
@ -397,7 +426,7 @@
|
|||
<li><i>[ChatGPT API]</i> Added a better error message when there is an error fetching models.</li>
|
||||
<li>When selecting a correct model in the options page, the field is no more highlighted in red [<a href="https://github.com/micz/ThunderAI/issues/100">#100</a>].</li>
|
||||
<li><i>[ChatGPT API]</i> The double quotes at the beginning and end of the response are removed [<a href="https://github.com/micz/ThunderAI/issues/99">#99</a>].</li>
|
||||
<li><i>[ChatGPT Web]</i>"Keep formatting" option removed.</li>
|
||||
<li><i>[ChatGPT Web]</i> "Keep formatting" option removed.</li>
|
||||
</ul>
|
||||
<h2>Version 2.0.1 - 09/08/2024</h2>
|
||||
<ul>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
@import url("tom-select.default.min.css");
|
||||
|
||||
tr.conntype_chatgpt_api, tr.conntype_chatgpt_api2{
|
||||
background-color: rgb(185, 220, 252) !important;
|
||||
}
|
||||
|
|
@ -91,6 +93,10 @@ span.opt_title{
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
.ts-control, .ts-dropdown{
|
||||
font-size: 14.4px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
tr.conntype_chatgpt_api, tr.conntype_chatgpt_api2{
|
||||
background-color: rgb(0, 0, 58) !important;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import './tom-select.base.js';
|
||||
import {
|
||||
prefs_default,
|
||||
integration_options_config
|
||||
|
|
@ -28,13 +29,21 @@ import { Anthropic } from '../../js/api/anthropic.js';
|
|||
import {
|
||||
validateCustomData_ChatGPTWeb,
|
||||
sanitizeChatGPTModelData,
|
||||
sanitizeChatGPTWebCustomData
|
||||
sanitizeChatGPTWebCustomData,
|
||||
prepareOriginURL,
|
||||
setTomSelectBorder
|
||||
} from '../../js/mzta-utils.js';
|
||||
import { openAICompConfigs } from '../../js/api/openai_comp_configs.js';
|
||||
import { loadPrompt, savePrompt, clearPromptAPI } from '../../js/mzta-prompts.js';
|
||||
import {
|
||||
loadPrompt,
|
||||
savePrompt,
|
||||
clearPromptAPI
|
||||
} from '../../js/mzta-prompts.js';
|
||||
|
||||
export const varConnectionUI = {
|
||||
permission_all_urls: false
|
||||
permission_all_urls: false,
|
||||
permission_ollama_host: false,
|
||||
permission_openai_comp_host: false
|
||||
}
|
||||
|
||||
export async function injectConnectionUI({
|
||||
|
|
@ -296,8 +305,9 @@ export async function injectConnectionUI({
|
|||
<td colspan="2" style="text-align:center;">
|
||||
__MSG_remember_CORS__ [<a href="https://micz.it/thunderbird-addon-thunderai/ollama-cors-information/">__MSG_more_info_string__</a>]
|
||||
<br><br><b>__MSG_CORS_alternative_1__</b>
|
||||
<br>__MSG_CORS_alternative_2__
|
||||
<br><br><button id="${modelId_prefix ? `${modelId_prefix}` : ''}btnGiveAllUrlsPermission_ollama_api">__MSG_CORS_give_allurls_perm__</button>
|
||||
<br>__MSG_CORS_alternative_2_new__
|
||||
<br><br><button id="${modelId_prefix ? `${modelId_prefix}` : ''}btnGiveAllUrlsPermission_ollama_api">__MSG_CORS_give_host_perm__</button>
|
||||
<br>__MSG_CORS_localhost_warn__
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="conntype_ollama_api${tr_class ? ` ${tr_class}` : ''}">
|
||||
|
|
@ -375,8 +385,9 @@ export async function injectConnectionUI({
|
|||
<td colspan="2" style="text-align:center;">
|
||||
__MSG_maybe_CORS_openai_comp__ [<a href="https://micz.it/thunderbird-addon-thunderai/ollama-cors-information/">__MSG_more_info_string__</a>]
|
||||
<br><br><b>__MSG_CORS_alternative_1__</b>
|
||||
<br>__MSG_CORS_alternative_2__
|
||||
<br><br><button id="${modelId_prefix ? `${modelId_prefix}` : ''}btnGiveAllUrlsPermission_openai_comp_api">__MSG_CORS_give_allurls_perm__</button>
|
||||
<br>__MSG_CORS_alternative_2_new__
|
||||
<br><br><button id="${modelId_prefix ? `${modelId_prefix}` : ''}btnGiveAllUrlsPermission_openai_comp_api">__MSG_CORS_give_host_perm__</button>
|
||||
<br>__MSG_CORS_localhost_warn__
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="conntype_openai_comp_api${tr_class ? ` ${tr_class}` : ''}">
|
||||
|
|
@ -660,6 +671,7 @@ export async function injectConnectionUI({
|
|||
while (openaiCompModelSelect.options.length > 0) {
|
||||
openaiCompModelSelect.remove(0);
|
||||
}
|
||||
syncTomSelect(openaiCompModelSelect);
|
||||
document.getElementById(getPrefixedId('openai_comp_use_v1')).checked = !!config.use_v1;
|
||||
document.getElementById(getPrefixedId('openai_comp_chat_name')).value = config.chat_name || '';
|
||||
// Trigger change events if needed
|
||||
|
|
@ -670,7 +682,17 @@ export async function injectConnectionUI({
|
|||
}
|
||||
});
|
||||
|
||||
let prefs = await browser.storage.sync.get({chatgpt_web_model: '', chatgpt_model: '', ollama_model: '', openai_comp_model: '', google_gemini_model: '', anthropic_model: '', anthropic_version: '', chatgpt_win_height: 0, chatgpt_win_width: 0 });
|
||||
let prefs = await browser.storage.sync.get({
|
||||
chatgpt_web_model: '',
|
||||
chatgpt_model: '',
|
||||
ollama_model: '',
|
||||
openai_comp_model: '',
|
||||
google_gemini_model: '',
|
||||
anthropic_model: '',
|
||||
anthropic_version: '',
|
||||
chatgpt_win_height: 0,
|
||||
chatgpt_win_width: 0
|
||||
});
|
||||
|
||||
// OpenAI API ChatGPT model fetching
|
||||
let select_chatgpt_model = getModelEl('chatgpt_model', modelId_prefix);
|
||||
|
|
@ -678,6 +700,7 @@ export async function injectConnectionUI({
|
|||
chatgpt_option.value = prefs.chatgpt_model;
|
||||
chatgpt_option.text = prefs.chatgpt_model;
|
||||
select_chatgpt_model.appendChild(chatgpt_option);
|
||||
select_chatgpt_model.value = prefs.chatgpt_model;
|
||||
select_chatgpt_model.addEventListener("change", () => warn_ChatGPT_APIKeyEmpty(modelId_prefix));
|
||||
|
||||
document.getElementById(getPrefixedId('btnUpdateChatGPTModels')).addEventListener('click', async () => {
|
||||
|
|
@ -715,6 +738,7 @@ export async function injectConnectionUI({
|
|||
select_chatgpt_model.appendChild(option);
|
||||
}
|
||||
});
|
||||
syncTomSelect(select_chatgpt_model);
|
||||
document.getElementById(getPrefixedId('chatgpt_model_fetch_loading')).style.display = 'none';
|
||||
});
|
||||
|
||||
|
|
@ -727,6 +751,7 @@ export async function injectConnectionUI({
|
|||
google_gemini_option.value = prefs.google_gemini_model;
|
||||
google_gemini_option.text = prefs.google_gemini_model;
|
||||
select_google_gemini_model.appendChild(google_gemini_option);
|
||||
select_google_gemini_model.value = prefs.google_gemini_model;
|
||||
select_google_gemini_model.addEventListener("change", () => warn_GoogleGemini_APIKeyEmpty(modelId_prefix));
|
||||
|
||||
document.getElementById(getPrefixedId('btnUpdateGoogleGeminiModels')).addEventListener('click', async () => {
|
||||
|
|
@ -757,6 +782,7 @@ export async function injectConnectionUI({
|
|||
select_google_gemini_model.appendChild(option);
|
||||
}
|
||||
});
|
||||
syncTomSelect(select_google_gemini_model);
|
||||
document.getElementById(getPrefixedId('google_gemini_model_fetch_loading')).style.display = 'none';
|
||||
});
|
||||
|
||||
|
|
@ -769,6 +795,7 @@ export async function injectConnectionUI({
|
|||
ollama_option.value = prefs.ollama_model;
|
||||
ollama_option.text = prefs.ollama_model;
|
||||
select_ollama_model.appendChild(ollama_option);
|
||||
select_ollama_model.value = prefs.ollama_model;
|
||||
select_ollama_model.addEventListener("change", () => warn_Ollama_HostEmpty(modelId_prefix));
|
||||
|
||||
document.getElementById(getPrefixedId('btnUpdateOllamaModels')).addEventListener('click', async () => {
|
||||
|
|
@ -812,6 +839,7 @@ export async function injectConnectionUI({
|
|||
select_ollama_model.appendChild(option);
|
||||
}
|
||||
});
|
||||
syncTomSelect(select_ollama_model);
|
||||
document.getElementById(getPrefixedId('ollama_model_fetch_loading')).style.display = 'none';
|
||||
} catch (error) {
|
||||
document.getElementById(getPrefixedId('ollama_model_fetch_loading')).style.display = 'none';
|
||||
|
|
@ -828,6 +856,7 @@ export async function injectConnectionUI({
|
|||
openai_comp_option.value = prefs.openai_comp_model;
|
||||
openai_comp_option.text = prefs.openai_comp_model;
|
||||
select_openai_comp_model.appendChild(openai_comp_option);
|
||||
select_openai_comp_model.value = prefs.openai_comp_model;
|
||||
select_openai_comp_model.addEventListener("change", () => warn_OpenAIComp_HostEmpty(modelId_prefix));
|
||||
|
||||
document.getElementById(getPrefixedId('btnUpdateOpenAICompModels')).addEventListener('click', async () => {
|
||||
|
|
@ -860,6 +889,7 @@ export async function injectConnectionUI({
|
|||
select_openai_comp_model.appendChild(option);
|
||||
}
|
||||
});
|
||||
syncTomSelect(select_openai_comp_model);
|
||||
document.getElementById(getPrefixedId('openai_comp_model_fetch_loading')).style.display = 'none';
|
||||
});
|
||||
|
||||
|
|
@ -872,6 +902,7 @@ export async function injectConnectionUI({
|
|||
anthropic_option.value = prefs.anthropic_model;
|
||||
anthropic_option.text = prefs.anthropic_model;
|
||||
select_anthropic_model.appendChild(anthropic_option);
|
||||
select_anthropic_model.value = prefs.anthropic_model;
|
||||
select_anthropic_model.addEventListener("change", () => warn_Anthropic_APIKeyEmpty(modelId_prefix));
|
||||
select_anthropic_model.addEventListener("change", () => warn_Anthropic_VersionEmpty(modelId_prefix));
|
||||
|
||||
|
|
@ -914,6 +945,7 @@ export async function injectConnectionUI({
|
|||
select_anthropic_model.appendChild(option);
|
||||
}
|
||||
});
|
||||
syncTomSelect(select_anthropic_model);
|
||||
document.getElementById(getPrefixedId('anthropic_model_fetch_loading')).style.display = 'none';
|
||||
});
|
||||
|
||||
|
|
@ -929,6 +961,7 @@ export async function injectConnectionUI({
|
|||
option.text = modelName;
|
||||
select_openai_comp_model.appendChild(option);
|
||||
select_openai_comp_model.value = modelName;
|
||||
syncTomSelect(select_openai_comp_model);
|
||||
select_openai_comp_model.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
});
|
||||
|
|
@ -942,15 +975,32 @@ export async function injectConnectionUI({
|
|||
select_openai_comp_model.remove(0);
|
||||
}
|
||||
select_openai_comp_model.value = '';
|
||||
syncTomSelect(select_openai_comp_model);
|
||||
select_openai_comp_model.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
});
|
||||
|
||||
document.getElementById(getPrefixedId('btnGiveAllUrlsPermission_ollama_api')).addEventListener('click', async () => {
|
||||
varConnectionUI.permission_all_urls = await messenger.permissions.request({ origins: ["<all_urls>"] });
|
||||
let ollama_host = document.getElementById(getPrefixedId("ollama_host")).value;
|
||||
if(ollama_host != ''){
|
||||
if (ollama_host.includes("localhost") || ollama_host.includes("127.0.0.1")) {
|
||||
varConnectionUI.permission_all_urls = await messenger.permissions.request({ origins: ["<all_urls>"] });
|
||||
}else{
|
||||
varConnectionUI.permission_ollama_host = await messenger.permissions.request({ origins: [prepareOriginURL(ollama_host)] });
|
||||
}
|
||||
updateCORSWarnings(modelId_prefix);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById(getPrefixedId('btnGiveAllUrlsPermission_openai_comp_api')).addEventListener('click', async () => {
|
||||
varConnectionUI.permission_all_urls = await messenger.permissions.request({ origins: ["<all_urls>"] });
|
||||
let openai_comp_host = document.getElementById(getPrefixedId("openai_comp_host")).value;
|
||||
if(openai_comp_host != ''){
|
||||
if (openai_comp_host.includes("localhost") || openai_comp_host.includes("127.0.0.1")) {
|
||||
varConnectionUI.permission_all_urls = await messenger.permissions.request({ origins: ["<all_urls>"] });
|
||||
}else{
|
||||
varConnectionUI.permission_openai_comp_host = await messenger.permissions.request({ origins: [prepareOriginURL(openai_comp_host)] });
|
||||
}
|
||||
updateCORSWarnings(modelId_prefix);
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelectorAll('.check-number').forEach(input => {
|
||||
|
|
@ -974,6 +1024,30 @@ export async function injectConnectionUI({
|
|||
}
|
||||
}
|
||||
|
||||
updateCORSWarnings(modelId_prefix);
|
||||
|
||||
['chatgpt_model', 'google_gemini_model', 'ollama_model', 'openai_comp_model', 'anthropic_model'].forEach(id => {
|
||||
const el = document.getElementById(getPrefixedId(id));
|
||||
if (el && !el.tomselect) {
|
||||
let ts = new TomSelect(el, {
|
||||
create: false,
|
||||
maxOptions: null,
|
||||
maxItems: 1,
|
||||
sortField: {
|
||||
field: "text",
|
||||
direction: "asc"
|
||||
}
|
||||
});
|
||||
ts.on('change', function() {
|
||||
setTomSelectBorder(this);
|
||||
});
|
||||
if (el.value) {
|
||||
ts.setValue(el.value);
|
||||
}
|
||||
setTomSelectBorder(ts);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
select: conntype_select,
|
||||
onTypeChange: (fn) => { onTypeChange = fn; fn(conntype_select.value, { select: conntype_select }); }
|
||||
|
|
@ -1086,6 +1160,7 @@ export async function initializeSpecificIntegrationUI({
|
|||
updateWarnings(model_prefix);
|
||||
}
|
||||
|
||||
|
||||
// From here there are exported functions
|
||||
|
||||
export function updateWarnings(modelId_prefix = '') {
|
||||
|
|
@ -1163,17 +1238,30 @@ export function showConnectionOptions(conntype_select, modelId_prefix = '') {
|
|||
parent.parentElement.querySelectorAll(".conntype_anthropic_api").forEach(element => {
|
||||
element.style.display = anthropic_api_display;
|
||||
});
|
||||
if (varConnectionUI.permission_all_urls) {
|
||||
const openaiCompWarning = parent.parentElement.getElementById((modelId_prefix ? modelId_prefix : '') + 'openai_comp_api_cors_warning');
|
||||
if (openaiCompWarning) openaiCompWarning.style.display = 'none';
|
||||
const ollamaWarning = parent.parentElement.getElementById((modelId_prefix ? modelId_prefix : '') + 'ollama_api_cors_warning');
|
||||
if (ollamaWarning) ollamaWarning.style.display = 'none';
|
||||
}
|
||||
updateCORSWarnings(modelId_prefix);
|
||||
}
|
||||
|
||||
|
||||
// From here there are internal functions
|
||||
|
||||
function syncTomSelect(element) {
|
||||
if (element && element.tomselect) {
|
||||
element.tomselect.sync();
|
||||
}
|
||||
}
|
||||
|
||||
function toggleTomSelectDisabled(element, disabled) {
|
||||
element.disabled = disabled;
|
||||
if (element.tomselect) {
|
||||
if (disabled) {
|
||||
element.tomselect.disable();
|
||||
element.tomselect.clear();
|
||||
} else {
|
||||
element.tomselect.enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getModelEl(model, modelId_prefix) {
|
||||
return document.getElementById((modelId_prefix ? modelId_prefix : '') + model);
|
||||
}
|
||||
|
|
@ -1204,6 +1292,8 @@ function populateConnectionTypeOptions(selectId, no_chatgpt_web = false) {
|
|||
|
||||
if (options.some(o => o.value === prevValue)) {
|
||||
conntype_select.value = prevValue;
|
||||
} else if (no_chatgpt_web) {
|
||||
conntype_select.value = "";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1226,13 +1316,13 @@ function warn_ChatGPT_APIKeyEmpty(modelId_prefix) {
|
|||
if(apiKeyInput.value === ''){
|
||||
apiKeyInput.style.border = '2px solid red';
|
||||
btnFetchChatGPTModels.disabled = true;
|
||||
modelChatGPT.disabled = true;
|
||||
toggleTomSelectDisabled(modelChatGPT, true);
|
||||
modelChatGPT.selectedIndex = -1;
|
||||
modelChatGPT.style.border = '';
|
||||
}else{
|
||||
apiKeyInput.style.border = '';
|
||||
btnFetchChatGPTModels.disabled = false;
|
||||
modelChatGPT.disabled = false;
|
||||
toggleTomSelectDisabled(modelChatGPT, false);
|
||||
if((modelChatGPT.selectedIndex === -1)||(modelChatGPT.value === '')){
|
||||
modelChatGPT.style.border = '2px solid red';
|
||||
}else{
|
||||
|
|
@ -1249,13 +1339,13 @@ function warn_GoogleGemini_APIKeyEmpty(modelId_prefix) {
|
|||
if(apiKeyInput.value === ''){
|
||||
apiKeyInput.style.border = '2px solid red';
|
||||
btnFetchGoogleGeminiModels.disabled = true;
|
||||
modelGoogleGemini.disabled = true;
|
||||
toggleTomSelectDisabled(modelGoogleGemini, true);
|
||||
modelGoogleGemini.selectedIndex = -1;
|
||||
modelGoogleGemini.style.border = '';
|
||||
}else{
|
||||
apiKeyInput.style.border = '';
|
||||
btnFetchGoogleGeminiModels.disabled = false;
|
||||
modelGoogleGemini.disabled = false;
|
||||
toggleTomSelectDisabled(modelGoogleGemini, false);
|
||||
if((modelGoogleGemini.selectedIndex === -1)||(modelGoogleGemini.value === '')){
|
||||
modelGoogleGemini.style.border = '2px solid red';
|
||||
}else{
|
||||
|
|
@ -1268,22 +1358,25 @@ function warn_Ollama_HostEmpty(modelId_prefix) {
|
|||
const getPrefixedId = (id) => `${modelId_prefix ? `${modelId_prefix}` : ''}${id}`;
|
||||
let hostInput = document.getElementById(getPrefixedId('ollama_host'));
|
||||
let btnFetchOllamaModels = document.getElementById(getPrefixedId('btnUpdateOllamaModels'));
|
||||
let btnGiveAllUrlsPermission_ollama_api = document.getElementById(getPrefixedId('btnGiveAllUrlsPermission_ollama_api'));
|
||||
let modelOllama = getModelEl('ollama_model', modelId_prefix);
|
||||
if(hostInput.value === ''){
|
||||
hostInput.style.border = '2px solid red';
|
||||
btnFetchOllamaModels.disabled = true;
|
||||
modelOllama.disabled = true;
|
||||
toggleTomSelectDisabled(modelOllama, true);
|
||||
modelOllama.selectedIndex = -1;
|
||||
modelOllama.style.border = '';
|
||||
btnGiveAllUrlsPermission_ollama_api.disabled = true;
|
||||
}else{
|
||||
hostInput.style.border = '';
|
||||
btnFetchOllamaModels.disabled = false;
|
||||
modelOllama.disabled = false;
|
||||
toggleTomSelectDisabled(modelOllama, false);
|
||||
if((modelOllama.selectedIndex === -1)||(modelOllama.value === '')){
|
||||
modelOllama.style.border = '2px solid red';
|
||||
}else{
|
||||
modelOllama.style.border = '';
|
||||
}
|
||||
btnGiveAllUrlsPermission_ollama_api.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1291,22 +1384,25 @@ function warn_OpenAIComp_HostEmpty(modelId_prefix) {
|
|||
const getPrefixedId = (id) => `${modelId_prefix ? `${modelId_prefix}` : ''}${id}`;
|
||||
let hostInput = document.getElementById(getPrefixedId('openai_comp_host'));
|
||||
let btnUpdateOpenAICompModels = document.getElementById(getPrefixedId('btnUpdateOpenAICompModels'));
|
||||
let btnGiveAllUrlsPermission_openai_comp_api = document.getElementById(getPrefixedId('btnGiveAllUrlsPermission_openai_comp_api'));
|
||||
let modelOpenAIComp = getModelEl('openai_comp_model', modelId_prefix);
|
||||
if(hostInput.value === ''){
|
||||
hostInput.style.border = '2px solid red';
|
||||
btnUpdateOpenAICompModels.disabled = true;
|
||||
modelOpenAIComp.disabled = true;
|
||||
toggleTomSelectDisabled(modelOpenAIComp, true);
|
||||
modelOpenAIComp.selectedIndex = -1;
|
||||
modelOpenAIComp.style.border = '';
|
||||
btnGiveAllUrlsPermission_openai_comp_api.disabled = true;
|
||||
}else{
|
||||
hostInput.style.border = '';
|
||||
btnUpdateOpenAICompModels.disabled = false;
|
||||
modelOpenAIComp.disabled = false;
|
||||
toggleTomSelectDisabled(modelOpenAIComp, false);
|
||||
if((modelOpenAIComp.selectedIndex === -1)||(modelOpenAIComp.value === '')){
|
||||
modelOpenAIComp.style.border = '2px solid red';
|
||||
}else{
|
||||
modelOpenAIComp.style.border = '';
|
||||
}
|
||||
btnGiveAllUrlsPermission_openai_comp_api.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1318,13 +1414,13 @@ function warn_Anthropic_APIKeyEmpty(modelId_prefix) {
|
|||
if(apiKeyInput.value === ''){
|
||||
apiKeyInput.style.border = '2px solid red';
|
||||
btnFetchAnthropicModels.disabled = true;
|
||||
modelAnthropic.disabled = true;
|
||||
toggleTomSelectDisabled(modelAnthropic, true);
|
||||
modelAnthropic.selectedIndex = -1;
|
||||
modelAnthropic.style.border = '';
|
||||
}else{
|
||||
apiKeyInput.style.border = '';
|
||||
btnFetchAnthropicModels.disabled = false;
|
||||
modelAnthropic.disabled = false;
|
||||
toggleTomSelectDisabled(modelAnthropic, false);
|
||||
if((modelAnthropic.selectedIndex === -1)||(modelAnthropic.value === '')){
|
||||
modelAnthropic.style.border = '2px solid red';
|
||||
}else{
|
||||
|
|
@ -1341,13 +1437,13 @@ function warn_Anthropic_VersionEmpty(modelId_prefix) {
|
|||
if(versionInput.value === ''){
|
||||
versionInput.style.border = '2px solid red';
|
||||
btnFetchAnthropicModels.disabled = true;
|
||||
modelAnthropic.disabled = true;
|
||||
toggleTomSelectDisabled(modelAnthropic, true);
|
||||
modelAnthropic.selectedIndex = -1;
|
||||
modelAnthropic.style.border = '';
|
||||
}else{
|
||||
versionInput.style.border = '';
|
||||
btnFetchAnthropicModels.disabled = false;
|
||||
modelAnthropic.disabled = false;
|
||||
toggleTomSelectDisabled(modelAnthropic, false);
|
||||
if((modelAnthropic.selectedIndex === -1)||(modelAnthropic.value === '')){
|
||||
modelAnthropic.style.border = '2px solid red';
|
||||
}else{
|
||||
|
|
@ -1370,3 +1466,27 @@ function loadOpenAICompConfigs(modelId_prefix = ''){
|
|||
select_openai_comp_model.appendChild(option);
|
||||
});
|
||||
}
|
||||
|
||||
async function loadURLsPermissions(modelId_prefix = ''){
|
||||
let ollama_host = document.getElementById((modelId_prefix ? modelId_prefix : '') + "ollama_host")?.value;
|
||||
if((ollama_host) && (ollama_host != '')){
|
||||
varConnectionUI.permission_ollama_host = await messenger.permissions.contains({ origins: [prepareOriginURL(ollama_host)] });
|
||||
}
|
||||
let openai_comp_host = document.getElementById((modelId_prefix ? modelId_prefix : '') + "openai_comp_host")?.value;
|
||||
if((openai_comp_host) && (openai_comp_host != '')){
|
||||
varConnectionUI.permission_openai_comp_host = await messenger.permissions.contains({ origins: [prepareOriginURL(openai_comp_host)] });
|
||||
}
|
||||
varConnectionUI.permission_all_urls = await messenger.permissions.contains({ origins: ["<all_urls>"] });
|
||||
}
|
||||
|
||||
async function updateCORSWarnings(modelId_prefix = ''){
|
||||
await loadURLsPermissions(modelId_prefix);
|
||||
if (varConnectionUI.permission_all_urls || varConnectionUI.permission_ollama_host) {
|
||||
const ollamaWarning = document.getElementById((modelId_prefix ? modelId_prefix : '') + 'ollama_api_cors_warning');
|
||||
if (ollamaWarning) ollamaWarning.style.display = 'none';
|
||||
}
|
||||
if (varConnectionUI.permission_all_urls || varConnectionUI.permission_openai_comp_host) {
|
||||
const openaiCompWarning = document.getElementById((modelId_prefix ? modelId_prefix : '') + 'openai_comp_api_cors_warning');
|
||||
if (openaiCompWarning) openaiCompWarning.style.display = 'none';
|
||||
}
|
||||
}
|
||||
4135
pages/_lib/tom-select.base.js
Normal file
4135
pages/_lib/tom-select.base.js
Normal file
File diff suppressed because it is too large
Load diff
2
pages/_lib/tom-select.default.min.css
vendored
Normal file
2
pages/_lib/tom-select.default.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -101,15 +101,7 @@
|
|||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="add_tags_tr">
|
||||
<td><span class="opt_title">__MSG_prefs_OptionText_add_tags_context_menu__</span></td>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" id="add_tags_context_menu" name="add_tags_context_menu" class="option-input" />
|
||||
__MSG_prefs_OptionText_add_tags_context_menu_Info__
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="add_tags_tr">
|
||||
<td><span class="opt_title">__MSG_prefs_OptionText_add_tags_auto_force_existing__</span></td>
|
||||
<td>
|
||||
|
|
|
|||
|
|
@ -34,7 +34,8 @@ import {
|
|||
import {
|
||||
getAccountsList,
|
||||
normalizeStringList,
|
||||
isAPIKeyValue
|
||||
isAPIKeyValue,
|
||||
setTomSelectBorder
|
||||
} from "../../js/mzta-utils.js";
|
||||
import {
|
||||
initializeSpecificIntegrationUI
|
||||
|
|
@ -301,6 +302,7 @@ function saveOptions(e) {
|
|||
async function restoreOptions() {
|
||||
function setCurrentChoice(result) {
|
||||
document.querySelectorAll(".option-input").forEach(element => {
|
||||
if(!element.id) return;
|
||||
taLog.log("Options restoring " + element.id + " = " + (isAPIKeyValue(element.id) ? "****************" : result[element.id]));
|
||||
switch (element.type) {
|
||||
case 'checkbox':
|
||||
|
|
@ -338,6 +340,10 @@ async function restoreOptions() {
|
|||
if (element.value === '') {
|
||||
element.selectedIndex = -1;
|
||||
}
|
||||
if (element.tomselect) {
|
||||
element.tomselect.setValue(element.value, true);
|
||||
setTomSelectBorder(element.tomselect);
|
||||
}
|
||||
}else{
|
||||
console.error("[ThunderAI] Unhandled input type:", element.type);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,20 @@
|
|||
*/
|
||||
|
||||
import { prefs_default } from "../../options/mzta-options-default.js";
|
||||
import { getLocalStorageUsedSpace, sanitizeHtml, isThunderbird128OrGreater, openTab } from "../../js/mzta-utils.js";
|
||||
import {
|
||||
getLocalStorageUsedSpace,
|
||||
sanitizeHtml,
|
||||
openTab
|
||||
} from "../../js/mzta-utils.js";
|
||||
import { taLogger } from "../../js/mzta-logger.js";
|
||||
import { getPlaceholders, setCustomPlaceholders, getCustomPlaceholders, prepareCustomDataPHsForExport, prepareCustomDataPHsForImport, placeholdersUtils } from "../../js/mzta-placeholders.js";
|
||||
import {
|
||||
getPlaceholders,
|
||||
setCustomPlaceholders,
|
||||
getCustomPlaceholders,
|
||||
prepareCustomDataPHsForExport,
|
||||
prepareCustomDataPHsForImport,
|
||||
placeholdersUtils
|
||||
} from "../../js/mzta-placeholders.js";
|
||||
import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js";
|
||||
|
||||
let prefs = null;
|
||||
|
|
@ -550,12 +561,8 @@ async function setStorageSpace() {
|
|||
document.getElementById('storage_space').textContent = storage_space;
|
||||
}
|
||||
|
||||
|
||||
if(await isThunderbird128OrGreater()){
|
||||
window.addEventListener('beforeunload', function (event) {
|
||||
// Check if any changes have been made (Only for Thunderbird 128+ see https://github.com/micz/ThunderAI/issues/88)
|
||||
if (somethingChanged) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
window.addEventListener('beforeunload', function (event) {
|
||||
if (somethingChanged) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -330,6 +330,17 @@ label:has(input[type="checkbox"]) {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
dialog.export{
|
||||
padding: 20px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
background-color: var(--dialog-bg-color, #fff);
|
||||
color: var(--dialog-text-color, #000);
|
||||
max-width: 400px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
background-color: #1C1B22;
|
||||
|
|
|
|||
|
|
@ -34,12 +34,12 @@ import {
|
|||
} from "../../pages/_lib/connection-ui.js";
|
||||
import {
|
||||
ChatGPTWeb_models,
|
||||
isThunderbird128OrGreater,
|
||||
getLocalStorageUsedSpace,
|
||||
sanitizeHtml,
|
||||
validateCustomData_ChatGPTWeb,
|
||||
getChatGPTWebModelsList_HTML,
|
||||
openTab
|
||||
openTab,
|
||||
setTomSelectBorder
|
||||
} from "../../js/mzta-utils.js";
|
||||
import { taLogger } from "../../js/mzta-logger.js";
|
||||
import {
|
||||
|
|
@ -145,7 +145,11 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
afterTrId: 'api_ui_anchor',
|
||||
selectId: 'new_prompt_api_type',
|
||||
no_chatgpt_web: true,
|
||||
taLog: taLog
|
||||
taLog: taLog,
|
||||
customButtonLabel: browser.i18n.getMessage("Reset"),
|
||||
customButtonCallback: () => {
|
||||
resetApiSettings('new_prompt_api_type');
|
||||
}
|
||||
});
|
||||
|
||||
// Fill defaults for new prompt form
|
||||
|
|
@ -350,7 +354,9 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
async function exportPrompts() {
|
||||
const manifest = browser.runtime.getManifest();
|
||||
const addonVersion = manifest.version;
|
||||
const outputPrompts = preparePromptsForExport(await getPrompts());
|
||||
const include_api_settings = await showYesNoDialog(browser.i18n.getMessage("customPrompts_export_include_api_settings"));
|
||||
if (include_api_settings === null) return;
|
||||
const outputPrompts = preparePromptsForExport(await getPrompts(), include_api_settings);
|
||||
let outputObj = {id: 'thunderai-prompts', addon_version: addonVersion, prompts: outputPrompts};
|
||||
const blob = new Blob([JSON.stringify(outputObj, null, 2)], {
|
||||
type: "application/json",
|
||||
|
|
@ -364,6 +370,82 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
});
|
||||
}
|
||||
|
||||
async function showYesNoDialog(message) {
|
||||
return new Promise((resolve) => {
|
||||
const dialog = document.createElement('dialog');
|
||||
dialog.className = 'export';
|
||||
// dialog.style.cssText = `
|
||||
// padding: 20px;
|
||||
// border: none;
|
||||
// border-radius: 8px;
|
||||
// background-color: var(--dialog-bg-color, #fff);
|
||||
// color: var(--dialog-text-color, #000);
|
||||
// max-width: 400px;
|
||||
// box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||
// font-family: system-ui, -apple-system, sans-serif;
|
||||
// `;
|
||||
|
||||
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
dialog.style.backgroundColor = '#2e2e2e';
|
||||
dialog.style.color = '#ffffff';
|
||||
}
|
||||
|
||||
const text = document.createElement('p');
|
||||
text.textContent = message;
|
||||
text.style.marginBottom = '20px';
|
||||
text.style.fontSize = '14px';
|
||||
text.style.lineHeight = '1.5';
|
||||
dialog.appendChild(text);
|
||||
|
||||
const btnContainer = document.createElement('div');
|
||||
btnContainer.style.display = 'flex';
|
||||
btnContainer.style.justifyContent = 'flex-end';
|
||||
btnContainer.style.gap = '10px';
|
||||
|
||||
const createBtn = (text, bgColor) => {
|
||||
const btn = document.createElement('button');
|
||||
btn.textContent = text;
|
||||
btn.style.padding = '8px 16px';
|
||||
btn.style.borderRadius = '4px';
|
||||
btn.style.border = 'none';
|
||||
btn.style.cursor = 'pointer';
|
||||
btn.style.fontSize = '14px';
|
||||
btn.style.color = 'white';
|
||||
btn.style.backgroundColor = bgColor;
|
||||
return btn;
|
||||
};
|
||||
|
||||
const cancelBtn = createBtn(browser.i18n.getMessage("customPrompts_btnCancel"), '#6c757d');
|
||||
cancelBtn.onclick = () => {
|
||||
dialog.close();
|
||||
dialog.remove();
|
||||
resolve(null);
|
||||
};
|
||||
|
||||
const noBtn = createBtn(browser.i18n.getMessage("no_string"), '#007bff');
|
||||
noBtn.onclick = () => {
|
||||
dialog.close();
|
||||
dialog.remove();
|
||||
resolve(false);
|
||||
};
|
||||
|
||||
const yesBtn = createBtn(browser.i18n.getMessage("yes_string"), '#6c757d');
|
||||
yesBtn.onclick = () => {
|
||||
dialog.close();
|
||||
dialog.remove();
|
||||
resolve(true);
|
||||
};
|
||||
|
||||
btnContainer.appendChild(cancelBtn);
|
||||
btnContainer.appendChild(noBtn);
|
||||
btnContainer.appendChild(yesBtn);
|
||||
dialog.appendChild(btnContainer);
|
||||
|
||||
document.body.appendChild(dialog);
|
||||
dialog.showModal();
|
||||
});
|
||||
}
|
||||
|
||||
const btnImport = document.getElementById('btnImport');
|
||||
btnImport.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
|
|
@ -477,42 +559,7 @@ function handleEditClick(e) {
|
|||
taLog: taLog,
|
||||
customButtonLabel: browser.i18n.getMessage("Reset"),
|
||||
customButtonCallback: () => {
|
||||
const selectEl = document.getElementById(selectId);
|
||||
if (selectEl) {
|
||||
selectEl.value = '';
|
||||
selectEl.dispatchEvent(new Event('change'));
|
||||
}
|
||||
|
||||
// Clear UI inputs
|
||||
for (const [integration, options] of Object.entries(integration_options_config)) {
|
||||
for (const key of Object.keys(options)) {
|
||||
const propName = `${integration}_${key}`;
|
||||
const inputId = `${prefix}${propName}`;
|
||||
const inputEl = document.getElementById(inputId);
|
||||
if (inputEl) {
|
||||
if (inputEl.type === 'checkbox') {
|
||||
inputEl.checked = false;
|
||||
} else {
|
||||
inputEl.value = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update promptsList
|
||||
const item = promptsList.get('id', id)[0];
|
||||
if (item) {
|
||||
let newValues = item.values();
|
||||
newValues.api_type = '';
|
||||
for (const [integration, options] of Object.entries(integration_options_config)) {
|
||||
for (const key of Object.keys(options)) {
|
||||
const propName = `${integration}_${key}`;
|
||||
newValues[propName] = '';
|
||||
}
|
||||
}
|
||||
item.values(newValues);
|
||||
}
|
||||
setSomethingChanged();
|
||||
resetApiSettings(selectId, id);
|
||||
}
|
||||
}).then(() => {
|
||||
populateConnectionUI(tr, id, prefix, selectId);
|
||||
|
|
@ -535,6 +582,47 @@ function handleEditClick(e) {
|
|||
toggleAdditionalPropertiesShow(tr);
|
||||
}
|
||||
|
||||
function resetApiSettings(selectId, id = null) {
|
||||
let prefix = '';
|
||||
if (id) prefix = `prompt_${id}_`;
|
||||
const selectEl = document.getElementById(selectId);
|
||||
if (selectEl) {
|
||||
selectEl.value = '';
|
||||
selectEl.dispatchEvent(new Event('change'));
|
||||
}
|
||||
|
||||
// Clear UI inputs
|
||||
for (const [integration, options] of Object.entries(integration_options_config)) {
|
||||
for (const key of Object.keys(options)) {
|
||||
const propName = `${integration}_${key}`;
|
||||
const inputId = `${prefix}${propName}`;
|
||||
const inputEl = document.getElementById(inputId);
|
||||
if (inputEl) {
|
||||
if (inputEl.type === 'checkbox') {
|
||||
inputEl.checked = false;
|
||||
} else {
|
||||
inputEl.value = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update promptsList
|
||||
const item = promptsList.get('id', id)[0];
|
||||
if (item) {
|
||||
let newValues = item.values();
|
||||
newValues.api_type = '';
|
||||
for (const [integration, options] of Object.entries(integration_options_config)) {
|
||||
for (const key of Object.keys(options)) {
|
||||
const propName = `${integration}_${key}`;
|
||||
newValues[propName] = '';
|
||||
}
|
||||
}
|
||||
item.values(newValues);
|
||||
}
|
||||
setSomethingChanged();
|
||||
}
|
||||
|
||||
function populateConnectionUI(tr, id, prefix, selectId) {
|
||||
const item = promptsList.get('id', id)[0];
|
||||
const itemValues = item.values();
|
||||
|
|
@ -558,7 +646,24 @@ function populateConnectionUI(tr, id, prefix, selectId) {
|
|||
val = prefs[propName];
|
||||
}
|
||||
}
|
||||
inputEl.type === 'checkbox' ? inputEl.checked = (val === true || val === 'true') : inputEl.value = val || '';
|
||||
if (inputEl.type === 'checkbox') {
|
||||
inputEl.checked = (val === true || val === 'true');
|
||||
} else {
|
||||
if (inputEl.tomselect) {
|
||||
const restoreValue = val || '';
|
||||
let optionExists = Array.from(inputEl.options).some(opt => opt.value === restoreValue);
|
||||
if (!optionExists && restoreValue !== '') {
|
||||
let newOption = new Option(restoreValue, restoreValue);
|
||||
inputEl.add(newOption);
|
||||
}
|
||||
inputEl.value = restoreValue;
|
||||
inputEl.tomselect.sync();
|
||||
inputEl.tomselect.setValue(restoreValue, true);
|
||||
setTomSelectBorder(inputEl.tomselect);
|
||||
} else {
|
||||
inputEl.value = val || '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -806,6 +911,23 @@ function handleConfirmClick(e) {
|
|||
async function handleCheckboxChange(e) {
|
||||
e.preventDefault();
|
||||
e.target.setAttribute('checked_val', e.target.checked ? '1' : '0');
|
||||
|
||||
if (e.target.classList.contains('enabled') || e.target.classList.contains('need_custom_text')) {
|
||||
let tr = e.target.closest('tr');
|
||||
if (tr) {
|
||||
let idnum = tr.getAttribute('data-idnum');
|
||||
let item = promptsList.get('idnum', idnum);
|
||||
if (item && item.length > 0) {
|
||||
if (e.target.classList.contains('enabled')) {
|
||||
item[0]._values.enabled = e.target.checked ? 1 : 0;
|
||||
}
|
||||
if (e.target.classList.contains('need_custom_text')) {
|
||||
item[0]._values.need_custom_text = e.target.checked ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//console.log('>>>>>>>> checked_val: ' + e.target.getAttribute('checked_val'));
|
||||
if (e.target.classList.contains('need_selected') || e.target.classList.contains('need_custom_text') || e.target.classList.contains('need_selected_new') || e.target.classList.contains('need_custom_text_new')) {
|
||||
let textarea = e.target.closest('tr').querySelector('.text_output');
|
||||
|
|
@ -1187,14 +1309,11 @@ async function setStorageSpace() {
|
|||
}
|
||||
|
||||
|
||||
if(await isThunderbird128OrGreater()){
|
||||
window.addEventListener('beforeunload', function (event) {
|
||||
// Check if any changes have been made (Only for Thunderbird 128+ see https://github.com/micz/ThunderAI/issues/88)
|
||||
if (somethingChanged) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
window.addEventListener('beforeunload', function (event) {
|
||||
if (somethingChanged) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
async function checkPromptsConfigForPlaceholders(textarea){
|
||||
let curr_text = textarea.value;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<title>ThunderAI - __MSG_GetCalendarEvent_PageTitle__</title>
|
||||
<link rel="stylesheet" href="mzta-get-calendar-event.css">
|
||||
<link rel="stylesheet" href="../_lib/connection-ui.css">
|
||||
<link rel="icon" href="../../images/icon-16px.png">
|
||||
</head>
|
||||
<body>
|
||||
|
|
@ -13,8 +14,20 @@
|
|||
</div>
|
||||
<div class="get_calendar_event_table_title section_title">__MSG_get_calendar_event_prompt_prefs_title__</div>
|
||||
<table id="miczPrefs">
|
||||
<tr class="get_calendar_event_tr specific_integration">
|
||||
<td><span class="opt_title">__MSG_prefs_OptionText_use_specific_integration__</span>
|
||||
</td>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" id="get_calendar_event_use_specific_integration" name="get_calendar_event_use_specific_integration" class="option-input" />
|
||||
__MSG_prefs_OptionText_get_calendar_event_use_specific_integration_Info__
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="connection_ui_anchor"></tr>
|
||||
<tr id="connection_ui_end"><td colspan="2"></td></tr>
|
||||
<tr class="get_calendar_event_tr">
|
||||
<td><span>__MSG_prefs_OptionText_calendar_enforce_timezone__</span></td>
|
||||
<td><span class="opt_title">__MSG_prefs_OptionText_calendar_enforce_timezone__</span></td>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" id="calendar_enforce_timezone" name="calendar_enforce_timezone" class="option-input" /> __MSG_prefs_OptionText_calendar_enforce_timezone_Info__
|
||||
|
|
|
|||
|
|
@ -16,23 +16,59 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { prefs_default } from '../../options/mzta-options-default.js';
|
||||
import {
|
||||
prefs_default,
|
||||
integration_options_config
|
||||
} from '../../options/mzta-options-default.js';
|
||||
import { taLogger } from '../../js/mzta-logger.js';
|
||||
import { getSpecialPrompts, setSpecialPrompts } from "../../js/mzta-prompts.js";
|
||||
import {
|
||||
getSpecialPrompts,
|
||||
setSpecialPrompts
|
||||
} from "../../js/mzta-prompts.js";
|
||||
import {
|
||||
getPlaceholders,
|
||||
mapPlaceholderToSuggestion
|
||||
} from "../../js/mzta-placeholders.js";
|
||||
import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js";
|
||||
import { isAPIKeyValue } from "../../js/mzta-utils.js";
|
||||
import {
|
||||
isAPIKeyValue,
|
||||
setTomSelectBorder
|
||||
} from "../../js/mzta-utils.js";
|
||||
import {
|
||||
initializeSpecificIntegrationUI
|
||||
} from "../_lib/connection-ui.js";
|
||||
|
||||
let autocompleteSuggestions = [];
|
||||
let taLog = new taLogger("mzta-get-calendar-event-page",true);
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
let specialPrompts = await getSpecialPrompts();
|
||||
let get_calendar_event_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_get_calendar_event');
|
||||
|
||||
if (get_calendar_event_prompt && get_calendar_event_prompt.api_type && get_calendar_event_prompt.api_type !== '') {
|
||||
let update_prefs = {};
|
||||
update_prefs['get_calendar_event_connection_type'] = get_calendar_event_prompt.api_type;
|
||||
|
||||
let integration = get_calendar_event_prompt.api_type.replace('_api', '');
|
||||
if (integration_options_config && integration_options_config[integration]) {
|
||||
for (const key of Object.keys(integration_options_config[integration])) {
|
||||
if (get_calendar_event_prompt[key] !== undefined) {
|
||||
update_prefs[`get_calendar_event_${integration}_${key}`] = get_calendar_event_prompt[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
await browser.storage.sync.set(update_prefs);
|
||||
}
|
||||
|
||||
await initializeSpecificIntegrationUI({
|
||||
prefix: 'get_calendar_event',
|
||||
promptId: 'prompt_get_calendar_event',
|
||||
taLog: taLog,
|
||||
restoreOptionsCallback: restoreOptions
|
||||
});
|
||||
|
||||
i18n.updateDocument();
|
||||
await restoreOptions();
|
||||
|
||||
document.querySelectorAll(".option-input").forEach(element => {
|
||||
element.addEventListener("change", saveOptions);
|
||||
|
|
@ -41,9 +77,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
let get_calendar_event_textarea = document.getElementById('get_calendar_event_prompt_text');
|
||||
let get_calendar_event_save_btn = document.getElementById('btn_save_prompt');
|
||||
let get_calendar_event_reset_btn = document.getElementById('btn_reset_prompt');
|
||||
|
||||
let specialPrompts = await getSpecialPrompts();
|
||||
let get_calendar_event_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_get_calendar_event');
|
||||
let get_calendar_event_use_specific_integration = document.getElementById('get_calendar_event_use_specific_integration');
|
||||
|
||||
get_calendar_event_textarea.addEventListener('input', (event) => {
|
||||
get_calendar_event_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_get_calendar_event_full_text'));
|
||||
|
|
@ -55,6 +89,12 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
}
|
||||
});
|
||||
|
||||
get_calendar_event_use_specific_integration.addEventListener('change', (event) => {
|
||||
if (!event.target.checked) {
|
||||
browser.storage.sync.set({ get_calendar_event_connection_type: '' });
|
||||
}
|
||||
});
|
||||
|
||||
get_calendar_event_reset_btn.addEventListener('click', () => {
|
||||
get_calendar_event_textarea.value = browser.i18n.getMessage('prompt_get_calendar_event_full_text');
|
||||
get_calendar_event_reset_btn.disabled = true;
|
||||
|
|
@ -97,8 +137,8 @@ function saveOptions(e) {
|
|||
case 'number':
|
||||
options[element.id] = element.valueAsNumber;
|
||||
break;
|
||||
case 'text':
|
||||
case 'password':
|
||||
case 'text':
|
||||
case 'password':
|
||||
options[element.id] = element.value.trim();
|
||||
break;
|
||||
case 'select-one':
|
||||
|
|
@ -114,6 +154,7 @@ function saveOptions(e) {
|
|||
async function restoreOptions() {
|
||||
function setCurrentChoice(result) {
|
||||
document.querySelectorAll(".option-input").forEach(element => {
|
||||
if(!element.id) return;
|
||||
taLog.log("Options restoring " + element.id + " = " + (isAPIKeyValue(element.id) ? "****************" : result[element.id]));
|
||||
switch (element.type) {
|
||||
case 'checkbox':
|
||||
|
|
@ -131,15 +172,28 @@ async function restoreOptions() {
|
|||
if(element.id == 'default_chatgpt_lang') default_text_value = prefs_default.default_chatgpt_lang;
|
||||
element.value = result[element.id] || default_text_value;
|
||||
break;
|
||||
case 'textarea':
|
||||
break;
|
||||
default:
|
||||
if (element.tagName === 'SELECT') {
|
||||
let default_select_value = '';
|
||||
if(element.id == 'reply_type') default_select_value = 'reply_all';
|
||||
if(element.id == 'connection_type') default_select_value = 'chatgpt_web';
|
||||
element.value = result[element.id] || default_select_value;
|
||||
if (element.value === '') {
|
||||
element.selectedIndex = -1;
|
||||
}
|
||||
let default_select_value = '';
|
||||
const restoreValue = result[element.id] || default_select_value;
|
||||
// Check if option exists
|
||||
let optionExists = Array.from(element.options).some(opt => opt.value === restoreValue);
|
||||
// If it doesn't exist and restoreValue is not empty, create it
|
||||
if (!optionExists && restoreValue !== '') {
|
||||
let newOption = new Option(restoreValue, restoreValue);
|
||||
element.add(newOption);
|
||||
}
|
||||
// Set value
|
||||
element.value = restoreValue;
|
||||
if (element.value === '') {
|
||||
element.selectedIndex = -1;
|
||||
}
|
||||
if (element.tomselect) {
|
||||
element.tomselect.setValue(element.value, true);
|
||||
setTomSelectBorder(element.tomselect);
|
||||
}
|
||||
}else{
|
||||
console.error("[ThunderAI] Unhandled input type:", element.type);
|
||||
}
|
||||
|
|
@ -148,5 +202,27 @@ async function restoreOptions() {
|
|||
}
|
||||
|
||||
let getting = await browser.storage.sync.get(prefs_default);
|
||||
|
||||
let specialPrompts = await getSpecialPrompts();
|
||||
let get_calendar_event_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_get_calendar_event');
|
||||
|
||||
if (get_calendar_event_prompt) {
|
||||
if (get_calendar_event_prompt.api_type && get_calendar_event_prompt.api_type !== '') {
|
||||
getting['get_calendar_event_connection_type'] = get_calendar_event_prompt.api_type;
|
||||
} else {
|
||||
getting['get_calendar_event_connection_type'] = getting['connection_type'];
|
||||
}
|
||||
for (const [integration, options] of Object.entries(integration_options_config)) {
|
||||
for (const key of Object.keys(options)) {
|
||||
const propName = `${integration}_${key}`;
|
||||
if (get_calendar_event_prompt[propName] !== undefined && get_calendar_event_prompt[propName] !== '') {
|
||||
getting[`get_calendar_event_${propName}`] = get_calendar_event_prompt[propName];
|
||||
} else {
|
||||
getting[`get_calendar_event_${propName}`] = getting[propName];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setCurrentChoice(getting);
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<title>ThunderAI - __MSG_GetTask_PageTitle__</title>
|
||||
<link rel="stylesheet" href="mzta-get-task.css">
|
||||
<link rel="stylesheet" href="../_lib/connection-ui.css">
|
||||
<link rel="icon" href="../../images/icon-16px.png">
|
||||
</head>
|
||||
<body>
|
||||
|
|
@ -11,10 +12,20 @@
|
|||
<h1 class="page_title">__MSG_GetTask_PageTitle__</h1>
|
||||
<p>__MSG_GetTask_info_default__</p>
|
||||
</div>
|
||||
<div class="get_calendar_event_table_title section_title">__MSG_get_calendar_event_prompt_prefs_title__</div>
|
||||
<div class="get_task_table_title section_title">__MSG_get_task_prompt_prefs_title__</div>
|
||||
<table id="miczPrefs">
|
||||
<tr class="get_calendar_event_tr">
|
||||
<td><span>__MSG_prefs_OptionText_calendar_enforce_timezone__</span></td>
|
||||
<tr>
|
||||
<td><span class="opt_title">__MSG_prefs_OptionText_use_specific_integration__</span></td>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" id="get_task_use_specific_integration" name="get_task_use_specific_integration" class="option-input" /> __MSG_prefs_OptionText_get_calendar_event_use_specific_integration_Info__
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="connection_ui_anchor" style="display:none"></tr>
|
||||
<tr id="connection_ui_end" style="display:none"></tr>
|
||||
<tr class="get_task_tr">
|
||||
<td><span class="opt_title">__MSG_prefs_OptionText_calendar_enforce_timezone__</span></td>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" id="calendar_enforce_timezone" name="calendar_enforce_timezone" class="option-input" /> __MSG_prefs_OptionText_calendar_enforce_timezone_Info__
|
||||
|
|
|
|||
|
|
@ -16,68 +16,108 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { prefs_default } from '../../options/mzta-options-default.js';
|
||||
import {
|
||||
prefs_default,
|
||||
integration_options_config
|
||||
} from '../../options/mzta-options-default.js';
|
||||
import { taLogger } from '../../js/mzta-logger.js';
|
||||
import { getSpecialPrompts, setSpecialPrompts } from "../../js/mzta-prompts.js";
|
||||
import {
|
||||
getSpecialPrompts,
|
||||
setSpecialPrompts
|
||||
} from "../../js/mzta-prompts.js";
|
||||
import {
|
||||
getPlaceholders,
|
||||
mapPlaceholderToSuggestion
|
||||
} from "../../js/mzta-placeholders.js";
|
||||
import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js";
|
||||
import { isAPIKeyValue } from "../../js/mzta-utils.js";
|
||||
import {
|
||||
isAPIKeyValue,
|
||||
setTomSelectBorder
|
||||
} from "../../js/mzta-utils.js";
|
||||
import {
|
||||
initializeSpecificIntegrationUI
|
||||
} from "../_lib/connection-ui.js";
|
||||
|
||||
let autocompleteSuggestions = [];
|
||||
let taLog = new taLogger("mzta-get-calendar-event-page",true);
|
||||
let taLog = new taLogger("mzta-get-task-page",true);
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
let specialPrompts = await getSpecialPrompts();
|
||||
let get_task_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_get_task');
|
||||
|
||||
if (get_task_prompt && get_task_prompt.api_type && get_task_prompt.api_type !== '') {
|
||||
let update_prefs = {};
|
||||
update_prefs['get_task_connection_type'] = get_task_prompt.api_type;
|
||||
|
||||
let integration = get_task_prompt.api_type.replace('_api', '');
|
||||
if (integration_options_config && integration_options_config[integration]) {
|
||||
for (const key of Object.keys(integration_options_config[integration])) {
|
||||
if (get_task_prompt[key] !== undefined) {
|
||||
update_prefs[`get_task_${integration}_${key}`] = get_task_prompt[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
await browser.storage.sync.set(update_prefs);
|
||||
}
|
||||
|
||||
await initializeSpecificIntegrationUI({
|
||||
prefix: 'get_task',
|
||||
promptId: 'prompt_get_task',
|
||||
taLog: taLog,
|
||||
restoreOptionsCallback: restoreOptions
|
||||
});
|
||||
|
||||
i18n.updateDocument();
|
||||
await restoreOptions();
|
||||
|
||||
document.querySelectorAll(".option-input").forEach(element => {
|
||||
element.addEventListener("change", saveOptions);
|
||||
});
|
||||
|
||||
let get_calendar_event_textarea = document.getElementById('get_task_prompt_text');
|
||||
let get_calendar_event_save_btn = document.getElementById('btn_save_prompt');
|
||||
let get_calendar_event_reset_btn = document.getElementById('btn_reset_prompt');
|
||||
let get_task_textarea = document.getElementById('get_task_prompt_text');
|
||||
let get_task_save_btn = document.getElementById('btn_save_prompt');
|
||||
let get_task_reset_btn = document.getElementById('btn_reset_prompt');
|
||||
let get_task_use_specific_integration = document.getElementById('get_task_use_specific_integration');
|
||||
|
||||
let specialPrompts = await getSpecialPrompts();
|
||||
let get_calendar_event_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_get_task');
|
||||
|
||||
get_calendar_event_textarea.addEventListener('input', (event) => {
|
||||
get_calendar_event_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_get_task_full_text'));
|
||||
get_calendar_event_save_btn.disabled = (event.target.value === get_calendar_event_prompt.text);
|
||||
if(get_calendar_event_save_btn.disabled){
|
||||
get_task_textarea.addEventListener('input', (event) => {
|
||||
get_task_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_get_task_full_text'));
|
||||
get_task_save_btn.disabled = (event.target.value === get_task_prompt.text);
|
||||
if(get_task_save_btn.disabled){
|
||||
document.getElementById('get_task_prompt_unsaved').classList.add('hidden');
|
||||
} else {
|
||||
document.getElementById('get_task_prompt_unsaved').classList.remove('hidden');
|
||||
}
|
||||
});
|
||||
|
||||
get_calendar_event_reset_btn.addEventListener('click', () => {
|
||||
get_calendar_event_textarea.value = browser.i18n.getMessage('prompt_get_task_full_text');
|
||||
get_calendar_event_reset_btn.disabled = true;
|
||||
let event = new Event('input', { bubbles: true, cancelable: true });
|
||||
get_calendar_event_textarea.dispatchEvent(event);
|
||||
get_task_use_specific_integration.addEventListener('change', (event) => {
|
||||
if (!event.target.checked) {
|
||||
browser.storage.sync.set({ get_task_connection_type: '' });
|
||||
}
|
||||
});
|
||||
|
||||
get_calendar_event_save_btn.addEventListener('click', () => {
|
||||
specialPrompts.find(prompt => prompt.id === 'prompt_get_task').text = get_calendar_event_textarea.value;
|
||||
get_task_reset_btn.addEventListener('click', () => {
|
||||
get_task_textarea.value = browser.i18n.getMessage('prompt_get_task_full_text');
|
||||
get_task_reset_btn.disabled = true;
|
||||
let event = new Event('input', { bubbles: true, cancelable: true });
|
||||
get_task_textarea.dispatchEvent(event);
|
||||
});
|
||||
|
||||
get_task_save_btn.addEventListener('click', () => {
|
||||
specialPrompts.find(prompt => prompt.id === 'prompt_get_task').text = get_task_textarea.value;
|
||||
setSpecialPrompts(specialPrompts);
|
||||
get_calendar_event_save_btn.disabled = true;
|
||||
get_task_save_btn.disabled = true;
|
||||
document.getElementById('get_task_prompt_unsaved').classList.add('hidden');
|
||||
browser.runtime.sendMessage({command: "reload_menus"});
|
||||
});
|
||||
|
||||
if(get_calendar_event_prompt.text === 'prompt_get_task_full_text'){
|
||||
get_calendar_event_prompt.text = browser.i18n.getMessage(get_calendar_event_prompt.text);
|
||||
if(get_task_prompt.text === 'prompt_get_task_full_text'){
|
||||
get_task_prompt.text = browser.i18n.getMessage(get_task_prompt.text);
|
||||
}
|
||||
get_calendar_event_textarea.value = get_calendar_event_prompt.text;
|
||||
get_calendar_event_reset_btn.disabled = (get_calendar_event_textarea.value === browser.i18n.getMessage('prompt_get_task_full_text'));
|
||||
get_task_textarea.value = get_task_prompt.text;
|
||||
get_task_reset_btn.disabled = (get_task_textarea.value === browser.i18n.getMessage('prompt_get_task_full_text'));
|
||||
|
||||
autocompleteSuggestions = (await getPlaceholders(true)).filter(p => !(p.id === 'additional_text')).map(mapPlaceholderToSuggestion);
|
||||
textareaAutocomplete(get_calendar_event_textarea, autocompleteSuggestions, 1); // type_value = 1, only when reading an email
|
||||
textareaAutocomplete(get_task_textarea, autocompleteSuggestions, 1); // type_value = 1, only when reading an email
|
||||
|
||||
});
|
||||
|
||||
|
|
@ -97,8 +137,8 @@ function saveOptions(e) {
|
|||
case 'number':
|
||||
options[element.id] = element.valueAsNumber;
|
||||
break;
|
||||
case 'text':
|
||||
case 'password':
|
||||
case 'text':
|
||||
case 'password':
|
||||
options[element.id] = element.value.trim();
|
||||
break;
|
||||
case 'select-one':
|
||||
|
|
@ -114,6 +154,7 @@ function saveOptions(e) {
|
|||
async function restoreOptions() {
|
||||
function setCurrentChoice(result) {
|
||||
document.querySelectorAll(".option-input").forEach(element => {
|
||||
if(!element.id) return;
|
||||
taLog.log("Options restoring " + element.id + " = " + (isAPIKeyValue(element.id) ? "****************" : result[element.id]));
|
||||
switch (element.type) {
|
||||
case 'checkbox':
|
||||
|
|
@ -131,15 +172,28 @@ async function restoreOptions() {
|
|||
if(element.id == 'default_chatgpt_lang') default_text_value = prefs_default.default_chatgpt_lang;
|
||||
element.value = result[element.id] || default_text_value;
|
||||
break;
|
||||
case 'textarea':
|
||||
break;
|
||||
default:
|
||||
if (element.tagName === 'SELECT') {
|
||||
let default_select_value = '';
|
||||
if(element.id == 'reply_type') default_select_value = 'reply_all';
|
||||
if(element.id == 'connection_type') default_select_value = 'chatgpt_web';
|
||||
element.value = result[element.id] || default_select_value;
|
||||
if (element.value === '') {
|
||||
element.selectedIndex = -1;
|
||||
}
|
||||
let default_select_value = '';
|
||||
const restoreValue = result[element.id] || default_select_value;
|
||||
// Check if option exists
|
||||
let optionExists = Array.from(element.options).some(opt => opt.value === restoreValue);
|
||||
// If it doesn't exist and restoreValue is not empty, create it
|
||||
if (!optionExists && restoreValue !== '') {
|
||||
let newOption = new Option(restoreValue, restoreValue);
|
||||
element.add(newOption);
|
||||
}
|
||||
// Set value
|
||||
element.value = restoreValue;
|
||||
if (element.value === '') {
|
||||
element.selectedIndex = -1;
|
||||
}
|
||||
if (element.tomselect) {
|
||||
element.tomselect.setValue(element.value, true);
|
||||
setTomSelectBorder(element.tomselect);
|
||||
}
|
||||
}else{
|
||||
console.error("[ThunderAI] Unhandled input type:", element.type);
|
||||
}
|
||||
|
|
@ -148,5 +202,27 @@ async function restoreOptions() {
|
|||
}
|
||||
|
||||
let getting = await browser.storage.sync.get(prefs_default);
|
||||
|
||||
let specialPrompts = await getSpecialPrompts();
|
||||
let get_task_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_get_task');
|
||||
|
||||
if (get_task_prompt) {
|
||||
if (get_task_prompt.api_type && get_task_prompt.api_type !== '') {
|
||||
getting['get_task_connection_type'] = get_task_prompt.api_type;
|
||||
} else {
|
||||
getting['get_task_connection_type'] = getting['connection_type'];
|
||||
}
|
||||
for (const [integration, options] of Object.entries(integration_options_config)) {
|
||||
for (const key of Object.keys(options)) {
|
||||
const propName = `${integration}_${key}`;
|
||||
if (get_task_prompt[propName] !== undefined && get_task_prompt[propName] !== '') {
|
||||
getting[`get_task_${propName}`] = get_task_prompt[propName];
|
||||
} else {
|
||||
getting[`get_task_${propName}`] = getting[propName];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setCurrentChoice(getting);
|
||||
}
|
||||
|
|
@ -35,15 +35,7 @@
|
|||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="spamfilter_tr">
|
||||
<td><span class="opt_title">__MSG_prefs_OptionText_spamfilter_context_menu__</span></td>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" id="spamfilter_context_menu" name="spamfilter_context_menu" class="option-input" />
|
||||
__MSG_prefs_OptionText_spamfilter_context_menu_Info__
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
<div id="spamfilter_container">
|
||||
<span class="section_title">__MSG_SpamFilter_prompt_text_title__</span><span id="spamfilter_prompt_unsaved" class="unsaved hidden"> __MSG_customPrompts_unsaved_changes__</span>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,11 @@ import {
|
|||
} from "../../js/mzta-placeholders.js";
|
||||
import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js";
|
||||
import { taSpamReport } from '../../js/mzta-spamreport.js';
|
||||
import { getAccountsList, isAPIKeyValue } from "../../js/mzta-utils.js";
|
||||
import {
|
||||
getAccountsList,
|
||||
isAPIKeyValue,
|
||||
setTomSelectBorder
|
||||
} from "../../js/mzta-utils.js";
|
||||
import {
|
||||
initializeSpecificIntegrationUI
|
||||
} from "../_lib/connection-ui.js";
|
||||
|
|
@ -240,7 +244,7 @@ async function loadSpamReport(){
|
|||
row.appendChild(tdSpamValue);
|
||||
|
||||
const tdMoved = document.createElement("td");
|
||||
tdMoved.textContent = (report.moved ? browser.i18n.getMessage("spamfilter_moved") : browser.i18n.getMessage("spamfilter_not_moved")) + ` (${report.SpamThreshold})`;
|
||||
tdMoved.textContent = (report.moved ? browser.i18n.getMessage("yes_string") : browser.i18n.getMessage("no_string")) + ` (${report.SpamThreshold})`;
|
||||
row.appendChild(tdMoved);
|
||||
|
||||
const tdExplanation = document.createElement("td");
|
||||
|
|
@ -290,6 +294,7 @@ function saveOptions(e) {
|
|||
async function restoreOptions() {
|
||||
function setCurrentChoice(result) {
|
||||
document.querySelectorAll(".option-input").forEach(element => {
|
||||
if(!element.id) return;
|
||||
taLog.log("Options restoring " + element.id + " = " + (isAPIKeyValue(element.id) ? "****************" : result[element.id]));
|
||||
switch (element.type) {
|
||||
case 'checkbox':
|
||||
|
|
@ -325,6 +330,10 @@ async function restoreOptions() {
|
|||
if (element.value === '') {
|
||||
element.selectedIndex = -1;
|
||||
}
|
||||
if (element.tomselect) {
|
||||
element.tomselect.setValue(element.value, true);
|
||||
setTomSelectBorder(element.tomselect);
|
||||
}
|
||||
}else{
|
||||
console.error("[ThunderAI] Unhandled input type:", element.type);
|
||||
}
|
||||
|
|
|
|||
193
pages/summarize/mzta-summarize.css
Normal file
193
pages/summarize/mzta-summarize.css
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
#summarize_prompt_container {
|
||||
width: 90%;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
#summarize_email_template_text {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#summarize_prompt_text {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#summarize_email_separator_text {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.infoline {
|
||||
font-size: 0.8em;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
#account_selector_container{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#account_selector_checkboxes{
|
||||
padding: 10px;
|
||||
border: 1px solid gray;
|
||||
width: 24em;
|
||||
margin-bottom: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.specific_integration{
|
||||
background-color: #dfeaff;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
.group td {
|
||||
border-top: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.specific_integration_sub td:first-child {
|
||||
border-left: 10px solid #dfeaff;
|
||||
}
|
||||
|
||||
.specific_integration_sub td:last-child {
|
||||
border-right: 10px solid #dfeaff;
|
||||
}
|
||||
|
||||
#connection_ui_end td{
|
||||
height: 6px;
|
||||
background-color: #dfeaff;
|
||||
}
|
||||
|
||||
#connection_ui_end{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.btn_div {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
table#miczPrefs {
|
||||
padding: 10px;
|
||||
border-spacing: 0px;
|
||||
width: 90%;
|
||||
margin: 0px auto 40px auto;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.addtags_table_title{
|
||||
width: 90%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.section_title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
table#miczPrefs td {
|
||||
border-top: 1px solid #ccc;
|
||||
border-bottom: 1px solid #ccc;
|
||||
vertical-align: top;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
table#miczPrefs tr:first-child td {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
table#miczPrefs tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.autocomplete-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.autocomplete-list {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: white;
|
||||
border: 1px solid #ccc;
|
||||
z-index: 1000;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.autocomplete-list li {
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.autocomplete-list li:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.autocomplete-list li.active {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.unsaved {
|
||||
color: red;
|
||||
}
|
||||
|
||||
label:has(input[type="checkbox"]) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
background-color: #1c1b22;
|
||||
color: rgb(251, 251, 254);
|
||||
}
|
||||
|
||||
a:link { color: #409eff; }
|
||||
a:visited { color: #409eff; }
|
||||
a:hover { color: #66b1ff; }
|
||||
a:active { color: #66b1ff; }
|
||||
a:active { color: #66b1ff; }
|
||||
|
||||
.autocomplete-list {
|
||||
background-color: #2e2f36;
|
||||
border: 1px solid #2e2f36;
|
||||
}
|
||||
|
||||
.autocomplete-list li:hover {
|
||||
background-color: #4c4e58;
|
||||
}
|
||||
|
||||
.autocomplete-list li.active {
|
||||
background-color: #4c4e58;
|
||||
}
|
||||
|
||||
.summarize_auto{
|
||||
background-color: #415c35;
|
||||
}
|
||||
|
||||
.specific_integration{
|
||||
background-color: #2E3A4F;
|
||||
}
|
||||
|
||||
.specific_integration_sub td:first-child {
|
||||
border-left: 10px solid #2E3A4F;
|
||||
}
|
||||
|
||||
.specific_integration_sub td:last-child {
|
||||
border-right: 10px solid #2E3A4F;
|
||||
}
|
||||
|
||||
#connection_ui_end td{
|
||||
background-color: #2E3A4F;
|
||||
}
|
||||
}
|
||||
123
pages/summarize/mzta-summarize.html
Normal file
123
pages/summarize/mzta-summarize.html
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>ThunderAI - __MSG_Summarize_PageTitle__</title>
|
||||
<link rel="stylesheet" href="mzta-summarize.css" />
|
||||
<link rel="stylesheet" href="../_lib/connection-ui.css">
|
||||
<link rel="icon" href="../../images/icon-16px.png" />
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h1 class="page_title">__MSG_Summarize_PageTitle__</h1>
|
||||
<p>__MSG_Summarize_info_default__</p>
|
||||
</div>
|
||||
<div class="summarize_table_title section_title">__MSG_Summarize_prompt_prefs_title__</div>
|
||||
<table id="miczPrefs">
|
||||
<tr class="summarize_tr specific_integration">
|
||||
<td><span class="opt_title">__MSG_prefs_OptionText_use_specific_integration__</span>
|
||||
</td>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" id="summarize_use_specific_integration" name="summarize_use_specific_integration" class="option-input" />
|
||||
__MSG_prefs_OptionText_summarize_use_specific_integration_Info__
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="connection_ui_anchor"></tr>
|
||||
<tr id="connection_ui_end"><td colspan="2"></td></tr>
|
||||
</table>
|
||||
|
||||
<!-- PROMPTS -->
|
||||
<div id="summarize_prompt_container">
|
||||
<!--title and description-->
|
||||
<span class="section_title">
|
||||
__MSG_Summarize_prompt_text_title__
|
||||
</span>
|
||||
|
||||
<br>
|
||||
|
||||
<span class="infoline">
|
||||
__MSG_prefs_OptionText_btnManagePrompts_infoline__
|
||||
<a href="https://micz.it/thunderbird-addon-thunderai/data-placeholders/">
|
||||
__MSG_more_info_string__
|
||||
</a>
|
||||
|
||||
<br>
|
||||
|
||||
<b>__MSG_prefs_OptionText_Summarize_infoline2__</b>
|
||||
</span>
|
||||
|
||||
<br>
|
||||
|
||||
<!--main prompt-->
|
||||
<span class="infoline">
|
||||
__MSG_prefs_OptionText_Summarize_main_prompt__
|
||||
</span>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="autocomplete-container">
|
||||
<textarea id="summarize_prompt_text" rows="15"></textarea>
|
||||
<ul class="autocomplete-list hidden"></ul>
|
||||
</div>
|
||||
|
||||
<div id="summarize_info_additional_statements"></div>
|
||||
<div class="btn_div">
|
||||
<button id="btn_reset_prompt" disabled>
|
||||
__MSG_reset_default__
|
||||
</button>
|
||||
<button id="btn_save_prompt" disabled>
|
||||
__MSG_save__
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!--email template-->
|
||||
<span class="infoline">
|
||||
__MSG_prefs_OptionText_Summarize_email_template__
|
||||
</span>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="autocomplete-container">
|
||||
<textarea id="summarize_email_template_text" rows="15"></textarea>
|
||||
<ul class="autocomplete-list hidden"></ul>
|
||||
</div>
|
||||
|
||||
<div id="summarize_info_additional_statements"></div>
|
||||
<div class="btn_div">
|
||||
<button id="btn_reset_email_template" disabled>
|
||||
__MSG_reset_default__
|
||||
</button>
|
||||
<button id="btn_save_email_template" disabled>
|
||||
__MSG_save__
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- separator -->
|
||||
<span class="infoline">
|
||||
__MSG_prefs_OptionText_Summarize_email_separator__
|
||||
</span>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="autocomplete-container">
|
||||
<textarea id="summarize_email_separator_text" rows="7"></textarea>
|
||||
<ul class="autocomplete-list hidden"></ul>
|
||||
</div>
|
||||
|
||||
<div id="summarize_info_additional_statements"></div>
|
||||
<div class="btn_div">
|
||||
<button id="btn_reset_email_separator" disabled>
|
||||
__MSG_reset_default__
|
||||
</button>
|
||||
<button id="btn_save_email_separator" disabled>
|
||||
__MSG_save__
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script src="mzta-summarize.js" type="module"></script>
|
||||
<script src="../../js/mzta-i18n.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
282
pages/summarize/mzta-summarize.js
Normal file
282
pages/summarize/mzta-summarize.js
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
|
||||
* Copyright (C) 2024 - 2025 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { prefs_default, integration_options_config } from '../../options/mzta-options-default.js';
|
||||
import { taLogger } from "../../js/mzta-logger.js";
|
||||
import {
|
||||
getSpecialPrompts,
|
||||
setSpecialPrompts
|
||||
} from "../../js/mzta-prompts.js";
|
||||
import {
|
||||
getPlaceholders,
|
||||
mapPlaceholderToSuggestion
|
||||
} from "../../js/mzta-placeholders.js";
|
||||
import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js";
|
||||
import {
|
||||
getAccountsList,
|
||||
normalizeStringList,
|
||||
isAPIKeyValue
|
||||
} from "../../js/mzta-utils.js";
|
||||
import {
|
||||
initializeSpecificIntegrationUI
|
||||
} from "../_lib/connection-ui.js";
|
||||
|
||||
let autocompleteSuggestions = [];
|
||||
let taLog = new taLogger("mzta-summarize-page", true);
|
||||
|
||||
document.addEventListener("DOMContentLoaded", async () => {
|
||||
|
||||
let specialPrompts = await getSpecialPrompts();
|
||||
let summarize_prompt = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize');
|
||||
let summarize_email_template = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_template');
|
||||
let summarize_email_separator = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_separator');
|
||||
|
||||
if (summarize_prompt && summarize_prompt.api_type && summarize_prompt.api_type !== '') {
|
||||
let update_prefs = {};
|
||||
update_prefs['summarize_connection_type'] = summarize_prompt.api_type;
|
||||
|
||||
let integration = summarize_prompt.api_type.replace('_api', '');
|
||||
if (integration_options_config && integration_options_config[integration]) {
|
||||
for (const key of Object.keys(integration_options_config[integration])) {
|
||||
if (summarize_prompt[key] !== undefined) {
|
||||
update_prefs[`summarize_${integration}_${key}`] = summarize_prompt[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
await browser.storage.sync.set(update_prefs);
|
||||
}
|
||||
|
||||
await initializeSpecificIntegrationUI({
|
||||
prefix: 'summarize',
|
||||
promptId: 'prompt_summarize',
|
||||
taLog: taLog,
|
||||
restoreOptionsCallback: restoreOptions
|
||||
});
|
||||
|
||||
i18n.updateDocument();
|
||||
|
||||
document.querySelectorAll(".option-input").forEach(element => {
|
||||
element.addEventListener("change", saveOptions);
|
||||
});
|
||||
let prefs_summarize = await browser.storage.sync.get({ summarize_enabled_accounts: [], connection_type: 'chatgpt_web' });
|
||||
|
||||
let summarize_textarea = document.getElementById("summarize_prompt_text");
|
||||
let summarize_save_btn = document.getElementById("btn_save_prompt");
|
||||
let summarize_reset_btn = document.getElementById("btn_reset_prompt");
|
||||
let summarize_textarea_email_template = document.getElementById("summarize_email_template_text");
|
||||
let summarize_reset_email_template_btn = document.getElementById("btn_reset_email_template");
|
||||
let summarize_save_email_template_btn = document.getElementById("btn_save_email_template");
|
||||
let summarize_email_separator_textarea = document.getElementById("summarize_email_separator_text");
|
||||
let summarize_email_separator_save_btn = document.getElementById("btn_save_email_separator");
|
||||
let summarize_email_separator_reset_btn = document.getElementById("btn_reset_email_separator");
|
||||
|
||||
|
||||
// on changing textareas
|
||||
summarize_textarea.addEventListener("input", (event) => {
|
||||
summarize_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_summarize_full_text'));
|
||||
summarize_save_btn.disabled = (event.target.value === summarize_prompt.text);
|
||||
});
|
||||
|
||||
summarize_textarea_email_template.addEventListener("input", (event) => {
|
||||
summarize_reset_email_template_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_summarize_email_template_full_text'));
|
||||
summarize_save_email_template_btn.disabled = (event.target.value === summarize_email_template.text);
|
||||
});
|
||||
|
||||
summarize_email_separator_textarea.addEventListener("input", (event) => {
|
||||
summarize_email_separator_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_summarize_email_separator_full_text'));
|
||||
summarize_email_separator_save_btn.disabled = (event.target.value === summarize_email_separator.text);
|
||||
});
|
||||
|
||||
|
||||
// on clicking buttons, reset
|
||||
summarize_reset_email_template_btn.addEventListener("click", () => {
|
||||
summarize_textarea_email_template.value = browser.i18n.getMessage("prompt_summarize_email_template_full_text");
|
||||
summarize_reset_email_template_btn.disabled = true;
|
||||
let event = new Event("input", { bubbles: true, cancelable: true });
|
||||
summarize_textarea_email_template.dispatchEvent(event);
|
||||
});
|
||||
|
||||
summarize_reset_btn.addEventListener("click", () => {
|
||||
summarize_textarea.value = browser.i18n.getMessage("prompt_summarize_full_text");
|
||||
summarize_reset_btn.disabled = true;
|
||||
let event = new Event("input", { bubbles: true, cancelable: true });
|
||||
summarize_textarea.dispatchEvent(event);
|
||||
});
|
||||
|
||||
summarize_email_separator_reset_btn.addEventListener("click", () => {
|
||||
summarize_email_separator_textarea.value = browser.i18n.getMessage("prompt_summarize_email_separator_full_text");
|
||||
summarize_email_separator_reset_btn.disabled = true;
|
||||
let event = new Event("input", { bubbles: true, cancelable: true });
|
||||
summarize_email_separator_textarea.dispatchEvent(event);
|
||||
});
|
||||
|
||||
// on clicking buttons, save
|
||||
summarize_save_email_template_btn.addEventListener("click", () => {
|
||||
specialPrompts.find(prompt => prompt.id === 'prompt_summarize_email_template').text = summarize_textarea_email_template.value;
|
||||
setSpecialPrompts(specialPrompts);
|
||||
summarize_save_email_template_btn.disabled = true;
|
||||
browser.runtime.sendMessage({ command: "reload_menus" });
|
||||
});
|
||||
|
||||
summarize_save_btn.addEventListener("click", () => {
|
||||
specialPrompts.find(prompt => prompt.id === 'prompt_summarize').text = summarize_textarea.value;
|
||||
setSpecialPrompts(specialPrompts);
|
||||
summarize_save_btn.disabled = true;
|
||||
browser.runtime.sendMessage({ command: "reload_menus" });
|
||||
});
|
||||
|
||||
summarize_email_separator_save_btn.addEventListener("click", () => {
|
||||
specialPrompts.find(prompt => prompt.id === 'prompt_summarize_email_separator').text = summarize_email_separator_textarea.value;
|
||||
setSpecialPrompts(specialPrompts);
|
||||
summarize_email_separator_save_btn.disabled = true;
|
||||
browser.runtime.sendMessage({ command: "reload_menus" });
|
||||
});
|
||||
|
||||
|
||||
if(summarize_prompt.text === 'prompt_summarize_full_text'){
|
||||
summarize_prompt.text = browser.i18n.getMessage(summarize_prompt.text);
|
||||
}
|
||||
if(summarize_email_template.text === 'prompt_summarize_email_template_full_text'){
|
||||
summarize_email_template.text = browser.i18n.getMessage(summarize_email_template.text);
|
||||
}
|
||||
if(summarize_email_separator.text === 'prompt_summarize_email_separator_full_text'){
|
||||
summarize_email_separator.text = browser.i18n.getMessage(summarize_email_separator.text);
|
||||
}
|
||||
|
||||
summarize_textarea_email_template.value = summarize_email_template.text;
|
||||
summarize_reset_email_template_btn.disabled = (summarize_textarea_email_template.value === browser.i18n.getMessage("prompt_summarize_email_template_full_text"));
|
||||
summarize_textarea.value = summarize_prompt.text;
|
||||
summarize_reset_btn.disabled = (summarize_textarea.value === browser.i18n.getMessage("prompt_summarize_full_text"));
|
||||
summarize_email_separator_textarea.value = summarize_email_separator.text;
|
||||
summarize_email_separator_reset_btn.disabled = (summarize_email_separator_textarea.value === browser.i18n.getMessage("prompt_summarize_email_separator_full_text"));
|
||||
|
||||
autocompleteSuggestions = (await getPlaceholders(true))
|
||||
.filter((p) => p.id !== "additional_text")
|
||||
.map(mapPlaceholderToSuggestion);
|
||||
|
||||
textareaAutocomplete(summarize_textarea, autocompleteSuggestions, 1);
|
||||
textareaAutocomplete(summarize_textarea_email_template, autocompleteSuggestions, 1);
|
||||
textareaAutocomplete(summarize_email_separator_textarea, autocompleteSuggestions, 1);
|
||||
|
||||
});
|
||||
|
||||
// Methods to manage options, derived from: /options/mzta-options.js
|
||||
|
||||
function saveOptions(e) {
|
||||
e.preventDefault();
|
||||
let options = {};
|
||||
let element = e.target;
|
||||
// console.log(">>>>>>>>>> Saving option: " + element.id + " = " + element.value);
|
||||
switch (element.type) {
|
||||
case 'checkbox':
|
||||
options[element.id] = element.checked;
|
||||
break;
|
||||
case 'number':
|
||||
options[element.id] = element.valueAsNumber;
|
||||
break;
|
||||
case 'text':
|
||||
case 'password':
|
||||
options[element.id] = element.value.trim();
|
||||
break;
|
||||
case 'select-one':
|
||||
// console.log(">>>>>>>>>> Saving option [select-one]: " + element.id + " = " + element.value);
|
||||
options[element.id] = element.value;
|
||||
break;
|
||||
case 'textarea':
|
||||
options[element.id] = normalizeStringList(element.value);
|
||||
break;
|
||||
default:
|
||||
console.error("[ThunderAI] Unhandled input type:", element.type);
|
||||
}
|
||||
|
||||
browser.storage.sync.set(options);
|
||||
}
|
||||
|
||||
async function restoreOptions() {
|
||||
function setCurrentChoice(result) {
|
||||
document.querySelectorAll(".option-input").forEach(element => {
|
||||
if(!element.id) return;
|
||||
taLog.log("Options restoring " + element.id + " = " + (isAPIKeyValue(element.id) ? "****************" : result[element.id]));
|
||||
switch (element.type) {
|
||||
case 'checkbox':
|
||||
element.checked = result[element.id] || false;
|
||||
break;
|
||||
case 'number':
|
||||
let default_number_value = 0;
|
||||
if(element.id == 'chatgpt_win_height') default_number_value = prefs_default.chatgpt_win_height;
|
||||
if(element.id == 'chatgpt_win_width') default_number_value = prefs_default.chatgpt_win_width;
|
||||
element.value = result[element.id] ?? default_number_value;
|
||||
break;
|
||||
case 'text':
|
||||
case 'textarea':
|
||||
case 'password':
|
||||
let default_text_value = '';
|
||||
if(element.id == 'default_chatgpt_lang') default_text_value = prefs_default.default_chatgpt_lang;
|
||||
element.value = result[element.id] || default_text_value;
|
||||
break;
|
||||
default:
|
||||
if (element.tagName === 'SELECT') {
|
||||
let default_select_value = '';
|
||||
const restoreValue = result[element.id] || default_select_value;
|
||||
// Check if option exists
|
||||
let optionExists = Array.from(element.options).some(opt => opt.value === restoreValue);
|
||||
// If it doesn't exist and restoreValue is not empty, create it
|
||||
if (!optionExists && restoreValue !== '') {
|
||||
let newOption = new Option(restoreValue, restoreValue);
|
||||
element.add(newOption);
|
||||
}
|
||||
// Set value
|
||||
element.value = restoreValue;
|
||||
if (element.value === '') {
|
||||
element.selectedIndex = -1;
|
||||
}
|
||||
if (element.tomselect) {
|
||||
element.tomselect.setValue(element.value, true);
|
||||
}
|
||||
}else{
|
||||
console.error("[ThunderAI] Unhandled input type:", element.type);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let getting = await browser.storage.sync.get(prefs_default);
|
||||
|
||||
let specialPrompts = await getSpecialPrompts();
|
||||
let addtags_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_summarize');
|
||||
|
||||
if (addtags_prompt) {
|
||||
if (addtags_prompt.api_type && addtags_prompt.api_type !== '') {
|
||||
getting['summarize_connection_type'] = addtags_prompt.api_type;
|
||||
} else {
|
||||
getting['summarize_connection_type'] = getting['connection_type'];
|
||||
}
|
||||
for (const [integration, options] of Object.entries(integration_options_config)) {
|
||||
for (const key of Object.keys(options)) {
|
||||
const propName = `${integration}_${key}`;
|
||||
if (addtags_prompt[propName] !== undefined && addtags_prompt[propName] !== '') {
|
||||
getting[`summarize_${propName}`] = addtags_prompt[propName];
|
||||
} else {
|
||||
getting[`summarize_${propName}`] = getting[propName];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setCurrentChoice(getting);
|
||||
}
|
||||
Loading…
Reference in a new issue