commit
9d4fbf368e
30 changed files with 6463 additions and 5217 deletions
18
CHANGELOG.md
18
CHANGELOG.md
|
|
@ -5,6 +5,18 @@
|
|||
|
||||
|
||||
|
||||
<h2>Version 3.2.0 - 27/02/2025</h2>
|
||||
<ul>
|
||||
<li><i>[All APIs]</i> Added an option to automatically tag incoming emails [<a href="https://github.com/micz/ThunderAI/issues/237">#237</a>].</li>
|
||||
<li><i>[All APIs]</i> Added an configurable antispam filter for incoming emails [<a href="https://github.com/micz/ThunderAI/issues/231">#231</a>].</li>
|
||||
<li>Tags related permissions are now optional and asked for only when the user activates the tags feature [<a href="https://github.com/micz/ThunderAI/issues/259">#259</a>].</li>
|
||||
<li>Added the <i>{%thunderai_def_sign%}</i> placeholder to get the default signature as defined in the options [<a href="https://github.com/micz/ThunderAI/issues/248">#248</a>].</li>
|
||||
<li>Added the <i>{%thunderai_def_lang%}</i> placeholder to get the default language as defined in the options [<a href="https://github.com/micz/ThunderAI/issues/248">#248</a>].</li>
|
||||
<li>Croatian (hr) translation added, thanks to Petar Jedvaj.</li>
|
||||
<li>German (de) translation errors fixed.</li>
|
||||
<li>Translations improved thanks to Hosted Weblate. <a href="https://micz.it/thunderbird-addon-thunderai/translate/">Help translating ThunderAI!</a>.</li>
|
||||
<li>Various minor improvements.</li>
|
||||
</ul>
|
||||
<h2>Version 3.1.3 - 02/02/2025</h2>
|
||||
<ul>
|
||||
<li><i>[ChatGPT Web]</i> Correctly hiding the "Download Sparks" message when using [<a href="https://github.com/micz/ThunderAI/issues/245">#245</a>].</li>
|
||||
|
|
@ -22,7 +34,7 @@
|
|||
</ul>
|
||||
<h2>Version 3.1.0 - 27/01/2025</h2>
|
||||
<ul>
|
||||
<li><i>[ChatGPT API][Ollama API][OpenAI Comp API][Gemini API]</i> Added a special prompt to get calendar events data from emails [<a href="https://github.com/micz/ThunderAI/issues/182">#182</a>]. To use this feature, you must install also the <a href="https://addons.thunderbird.net/it/thunderbird/addon/thunderai-sparks/">Sparks</a> add-on.</li>
|
||||
<li><i>[All APIs]</i> Added a special prompt to get calendar events data from emails [<a href="https://github.com/micz/ThunderAI/issues/182">#182</a>]. To use this feature, you must install also the <a href="https://addons.thunderbird.net/it/thunderbird/addon/thunderai-sparks/">Sparks</a> add-on.</li>
|
||||
<li>Added Google Gemini API support [<a href="https://github.com/micz/ThunderAI/issues/204">#204</a>, <a href="https://github.com/micz/ThunderAI/issues/217">#217</a>].</li>
|
||||
<li>Added the <i>{%mail_typed_text%}</i> placeholder to get the text inserted before the quoted mail body when replying [<a href="https://github.com/micz/ThunderAI/issues/196">#196</a>].</li>
|
||||
<li>Using the <i>{%mail_typed_text%}</i> placeholder the typed text inserted before the quoted mail body will be selected automatically to be replaced afterwards with the AI response [<a href="https://github.com/micz/ThunderAI/issues/229">#229</a>].</li>
|
||||
|
|
@ -32,7 +44,7 @@
|
|||
</ul>
|
||||
<h2>Version 3.0.0 - 05/01/2025</h2>
|
||||
<ul>
|
||||
<li><i>[ChatGPT API][Ollama API][OpenAI Comp API]</i> Added a special prompt to apply tags to emails [<a href="https://github.com/micz/ThunderAI/issues/183">#183</a>].</li>
|
||||
<li><i>[All APIs]</i> Added a special prompt to apply tags to emails [<a href="https://github.com/micz/ThunderAI/issues/183">#183</a>].</li>
|
||||
<li>Default prompts text has been translated [<a href="https://github.com/micz/ThunderAI/issues/185">#185</a>].</li>
|
||||
<li>Added the <i>{%tags_full_list%}</i> data placeholder for the full available tags list added [<a href="https://github.com/micz/ThunderAI/issues/197">#197</a>].</li>
|
||||
<li>Added the <i>{%tags_current_email%}</i> data placeholder for the single mail tags list added [<a href="https://github.com/micz/ThunderAI/issues/198">#198</a>].</li>
|
||||
|
|
@ -100,7 +112,7 @@
|
|||
<li>Fixed a bug that occurred when importing prompts after an export without closing the Custom Prompts page.</li>
|
||||
<li>Brazilian Portuguese (pt-br) translation added, thanks to Bruno Pereira de Souza.</li>
|
||||
<li><i>[Ollama API]</i> Added a link to the <a href="https://micz.it/thunderbird-addon-thunderai/ollama-cors-information/">CORS information page</a>.</li>
|
||||
<li><i>[ChatGPT API][Ollama API][OpenAI Comp API]</i> Improved handling of streaming responses even in case of broken chunks [<a href="https://github.com/micz/ThunderAI/issues/147">#147</a>].</li>
|
||||
<li><i>[All APIs]</i> Improved handling of streaming responses even in case of broken chunks [<a href="https://github.com/micz/ThunderAI/issues/147">#147</a>].</li>
|
||||
<li>Fixed a race condition that occurred when opening the chat window under certain circumstances. Thanks to <a href="https://github.com/jobisoft" target="_blank">@jobisoft</a> for helping refine the code, and to <a href="https://github.com/Mikilio" target="_blank">@Mikilio</a> and <a href="https://github.com/mattcaron" target="_blank">@mattcaron</a> for the extensive testing [<a href="https://github.com/micz/ThunderAI/issues/143">#143</a>].</li>
|
||||
</ul>
|
||||
<h2>Version 2.1.5 - 23/09/2024</h2>
|
||||
|
|
|
|||
7
LANG.md
Normal file
7
LANG.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
de
|
||||
en
|
||||
fr
|
||||
hr
|
||||
it
|
||||
pl
|
||||
pt-br
|
||||
|
|
@ -10,6 +10,9 @@ You can also define, export and import your own **[custom prompts](https://micz.
|
|||
|
||||
In any custom prompt you can use additional **[data placeholders](https://micz.it/thunderbird-addon-thunderai/data-placeholders/)**!
|
||||
|
||||
You can activate some automatic features:
|
||||
- Tagging incoming emails
|
||||
- Moving spam emails to the junk folder
|
||||
|
||||
<br>
|
||||
|
||||
|
|
@ -85,7 +88,6 @@ Are you using this addon in your Thunderbird?
|
|||
- Português Brasileiro (pt-br): Bruno Pereira de Souza
|
||||
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
### Graphics
|
||||
|
|
@ -101,4 +103,5 @@ Are you using this addon in your Thunderbird?
|
|||
### Miscellaneous
|
||||
- <a href="https://github.com/KudoAI/chatgpt.js">chatgpt.js</a> for providing methods to interact with the ChatGPT web frontend
|
||||
- <a href="https://github.com/boxabirds">Julian Harris</a> for his project <a href="https://github.com/boxabirds/chatgpt-frontend-nobuild">chatgpt-frontend-nobuild</a>, that has been used as a starting point for the API Web Interface
|
||||
- <a href="https://hosted.weblate.org/widgets/thunderai/">Hosted Weblate</a> to manage the localizations
|
||||
- <a href="https://github.com/ali-raheem/Aify">Aify</a> for inspiration
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"extensionDescription": {
|
||||
"message": "Use ChatGPT or Ollama to enhance you emails!",
|
||||
"message": "Use ChatGPT, Goolge Gemini or Ollama to enhance you emails!",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"menu_title": {
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"description": ""
|
||||
},
|
||||
"prompt_lang": {
|
||||
"message": "Reply in ",
|
||||
"message": "Reply in",
|
||||
"description": ""
|
||||
},
|
||||
"prompt_reply": {
|
||||
|
|
@ -695,6 +695,10 @@
|
|||
"message": "If checked, the \"v1\" segment in the path of API calls will be kept, like \"http://localhost:1234/v1/chat/completions\".",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_openai_comp_info_remote": {
|
||||
"message": "Here you can insert also a remote server address.",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_owl_warning": {
|
||||
"message": "It appears that at least one of your accounts is using the Owl for Exchange add-on. There is a known issue between Thunderbird and Owl, which is currently being addressed. At this time, you can use ThunderAI while composing emails, but not when reading them.",
|
||||
"description": ""
|
||||
|
|
@ -1014,5 +1018,141 @@
|
|||
"calendar_opening_dialog_error": {
|
||||
"message": "Error opening the calendar event dialog",
|
||||
"description": ""
|
||||
},
|
||||
"sparks_not_installed": {
|
||||
"message": "ThunderAI Sparks not installed!",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_add_tags_auto": {
|
||||
"message": "Add tags automatically",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_add_tags_auto_Info": {
|
||||
"message": "If checked, the AI will automatically add tags to newly received emails.",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_add_tags_auto_force_existing": {
|
||||
"message": "Force existing tags when autotagging",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_add_tags_auto_force_existing_Info": {
|
||||
"message": "If checked, the AI will add only existing tags to newly received emails, and won't create new tags.",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_add_tags_auto_only_inbox": {
|
||||
"message": "Only add tags to inbox emails",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_add_tags_auto_only_inbox_Info": {
|
||||
"message": "If checked, the AI will only add tags to emails received in the inbox folder.",
|
||||
"description": ""
|
||||
},
|
||||
"placeholder_thunderai_def_sign": {
|
||||
"message": "Default signature as defined in ThunderAI options.",
|
||||
"description": ""
|
||||
},
|
||||
"thunderai_def_lang": {
|
||||
"message": "Default language as defined in ThunderAI options.",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_spamfilter": {
|
||||
"message": "Automatic Spam Filter",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_spamfilter_Info": {
|
||||
"message": "If checked, ThunderAI will automatically move spam emails to the spam folder.",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_btnManageSpamFilterInfo": {
|
||||
"message": "Manage spam filter settings",
|
||||
"description": ""
|
||||
},
|
||||
"SpamFilter_PageTitle": {
|
||||
"message": "Manage Spam Filter Settings",
|
||||
"description": ""
|
||||
},
|
||||
"SpamFilter_info_default": {
|
||||
"message": "In this page you can modify the default prompt used to detect spam emails.",
|
||||
"description": ""
|
||||
},
|
||||
"SpamFilter_prompt_text_title": {
|
||||
"message": "Current prompt text",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_spamfilter_infoline": {
|
||||
"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": ""
|
||||
},
|
||||
"prompt_spamfilter" : {
|
||||
"message" : "Detect spam emails",
|
||||
"description" : ""
|
||||
},
|
||||
"prompt_spamfilter_full_text" : {
|
||||
"message" : "Analyze the following email and determine if it is spam or not. Consider factors such as suspicious keywords, excessive promotional language, misleading subject lines, requests for personal information, and unusual sender addresses.\nProvide a value from 0 (not spam) to 100 (spam) and an explaination of no more than 10 words.\nGenerate a response in JSON format only. Do not include any additional text or explanation; provide only the JSON. Here is the format to be used:\n{\n\"spamValue\": <integer from 0 to 100>,\n\"explanation\": \"Brief explanation of your reasoning\",\n}\nHere there are the mail information:\nSender: \"{%author%}\"\nSubject: \"{%mail_subject%}\"\nHtml body: \"{%mail_html_body%}\"",
|
||||
"description" : ""
|
||||
},
|
||||
"SpamFilter_prompt_prefs_title": {
|
||||
"message": "Spam Filter Options",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_spamfilter_threshold": {
|
||||
"message": "Spam threshold",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_spamfilter_threshold_Info": {
|
||||
"message": "If the value returned by the AI is above this threshold, the email will be moved to the spam folder.",
|
||||
"description": ""
|
||||
},
|
||||
"spamfilter_threshold_too_low": {
|
||||
"message": "The spam threshold is too low! You will likely mark too much mails as spam!",
|
||||
"description": ""
|
||||
},
|
||||
"spamfilter_threshold_zero": {
|
||||
"message": "The spam threshold is zero! You will mark all mails as spam!",
|
||||
"description": ""
|
||||
},
|
||||
"spamfilter_no_reports": {
|
||||
"message": "No messages have screened for spam yet. Here you'll find a list of the last 100 spam reports for the current session only.",
|
||||
"description": ""
|
||||
},
|
||||
"SpamReport_Title": {
|
||||
"message": "Spam Filter Reports",
|
||||
"description": ""
|
||||
},
|
||||
"Date": {
|
||||
"message": "Date",
|
||||
"description": ""
|
||||
},
|
||||
"From": {
|
||||
"message": "From",
|
||||
"description": ""
|
||||
},
|
||||
"Subject": {
|
||||
"message": "Subject",
|
||||
"description": ""
|
||||
},
|
||||
"Spam_Value": {
|
||||
"message": "Spam Value",
|
||||
"description": ""
|
||||
},
|
||||
"Moved_to_Spam": {
|
||||
"message": "Moved to Spam",
|
||||
"description": ""
|
||||
},
|
||||
"Explanation": {
|
||||
"message": "Explanation",
|
||||
"description": ""
|
||||
},
|
||||
"Report_Date": {
|
||||
"message": "Report Date",
|
||||
"description": ""
|
||||
},
|
||||
"spamfilter_moved": {
|
||||
"message": "Yes",
|
||||
"description": ""
|
||||
},
|
||||
"spamfilter_not_moved": {
|
||||
"message": "No",
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
32
_locales/es/messages.json
Normal file
32
_locales/es/messages.json
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"extensionDescription": {
|
||||
"message": "¡Usa ChatGPT, Goolge Gemini u Ollama para mejorar tus emails!"
|
||||
},
|
||||
"menu_title": {
|
||||
"message": "IA"
|
||||
},
|
||||
"prompt_lang": {
|
||||
"message": "Respuesta en"
|
||||
},
|
||||
"prompt_reply": {
|
||||
"message": "Respuesta a este email"
|
||||
},
|
||||
"prompt_reply_advanced": {
|
||||
"message": "Respuesta a este hilo"
|
||||
},
|
||||
"prompt_rewrite_polite": {
|
||||
"message": "Reescribe educado"
|
||||
},
|
||||
"prompt_rewrite_formal": {
|
||||
"message": "Reescribir formal"
|
||||
},
|
||||
"prompt_summarize_this": {
|
||||
"message": "Resume esto"
|
||||
},
|
||||
"prompt_translate_this": {
|
||||
"message": "Traducir esto"
|
||||
},
|
||||
"prompt_classify": {
|
||||
"message": "Clasificar"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
870
_locales/hr/messages.json
Normal file
870
_locales/hr/messages.json
Normal file
|
|
@ -0,0 +1,870 @@
|
|||
{
|
||||
"extensionDescription": {
|
||||
"message": "Koristite ChatGPT, Google Gemini ili Ollama kako bi poboljšali vaše e-poruke!",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"menu_title": {
|
||||
"message": "AI"
|
||||
},
|
||||
"prompt_lang": {
|
||||
"message": "Odgovori u"
|
||||
},
|
||||
"prompt_reply": {
|
||||
"message": "Odgovori na ovu e-poruku"
|
||||
},
|
||||
"prompt_reply_advanced": {
|
||||
"message": "Odgovori na ovu nit"
|
||||
},
|
||||
"prompt_rewrite_polite": {
|
||||
"message": "Prepravi pristojno"
|
||||
},
|
||||
"prompt_rewrite_formal": {
|
||||
"message": "Prepravi formalno"
|
||||
},
|
||||
"prompt_classify": {
|
||||
"message": "Klasificiraj"
|
||||
},
|
||||
"prompt_summarize_this": {
|
||||
"message": "Sažmi ovo"
|
||||
},
|
||||
"prompt_translate_this": {
|
||||
"message": "Prevedi ovo"
|
||||
},
|
||||
"prompt_this": {
|
||||
"message": "Upitaj ovo"
|
||||
},
|
||||
"prompt_selection_needed": {
|
||||
"message": "Za nastavak morate odabrati neki tekst!"
|
||||
},
|
||||
"customPrompts_managePrompts": {
|
||||
"message": "Upravljaj upitima"
|
||||
},
|
||||
"customPrompts_managePrompts_help": {
|
||||
"message": "Više informacija"
|
||||
},
|
||||
"customPrompts_managePrompts_info_default": {
|
||||
"message": "Zadane upite nije moguće uređivati. Možete ih onemogućiti, a zatim kopirati tekst upita i zalijepiti ga u novi kako biste stvorili modificiranu verziju."
|
||||
},
|
||||
"customPrompts_managePrompts_info_default_2": {
|
||||
"message": "Možete uvoziti i izvoziti upite. Postojeći upiti s istim ID-om bit će prebrisani. Dodat će se upiti s novim ID-ovima."
|
||||
},
|
||||
"customPrompts_managePrompts_info_default_3": {
|
||||
"message": "Ako je sve ispravno, nakon uvoza pritisnite gumb 'Spremi sve'."
|
||||
},
|
||||
"customPrompts_start_saving": {
|
||||
"message": "Spremanje upita..."
|
||||
},
|
||||
"customPrompts_reindexing_list": {
|
||||
"message": "Ponovno indeksiranje popisa..."
|
||||
},
|
||||
"customPrompts_filtering_prompts": {
|
||||
"message": "Filtriranje upita..."
|
||||
},
|
||||
"customPrompts_saving_default_prompts": {
|
||||
"message": "Spremanje zadanih upita..."
|
||||
},
|
||||
"customPrompts_saving_custom_prompts": {
|
||||
"message": "Spremanje prilagođenih upita..."
|
||||
},
|
||||
"customPrompts_reloading_menus": {
|
||||
"message": "Ponovno učitavanje izbornika..."
|
||||
},
|
||||
"customPrompts_saved": {
|
||||
"message": "Upiti su spremljeni!"
|
||||
},
|
||||
"customPrompts_form_label_ID": {
|
||||
"message": "ID"
|
||||
},
|
||||
"customPrompts_form_label_ID_rules": {
|
||||
"message": "Mora biti jedinstveno, malim slovima i bez razmaka"
|
||||
},
|
||||
"customPrompts_form_label_Name": {
|
||||
"message": "Ime"
|
||||
},
|
||||
"customPrompts_form_label_Text": {
|
||||
"message": "Tekst upita"
|
||||
},
|
||||
"customPrompts_form_label_Action": {
|
||||
"message": "Radnja"
|
||||
},
|
||||
"customPrompts_form_label_need_selected": {
|
||||
"message": "Potreban je odabir teksta"
|
||||
},
|
||||
"customPrompts_form_label_need_signature": {
|
||||
"message": "Uvijek dodaj potpis"
|
||||
},
|
||||
"customPrompts_form_label_need_custom_text": {
|
||||
"message": "Zatraži dodatni tekst"
|
||||
},
|
||||
"customPrompts_form_label_enabled": {
|
||||
"message": "Omogućeno"
|
||||
},
|
||||
"customPrompts_form_required_fields": {
|
||||
"message": "Obavezna polja"
|
||||
},
|
||||
"customPrompts_btnEdit": {
|
||||
"message": "Uredi"
|
||||
},
|
||||
"customPrompts_btnCancel": {
|
||||
"message": "Otkaži"
|
||||
},
|
||||
"customPrompts_btnOK": {
|
||||
"message": "U redu"
|
||||
},
|
||||
"customPrompts_btnDelete": {
|
||||
"message": "Obriši"
|
||||
},
|
||||
"customPrompts_btnDelete_confirmText": {
|
||||
"message": "Jeste li sigurni da želite izbrisati ovu stavku?"
|
||||
},
|
||||
"customPrompts_unsaved_changes": {
|
||||
"message": "Ima nespremljenih promjena!"
|
||||
},
|
||||
"customPrompts_btnSaveAll": {
|
||||
"message": "Spremi sve"
|
||||
},
|
||||
"customPrompts_save_button": {
|
||||
"message": "Spremi"
|
||||
},
|
||||
"customPrompts_btnNew": {
|
||||
"message": "Dodaj novo"
|
||||
},
|
||||
"customPrompts_btnAddNewCommit": {
|
||||
"message": "Dodaj upit"
|
||||
},
|
||||
"customPrompts_add_to_menu": {
|
||||
"message": "Dodaj u izbornik"
|
||||
},
|
||||
"customPrompts_add_to_menu_always": {
|
||||
"message": "Uvijek"
|
||||
},
|
||||
"customPrompts_add_to_menu_reading": {
|
||||
"message": "Čitanje e-poruke"
|
||||
},
|
||||
"customPrompts_add_to_menu_composing": {
|
||||
"message": "Sastavljanje e-poruke"
|
||||
},
|
||||
"customPrompts_close_button": {
|
||||
"message": "gumb Zatvori"
|
||||
},
|
||||
"customPrompts_do_reply": {
|
||||
"message": "Odgovori"
|
||||
},
|
||||
"customPrompts_substitute_text": {
|
||||
"message": "Zamijeni tekst"
|
||||
},
|
||||
"chatgpt_win_working": {
|
||||
"message": "Radovi u tijeku..."
|
||||
},
|
||||
"chatgpt_win_job_completed": {
|
||||
"message": "Završeno!"
|
||||
},
|
||||
"chatgpt_win_job_completed_select": {
|
||||
"message": "Odaberite tekst koji želite koristiti i pritisnite gumb."
|
||||
},
|
||||
"chatgpt_win_get_answer": {
|
||||
"message": "Koristite odabrani odgovor"
|
||||
},
|
||||
"chatgpt_win_close": {
|
||||
"message": "Zatvori"
|
||||
},
|
||||
"chatgpt_textarea_not_found_error": {
|
||||
"message": "Čini se da se stranica ChatGPT predugo učitava. Ako završi s učitavanjem, pritisnite gumb s desne strane. Ako se problem nastavi, provjerite status usluge."
|
||||
},
|
||||
"chatgpt_btn_retry": {
|
||||
"message": "Pokušaj ponovo"
|
||||
},
|
||||
"chatgpt_sendbutton_not_found_error": {
|
||||
"message": "Pritisnite gumb Pošalji kako biste poslali upit."
|
||||
},
|
||||
"chatgpt_user_not_logged_in": {
|
||||
"message": "Niste prijavljeni na ChatGPT. Prijavite se sa svojim vjerodajnicama, zatvorite prozor ChatGPT, a zatim ponovite radnju koju ste pokušali. Nakon toga ćete ostati prijavljeni."
|
||||
},
|
||||
"chatgpt_win_model_warning": {
|
||||
"message": "Postavili ste opciju korištenja određenog modela, ali čini se da se ne učitava ispravno. Provjerite vrijednost i pokušajte ponovno. Za sada možete pritisnuti plavi gumb za nastavak."
|
||||
},
|
||||
"chatgpt_win_custom_text": {
|
||||
"message": "Ovdje umetnite dodatni tekst za upit."
|
||||
},
|
||||
"chatgpt_win_send": {
|
||||
"message": "Pošalji"
|
||||
},
|
||||
"chatgpt_use_gpt35": {
|
||||
"message": "Koristi GPT3.5"
|
||||
},
|
||||
"chatgpt_force_completion": {
|
||||
"message": "prisilno dovrši"
|
||||
},
|
||||
"chatgpt_force_completion_title": {
|
||||
"message": "Pritisnite ovdje za prikaz gumba 'Koristi zadnji odgovor' ako je ChatGPT završio svoj posao, ali se gumb nije pojavio."
|
||||
},
|
||||
"msg_prompt_too_long": {
|
||||
"message": "Tekst koji ste unijeli je predug. Morate ga skratiti."
|
||||
},
|
||||
"prefs_OptionText_release_notes": {
|
||||
"message": "Bilješke o izdanju"
|
||||
},
|
||||
"prefs_status_page": {
|
||||
"message": "status usluge"
|
||||
},
|
||||
"prefs_OptionText_chatgpt_win_text": {
|
||||
"message": "Dimenzije prozora ChatGPT"
|
||||
},
|
||||
"prefs_OptionText_chatgpt_win_height": {
|
||||
"message": "Visina"
|
||||
},
|
||||
"prefs_OptionText_chatgpt_win_width": {
|
||||
"message": "Širina"
|
||||
},
|
||||
"prefs_OptionText_default_sign_name": {
|
||||
"message": "Zadani naziv potpisa"
|
||||
},
|
||||
"prefs_OptionText_default_chatgpt_lang": {
|
||||
"message": "Zadani jezik za odgovore"
|
||||
},
|
||||
"prefs_OptionText_reply_all": {
|
||||
"message": "Odgovori svima"
|
||||
},
|
||||
"prefs_OptionText_reply_sender": {
|
||||
"message": "Odgovori pošiljatelju"
|
||||
},
|
||||
"prefs_OptionText_reply_type": {
|
||||
"message": "Vrsta odgovora"
|
||||
},
|
||||
"prefs_OptionText_btnManagePrompts": {
|
||||
"message": "Upravljaj svojim upitima"
|
||||
},
|
||||
"prefsInfoTitle": {
|
||||
"message": "Važne informacije"
|
||||
},
|
||||
"prefsInfoDesc_1": {
|
||||
"message": "Može se dogoditi da se ChatGPT web sučelje promijeni na način koji pokvari rad dodatka. Provjerite stranicu \"Status usluge\" povezanu na dnu ove stranice. Također, zapamtite da kada prvi put koristite ThunderAI, morate se prijaviti na ChatGPT."
|
||||
},
|
||||
"prefsInfoDesc_2": {
|
||||
"message": "Za korištenje ChatGPT API-ja potreban vam je OpenAI ChatGPT API ključ i morate odabrati model."
|
||||
},
|
||||
"prefsInfoDesc_3": {
|
||||
"message": "Za korištenje integracije s Ollama, morate postaviti lokalni Ollama poslužitelj. Nakon što je poslužitelj pokrenut, unesite njegovu adresu u predviđeno polje unutar aplikacije. Kako biste osigurali ispravnu komunikaciju između ThunderAI i Ollama poslužitelja, ne zaboravite postaviti OLLAMA_ORIGINS=moz-extension://*."
|
||||
},
|
||||
"prefsInfoDesc_4": {
|
||||
"message": "Za korištenje ove integracije morate postaviti lokalni poslužitelj kompatibilan s OpenAI API-jem, poput LM Studio. Nakon što je poslužitelj pokrenut, unesite njegovu adresu u predviđeno polje unutar aplikacije. Kako biste osigurali ispravnu komunikaciju između ThunderAI i lokalnog poslužitelja, ne zaboravite pravilno postaviti CORS postavke."
|
||||
},
|
||||
"prefsInfoDesc_5": {
|
||||
"message": "Ne zaboravite da možete otvoriti izbornik ThunderAI pomoću tipkovničke prečice CTRL+ALT+A."
|
||||
},
|
||||
"prefsInfoDesc_6": {
|
||||
"message": "Prečac možete promijeniti pritiskom ikone zupčanika u gornjem desnom kutu ove stranice i odabirom \"Upravljaj tipkovničkim prečacima dodatka\"."
|
||||
},
|
||||
"prefsDonation_1": {
|
||||
"message": "Sviđa li vam se ovaj dodatak?"
|
||||
},
|
||||
"prefsDonation_2": {
|
||||
"message": "Razmislite o davanju donacije!"
|
||||
},
|
||||
"backToOptionsText": {
|
||||
"message": "Mogućnosti"
|
||||
},
|
||||
"TranslateText": {
|
||||
"message": "Želite li pomoći u prijevodu ovog dodatka?"
|
||||
},
|
||||
"TranslateLink": {
|
||||
"message": "Saznajte kako!"
|
||||
},
|
||||
"customPrompts_ExportAll": {
|
||||
"message": "Izvezi sve upite"
|
||||
},
|
||||
"customPrompts_Import": {
|
||||
"message": "Uvezi nove upite"
|
||||
},
|
||||
"importPrompts_confirmText": {
|
||||
"message": "Upravo ćete uvesti nove upite."
|
||||
},
|
||||
"customPrompts_start_import": {
|
||||
"message": "Pokretanje uvoza prilagođenih upita..."
|
||||
},
|
||||
"customPrompts_import_completed": {
|
||||
"message": "Uvoz prilagođenih upita dovršen! Morate pritisnuti gumb 'Spremi sve' da biste spremili svoje promjene."
|
||||
},
|
||||
"importPrompts_invalidFile": {
|
||||
"message": "Datoteka koju pokušavate uvesti nije važeća datoteka prilagođenih upita."
|
||||
},
|
||||
"importPrompts_invalidPrompts": {
|
||||
"message": "Datoteka koju pokušavate uvesti ne sadrži valjane upite."
|
||||
},
|
||||
"currently_used_prompt": {
|
||||
"message": "Trenutno korišteno ime upita"
|
||||
},
|
||||
"customprompts_form_label_define_response_lang": {
|
||||
"message": "Odredite jezik odgovora u upitu"
|
||||
},
|
||||
"prefs_Connection_type": {
|
||||
"message": "Vrsta veze"
|
||||
},
|
||||
"prefs_Connection_type_ChatGPT_Web": {
|
||||
"message": "ChatGPT web sučelje"
|
||||
},
|
||||
"prefs_Connection_type_ChatGPT_API": {
|
||||
"message": "ChatGPT OpenAI API"
|
||||
},
|
||||
"prefs_ChatGPT_API_Key": {
|
||||
"message": "ChatGPT API ključ"
|
||||
},
|
||||
"ChatGPT_Models": {
|
||||
"message": "ChatGPT modeli"
|
||||
},
|
||||
"ChatGPT_Models_Fetch": {
|
||||
"message": "Ažuriraj popis ChatGPT modela"
|
||||
},
|
||||
"ChatGPT_Models_Error_fetching": {
|
||||
"message": "Pogreška pri pokušaju dohvaćanja ChatGPT modela"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Učitavanje..."
|
||||
},
|
||||
"error": {
|
||||
"message": "ThunderAI greška!"
|
||||
},
|
||||
"chatgpt_empty_apikey": {
|
||||
"message": "Niste dodali API ključ za ChatGPT API. Unesite jedan na stranicu s opcijama."
|
||||
},
|
||||
"chatgpt_empty_model": {
|
||||
"message": "Niste odabrali model za ChatGPT API. Odaberite jedan na stranici s opcijama."
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"prefs_OptionText_do_debug_info": {
|
||||
"message": "Aktiviraj sustav za otklanjanje pogrešaka"
|
||||
},
|
||||
"prefs_Connection_type_Ollama_API": {
|
||||
"message": "Ollama API (lokalni LLM)"
|
||||
},
|
||||
"prefs_Connection_type_OpenAI_Comp_API": {
|
||||
"message": "OpenAI kompatibilan API"
|
||||
},
|
||||
"prefs_API_Host": {
|
||||
"message": "Adresa glavnog računala"
|
||||
},
|
||||
"Ollama_Models": {
|
||||
"message": "Ollama modeli"
|
||||
},
|
||||
"Ollama_Models_Fetch": {
|
||||
"message": "Ažurirajte popis Ollama modela"
|
||||
},
|
||||
"Ollama_Models_Error_fetching": {
|
||||
"message": "Pogreška pri pokušaju dohvaćanja Ollama modela"
|
||||
},
|
||||
"API_Models_Error_NoModels": {
|
||||
"message": "Nema pronađenih modela"
|
||||
},
|
||||
"ollama_empty_host": {
|
||||
"message": "Niste dodali adresu glavnog računala za Ollama API. Unesite jednu na stranici s mogućnostima."
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"ollama_api_request_failed": {
|
||||
"message": "Ollama API zahtjev nije uspio"
|
||||
},
|
||||
"chatgpt_api_request_failed": {
|
||||
"message": "OpenAI ChatGPT API zahtjev nije uspio"
|
||||
},
|
||||
"WaitingServerReponse": {
|
||||
"message": "Čeka se odgovor poslužitelja"
|
||||
},
|
||||
"prefs_API_Host_Info": {
|
||||
"message": "Nešto poput"
|
||||
},
|
||||
"OpenAIComp_Models": {
|
||||
"message": "OpenAI kompatibilni API modeli"
|
||||
},
|
||||
"OpenAIComp_Models_Fetch": {
|
||||
"message": "Ažuriraj popis OpenAI kompatibilnih API modela"
|
||||
},
|
||||
"OpenAIComp_Models_Error_fetching": {
|
||||
"message": "Pogreška pri pokušaju dohvaćanja OpenAI kompatibilnih API modela"
|
||||
},
|
||||
"OpenAIComp_empty_host": {
|
||||
"message": "Niste dodali adresu glavnog računala za OpenAI kompatibilan API. Unesite jedan na stranicu s mogućnostima."
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"prefs_OpenAIComp_ChatName": {
|
||||
"message": "Naziv čavrljanja"
|
||||
},
|
||||
"prefs_OpenAIComp_ChatName_Info": {
|
||||
"message": "Ovo je ime koje će se koristiti u čavrljanju s AI."
|
||||
},
|
||||
"StorageSpace": {
|
||||
"message": "Ukupan zauzeto prostora za pohranu"
|
||||
},
|
||||
"SearchPrompt": {
|
||||
"message": "Pretraži upite"
|
||||
},
|
||||
"prefs_OptionText_dynamic_menu_force_enter": {
|
||||
"message": "Izbornik: neposredno slanje upita"
|
||||
},
|
||||
"prefs_OptionText_dynamic_menu_force_enter_info": {
|
||||
"message": "Ako je označeno, korištenje tipkovničkog prečaca CTRL+ALT+A automatski će poslati istaknuti upit iz izbornika. U protivnom će korisniku biti prikazan naziv upita, koji će zahtijevati još jedan pritisak tipke Enter za slanje."
|
||||
},
|
||||
"prefs_OptionText_dynamic_menu_order_alphabet": {
|
||||
"message": "Izbornik: redoslijed po abecedi"
|
||||
},
|
||||
"prefs_OptionText_dynamic_menu_order_alphabet_info": {
|
||||
"message": "Ako je označeno, upiti u izborniku bit će poredani abecednim redom."
|
||||
},
|
||||
"prefs_OptionText_chatgpt_win_dims_info": {
|
||||
"message": "Postavite na 0 ako ne želite odrediti veličinu prozora."
|
||||
},
|
||||
"prefs_OpenAIComp_API_Key": {
|
||||
"message": "OpenAI Comp API ključ"
|
||||
},
|
||||
"Optional": {
|
||||
"message": "Neobavezno"
|
||||
},
|
||||
"OpenChatGPTTab": {
|
||||
"message": "Otvorite karticu ChatGPT"
|
||||
},
|
||||
"OpenChatGPTTab_Info": {
|
||||
"message": "U slučaju problema s prijavom u prozor ThunderAI, otvorite ChatGPT u novoj kartici pomoću gumba s desne strane, prijavite se, zatim zatvorite karticu i nastavite koristiti ThunderAI."
|
||||
},
|
||||
"placeholder_mail_text_body": {
|
||||
"message": "Tijelo e-poruke"
|
||||
},
|
||||
"placeholder_mail_html_body": {
|
||||
"message": "HTML tijelo e-poruke"
|
||||
},
|
||||
"placeholder_mail_subject": {
|
||||
"message": "Naslov e-poruke"
|
||||
},
|
||||
"placeholder_selected_text": {
|
||||
"message": "Odabrani tekst"
|
||||
},
|
||||
"placeholder_additional_text": {
|
||||
"message": "Dodatni tekst"
|
||||
},
|
||||
"placeholder_junk_score": {
|
||||
"message": "Rezultat smeća"
|
||||
},
|
||||
"placeholder_recipients": {
|
||||
"message": "Primatelji"
|
||||
},
|
||||
"placeholder_cc_list": {
|
||||
"message": "CC popis"
|
||||
},
|
||||
"placeholder_author": {
|
||||
"message": "Autor"
|
||||
},
|
||||
"prefs_OptionText_placeholders_use_default_value": {
|
||||
"message": "Rezervirana mjesta: koristite zadanu vrijednost"
|
||||
},
|
||||
"prefs_OptionText_placeholders_use_default_value_info": {
|
||||
"message": "Ako je označeno, rezervirana mjesta bit će ispunjena zadanim vrijednostima kada nije navedena vrijednost. U suprotnom će rezervirana mjesta ostati umjesto."
|
||||
},
|
||||
"prefs_OptionText_max_prompt_length": {
|
||||
"message": "Maksimalna duljina upita"
|
||||
},
|
||||
"prefs_OptionText_max_prompt_length_Info": {
|
||||
"message": "Ovo je najveći broj znakova koji se mogu koristiti u upitu. U protivnom će se prikazati poruka o pogrešci. Vrijednost nije moguće uređivati za ChatGPT web sučelje."
|
||||
},
|
||||
"prefs_OptionText_chatgpt_web_model": {
|
||||
"message": "ChatGPT web model"
|
||||
},
|
||||
"prefs_OptionText_chatgpt_web_model_info": {
|
||||
"message": "Ovo je model koji će se provoditi za ChatGPT web sučelje. Ako nijedan nije naveden ili je naveden netočan, zadani model postavit će ChatGPT na web stranici."
|
||||
},
|
||||
"prefs_OptionText_chatgpt_web_tempchat": {
|
||||
"message": "ChatGPT Web privremeno čavrljanje"
|
||||
},
|
||||
"prefs_OptionText_chatgpt_web_tempchat_info": {
|
||||
"message": "Ako je označeno, privremeno čavrljanje koristit će se u web sučelju ChatGPT."
|
||||
},
|
||||
"chatgpt_btn_model": {
|
||||
"message": "Koristi trenutni model"
|
||||
},
|
||||
"SendingPrompt": {
|
||||
"message": "Slanje upita..."
|
||||
},
|
||||
"AllowedValues": {
|
||||
"message": "Dopuštene vrijednosti"
|
||||
},
|
||||
"prefs_OptionText_btnManagePrompts_infoline": {
|
||||
"message": "Možete koristiti dodatna rezervirana mjesta za podatke."
|
||||
},
|
||||
"prefs_OptionText_btnManagePrompts_infoline2": {
|
||||
"message": "Možete promijeniti upit kako želite, ali odgovor primljen od AI mora biti popis oznaka odvojenih zarezima!"
|
||||
},
|
||||
"prefs_OptionText_openai_comp_use_v1": {
|
||||
"message": "Zadrži \"v1\" kompatibilnost"
|
||||
},
|
||||
"prefs_OptionText_openai_comp_use_v1_info": {
|
||||
"message": "Ako je označeno, segment \"v1\" na putanji API poziva će se zadržati, poput \"http://localhost:1234/v1/chat/completions\"."
|
||||
},
|
||||
"prefs_OptionText_owl_warning": {
|
||||
"message": "Čini se da barem jedan od vaših računa koristi dodatak Owl for Exchange. Postoji poznati problem između Thunderbirda i Owl, koji se trenutno rješava. Trenutačno možete koristiti ThunderAI dok sastavljate e-poruke, ali ne i dok ih čitate."
|
||||
},
|
||||
"prefs_OptionText_chatgpt_web_model_tooltip": {
|
||||
"message": "Pritisnite vrijednost da biste je postavili."
|
||||
},
|
||||
"prompt_reply_full_text": {
|
||||
"message": "Odgovori na sljedeću e-poruku. Odgovorit samo s potrebnim tekstom i bez dodatnih komentara ili drugog teksta."
|
||||
},
|
||||
"prompt_reply_additional_text": {
|
||||
"message": "Nemoj dodavati naslov u odgovor."
|
||||
},
|
||||
"reply_same_lang": {
|
||||
"message": "Odgovori na istom jeziku."
|
||||
},
|
||||
"sign_msg_as": {
|
||||
"message": "Potpiši e-poruku kao"
|
||||
},
|
||||
"prompt_reply_advanced_full_text": {
|
||||
"message": "Odgovori na sljedeću e-poruku \"{%selected_text%}\", s obzirom da je ovo cijela nit e-poruka \"{%mail_html_body%}\". Odgovori samo s potrebnim tekstom i bez dodatnih komentara ili drugog teksta."
|
||||
},
|
||||
"prompt_rewrite_full_text": {
|
||||
"message": "Prepravi sljedeći tekst kako biste bili pristojniji. Odgovori samo s prepravljenim tekstom i bez dodatnih komentara ili drugog teksta."
|
||||
},
|
||||
"prompt_rewrite_formal_full_text": {
|
||||
"message": "Prepravi sljedeći tekst da bude formalniji. Odgovori samo s prepravljenim tekstom i bez dodatnih komentara ili drugog teksta."
|
||||
},
|
||||
"prompt_classify_full_text": {
|
||||
"message": "Klasificiraj sljedeći tekst u smislu ljubaznosti, topline, formalnosti, asertivnosti, uvredljivosti dajući postotak za svaku kategoriju. Odgovori samo kategorijom i ocijeni bez dodatnih komentara ili drugog teksta."
|
||||
},
|
||||
"prompt_summarize_this_full_text": {
|
||||
"message": "Sažmi sljedeću e-poruku u popis s točkama."
|
||||
},
|
||||
"prompt_translate_this_full_text": {
|
||||
"message": "Prevedi sljedeću e-poruku na"
|
||||
},
|
||||
"prompt_this_full_text": {
|
||||
"message": "Odgovori samo s potrebnim tekstom i bez dodatnih komentara ili drugog teksta."
|
||||
},
|
||||
"prefs_OptionText_add_tags": {
|
||||
"message": "Dodaj oznake e-porukama"
|
||||
},
|
||||
"prefs_OptionText_add_tags_Info": {
|
||||
"message": "Ako je označeno, stavka će biti uključena u izbornik za primjenu oznaka na e-poruke."
|
||||
},
|
||||
"prompt_add_tags": {
|
||||
"message": "Dodaj oznake ovoj e-poruci"
|
||||
},
|
||||
"prompt_add_tags_full_text": {
|
||||
"message": "Analiziraj sljedeći tekst e-poruke i generiraj popis oznaka odvojenih zarezima koji sažimaju njegov sadržaj. Koristi teme, ključne teme i relevantne deskriptore kao oznake. Provjeri jesu li oznake sažete i relevantne za sadržaj e-poruke.\nTekst e-poruke: {%mail_text_body%}\nUzmi u obzir sljedeće pojedinosti za kontekst:\n- Šalje: {%author%}\n- Primatelji: {%recipients%}\n- CC popis: {%cc_list%}\n- Naslov: {%mail_subject%}\nTemelji svoje oznake na tekstu i kontekstu e-poruke, zanemarujući nepotrebne informacije ili trivijalne detalje. Izlaz bi trebao biti samo popis oznaka odvojenih zarezom bez dodatnih komentara ili teksta."
|
||||
},
|
||||
"placeholder_tags_current_email": {
|
||||
"message": "Oznake e-pošte"
|
||||
},
|
||||
"placeholder_tags_full_list": {
|
||||
"message": "Postojeće oznake"
|
||||
},
|
||||
"prefs_OptionText_add_tags_maxnum": {
|
||||
"message": "Maksimalan broj oznaka"
|
||||
},
|
||||
"prefs_OptionText_add_tags_maxnum_Info": {
|
||||
"message": "Maksimalni broj oznaka koje je predložio AI. Postavite na 0 ako ne želite ograničiti broj oznaka."
|
||||
},
|
||||
"prompt_add_tags_maxnum": {
|
||||
"message": "Ograniči broj oznaka na"
|
||||
},
|
||||
"prefs_OptionText_add_tags_hide_exclusions": {
|
||||
"message": "Sakrij izuzete oznake"
|
||||
},
|
||||
"prefs_OptionText_add_tags_hide_exclusions_Info": {
|
||||
"message": "Ako je označeno, oznake koje se nalaze na popisu izuzetaka bit će skrivene u dijaloškom okviru za potvrdu."
|
||||
},
|
||||
"prefs_OptionText_btnManageTagsInfo": {
|
||||
"message": "Upravljaj postavkama oznaka"
|
||||
},
|
||||
"AddTags_PageTitle": {
|
||||
"message": "Upravljaj postavkama oznaka"
|
||||
},
|
||||
"AddTags_info_default": {
|
||||
"message": "Na ovoj stranici možete promijeniti zadani upit koji se koristi za dodavanje oznaka u e-poruke i upravljanje popisom izuzetaka."
|
||||
},
|
||||
"AddTags_prompt_text_title": {
|
||||
"message": "Trenutačni tekst upita"
|
||||
},
|
||||
"AddTags_excl_list_title": {
|
||||
"message": "Popis izuzetaka"
|
||||
},
|
||||
"AddTags_excl_list_infoline": {
|
||||
"message": "Ovo je popis oznaka koje nije dopušteno dodavati e-porukama."
|
||||
},
|
||||
"save": {
|
||||
"message": "Spremi"
|
||||
},
|
||||
"addtags_info_additional_statements": {
|
||||
"message": "Ova će izjava biti dodana na kraju upita:"
|
||||
},
|
||||
"reset_default": {
|
||||
"message": "Vrati na zadano"
|
||||
},
|
||||
"addtags_excl_list_infoline2": {
|
||||
"message": "Dodaj riječ po retku ili odvojenu zarezom."
|
||||
},
|
||||
"addtags_dialog_title": {
|
||||
"message": "Dodaj oznake e-poruci"
|
||||
},
|
||||
"addtags_exclude_tag": {
|
||||
"message": "Isključi oznaku"
|
||||
},
|
||||
"addtags_no_tags_received": {
|
||||
"message": "Nisu primljene oznake od AI."
|
||||
},
|
||||
"addtags_no_valid_tags": {
|
||||
"message": "Nisu pronađene važeće oznake nakon filtriranja s popisom izuzetaka."
|
||||
},
|
||||
"thunderai_error_title": {
|
||||
"message": "ThunderAI greška"
|
||||
},
|
||||
"thunderai_warning_title": {
|
||||
"message": "ThunderAI upozorenje"
|
||||
},
|
||||
"prefs_OptionText_add_tags_first_uppercase": {
|
||||
"message": "Prvo slovo veliko"
|
||||
},
|
||||
"prefs_OptionText_add_tags_first_uppercase_Info": {
|
||||
"message": "Ako je označeno, etiketa oznaka bit će postavljena na mala slova sa samo prvim velikim slovom."
|
||||
},
|
||||
"AddTags_prompt_prefs_title": {
|
||||
"message": "Mogućnosti dodavanja oznaka"
|
||||
},
|
||||
"prefs_SurveyLinkText": {
|
||||
"message": "Podijelite svoje povratne informacije i pomozite nam poboljšati ThunderAI!"
|
||||
},
|
||||
"prefs_SurveyLinkText2": {
|
||||
"message": "Pritisnite ovdje, traje samo minutu!"
|
||||
},
|
||||
"prefs_OpenAIComp_ForceModel": {
|
||||
"message": "Ručno umetni model"
|
||||
},
|
||||
"OpenAIComp_force_model_ask": {
|
||||
"message": "Ovdje umetni naziv modela koji želiš koristiti."
|
||||
},
|
||||
"prefs_OptionText_add_tags_force_lang": {
|
||||
"message": "Nametni jezik"
|
||||
},
|
||||
"prefs_OptionText_add_tags_force_lang_Info": {
|
||||
"message": "Ako je označeno, jezik oznaka će biti prisiljen odgovarati jeziku definiranom na stranici mogućnosti ThunderAI, ako je navedeno."
|
||||
},
|
||||
"prompt_add_tags_force_lang": {
|
||||
"message": "Oznake moraju biti upisane"
|
||||
},
|
||||
"prefs_Connection_type_Google_Gemini_API": {
|
||||
"message": "Google Gemini API"
|
||||
},
|
||||
"prefs_GoogleGemini_API_Key": {
|
||||
"message": "API ključ"
|
||||
},
|
||||
"GoogleGemini_Models": {
|
||||
"message": "Google Gemini API modeli"
|
||||
},
|
||||
"GoogleGemini_Models_Fetch": {
|
||||
"message": "Ažuriraj popis Google Gemini modela"
|
||||
},
|
||||
"GoogleGemini_Models_Error_fetching": {
|
||||
"message": "Pogreška pri pokušaju dohvaćanja modela Google Gemini"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"google_gemini_empty_model": {
|
||||
"message": "Niste odabrali model za Google Gemini API. Odaberite jedan na stranici s mogućnostima."
|
||||
},
|
||||
"GoogleGemini_SystemInstruction": {
|
||||
"message": "Uputa za sustav"
|
||||
},
|
||||
"GoogleGemini_SystemInstruction_Info": {
|
||||
"message": "Kada postavite uputu za sustav, dajete modelu dodatni kontekst za razumijevanje zadatka, dajete prilagođenije odgovore i pridržavate se specifičnih smjernica u vezi s upitom koji će biti poslan."
|
||||
},
|
||||
"ChatGPT_Developer_Messages": {
|
||||
"message": "Poruke razvojnog programera"
|
||||
},
|
||||
"ChatGPT_Developer_Messages_Info": {
|
||||
"message": "Kada postavite poruke razvojnog programera, modelu dajete dodatni kontekst za razumijevanje zadatka, dajete prilagođenije odgovore i pridržavate se specifičnih smjernica za upit koji će biti poslan."
|
||||
},
|
||||
"prefs_OptionText_btnManagePrompts_infoline3": {
|
||||
"message": "Možete upotrijebiti {%tags_full_list%} rezervirano mjesto podataka u upitu za popis dostupnih oznaka. Uz odgovarajući upit, tada možete prisiliti da se oznake izaberu samo s popisa onih koji već postoje."
|
||||
},
|
||||
"placeholder_mail_typed_text": {
|
||||
"message": "Upisani tekst prije citiranog tijela e-poruke"
|
||||
},
|
||||
"prompt_get_calendar_event": {
|
||||
"message": "Dodaj novi kalendarski događaj"
|
||||
},
|
||||
"prompt_get_calendar_event_full_text": {
|
||||
"message": "Izdvoji sve relevantne detalje potrebne za generiranje kalendarskog događaja iz sljedećeg teksta. Izdvojene informacije trebaju uključivati:\n- Naslov događaja\n- Datum i vrijeme početka (uključujući vremensku zonu, ako je navedeno)\n- Datum i vrijeme završetka (uključujući vremensku zonu, ako je navedeno)\n- Cijeli dan (ako je navedeno)\nOsiguraj da su podaci oblikovani jasno i dosljedno kako bi se mogli izravno koristiti za stvaranje kalendarskog događaja.\nAko postoje relativne vremenske napomene, smatraj da su datum i vrijeme e-poruke \"{%mail_datetime%}\". Izračunajte datum i vrijeme početka na temelju ove napomene. Ako su izračunati početni datum i vrijeme raniji od \"{%current_datetime%}\", ponovno izračunaj početni datum i vrijeme koristeći \"{%current_datetime%}\" kao osnovu.\nAko trajanje nije navedeno, postavi ga na jedan sat.\nAko ne možeš dobiti jednu ili više potrebnih informacija, odgovori praznim nizom.\nGeneriraj odgovor samo u JSON formatu. Nemoj uključivati nikakav dodatni tekst ili objašnjenja; pruži samo JSON. Ovo je format koji će se koristiti:\n{\n\"startDate\": \"YYYYMMDDTHHMMSS\",\n\"endDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"Sažetak kalendarskih događaja ovdje\",\n\"forceAllDay\": false\n}\nOvo je tekst:\"{%selected_text%}\""
|
||||
},
|
||||
"prefs_OptionText_get_calendar_event": {
|
||||
"message": "Dodaj novi kalendarski događaj iz odabranog teksta"
|
||||
},
|
||||
"prefs_OptionText_get_calendar_event_Info": {
|
||||
"message": "Ako je označeno, stavka će biti uključena u izbornik za dobivanje informacija o kalendarskom događaju iz odabranog teksta."
|
||||
},
|
||||
"prefs_OptionText_btnManageCalendarEventInfo": {
|
||||
"message": "Upravljaj postavkama kalendarskih događaja"
|
||||
},
|
||||
"GetCalendarEvent_PageTitle": {
|
||||
"message": "Upravljaj postavkama kalendarskih događaja"
|
||||
},
|
||||
"GetCalendarEvent_info_default": {
|
||||
"message": "Na ovoj stranici možete promijeniti zadani upit koji se koristi za dobivanje kalendarskih događaja iz odabranog teksta."
|
||||
},
|
||||
"GetCalendarEvent_prompt_text_title": {
|
||||
"message": "Trenutačni tekst upita"
|
||||
},
|
||||
"prefs_OptionText_GetCalendarEvent_infoline2": {
|
||||
"message": "Možete promijeniti upit kako želite, ali odgovor primljen od AI mora biti u JSON formatu kako je navedeno u zadanom upitu!"
|
||||
},
|
||||
"prefs_OptionText_get_calendar_event_Sparks_not_present": {
|
||||
"message": "Za korištenje značajke kalendarskih događaja instalirajte dodatak ThunderAI Sparks."
|
||||
},
|
||||
"prefs_OptionText_download_now": {
|
||||
"message": "Preuzmite ThunderAI Sparks sada!"
|
||||
},
|
||||
"placeholder_mail_datetime": {
|
||||
"message": "Datum i vrijeme e-poruke"
|
||||
},
|
||||
"placeholder_current_datetime": {
|
||||
"message": "Trenutačni datum i vrijeme"
|
||||
},
|
||||
"calendar_getting_data_error": {
|
||||
"message": "Pogreška pri dohvaćanju podataka o kalendarskom događaju"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"prefs_OptionText_add_tags_auto_Info": {
|
||||
"message": "Ako je označeno, AI će automatski dodati oznake novoprimljenim e-porukama."
|
||||
},
|
||||
"prefs_OptionText_add_tags_auto_force_existing": {
|
||||
"message": "Nametni postojeće oznake prilikom automatskog označavanja"
|
||||
},
|
||||
"prefs_OptionText_add_tags_auto_force_existing_Info": {
|
||||
"message": "Ako je označeno, AI će novoprimljenim e-porukama dodati samo postojeće oznake i neće stvarati nove oznake."
|
||||
},
|
||||
"prefs_OptionText_add_tags_auto_only_inbox": {
|
||||
"message": "Dodajte oznake samo e-porukama u Primljenoj pošti"
|
||||
},
|
||||
"prefs_OptionText_add_tags_auto_only_inbox_Info": {
|
||||
"message": "Ako je označeno, AI će dodati oznake samo e-porukama u mapu Primljena pošta."
|
||||
},
|
||||
"placeholder_thunderai_def_sign": {
|
||||
"message": "Zadani potpis kako je određeno u mogućnostima ThunderAI."
|
||||
},
|
||||
"thunderai_def_lang": {
|
||||
"message": "Zadani jezik kako je određeno u mogućnostima ThunderAI."
|
||||
},
|
||||
"prefs_OptionText_spamfilter": {
|
||||
"message": "Automatski filter neželjene pošte"
|
||||
},
|
||||
"prefs_OptionText_spamfilter_Info": {
|
||||
"message": "Ako je označeno, ThunderAI će automatski premjestiti neželjenu poštu u mapu Neželjena pošta."
|
||||
},
|
||||
"prefs_OptionText_btnManageSpamFilterInfo": {
|
||||
"message": "Upravljaj postavkama filtera neželjene pošte"
|
||||
},
|
||||
"SpamFilter_PageTitle": {
|
||||
"message": "Upravljaj postavkama filtera neželjene pošte"
|
||||
},
|
||||
"SpamFilter_info_default": {
|
||||
"message": "Na ovoj stranici možete promijeniti zadani upit koji se koristi za otkrivanje neželjene pošte."
|
||||
},
|
||||
"SpamFilter_prompt_text_title": {
|
||||
"message": "Trenutačni tekst upita"
|
||||
},
|
||||
"prefs_OptionText_spamfilter_infoline": {
|
||||
"message": "Možete promijeniti upit kako želite, ali odgovor primljen od AI mora biti u JSON formatu kako je navedeno u zadanom upitu!"
|
||||
},
|
||||
"prompt_spamfilter": {
|
||||
"message": "Prepoznaj neželjenu poštu"
|
||||
},
|
||||
"prompt_spamfilter_full_text": {
|
||||
"message": "Analiziraj sljedeću e-poruku i utvrdi je li neželjena ili ne. Razmotri čimbenike kao što su sumnjive ključne riječi, pretjerani promotivni jezik, zavaravajuće linije predmeta, zahtjevi za osobnim podacima i neobične adrese pošiljatelja.\nNavedi vrijednost od 0 (nije spam) do 100 (neželjena pošta) i objašnjenje od najviše 10 riječi.\nGeneriraj odgovor samo u JSON formatu. Nemoj uključivati nikakav dodatni tekst ili objašnjenje; pruži samo JSON. Ovdje je format koji treba koristiti:\n{\n\"spamValue\": <cijeli broj od 0 do 100>,\n\"explanation\": \"Kratko objašnjenje vašeg obrazloženja\",\n}\nOvdje su informacije o e-poruci:\nŠalje: \"{%author%}\"\nNaslov: \"{%mail_subject%}\"\nHtml tijelo: \"{%mail_html_body%}\""
|
||||
},
|
||||
"SpamFilter_prompt_prefs_title": {
|
||||
"message": "Mogućnosti filtera neželjene pošte"
|
||||
},
|
||||
"prefs_OptionText_spamfilter_threshold": {
|
||||
"message": "Prag neželjene pošte"
|
||||
},
|
||||
"prefs_OptionText_spamfilter_threshold_Info": {
|
||||
"message": "Ako je vrijednost koju vraća AI iznad ovog praga, e-poruka će biti premještena u mapu Neželjena pošta."
|
||||
},
|
||||
"spamfilter_threshold_too_low": {
|
||||
"message": "Prag neželjene pošte je prenizak! Vjerojatno ćete označiti previše e-poruka kao neželjenu poštu!"
|
||||
},
|
||||
"spamfilter_threshold_zero": {
|
||||
"message": "Prag neželjene pošte je nula! Označit ćete sve e-poruke kao neželjenu poštu!"
|
||||
},
|
||||
"spamfilter_no_reports": {
|
||||
"message": "Nijedna poruka još nije pregledana na neželjenu poštu. Ovdje ćete pronaći popis zadnjih 100 izvješća o neželjenoj pošti samo za trenutnu sjednicu."
|
||||
},
|
||||
"SpamReport_Title": {
|
||||
"message": "Izvješća filtera neželjene pošte"
|
||||
},
|
||||
"Date": {
|
||||
"message": "Datum"
|
||||
},
|
||||
"From": {
|
||||
"message": "Šalje"
|
||||
},
|
||||
"Subject": {
|
||||
"message": "Naslov"
|
||||
},
|
||||
"Spam_Value": {
|
||||
"message": "Vrijednost neželjene pošte"
|
||||
},
|
||||
"Moved_to_Spam": {
|
||||
"message": "Premješteno u Neželjenu poštu"
|
||||
},
|
||||
"Explanation": {
|
||||
"message": "Obrazloženje"
|
||||
},
|
||||
"Report_Date": {
|
||||
"message": "Datum izvješća"
|
||||
},
|
||||
"spamfilter_moved": {
|
||||
"message": "Da"
|
||||
},
|
||||
"spamfilter_not_moved": {
|
||||
"message": "Ne"
|
||||
},
|
||||
"prefs_OptionText_openai_comp_info_remote": {
|
||||
"message": "Ovdje možete unijeti i adresu udaljenog poslužitelja."
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
102
js/mzta-menus.js
102
js/mzta-menus.js
|
|
@ -19,7 +19,8 @@
|
|||
// Some original methods are derived from https://github.com/ali-raheem/Aify/blob/cfadf52f576b7be3720b5b73af7c8d3129c054da/plugin/html/actions.js
|
||||
|
||||
import { getPrompts } from './mzta-prompts.js';
|
||||
import { getLanguageDisplayName, getMenuContextCompose, getMenuContextDisplay, i18nConditionalGet, getMailSubject, getTagsList, transformTagsLabels } from './mzta-utils.js'
|
||||
import { getLanguageDisplayName, getMenuContextCompose, getMenuContextDisplay, i18nConditionalGet, getMailSubject, getTagsList } from './mzta-utils.js'
|
||||
import { taPromptUtils } from './mzta-utils-prompt.js';
|
||||
import { taLogger } from './mzta-logger.js';
|
||||
import { placeholdersUtils } from './mzta-placeholders.js';
|
||||
import { mzta_specialCommand } from './mzta-special-commands.js';
|
||||
|
|
@ -106,18 +107,8 @@ export class mzta_Menus {
|
|||
only_typed_text = msg_text.only_typed_text.replace(/\s+/g, ' ').trim();
|
||||
//open chatgpt window
|
||||
//console.log("Click menu item...");
|
||||
let chatgpt_lang = '';
|
||||
if(String(curr_prompt.define_response_lang) == "1"){
|
||||
let prefs = await browser.storage.sync.get({default_chatgpt_lang: ''});
|
||||
chatgpt_lang = prefs.default_chatgpt_lang;
|
||||
//console.log(" >>>>>>>>>>>> chatgpt_lang: " + chatgpt_lang);
|
||||
if(chatgpt_lang === ''){
|
||||
chatgpt_lang = browser.i18n.getMessage("reply_same_lang");
|
||||
}else{
|
||||
chatgpt_lang = browser.i18n.getMessage("prompt_lang") + " " + chatgpt_lang + ".";
|
||||
}
|
||||
}
|
||||
|
||||
let chatgpt_lang = taPromptUtils.getDefaultLang(curr_prompt);
|
||||
|
||||
let fullPrompt = '';
|
||||
let tags_full_list = await getTagsList();
|
||||
|
||||
|
|
@ -137,65 +128,7 @@ export class mzta_Menus {
|
|||
break;
|
||||
}
|
||||
|
||||
if(!placeholdersUtils.hasPlaceholder(curr_prompt.text)){
|
||||
// no placeholders, do as usual
|
||||
fullPrompt = curr_prompt.text + (String(curr_prompt.need_signature) == "1" ? " " + await this.getDefaultSignature():"") + " " + chatgpt_lang + " \"" + (selection_text=='' ? body_text : selection_text) + "\" ";
|
||||
}else{
|
||||
// we have at least a placeholder, do the magic!
|
||||
let currPHs = await placeholdersUtils.extractPlaceholders(curr_prompt.text);
|
||||
// console.log(">>>>>>>>>> currPHs: " + JSON.stringify(currPHs));
|
||||
let finalSubs = {};
|
||||
for(let currPH of currPHs){
|
||||
switch(currPH.id){
|
||||
case 'mail_text_body':
|
||||
finalSubs['mail_text_body'] = body_text;
|
||||
break;
|
||||
case 'mail_html_body':
|
||||
finalSubs['mail_html_body'] = msg_text.html;
|
||||
break;
|
||||
case 'mail_typed_text':
|
||||
finalSubs['mail_typed_text'] = only_typed_text;
|
||||
break;
|
||||
case 'mail_subject':
|
||||
let mail_subject = await getMailSubject(tabs[0]);
|
||||
finalSubs['mail_subject'] = mail_subject;
|
||||
break;
|
||||
case 'selected_text':
|
||||
finalSubs['selected_text'] = selection_text;
|
||||
break;
|
||||
case 'author':
|
||||
finalSubs['author'] = curr_message.author;
|
||||
break;
|
||||
case 'recipients':
|
||||
finalSubs['recipients'] = curr_message.recipients.join(", ");
|
||||
break;
|
||||
case 'cc_list':
|
||||
finalSubs['cc_list'] = curr_message.ccList.join(", ");
|
||||
break;
|
||||
case 'junk_score':
|
||||
finalSubs['junk_score'] = curr_message.junkScore;
|
||||
break;
|
||||
case 'mail_datetime':
|
||||
finalSubs['mail_datetime'] = curr_message.date;
|
||||
break;
|
||||
case 'current_datetime':
|
||||
finalSubs['current_datetime'] = new Date().toString();
|
||||
break;
|
||||
case 'tags_current_email':
|
||||
let tags_current_email_array = await transformTagsLabels(curr_message.tags, tags_full_list[1]);
|
||||
finalSubs['tags_current_email'] = tags_current_email_array.join(", ");
|
||||
break;
|
||||
case 'tags_full_list':
|
||||
finalSubs['tags_full_list'] = tags_full_list[0];
|
||||
break;
|
||||
default: // TODO Manage custom placeholders https://github.com/micz/ThunderAI/issues/156
|
||||
break;
|
||||
}
|
||||
}
|
||||
// console.log(">>>>>>>>>> finalSubs: " + JSON.stringify(finalSubs));
|
||||
let prefs_ph = await browser.storage.sync.get({placeholders_use_default_value: false});
|
||||
fullPrompt = (placeholdersUtils.replacePlaceholders(curr_prompt.text, finalSubs, prefs_ph.placeholders_use_default_value, true) + (String(curr_prompt.need_signature) == "1" ? " " + await this.getDefaultSignature():"") + " " + chatgpt_lang).trim();
|
||||
}
|
||||
fullPrompt = await taPromptUtils.preparePrompt(curr_prompt, curr_message, chatgpt_lang, selection_text, body_text, await getMailSubject(tabs[0]), msg_text, only_typed_text, tags_full_list);
|
||||
|
||||
switch(curr_prompt.id){
|
||||
case 'prompt_translate_this':
|
||||
|
|
@ -220,26 +153,20 @@ export class mzta_Menus {
|
|||
switch(curr_prompt.id){
|
||||
case 'prompt_add_tags': { // Add tags to the email
|
||||
let tags_current_email = '';
|
||||
let prefs_at = await browser.storage.sync.get({add_tags_maxnum: 3, connection_type: '', add_tags_force_lang: true, default_chatgpt_lang: ''});
|
||||
let prefs_at = await browser.storage.sync.get({add_tags_maxnum: 3, connection_type: '', add_tags_force_lang: true, default_chatgpt_lang: '', do_debug: false});
|
||||
if((prefs_at.connection_type === '')||(prefs_at.connection_type === null)||(prefs_at.connection_type === undefined)||(prefs_at.connection_type === 'chatgpt_web')){
|
||||
console.error("[ThunderAI | AddTags] Invalid connection type: " + prefs_at.connection_type);
|
||||
return {ok:'0'};
|
||||
}
|
||||
let add_tags_maxnum = prefs_at.add_tags_maxnum;
|
||||
if(add_tags_maxnum > 0){
|
||||
fullPrompt += " " + browser.i18n.getMessage("prompt_add_tags_maxnum") + " " + add_tags_maxnum +".";
|
||||
}
|
||||
if(prefs_at.add_tags_force_lang && prefs_at.default_chatgpt_lang !== ''){
|
||||
fullPrompt += " " + browser.i18n.getMessage("prompt_add_tags_force_lang") + " " + prefs_at.default_chatgpt_lang + ".";
|
||||
}
|
||||
fullPrompt = taPromptUtils.finalizePrompt_add_tags(fullPrompt, prefs_at.add_tags_maxnum, prefs_at.add_tags_force_lang, prefs_at.default_chatgpt_lang);
|
||||
this.logger.log("fullPrompt: " + fullPrompt);
|
||||
// TODO: use the current API, abort if using chatgpt web
|
||||
// COMMENTED TO DO TESTS
|
||||
// tags_current_email = "recipients, TEST, home, work, CAR, light";
|
||||
let cmd_addTags = new mzta_specialCommand(fullPrompt,prefs_at.connection_type,true);
|
||||
let cmd_addTags = new mzta_specialCommand(fullPrompt,prefs_at.connection_type,prefs_at.do_debug);
|
||||
await cmd_addTags.initWorker();
|
||||
try{
|
||||
tags_current_email = await cmd_addTags.sendPrompt();
|
||||
tags_current_email = (await cmd_addTags.sendPrompt()).trim();
|
||||
// console.log(">>>>>>>>>>> tags_current_email: " + tags_current_email);
|
||||
}catch(err){
|
||||
console.error("[ThunderAI] Error getting tags: ", err);
|
||||
|
|
@ -289,7 +216,7 @@ export class mzta_Menus {
|
|||
}
|
||||
}catch(err){
|
||||
console.error("[ThunderAI] Error opening calendar event dialog: ", JSON.stringify(err));
|
||||
browser.tabs.sendMessage(tabs[0].id, { command: "sendAlert", curr_tab_type: tabs[0].type, message: browser.i18n.getMessage("calendar_opening_dialog_error") + ": " + "Sparks not installed!" });
|
||||
browser.tabs.sendMessage(tabs[0].id, { command: "sendAlert", curr_tab_type: tabs[0].type, message: browser.i18n.getMessage("calendar_opening_dialog_error") + ": " + browser.i18n.getMessage("sparks_not_installed") });
|
||||
return {ok:'0'};
|
||||
}
|
||||
break; // Get a calendar event info - END
|
||||
|
|
@ -306,15 +233,6 @@ export class mzta_Menus {
|
|||
this.rootMenu.push(curr_menu_entry);
|
||||
};
|
||||
|
||||
async getDefaultSignature(){
|
||||
let prefs = await browser.storage.sync.get({default_sign_name: ''});
|
||||
if(prefs.default_sign_name===''){
|
||||
return '';
|
||||
}else{
|
||||
return browser.i18n.getMessage("sign_msg_as") + " " + prefs.default_sign_name + ".";
|
||||
}
|
||||
}
|
||||
|
||||
loadShortcutMenu() {
|
||||
this.shortcutMenu = [];
|
||||
this.allPrompts.forEach((prompt) => {
|
||||
|
|
|
|||
|
|
@ -131,6 +131,20 @@ const defaultPlaceholders = [
|
|||
type: 0,
|
||||
is_default: "1",
|
||||
},
|
||||
{
|
||||
id: 'thunderai_def_sign',
|
||||
name: "__MSG_placeholder_thunderai_def_sign__",
|
||||
default_value: "",
|
||||
type: 0,
|
||||
is_default: "1",
|
||||
},
|
||||
{
|
||||
id: 'thunderai_def_lang',
|
||||
name: "__MSG_placeholder_thunderai_def_lang__",
|
||||
default_value: "",
|
||||
type: 0,
|
||||
is_default: "1",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
|
|
@ -246,4 +260,66 @@ export const placeholdersUtils = {
|
|||
return regex.test(text);
|
||||
},
|
||||
|
||||
async getPlaceholdersValues(prompt_text, curr_message, mail_subject, body_text, msg_text, only_typed_text, selection_text, tags_full_list) {
|
||||
let currPHs = await placeholdersUtils.extractPlaceholders(prompt_text);
|
||||
// console.log(">>>>>>>>>> currPHs: " + JSON.stringify(currPHs));
|
||||
let finalSubs = {};
|
||||
for(let currPH of currPHs){
|
||||
switch(currPH.id){
|
||||
case 'mail_text_body':
|
||||
finalSubs['mail_text_body'] = body_text;
|
||||
break;
|
||||
case 'mail_html_body':
|
||||
finalSubs['mail_html_body'] = msg_text.html;
|
||||
break;
|
||||
case 'mail_typed_text':
|
||||
finalSubs['mail_typed_text'] = only_typed_text;
|
||||
break;
|
||||
case 'mail_subject':
|
||||
finalSubs['mail_subject'] = mail_subject;
|
||||
break;
|
||||
case 'selected_text':
|
||||
finalSubs['selected_text'] = selection_text;
|
||||
break;
|
||||
case 'author':
|
||||
finalSubs['author'] = curr_message.author;
|
||||
break;
|
||||
case 'recipients':
|
||||
finalSubs['recipients'] = curr_message.recipients.join(", ");
|
||||
break;
|
||||
case 'cc_list':
|
||||
finalSubs['cc_list'] = curr_message.ccList.join(", ");
|
||||
break;
|
||||
case 'junk_score':
|
||||
finalSubs['junk_score'] = curr_message.junkScore;
|
||||
break;
|
||||
case 'mail_datetime':
|
||||
finalSubs['mail_datetime'] = curr_message.date;
|
||||
break;
|
||||
case 'current_datetime':
|
||||
finalSubs['current_datetime'] = new Date().toString();
|
||||
break;
|
||||
case 'tags_current_email':
|
||||
let tags_current_email_array = await transformTagsLabels(curr_message.tags, tags_full_list[1]);
|
||||
finalSubs['tags_current_email'] = tags_current_email_array.join(", ");
|
||||
break;
|
||||
case 'tags_full_list':
|
||||
finalSubs['tags_full_list'] = tags_full_list[0];
|
||||
break;
|
||||
case 'thunderai_def_sign':
|
||||
let prefs_def_sign = await browser.storage.sync.get({default_sign_name: ''});
|
||||
finalSubs['thunderai_def_sign'] = prefs_def_sign.default_sign_name;
|
||||
break;
|
||||
case 'thunderai_def_lang':
|
||||
let prefs_def_lang = await browser.storage.sync.get({default_chatgpt_lang: ''});
|
||||
finalSubs['thunderai_def_lang'] = prefs_def_lang.default_chatgpt_lang;
|
||||
break;
|
||||
default: // TODO Manage custom placeholders https://github.com/micz/ThunderAI/issues/156
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return finalSubs;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -195,6 +195,19 @@ const specialPrompts = [
|
|||
is_default: "1",
|
||||
is_special: "1",
|
||||
},
|
||||
{
|
||||
id: 'prompt_spamfilter',
|
||||
name: "__MSG_prompt_spamfilter__",
|
||||
text: "prompt_spamfilter_full_text",
|
||||
type: "1",
|
||||
action: "0",
|
||||
need_selected: "0",
|
||||
need_signature: "0",
|
||||
need_custom_text: "0",
|
||||
define_response_lang: "0",
|
||||
is_default: "1",
|
||||
is_special: "1",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
|
|
@ -359,4 +372,8 @@ export async function getSpecialPrompts(){
|
|||
export async function setSpecialPrompts(prompts) {
|
||||
// console.log(">>>>>>>>>>>> setSpecialPrompts prompts: " + JSON.stringify(prompts));
|
||||
await browser.storage.local.set({_special_prompts: prompts});
|
||||
}
|
||||
|
||||
export async function getSpamFilterPrompt(){
|
||||
return (await getSpecialPrompts()).find(prompt => prompt.id == 'prompt_spamfilter');
|
||||
}
|
||||
91
js/mzta-spamreport.js
Normal file
91
js/mzta-spamreport.js
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
export const taSpamReport = {
|
||||
|
||||
logger: console,
|
||||
_internal_data_id: 'mzta-spam-report-data',
|
||||
_max_reports: 100,
|
||||
|
||||
async saveReportData(data, data_id){
|
||||
let obj = await browser.storage.session.get(taSpamReport._internal_data_id);
|
||||
//console.log(">>>>>>>> saveReportData obj 1: " + JSON.stringify(obj));
|
||||
if(obj == undefined){
|
||||
obj = {};
|
||||
obj[taSpamReport._internal_data_id] = {};
|
||||
//console.log(">>>>>>>> saveReportData obj 2a: " + JSON.stringify(obj));
|
||||
}
|
||||
if(Object.keys(obj).length === 0){
|
||||
obj[taSpamReport._internal_data_id] = {};
|
||||
//console.log(">>>>>>>> saveReportData obj 2b: " + JSON.stringify(obj));
|
||||
}
|
||||
|
||||
obj[taSpamReport._internal_data_id][data_id] = data;
|
||||
//console.log(">>>>>>>> saveReportData obj 3: " + JSON.stringify(obj));
|
||||
await browser.storage.session.set(obj);
|
||||
},
|
||||
|
||||
async loadReportData(data_id){
|
||||
let output = await browser.storage.session.get(taSpamReport._internal_data_id);
|
||||
return output[taSpamReport._internal_data_id][data_id];
|
||||
},
|
||||
|
||||
async getAllReportData(){
|
||||
let data = await browser.storage.session.get(taSpamReport._internal_data_id);
|
||||
//console.log(">>>>>>>>>>> getAllReportData: " + JSON.stringify(data));
|
||||
return data[taSpamReport._internal_data_id];
|
||||
},
|
||||
|
||||
saveAllData(data){
|
||||
browser.storage.session.set({[taSpamReport._internal_data_id]: data});
|
||||
},
|
||||
|
||||
clearReportData(){
|
||||
browser.storage.session.clear();
|
||||
},
|
||||
|
||||
async truncReportData(){
|
||||
let data = taSpamReport.sortReportsByDate(await taSpamReport.getAllReportData());
|
||||
if(data == undefined) return;
|
||||
//console.log(">>>>>>>>>> truncReportData: " + JSON.stringify(data));
|
||||
if(Object.keys(data).length > taSpamReport._max_reports){
|
||||
let keys = Object.keys(data);
|
||||
for(let i = taSpamReport._max_reports; i < keys.length; i++){
|
||||
// console.log(">>>>>>>>>> truncReportData: " + keys[i]);
|
||||
// console.log(">>>>>>>>>> truncReportData i: " + i);
|
||||
delete data[keys[i]];
|
||||
}
|
||||
}
|
||||
taSpamReport.saveAllData(data);
|
||||
},
|
||||
|
||||
sortReportsByDate(data) {
|
||||
if(data == undefined) return undefined;
|
||||
const reportKeys = Object.keys(data);
|
||||
reportKeys.sort((a, b) => {
|
||||
const dateA = new Date(data[a].report_date);
|
||||
const dateB = new Date(data[b].report_date);
|
||||
return dateB - dateA;
|
||||
});
|
||||
const sortedReports = {};
|
||||
reportKeys.forEach((key) => {
|
||||
sortedReports[key] = data[key];
|
||||
});
|
||||
return sortedReports;
|
||||
}
|
||||
}
|
||||
74
js/mzta-utils-prompt.js
Normal file
74
js/mzta-utils-prompt.js
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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 { placeholdersUtils } from './mzta-placeholders.js';
|
||||
|
||||
export const taPromptUtils = {
|
||||
|
||||
async getDefaultSignature(){
|
||||
let prefs = await browser.storage.sync.get({default_sign_name: ''});
|
||||
if(prefs.default_sign_name===''){
|
||||
return '';
|
||||
}else{
|
||||
return browser.i18n.getMessage("sign_msg_as") + " " + prefs.default_sign_name + ".";
|
||||
}
|
||||
},
|
||||
|
||||
async preparePrompt(curr_prompt, curr_message, chatgpt_lang, selection_text, body_text, subject_text, msg_text, only_typed_text, tags_full_list){
|
||||
let fullPrompt = '';
|
||||
|
||||
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) + "\" ";
|
||||
}else{
|
||||
// we have at least a placeholder, do the magic!
|
||||
let finalSubs = await placeholdersUtils.getPlaceholdersValues(curr_prompt.text, curr_message, subject_text, body_text, msg_text, only_typed_text, selection_text, tags_full_list);
|
||||
// console.log(">>>>>>>>>> finalSubs: " + JSON.stringify(finalSubs));
|
||||
let prefs_ph = await browser.storage.sync.get({placeholders_use_default_value: false});
|
||||
fullPrompt = (placeholdersUtils.replacePlaceholders(curr_prompt.text, finalSubs, prefs_ph.placeholders_use_default_value, true) + (String(curr_prompt.need_signature) == "1" ? " " + await taPromptUtils.getDefaultSignature():"") + " " + chatgpt_lang).trim();
|
||||
}
|
||||
|
||||
return fullPrompt;
|
||||
},
|
||||
|
||||
finalizePrompt_add_tags(fullPrompt, add_tags_maxnum, add_tags_force_lang, default_chatgpt_lang){
|
||||
if(add_tags_maxnum > 0){
|
||||
fullPrompt += " " + browser.i18n.getMessage("prompt_add_tags_maxnum") + " " + add_tags_maxnum +".";
|
||||
}
|
||||
if(add_tags_force_lang && default_chatgpt_lang !== ''){
|
||||
fullPrompt += " " + browser.i18n.getMessage("prompt_add_tags_force_lang") + " " + default_chatgpt_lang + ".";
|
||||
}
|
||||
|
||||
return fullPrompt;
|
||||
},
|
||||
|
||||
async getDefaultLang(curr_prompt){
|
||||
let chatgpt_lang = '';
|
||||
if(String(curr_prompt.define_response_lang) == "1"){
|
||||
let prefs = await browser.storage.sync.get({default_chatgpt_lang: ''});
|
||||
chatgpt_lang = prefs.default_chatgpt_lang;
|
||||
if(chatgpt_lang === ''){
|
||||
chatgpt_lang = browser.i18n.getMessage("reply_same_lang");
|
||||
}else{
|
||||
chatgpt_lang = browser.i18n.getMessage("prompt_lang") + " " + chatgpt_lang + ".";
|
||||
}
|
||||
}
|
||||
|
||||
return chatgpt_lang;
|
||||
},
|
||||
};
|
||||
|
|
@ -83,6 +83,29 @@ export async function getMailSubject(tab){
|
|||
}
|
||||
}
|
||||
|
||||
export async function getMailBody(fullMessage){
|
||||
let text = '';
|
||||
let html = '';
|
||||
|
||||
if (fullMessage.contentType.trim().toLowerCase() === "text/plain") {
|
||||
text = fullMessage.body;
|
||||
}
|
||||
if (fullMessage.contentType.trim().toLowerCase() === "text/html") {
|
||||
html = fullMessage.body;
|
||||
}
|
||||
|
||||
for (let part of fullMessage.parts) {
|
||||
if (part.contentType.trim().toLowerCase() === "text/plain") {
|
||||
text = part.body;
|
||||
}
|
||||
if (part.contentType.trim().toLowerCase() === "text/html") {
|
||||
html = part.body;
|
||||
}
|
||||
}
|
||||
|
||||
return {text, html};
|
||||
}
|
||||
|
||||
export async function reloadBody(tabId){
|
||||
let composeDetails = await messenger.compose.getComposeDetails(tabId);
|
||||
let originalHtmlBody = composeDetails.body + " ";
|
||||
|
|
@ -282,6 +305,23 @@ export function getActiveSpecialPromptsIDs(addtags = false, get_calendar_event =
|
|||
return output;
|
||||
}
|
||||
|
||||
export function extractJsonObject(inputString) {
|
||||
try {
|
||||
const jsonMatch = inputString.match(/\{[\s\S]*\}/);
|
||||
if (jsonMatch) {
|
||||
const jsonObject = JSON.parse(jsonMatch[0]);
|
||||
// console.log(">>>>>>>>>> Extracted JSON object:", jsonObject);
|
||||
return jsonObject;
|
||||
} else {
|
||||
console.error("[ThunderAI] No JSON object found in the input string.");
|
||||
return null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[ThunderAI] Error extracting JSON object:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkSparksPresence() {
|
||||
try {
|
||||
return (await browser.runtime.sendMessage('thunderai-sparks@micz.it',{action: "checkPresence"}) === 'ok');
|
||||
|
|
@ -406,3 +446,17 @@ export async function migrateDefaultPromptsPropStorage(){
|
|||
await browser.storage.sync.remove("_default_prompts_properties");
|
||||
// console.log("migrateDefaultPromptsPropStorage: migrated default prompts properties from storage.sync to storage.local");
|
||||
}
|
||||
|
||||
export async function* getMessages(list) {
|
||||
let page = await list;
|
||||
for (let message of page.messages) {
|
||||
yield message;
|
||||
}
|
||||
|
||||
while (page.id) {
|
||||
page = await messenger.messages.continueList(page.id);
|
||||
for (let message of page.messages) {
|
||||
yield message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
"manifest_version": 2,
|
||||
"name": "ThunderAI",
|
||||
"description": "__MSG_extensionDescription__",
|
||||
"version": "3.1.3",
|
||||
"version": "3.2.0",
|
||||
"author": "Mic (m@micz.it)",
|
||||
"homepage_url": "https://micz.it/thunderbird-addon-thunderai/",
|
||||
"browser_specific_settings": {
|
||||
|
|
@ -31,10 +31,13 @@
|
|||
"activeTab",
|
||||
"accountsRead",
|
||||
"downloads",
|
||||
"https://*.chatgpt.com/*"
|
||||
],
|
||||
"optional_permissions": [
|
||||
"messagesTagsList",
|
||||
"messagesTags",
|
||||
"messagesUpdate",
|
||||
"https://*.chatgpt.com/*"
|
||||
"messagesMove"
|
||||
],
|
||||
"background": {
|
||||
"page": "mzta-background.html"
|
||||
|
|
|
|||
|
|
@ -20,7 +20,13 @@ import { mzta_script } from './js/mzta-chatgpt.js';
|
|||
import { prefs_default } from './options/mzta-options-default.js';
|
||||
import { mzta_Menus } from './js/mzta-menus.js';
|
||||
import { taLogger } from './js/mzta-logger.js';
|
||||
import { getCurrentIdentity, getOriginalBody, replaceBody, setBody, i18nConditionalGet, generateCallID, migrateCustomPromptsStorage, migrateDefaultPromptsPropStorage, getGPTWebModelString, getTagsList, createTag, assignTagsToMessage, checkIfTagExists, getActiveSpecialPromptsIDs, checkSparksPresence } from './js/mzta-utils.js';
|
||||
import { getCurrentIdentity, getOriginalBody, replaceBody, setBody, i18nConditionalGet, generateCallID, migrateCustomPromptsStorage, migrateDefaultPromptsPropStorage, getGPTWebModelString, getTagsList, createTag, assignTagsToMessage, checkIfTagExists, getActiveSpecialPromptsIDs, checkSparksPresence, getMessages, getMailBody, extractJsonObject } 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 { taSpamReport } from './js/mzta-spamreport.js';
|
||||
|
||||
browser.permissions.remove({ permissions: ["messagesMove", "messagesTagsList", "messagesTags", "messagesUpdate"]}).then(console.log);
|
||||
|
||||
await migrateCustomPromptsStorage();
|
||||
await migrateDefaultPromptsPropStorage();
|
||||
|
|
@ -28,7 +34,9 @@ await migrateDefaultPromptsPropStorage();
|
|||
var original_html = '';
|
||||
var modified_html = '';
|
||||
|
||||
let prefs_init = await browser.storage.sync.get({do_debug: false, add_tags: true, get_calendar_event: true, connection_type: 'chatgpt_web'});
|
||||
let prefs_init = {};
|
||||
await reload_pref_init();
|
||||
|
||||
let taLog = new taLogger("mzta-background",prefs_init.do_debug);
|
||||
|
||||
let special_prompts_ids = getActiveSpecialPromptsIDs(prefs_init.add_tags, await doGetCalendarEvent(prefs_init.get_calendar_event), (prefs_init.connection_type === "chatgpt_web"));
|
||||
|
|
@ -134,6 +142,24 @@ async function _reload_menus() {
|
|||
return true;
|
||||
}
|
||||
|
||||
async function _assign_tags(_data, create_new_tags = true) {
|
||||
let all_tags_list = await getTagsList();
|
||||
all_tags_list = all_tags_list[1];
|
||||
// console.log(">>>>>>>>>>>>>>> all_tags_list: " + JSON.stringify(all_tags_list));
|
||||
taLog.log("assign_tags data: " + JSON.stringify(_data));
|
||||
let new_tags = [];
|
||||
for (const tag of _data.tags) {
|
||||
// console.log(">>>>>>>>>>>>>>> tag: " + tag);
|
||||
if (create_new_tags && !checkIfTagExists(tag, all_tags_list)) {
|
||||
taLog.log("Creating tag: " + tag);
|
||||
await createTag(tag);
|
||||
}
|
||||
new_tags.push(tag);
|
||||
}
|
||||
await assignTagsToMessage(_data.messageId, new_tags);
|
||||
taLog.log("Assigned tags: " + JSON.stringify(new_tags));
|
||||
}
|
||||
|
||||
messenger.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
// Check what type of message we have received and invoke the appropriate
|
||||
// handler function.
|
||||
|
|
@ -240,24 +266,7 @@ messenger.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|||
return _popup_menu_ready();
|
||||
break;
|
||||
case 'assign_tags':
|
||||
async function _assign_tags() {
|
||||
let all_tags_list = await getTagsList();
|
||||
all_tags_list = all_tags_list[1];
|
||||
// console.log(">>>>>>>>>>>>>>> all_tags_list: " + JSON.stringify(all_tags_list));
|
||||
taLog.log("assign_tags data: " + JSON.stringify(message));
|
||||
let new_tags = [];
|
||||
for (const tag of message.tags) {
|
||||
// console.log(">>>>>>>>>>>>>>> tag: " + tag);
|
||||
if (!checkIfTagExists(tag, all_tags_list)) {
|
||||
taLog.log("Creating tag: " + tag);
|
||||
await createTag(tag);
|
||||
}
|
||||
new_tags.push(tag);
|
||||
}
|
||||
await assignTagsToMessage(message.messageId, new_tags);
|
||||
taLog.log("Assigned tags: " + JSON.stringify(new_tags));
|
||||
}
|
||||
return _assign_tags();
|
||||
return _assign_tags(message);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -596,7 +605,7 @@ async function doGetCalendarEvent(get_calendar_event) {
|
|||
}
|
||||
|
||||
async function reload_pref_init(){
|
||||
prefs_init = await browser.storage.sync.get({do_debug: false, add_tags: true, get_calendar_event: true, connection_type: 'chatgpt_web'});
|
||||
prefs_init = await browser.storage.sync.get({do_debug: false, add_tags: true, get_calendar_event: true, connection_type: 'chatgpt_web', add_tags_auto: false, add_tags_auto_force_existing: false, add_tags_auto_only_inbox: true, spamfilter: false, spamfilter_threshold: 70, dynamic_menu_force_enter: false});
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -639,7 +648,154 @@ function setupStorageChangeListener() {
|
|||
// Call the function to set up the listener
|
||||
setupStorageChangeListener();
|
||||
|
||||
|
||||
// Menus handling
|
||||
const menus = new mzta_Menus(openChatGPT, prefs_init.do_debug);
|
||||
menus.loadMenus(special_prompts_ids);
|
||||
menus.loadMenus(special_prompts_ids);
|
||||
|
||||
|
||||
// Listening for new received emails
|
||||
const newEmailListener = (folder, messagesList) => {
|
||||
taLog.log("New mail received");
|
||||
taLog.log(`Folder: ${folder.name}`);
|
||||
|
||||
async function _newEmailListener(){
|
||||
let messages = getMessages(messagesList);
|
||||
|
||||
taSpamReport.logger = taLog;
|
||||
|
||||
for await (let message of messages) {
|
||||
// let fullMessage = await browser.messages.getFull(message.id);
|
||||
// taLog.log(`From: ${fullMessage.headers.from}`);
|
||||
// taLog.log(`Subject: ${fullMessage.headers.subject}`);
|
||||
// taLog.log(`Name: ${fullMessage.name}`);
|
||||
// taLog.log(`Body: ${fullMessage.body}`);
|
||||
// taLog.log(`contentType: [${fullMessage.contentType}]`);
|
||||
// taLog.log(`fullMessage.parts.length: ${fullMessage.parts.length}`);
|
||||
|
||||
// if (fullMessage.parts.length > 0) {
|
||||
// for (let part of fullMessage.parts) {
|
||||
// taLog.log(`From: ${part.headers.from}`);
|
||||
// taLog.log(`Subject: ${part.headers.subject}`);
|
||||
// taLog.log(`Name: ${part.name}`);
|
||||
// taLog.log(`Body: ${part.body}`);
|
||||
// taLog.log(`contentType: [${part.contentType}]`);
|
||||
// taLog.log('contentType JSON: '+JSON.stringify(part.contentType));
|
||||
// if (part.contentType.trim().toLowerCase() === "text/plain") {
|
||||
// taLog.log("Body (text/plain):" + part.body);
|
||||
// // return part.body;
|
||||
// }
|
||||
// if (part.contentType.trim().toLowerCase() === "text/html") {
|
||||
// taLog.log("Body (text/html):" + part.body);
|
||||
// // return part.body;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
let curr_fullMessage = null;
|
||||
let msg_text = null;
|
||||
let body_text = '';
|
||||
|
||||
// if some auto feature is active prepare some data
|
||||
// this will be used when will be implemented also the auto translator https://github.com/micz/ThunderAI/issues/247
|
||||
if(prefs_init.add_tags_auto || prefs_init.spamfilter){
|
||||
curr_fullMessage = await browser.messages.getFull(message.id);
|
||||
msg_text = await getMailBody(curr_fullMessage);
|
||||
body_text = msg_text.text.replace(/\s+/g, ' ').trim();
|
||||
}
|
||||
|
||||
// Auto add_tags
|
||||
if(prefs_init.add_tags_auto){
|
||||
let specialFullPrompt_add_tags = '';
|
||||
let curr_prompt_add_tags = menus.allPrompts.find(p => p.id === 'prompt_add_tags');
|
||||
let tags_full_list = await getTagsList();
|
||||
let chatgpt_lang = await taPromptUtils.getDefaultLang(curr_prompt_add_tags);
|
||||
specialFullPrompt_add_tags = await taPromptUtils.preparePrompt(curr_prompt_add_tags, message, chatgpt_lang, /*selection_text*/ '', body_text, curr_fullMessage.headers.subject, msg_text, /*only_typed_text*/ '', tags_full_list);
|
||||
let prefs_aat = await browser.storage.sync.get({add_tags_maxnum: 3, connection_type: '', add_tags_force_lang: true, default_chatgpt_lang: '', add_tags_auto_force_existing: false});
|
||||
specialFullPrompt_add_tags = taPromptUtils.finalizePrompt_add_tags(specialFullPrompt_add_tags, prefs_aat.add_tags_maxnum, prefs_aat.add_tags_force_lang, prefs_aat.default_chatgpt_lang);
|
||||
taLog.log("Special prompt: " + specialFullPrompt_add_tags);
|
||||
let cmd_addTags = new mzta_specialCommand(specialFullPrompt_add_tags,prefs_aat.connection_type,prefs_init.do_debug);
|
||||
await cmd_addTags.initWorker();
|
||||
let tags_current_email = '';
|
||||
try{
|
||||
tags_current_email = (await cmd_addTags.sendPrompt()).trim();
|
||||
}catch(err){
|
||||
console.error("[ThunderAI | Auto add_tags] Error getting tags: ", err);
|
||||
}
|
||||
taLog.log("tags_current_email: " + tags_current_email);
|
||||
let _data = {messageId: message.id, tags: tags_current_email.split(/,\s*/)};
|
||||
_assign_tags(_data, !prefs_aat.add_tags_auto_force_existing);
|
||||
}
|
||||
|
||||
|
||||
// Spam filter
|
||||
if(prefs_init.spamfilter){
|
||||
let curr_prompt_spamfilter = await getSpamFilterPrompt();
|
||||
//console.log(">>>>>>>>>>>> curr_prompt_spamfilter: " + JSON.stringify(curr_prompt_spamfilter));
|
||||
let chatgpt_lang = await taPromptUtils.getDefaultLang(curr_prompt_spamfilter);
|
||||
let specialFullPrompt_spamfilter = await taPromptUtils.preparePrompt(curr_prompt_spamfilter, message, chatgpt_lang, /*selection_text*/ '', body_text, curr_fullMessage.headers.subject, msg_text, /*only_typed_text*/ '', '');
|
||||
taLog.log("Special prompt: " + specialFullPrompt_spamfilter);
|
||||
let cmd_spamfilter = new mzta_specialCommand(specialFullPrompt_spamfilter,prefs_init.connection_type,prefs_init.do_debug);
|
||||
await cmd_spamfilter.initWorker();
|
||||
/* We expect to receive from the AI a JSON object like this:
|
||||
* {
|
||||
* "spamValue": <integer from 0 to 100>,
|
||||
* "explanation": "Brief explanation of your reasoning",
|
||||
* }
|
||||
*/
|
||||
let spamfilter_result = '';
|
||||
taLog.log("Sending the prompt...");
|
||||
try{
|
||||
spamfilter_result = (await cmd_spamfilter.sendPrompt()).trim();
|
||||
}catch(err){
|
||||
console.error("[ThunderAI | SpamFilter] Error getting spamfilter: ", err);
|
||||
}
|
||||
taLog.log("spamfilter_result: " + spamfilter_result);
|
||||
let jsonObj = {};
|
||||
taLog.log("Decoding the AI response...");
|
||||
try{
|
||||
jsonObj = extractJsonObject(spamfilter_result);
|
||||
}catch(e){
|
||||
console.error("[ThunderAI | SpamFilter] Error extracting JSON from AI response: ", e);
|
||||
}
|
||||
taLog.log("SpamFilter jsonObj: " + JSON.stringify(jsonObj));
|
||||
|
||||
let report_data = {};
|
||||
report_data.report_date = new Date();
|
||||
report_data.headerMessageId = message.headerMessageId;
|
||||
report_data.spamValue = jsonObj.spamValue;
|
||||
report_data.explanation = jsonObj.explanation;
|
||||
report_data.subject = curr_fullMessage.headers.subject;
|
||||
report_data.from = curr_fullMessage.headers.from;
|
||||
report_data.message_date = new Date(message.date);
|
||||
report_data.moved = false;
|
||||
report_data.SpamThreshold = prefs_init.spamfilter_threshold;
|
||||
//console.log(">>>>>>>>>>>> report_data.SpamThreshold: " + JSON.stringify(report_data.SpamThreshold));
|
||||
|
||||
//TODO move email if it's spam
|
||||
if(jsonObj.spamValue >= prefs_init.spamfilter_threshold){
|
||||
taLog.log("Marking as spam ["+message.headerMessageId+"]");
|
||||
// mark as spam
|
||||
messenger.messages.update(message.id, { junk: true });
|
||||
//get the spam folder
|
||||
let spamFolder = await messenger.folders.query({accountId: message.folder.accountId, specialUse: ['junk']})
|
||||
//console.log(">>>>>>>>>>>> spamFolder: " + JSON.stringify(spamFolder));
|
||||
//move the message
|
||||
messenger.messages.move([message.id], spamFolder[0].id);
|
||||
report_data.moved = true;
|
||||
taLog.log("Marked as spam ["+message.headerMessageId+"]");
|
||||
}
|
||||
|
||||
// Save the operation log
|
||||
taSpamReport.saveReportData(report_data,message.headerMessageId);
|
||||
}
|
||||
}
|
||||
|
||||
if(prefs_init.spamfilter){
|
||||
taSpamReport.truncReportData();
|
||||
}
|
||||
}
|
||||
|
||||
return _newEmailListener();
|
||||
}
|
||||
|
||||
browser.messages.onNewMailReceived.addListener(newEmailListener, !prefs_init.add_tags_auto_only_inbox);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ export const prefs_default = {
|
|||
chatgpt_win_height: 800,
|
||||
chatgpt_win_width: 700,
|
||||
default_chatgpt_lang: '',
|
||||
default_sign_name: '',
|
||||
connection_type: 'chatgpt_web', //Other values: 'chatgpt_api', 'ollama_api', 'openai_comp_api', 'google_gemini_api'
|
||||
chatgpt_web_model: '',
|
||||
chatgpt_web_tempchat: false,
|
||||
|
|
@ -41,10 +42,15 @@ export const prefs_default = {
|
|||
dynamic_menu_order_alphabet: true,
|
||||
placeholders_use_default_value: false,
|
||||
max_prompt_length: 30000, // max string length for prompt
|
||||
add_tags: true,
|
||||
add_tags: false,
|
||||
add_tags_maxnum: 3,
|
||||
add_tags_hide_exclusions: false,
|
||||
add_tags_first_uppercase: true,
|
||||
add_tags_force_lang: true,
|
||||
add_tags_auto: false,
|
||||
add_tags_auto_force_existing: false,
|
||||
add_tags_auto_only_inbox: true,
|
||||
get_calendar_event: true,
|
||||
spamfilter: false,
|
||||
spamfilter_threshold: 70,
|
||||
}
|
||||
|
|
@ -88,6 +88,10 @@ div#miczTranslate{
|
|||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.small_info{
|
||||
font-size:smaller;
|
||||
}
|
||||
|
||||
tr.conntype_chatgpt_api, tr.conntype_chatgpt_api2{
|
||||
background-color: rgb(185, 220, 252);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@
|
|||
<tr class="conntype_chatgpt_web">
|
||||
<td><label>
|
||||
<span>__MSG_prefs_OptionText_chatgpt_web_model__</span>
|
||||
<br><table title="__MSG_prefs_OptionText_chatgpt_web_model_tooltip__"><tr><td><i style="font-size:smaller;"><nobr>__MSG_AllowedValues__:</nobr></i></td><td><i style="font-size:smaller;"> <nobr class="conntype_chatgpt_web_option">gpt-4o</nobr> <nobr class="conntype_chatgpt_web_option">gpt-4o-mini</nobr> <nobr class="conntype_chatgpt_web_option">gpt-4</nobr> <nobr class="conntype_chatgpt_web_option">o1</nobr> <nobr class="conntype_chatgpt_web_option">o3-mini</nobr> <nobr class="conntype_chatgpt_web_option">o3-mini-high</nobr></i></td></tr></table>
|
||||
<br><table title="__MSG_prefs_OptionText_chatgpt_web_model_tooltip__"><tr><td><i class="small_info"><nobr>__MSG_AllowedValues__:</nobr></i></td><td><i class="small_info"> <nobr class="conntype_chatgpt_web_option">gpt-4o</nobr> <nobr class="conntype_chatgpt_web_option">gpt-4o-mini</nobr> <nobr class="conntype_chatgpt_web_option">gpt-4</nobr> <nobr class="conntype_chatgpt_web_option">o1</nobr> <nobr class="conntype_chatgpt_web_option">o3-mini</nobr> <nobr class="conntype_chatgpt_web_option">o3-mini-high</nobr></i></td></tr></table>
|
||||
</label></td>
|
||||
<td>
|
||||
<label>
|
||||
|
|
@ -231,7 +231,7 @@
|
|||
<tr class="conntype_ollama_api">
|
||||
<td><label>
|
||||
<span>__MSG_prefs_API_Host__</span>
|
||||
<br><i style="font-size:smaller;">__MSG_prefs_API_Host_Info__ http://127.0.0.1:11434</i>
|
||||
<br><i class="small_info">__MSG_prefs_API_Host_Info__ http://127.0.0.1:11434</i>
|
||||
</label></td>
|
||||
<td>
|
||||
<label>
|
||||
|
|
@ -256,11 +256,12 @@
|
|||
<tr class="conntype_openai_comp_api">
|
||||
<td><label>
|
||||
<span>__MSG_prefs_API_Host__</span>
|
||||
<br><i style="font-size:smaller;">__MSG_prefs_API_Host_Info__ http://localhost:1234</i>
|
||||
<br><i class="small_info">__MSG_prefs_API_Host_Info__ http://localhost:1234</i>
|
||||
</label></td>
|
||||
<td>
|
||||
<label>
|
||||
<input type="text" id="openai_comp_host" name="openai_comp_host" class="option-input" />
|
||||
<br><i class="small_info">__MSG_prefs_OptionText_openai_comp_info_remote__</i>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
@ -278,7 +279,7 @@
|
|||
<tr class="conntype_openai_comp_api">
|
||||
<td><label>
|
||||
<span>__MSG_prefs_OpenAIComp_API_Key__</span>
|
||||
<br><i style="font-size:smaller;">__MSG_Optional__</i>
|
||||
<br><i class="small_info">__MSG_Optional__</i>
|
||||
</label></td>
|
||||
<td>
|
||||
<div class="api_key-container">
|
||||
|
|
@ -334,6 +335,16 @@
|
|||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="spamfilter_tr">
|
||||
<td><span>__MSG_prefs_OptionText_spamfilter__</span>
|
||||
<br><button id="btnManageSpamFilterInfo" class="btn_small">__MSG_prefs_OptionText_btnManageSpamFilterInfo__</button></td>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" id="spamfilter" name="spamfilter" class="option-input" />
|
||||
__MSG_prefs_OptionText_spamfilter_Info__
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="get_calendar_event_tr">
|
||||
<td><span>__MSG_prefs_OptionText_get_calendar_event__</span>
|
||||
<br><button id="btnManageCalendarEventInfo" class="btn_small">__MSG_prefs_OptionText_btnManageCalendarEventInfo__</button></td>
|
||||
|
|
|
|||
|
|
@ -300,10 +300,37 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
let addtags_el = document.getElementById('add_tags');
|
||||
let addtags_info_btn = document.getElementById('btnManageTagsInfo');
|
||||
addtags_el.addEventListener('click', (event) => {
|
||||
async function _addtags_el_change() {
|
||||
if (event.target.checked) {
|
||||
const granted = await messenger.permissions.request({ permissions: ["messagesTagsList", "messagesTags", "messagesUpdate"] });
|
||||
if (!granted) {
|
||||
event.target.checked = false;
|
||||
addtags_info_btn.disabled = 'disabled';
|
||||
}
|
||||
}
|
||||
}
|
||||
_addtags_el_change();
|
||||
addtags_info_btn.disabled = event.target.checked ? '' : 'disabled';
|
||||
});
|
||||
addtags_info_btn.disabled = addtags_el.checked ? '' : 'disabled';
|
||||
|
||||
let spamfilter_el = document.getElementById('spamfilter');
|
||||
let spamfilter_info_btn = document.getElementById('btnManageSpamFilterInfo');
|
||||
spamfilter_el.addEventListener('click', (event) => {
|
||||
async function _spamfilter_el_change() {
|
||||
if (event.target.checked) {
|
||||
const granted = await messenger.permissions.request({ permissions: ["messagesMove"] });
|
||||
if (!granted) {
|
||||
event.target.checked = false;
|
||||
spamfilter_info_btn.disabled = 'disabled';
|
||||
}
|
||||
}
|
||||
}
|
||||
_spamfilter_el_change();
|
||||
spamfilter_info_btn.disabled = event.target.checked ? '' : 'disabled';
|
||||
});
|
||||
spamfilter_info_btn.disabled = spamfilter_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) => {
|
||||
|
|
@ -337,6 +364,19 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
})
|
||||
});
|
||||
|
||||
document.getElementById('btnManageSpamFilterInfo').addEventListener('click', () => {
|
||||
// check if the tab is already there
|
||||
browser.tabs.query({url: browser.runtime.getURL('../pages/spamfilter/mzta-spamfilter.html')}).then((tabs) => {
|
||||
if (tabs.length > 0) {
|
||||
// if the tab is already there, focus it
|
||||
browser.tabs.update(tabs[0].id, {active: true});
|
||||
} else {
|
||||
// if the tab is not there, create it
|
||||
browser.tabs.create({url: browser.runtime.getURL('../pages/spamfilter/mzta-spamfilter.html')});
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
document.getElementById('btnManageCalendarEventInfo').addEventListener('click', () => {
|
||||
// check if the tab is already there
|
||||
browser.tabs.query({url: browser.runtime.getURL('../pages/get-calendar-event/mzta-get-calendar-event.html')}).then((tabs) => {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,18 @@
|
|||
<body>
|
||||
<div id="miczBackPrefs"><a href="mzta-options.html">__MSG_backToOptionsText__</a></div>
|
||||
<div id="miczRelNotes"><h1>ThunderAI Release Notes</h1>
|
||||
<h2>Version 3.2.0 - 27/02/2025</h2>
|
||||
<ul>
|
||||
<li><i>[All APIs]</i> Added an option to automatically tag incoming emails [<a href="https://github.com/micz/ThunderAI/issues/237">#237</a>].</li>
|
||||
<li><i>[All APIs]</i> Added an configurable antispam filter for incoming emails [<a href="https://github.com/micz/ThunderAI/issues/231">#231</a>].</li>
|
||||
<li>Tags related permissions are now optional and asked for only when the user activates the tags feature [<a href="https://github.com/micz/ThunderAI/issues/259">#259</a>].</li>
|
||||
<li>Added the <i>{%thunderai_def_sign%}</i> placeholder to get the default signature as defined in the options [<a href="https://github.com/micz/ThunderAI/issues/248">#248</a>].</li>
|
||||
<li>Added the <i>{%thunderai_def_lang%}</i> placeholder to get the default language as defined in the options [<a href="https://github.com/micz/ThunderAI/issues/248">#248</a>].</li>
|
||||
<li>Croatian (hr) translation added, thanks to Petar Jedvaj.</li>
|
||||
<li>German (de) translation errors fixed.</li>
|
||||
<li>Translations improved thanks to Hosted Weblate. <a href="https://micz.it/thunderbird-addon-thunderai/translate/">Help translating ThunderAI!</a>.</li>
|
||||
<li>Various minor improvements.</li>
|
||||
</ul>
|
||||
<h2>Version 3.1.3 - 02/02/2025</h2>
|
||||
<ul>
|
||||
<li><i>[ChatGPT Web]</i> Correctly hiding the "Download Sparks" message when using [<a href="https://github.com/micz/ThunderAI/issues/245">#245</a>].</li>
|
||||
|
|
@ -24,7 +36,7 @@
|
|||
</ul>
|
||||
<h2>Version 3.1.0 - 27/01/2025</h2>
|
||||
<ul>
|
||||
<li><i>[ChatGPT API][Ollama API][OpenAI Comp API][Gemini API]</i> Added a special prompt to get calendar events data from emails [<a href="https://github.com/micz/ThunderAI/issues/182">#182</a>]. To use this feature, you must install also the <a href="https://addons.thunderbird.net/it/thunderbird/addon/thunderai-sparks/">Sparks</a> add-on.</li>
|
||||
<li><i>[All APIs]</i> Added a special prompt to get calendar events data from emails [<a href="https://github.com/micz/ThunderAI/issues/182">#182</a>]. To use this feature, you must install also the <a href="https://addons.thunderbird.net/it/thunderbird/addon/thunderai-sparks/">Sparks</a> add-on.</li>
|
||||
<li>Added Google Gemini API support [<a href="https://github.com/micz/ThunderAI/issues/204">#204</a>, <a href="https://github.com/micz/ThunderAI/issues/217">#217</a>].</li>
|
||||
<li>Added the <i>{%mail_typed_text%}</i> placeholder to get the text inserted before the quoted mail body when replying [<a href="https://github.com/micz/ThunderAI/issues/196">#196</a>].</li>
|
||||
<li>Using the <i>{%mail_typed_text%}</i> placeholder the typed text inserted before the quoted mail body will be selected automatically to be replaced afterwards with the AI response [<a href="https://github.com/micz/ThunderAI/issues/229">#229</a>].</li>
|
||||
|
|
@ -34,7 +46,7 @@
|
|||
</ul>
|
||||
<h2>Version 3.0.0 - 05/01/2025</h2>
|
||||
<ul>
|
||||
<li><i>[ChatGPT API][Ollama API][OpenAI Comp API]</i> Added a special prompt to apply tags to emails [<a href="https://github.com/micz/ThunderAI/issues/183">#183</a>].</li>
|
||||
<li><i>[All APIs]</i> Added a special prompt to apply tags to emails [<a href="https://github.com/micz/ThunderAI/issues/183">#183</a>].</li>
|
||||
<li>Default prompts text has been translated [<a href="https://github.com/micz/ThunderAI/issues/185">#185</a>].</li>
|
||||
<li>Added the <i>{%tags_full_list%}</i> placeholder for the full available tags list added [<a href="https://github.com/micz/ThunderAI/issues/197">#197</a>].</li>
|
||||
<li>Added the <i>{%tags_current_email%}</i> placeholder for the single mail tags list added [<a href="https://github.com/micz/ThunderAI/issues/198">#198</a>].</li>
|
||||
|
|
@ -102,7 +114,7 @@
|
|||
<li>Fixed a bug that occurred when importing prompts after an export without closing the Custom Prompts page.</li>
|
||||
<li>Brazilian Portuguese (pt-br) translation added, thanks to Bruno Pereira de Souza.</li>
|
||||
<li><i>[Ollama API]</i> Added a link to the <a href="https://micz.it/thunderbird-addon-thunderai/ollama-cors-information/">CORS information page</a>.</li>
|
||||
<li><i>[ChatGPT API][Ollama API][OpenAI Comp API]</i> Improved handling of streaming responses even in case of broken chunks [<a href="https://github.com/micz/ThunderAI/issues/147">#147</a>].</li>
|
||||
<li><i>[All APIs]</i> Improved handling of streaming responses even in case of broken chunks [<a href="https://github.com/micz/ThunderAI/issues/147">#147</a>].</li>
|
||||
<li>Fixed a race condition that occurred when opening the chat window under certain circumstances. Thanks to <a href="https://github.com/jobisoft" target="_blank">@jobisoft</a> for helping refine the code, and to <a href="https://github.com/Mikilio" target="_blank">@Mikilio</a> and <a href="https://github.com/mattcaron" target="_blank">@mattcaron</a> for the extensive testing [<a href="https://github.com/micz/ThunderAI/issues/143">#143</a>].</li>
|
||||
</ul>
|
||||
<h2>Version 2.1.5 - 23/09/2024</h2>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#addtags_info_additional_statements{
|
||||
#addtags_info_additional_statements, #add_tags_auto_force_existing_tr, #add_tags_auto_only_inbox_tr{
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,33 @@
|
|||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="add_tags_tr">
|
||||
<td><span>__MSG_prefs_OptionText_add_tags_auto__</span></td>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" id="add_tags_auto" name="add_tags_auto" class="option-input" />
|
||||
__MSG_prefs_OptionText_add_tags_auto_Info__
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="add_tags_tr" id="add_tags_auto_force_existing_tr">
|
||||
<td><span>__MSG_prefs_OptionText_add_tags_auto_force_existing__</span></td>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" id="add_tags_auto_force_existing" name="add_tags_auto_force_existing" class="option-input" />
|
||||
__MSG_prefs_OptionText_add_tags_auto_force_existing_Info__
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="add_tags_tr" id="add_tags_auto_only_inbox_tr">
|
||||
<td><span>__MSG_prefs_OptionText_add_tags_auto_only_inbox__</span></td>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" id="add_tags_auto_only_inbox" name="add_tags_auto_only_inbox" class="option-input" />
|
||||
__MSG_prefs_OptionText_add_tags_auto_only_inbox_Info__
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div id="addtags_prompt_container">
|
||||
<span class="section_title">__MSG_AddTags_prompt_text_title__</span><span id="addtags_prompt_unsaved" class="unsaved hidden"> __MSG_customPrompts_unsaved_changes__</span>
|
||||
|
|
|
|||
|
|
@ -53,6 +53,16 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
}
|
||||
});
|
||||
|
||||
let add_tags_auto_el = document.getElementById('add_tags_auto');
|
||||
let add_tags_auto_force_existing_tr = document.getElementById('add_tags_auto_force_existing_tr');
|
||||
let add_tags_auto_only_inbox_tr = document.getElementById('add_tags_auto_only_inbox_tr');
|
||||
add_tags_auto_el.addEventListener('click', (event) => {
|
||||
add_tags_auto_force_existing_tr.style.display = event.target.checked ? 'table-row' : 'none';
|
||||
add_tags_auto_only_inbox_tr.style.display = event.target.checked ? 'table-row' : 'none';
|
||||
});
|
||||
add_tags_auto_force_existing_tr.style.display = add_tags_auto_el.checked ? 'table-row' : 'none';
|
||||
add_tags_auto_only_inbox_tr.style.display = add_tags_auto_el.checked ? 'table-row' : 'none';
|
||||
|
||||
addtags_reset_btn.addEventListener('click', () => {
|
||||
addtags_textarea.value = browser.i18n.getMessage('prompt_add_tags_full_text');
|
||||
addtags_reset_btn.disabled = true;
|
||||
|
|
|
|||
154
pages/spamfilter/mzta-spamfilter.css
Normal file
154
pages/spamfilter/mzta-spamfilter.css
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
#spamfilter_prompt_container{
|
||||
width: 90%;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
#spamfilter_prompt_text{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.infoline{
|
||||
font-size: 0.8em;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.spamfilter_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;
|
||||
}
|
||||
|
||||
#spamfilter_threshold_too_low{
|
||||
display: none;
|
||||
color:red;
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
table#report_data {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
table#report_data th, table#report_data td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
}
|
||||
table#report_data th {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
table#report_data th,
|
||||
table#report_data td {
|
||||
border-color: #444;
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
table#report_data th {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
table#report_data td {
|
||||
background-color: #222;
|
||||
}
|
||||
}
|
||||
59
pages/spamfilter/mzta-spamfilter.html
Normal file
59
pages/spamfilter/mzta-spamfilter.html
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>ThunderAI - __MSG_SpamFilter_PageTitle__</title>
|
||||
<link rel="stylesheet" href="mzta-spamfilter.css">
|
||||
<link rel="icon" href="../../images/icon-16px.png">
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h1 class="page_title">__MSG_SpamFilter_PageTitle__</h1>
|
||||
<p>__MSG_SpamFilter_info_default__</p>
|
||||
</div>
|
||||
<div class="spamfilter_table_title section_title">__MSG_SpamFilter_prompt_prefs_title__</div>
|
||||
<table id="miczPrefs">
|
||||
<tr class="spamfilter_tr">
|
||||
<td><span>__MSG_prefs_OptionText_spamfilter_threshold__</span></td>
|
||||
<td>
|
||||
<label>
|
||||
<input type="number" id="spamfilter_threshold" name="spamfilter_threshold" min="0" max="100" class="option-input" /><span id="spamfilter_threshold_too_low">__MSG_spamfilter_threshold_too_low__</span>
|
||||
<br>__MSG_prefs_OptionText_spamfilter_threshold_Info__
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div id="spamfilter_container">
|
||||
<span class="section_title">__MSG_GetCalendarEvent_prompt_text_title__</span><span id="spamfilter_event_prompt_unsaved" class="unsaved hidden"> __MSG_customPrompts_unsaved_changes__</span>
|
||||
<br><span class="infoline">__MSG_prefs_OptionText_btnManagePrompts_infoline__ <a href="https://micz.it/thunderbird-addon-thunderai/data-placeholders/">__MSG_customPrompts_managePrompts_help__</a>
|
||||
<br><b>__MSG_prefs_OptionText_GetCalendarEvent_infoline2__</b></span>
|
||||
<br>
|
||||
<div class="autocomplete-container">
|
||||
<textarea id="spamfilter_prompt_text" rows="15"></textarea>
|
||||
<ul class="autocomplete-list hidden"></ul>
|
||||
</div>
|
||||
<div id="spamfilter_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>
|
||||
</div>
|
||||
<h2>__MSG_SpamReport_Title__</h2>
|
||||
<table id="report_data">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Message_ID</th>
|
||||
<th>__MSG_Date__</th>
|
||||
<th>__MSG_From__</th>
|
||||
<th>__MSG_Subject__</th>
|
||||
<th>__MSG_Spam_Value__</th>
|
||||
<th>__MSG_Moved_to_Spam__</th>
|
||||
<th>__MSG_Explanation__</th>
|
||||
<th>__MSG_Report_Date__</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="report_data_body">
|
||||
<!-- Rows will be inserted dynamically -->
|
||||
</tbody>
|
||||
</table>
|
||||
<script src="mzta-spamfilter.js" type="module"></script>
|
||||
<script src="../../js/mzta-i18n.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
207
pages/spamfilter/mzta-spamfilter.js
Normal file
207
pages/spamfilter/mzta-spamfilter.js
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* 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 } from '../../options/mzta-options-default.js';
|
||||
import { taLogger } from '../../js/mzta-logger.js';
|
||||
import { getSpecialPrompts, setSpecialPrompts } from "../../js/mzta-prompts.js";
|
||||
import { getPlaceholders } from "../../js/mzta-placeholders.js";
|
||||
import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js";
|
||||
import { taSpamReport } from '../../js/mzta-spamreport.js';
|
||||
|
||||
let autocompleteSuggestions = [];
|
||||
let taLog = new taLogger("mzta-spamfilter-page",true);
|
||||
taSpamReport.logger = taLog;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
i18n.updateDocument();
|
||||
await restoreOptions();
|
||||
|
||||
document.querySelectorAll(".option-input").forEach(element => {
|
||||
element.addEventListener("change", saveOptions);
|
||||
});
|
||||
|
||||
document.getElementById("spamfilter_threshold").addEventListener("input", check_spamfilter_threshold);
|
||||
check_spamfilter_threshold({target: document.getElementById("spamfilter_threshold")});
|
||||
|
||||
let spamfilter_textarea = document.getElementById('spamfilter_prompt_text');
|
||||
let spamfilter_save_btn = document.getElementById('btn_save_prompt');
|
||||
let spamfilter_reset_btn = document.getElementById('btn_reset_prompt');
|
||||
|
||||
let specialPrompts = await getSpecialPrompts();
|
||||
let spamfilter_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_spamfilter');
|
||||
|
||||
spamfilter_textarea.addEventListener('input', (event) => {
|
||||
spamfilter_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_spamfilter_full_text'));
|
||||
spamfilter_save_btn.disabled = (event.target.value === spamfilter_prompt.text);
|
||||
if(spamfilter_save_btn.disabled){
|
||||
document.getElementById('spamfilter_prompt_unsaved').classList.add('hidden');
|
||||
} else {
|
||||
document.getElementById('spamfilter_prompt_unsaved').classList.remove('hidden');
|
||||
}
|
||||
});
|
||||
|
||||
spamfilter_reset_btn.addEventListener('click', () => {
|
||||
spamfilter_textarea.value = browser.i18n.getMessage('prompt_spamfilter_full_text');
|
||||
spamfilter_reset_btn.disabled = true;
|
||||
let event = new Event('input', { bubbles: true, cancelable: true });
|
||||
spamfilter_textarea.dispatchEvent(event);
|
||||
});
|
||||
|
||||
spamfilter_save_btn.addEventListener('click', () => {
|
||||
specialPrompts.find(prompt => prompt.id === 'prompt_spamfilter').text = spamfilter_textarea.value;
|
||||
setSpecialPrompts(specialPrompts);
|
||||
spamfilter_save_btn.disabled = true;
|
||||
document.getElementById('spamfilter_prompt_unsaved').classList.add('hidden');
|
||||
browser.runtime.sendMessage({command: "reload_menus"});
|
||||
});
|
||||
|
||||
if(spamfilter_prompt.text === 'prompt_spamfilter_full_text'){
|
||||
spamfilter_prompt.text = browser.i18n.getMessage(spamfilter_prompt.text);
|
||||
}
|
||||
spamfilter_textarea.value = spamfilter_prompt.text;
|
||||
spamfilter_reset_btn.disabled = (spamfilter_textarea.value === browser.i18n.getMessage('prompt_spamfilter_full_text'));
|
||||
|
||||
autocompleteSuggestions = (await getPlaceholders(true)).filter(p => !(p.id === 'additional_text')).map(p => ({command: '{%'+p.id+'%}', type: p.type}));
|
||||
textareaAutocomplete(spamfilter_textarea, autocompleteSuggestions, 1); // type_value = 1, only when reading an email
|
||||
|
||||
loadSpamReport()
|
||||
});
|
||||
|
||||
function check_spamfilter_threshold(event) {
|
||||
let spamfilter_threshold_too_low = document.getElementById("spamfilter_threshold_too_low");
|
||||
if(event.target.value < 50){
|
||||
spamfilter_threshold_too_low.style.display = "inline";
|
||||
if(event.target.value == 0){
|
||||
spamfilter_threshold_too_low.textContent = browser.i18n.getMessage('spamfilter_threshold_zero');
|
||||
spamfilter_threshold_too_low.style.fontSize = "1.5em";
|
||||
}else{
|
||||
spamfilter_threshold_too_low.textContent = browser.i18n.getMessage('spamfilter_threshold_too_low');
|
||||
spamfilter_threshold_too_low.style.fontSize = "1.1em";
|
||||
}
|
||||
}else{
|
||||
spamfilter_threshold_too_low.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
async function loadSpamReport(){
|
||||
let report_data = await taSpamReport.getAllReportData();
|
||||
console.log(">>>>>>>>>>>> loadSpamReport: " + JSON.stringify(report_data));
|
||||
//document.getElementById("report_data").textContent = JSON.stringify(report_data, null, 2);
|
||||
if(report_data == undefined){
|
||||
document.getElementById("report_data").innerText = browser.i18n.getMessage("spamfilter_no_reports");
|
||||
}else{
|
||||
populateTable(report_data);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to populate the table
|
||||
function populateTable(data) {
|
||||
const tableBody = document.getElementById("report_data_body");
|
||||
tableBody.innerHTML = ""; // Clear table before inserting new data
|
||||
|
||||
Object.keys(data).forEach(email => {
|
||||
const report = data[email];
|
||||
|
||||
// Create a new row
|
||||
const row = document.createElement("tr");
|
||||
|
||||
row.innerHTML = `
|
||||
<td>${report.headerMessageId}</td>
|
||||
<td>${new Date(report.message_date).toLocaleString()}</td>
|
||||
<td>${report.from.join(", ")}</td>
|
||||
<td>${report.subject.join(", ")}</td>
|
||||
<td>${report.spamValue}</td>
|
||||
<td>${report.moved?browser.i18n.getMessage("spamfilter_moved"):browser.i18n.getMessage("spamfilter_not_moved")} (${report.SpamThreshold})</td>
|
||||
<td>${report.explanation}</td>
|
||||
<td>${new Date(report.report_date).toLocaleString()}</td>
|
||||
`;
|
||||
|
||||
// Append the row to the table
|
||||
tableBody.appendChild(row);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Methods to manage options, derived from: /options/mzta-options.js
|
||||
function saveOptions(e) {
|
||||
e.preventDefault();
|
||||
let options = {};
|
||||
let element = e.target;
|
||||
|
||||
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;
|
||||
default:
|
||||
if (element.tagName === 'SELECT') {
|
||||
options[element.id] = element.value;
|
||||
}else{
|
||||
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 => {
|
||||
taLog.log("Options restoring " + element.id + " = " + (element.id=="chatgpt_api_key" || element.id=="openai_comp_api_key" ? "****************" : 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 '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 = '';
|
||||
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;
|
||||
}
|
||||
}else{
|
||||
console.error("[ThunderAI] Unhandled input type:", element.type);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let getting = await browser.storage.sync.get(prefs_default);
|
||||
setCurrentChoice(getting);
|
||||
}
|
||||
Loading…
Reference in a new issue