Merge pull request #313 from micz/v3.3.0

v3.3.0
This commit is contained in:
Mic 2025-03-31 21:48:47 +02:00 committed by GitHub
commit d5f4d7ef69
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
41 changed files with 5241 additions and 221 deletions

View file

@ -4,6 +4,21 @@
<h2>Version 3.3.0 - 31/03/2025</h2>
<ul>
<li>Added the <i>{%mail_folder_name%}</i> placeholder to get the mail folder name [<a href="https://github.com/micz/ThunderAI/issues/253">#253</a>].</li>
<li>Added the <i>{%mail_folder_path%}</i> placeholder to get the mail folder path [<a href="https://github.com/micz/ThunderAI/issues/253">#253</a>].</li>
<li>Added the <i>{%account_email_address%}</i> placeholder to get the current account mail address [<a href="https://github.com/micz/ThunderAI/issues/272">#272</a>].</li>
<li><i>[ChatGPT Web][All APIs]</i> Added a diff viewer to compare the old and new text. This feature could be activated at prompt level, and it's useful for "rewrite" prompts [<a href="https://github.com/micz/ThunderAI/issues/109">#109</a>].</li>
<li><i>[All APIs]</i> Added a context menu to automatically add tags and run the spam filter on selected messages. [<a href="https://github.com/micz/ThunderAI/issues/262">#262</a>].</li>
<li><i>[All APIs]</i> It's now possibile to define a timezone in the calendar event settings page [<a href="https://github.com/micz/ThunderAI/issues/250">#250</a>].</li>
<li><i>[All APIs]</i> It's now possibile to add the attendees in the calendar event, be sure to update the prompt in the settings [<a href="https://github.com/micz/ThunderAI/issues/258">#258</a>].</li>
<li>The button icon now shows a loading indicator when ThunderAI is performing an operation [<a href="https://github.com/micz/ThunderAI/issues/295">#295</a>].</li>
<li>Improved the handling of null or undefined placeholders [<a href="https://github.com/micz/ThunderAI/issues/288">#288</a>].</li>
<li>Czech (cs) translation added, thanks to <a href="https://hosted.weblate.org/user/jaroush/">Jaroslav Staněk</a> and <a href="https://hosted.weblate.org/user/Fjuro/">Fjuro</a>.</li>
<li>Simplified Chinese (zh_Hans) translation added, thanks to <a href="https://github.com/jeklau">jeklau</a>.</li>
<li>Some old strings are now translated in the API webchat [<a href="https://github.com/micz/ThunderAI/issues/298">#298</a>].</li>
</ul>
<h2>Version 3.2.3 - 06/03/2025</h2>
<ul>
<li><i>[ChatGPT Web]</i> Fixed hiding the Spam Filter options [<a href="https://github.com/micz/ThunderAI/issues/284">#284</a>].</li>

View file

@ -4,4 +4,6 @@ fr
hr
it
pl
pt-br
pt-br
cs
zh_Hans

View file

@ -80,6 +80,8 @@ Are you using this addon in your Thunderbird?
## Attributions
### Translations
- Chinese (Simplified): [jeklau](https://github.com/jeklau)
- Czech (cs): [Fjuro](https://hosted.weblate.org/user/Fjuro/), [Jaroslav Staněk](https://hosted.weblate.org/user/jaroush/)
- English (en-US): [Mic](https://github.com/micz/)
- French (fr): Generated automatically, [Noam](https://github.com/noam-sc)
- German (de): Generated automatically

911
_locales/cs/messages.json Normal file
View file

@ -0,0 +1,911 @@
{
"customPrompts_saving_custom_prompts": {
"message": "Ukládání vlastních dotazů…"
},
"prompt_rewrite_formal": {
"message": "Přepsat formálně"
},
"customPrompts_reloading_menus": {
"message": "Načítání nabídek…"
},
"customPrompts_form_label_Action": {
"message": "Akce"
},
"customPrompts_btnCancel": {
"message": "Zrušit"
},
"customPrompts_btnDelete_confirmText": {
"message": "Opravdu chcete odstranit tuto položku?"
},
"customPrompts_form_label_ID": {
"message": "ID"
},
"customPrompts_add_to_menu": {
"message": "Přidat do nabídky"
},
"extensionDescription": {
"message": "Použijte ChatGPT, Google Gemini nebo Ollama pro vylepšení vašich e-mailů!"
},
"menu_title": {
"message": "AI"
},
"prompt_lang": {
"message": "Odpovědět v jazyce"
},
"prompt_reply": {
"message": "Odpovědět na tento e-mail"
},
"prompt_reply_advanced": {
"message": "Odpovědět na toto vlákno"
},
"prompt_this": {
"message": "Zeptat se"
},
"customPrompts_managePrompts_help": {
"message": "Další informace"
},
"customPrompts_start_saving": {
"message": "Ukládání dotazů…"
},
"customPrompts_reindexing_list": {
"message": "Indexování seznamu…"
},
"customPrompts_filtering_prompts": {
"message": "Filtrování dotazů…"
},
"customPrompts_saving_default_prompts": {
"message": "Ukládání výchozích dotazů…"
},
"prompt_translate_this": {
"message": "Přeložit"
},
"prompt_summarize_this": {
"message": "Shrnout"
},
"customPrompts_managePrompts": {
"message": "Spravovat dotazy"
},
"customPrompts_form_label_Name": {
"message": "Název"
},
"customPrompts_form_required_fields": {
"message": "Požadovaná pole"
},
"customPrompts_form_label_need_selected": {
"message": "Potřebný výběr textu"
},
"customPrompts_saved": {
"message": "Dotazy uloženy!"
},
"customPrompts_form_label_enabled": {
"message": "Povoleno"
},
"customPrompts_btnSaveAll": {
"message": "Uložit vše"
},
"customPrompts_do_reply": {
"message": "Odpovědět"
},
"customPrompts_btnNew": {
"message": "Přidat nový"
},
"customPrompts_close_button": {
"message": "Tlačítko pro zavření"
},
"customPrompts_btnAddNewCommit": {
"message": "Přidat dotaz"
},
"customPrompts_add_to_menu_always": {
"message": "Vždy"
},
"prompt_selection_needed": {
"message": "Pro pokračování vyberte nějaký text!"
},
"customPrompts_form_label_need_custom_text": {
"message": "Zeptat se na dodatečný text"
},
"customPrompts_form_label_Text": {
"message": "Text dotazu"
},
"customPrompts_add_to_menu_reading": {
"message": "Čtení e-mailu"
},
"customPrompts_form_label_ID_rules": {
"message": "Musí být unikátní, být malými písmeny a bez mezer"
},
"customPrompts_btnDelete": {
"message": "Odstranit"
},
"customPrompts_form_label_need_signature": {
"message": "Vždy přidat podpis"
},
"customPrompts_btnEdit": {
"message": "Upravit"
},
"customPrompts_add_to_menu_composing": {
"message": "Psaní e-mailu"
},
"prompt_rewrite_polite": {
"message": "Přepsat zdvořile"
},
"prompt_classify": {
"message": "Zařadit"
},
"customPrompts_btnOK": {
"message": "OK"
},
"customPrompts_save_button": {
"message": "Uložit"
},
"customPrompts_unsaved_changes": {
"message": "Máte neuložené změny!"
},
"customPrompts_managePrompts_info_default": {
"message": "Výchozí dotazy nelze upravovat. Pro vytvoření upravené verze je můžete zakázat, poté zkopírovat text dotazu a vložit jej do nového."
},
"customPrompts_managePrompts_info_default_2": {
"message": "Můžete importovat a exportovat dotazy. Existující dotazy se stejným ID budou přepsány. Dotazy s novými ID budou přidány."
},
"customPrompts_managePrompts_info_default_3": {
"message": "Pokud je všechno správně, po importu klikněte na tlačítko „Uložit vše“."
},
"customPrompts_substitute_text": {
"message": "Nahrazující text"
},
"chatgpt_win_working": {
"message": "Pracuji…"
},
"chatgpt_win_job_completed": {
"message": "Dokončeno!"
},
"chatgpt_win_get_answer": {
"message": "Použít vybranou odpověď"
},
"chatgpt_btn_retry": {
"message": "Zkusit znovu"
},
"chatgpt_sendbutton_not_found_error": {
"message": "Klikněte na tlačítko pro odeslání dotazu."
},
"chatgpt_user_not_logged_in": {
"message": "Nejste přihlášeni do ChatGPT. Přihlaste se svými údaji, zavřete okno ChatGPT a poté opakujte akci. Následně již zůstanete přihlášeni."
},
"chatgpt_win_model_warning": {
"message": "Nastavili jste možnost použití určitého modelu, ten se ale nejspíše nenačítá správně. Zkontrolujte prosím danou hodnotu a zkuste to znovu. Pro pokračování můžete stisknout modré tlačítko."
},
"chatgpt_win_custom_text": {
"message": "Sem zadejte dodatečný text pro dotaz."
},
"chatgpt_textarea_not_found_error": {
"message": "Zdá se, že stránka ChatGPT se načítá příliš dlouho. Pokud se načte, klikněte na tlačítko vpravo. Pokud problém přetrvává, zkontrolujte stav služby."
},
"chatgpt_win_job_completed_select": {
"message": "Vyberte text, který chcete použít, a klikněte na tlačítko."
},
"chatgpt_win_close": {
"message": "Zavřít"
},
"chatgpt_win_send": {
"message": "Odeslat"
},
"chatgpt_use_gpt35": {
"message": "Použít GPT3.5"
},
"chatgpt_force_completion": {
"message": "vynutit doplnění"
},
"chatgpt_force_completion_title": {
"message": "Klikněte zde pro zobrazení tlačítka 'Použít poslední odpověď', pokud ChatGPT dokončil svou práci, ale tlačítko se nezobrazilo."
},
"msg_prompt_too_long": {
"message": "Poskytnutý text je příliš dlouhý. Musíte ho zkrátit."
},
"prefs_OptionText_release_notes": {
"message": "Poznámky k vydání"
},
"prefs_status_page": {
"message": "stav služby"
},
"prefs_OptionText_chatgpt_win_text": {
"message": "Rozměry okna ChatGPT"
},
"prefs_OptionText_chatgpt_win_height": {
"message": "Výška"
},
"prefs_OptionText_chatgpt_win_width": {
"message": "Šířka"
},
"prefs_OptionText_default_sign_name": {
"message": "Přednastavený podpis"
},
"prefs_OptionText_default_chatgpt_lang": {
"message": "Výchozí jazyk pro odpovědi"
},
"prefs_OptionText_reply_all": {
"message": "Odpovědět všem"
},
"prefs_OptionText_reply_sender": {
"message": "Odpovědět odesílateli"
},
"prefs_OptionText_btnManagePrompts": {
"message": "Spravovat vaše příkazy"
},
"prefsInfoTitle": {
"message": "Důležité informace"
},
"prefs_OptionText_reply_type": {
"message": "Typ odpovědi"
},
"prefsInfoDesc_2": {
"message": "Pro použití ChatGPT API potřebujete klíč OpenAI ChatGPT API a musíte vybrat model."
},
"prefsInfoDesc_3": {
"message": "Pro použití integrace s Ollama je nutné nastavit místní server Ollama. Jakmile server běží, zadejte jeho adresu do určeného pole v aplikaci. Pro zajištění správné komunikace mezi ThunderAI a serverem Ollama nezapomeňte nastavit proměnnou OLLAMA_ORIGINS=moz-extension://*."
},
"prefsInfoDesc_5": {
"message": "Pamatujte, že nabídku ThunderAI můžete otevřít pomocí klávesové zkratky CTRL+ALT+A."
},
"prefsInfoDesc_6": {
"message": "Zkratku můžete změnit kliknutím na ikonu ozubeného kola v pravém horním rohu této stránky a výběrem možnosti „Spravovat zkratku rozšíření“."
},
"prefsDonation_1": {
"message": "Líbí se vám tento doplněk?"
},
"prefsDonation_2": {
"message": "Zvažte dar!"
},
"backToOptionsText": {
"message": "Možnosti"
},
"TranslateText": {
"message": "Chcete pomoci s překladem tohoto doplňku?"
},
"customPrompts_ExportAll": {
"message": "Exportovat všechny příkazy"
},
"customPrompts_Import": {
"message": "Importovat nové příkazy"
},
"importPrompts_confirmText": {
"message": "Chystáte se importovat nové příkazy."
},
"customPrompts_import_completed": {
"message": "Import vlastních příkazů dokončen! Pro uložení změn musíte kliknout na tlačítko 'Uložit vše'."
},
"importPrompts_invalidPrompts": {
"message": "Soubor, který se snažíte importovat, neobsahuje žádné platné příkazy."
},
"customprompts_form_label_define_response_lang": {
"message": "Určete jazyk odpovědi v příkazu"
},
"prefs_Connection_type": {
"message": "Typ připojení"
},
"prefs_Connection_type_ChatGPT_Web": {
"message": "Webové rozhraní ChatGPT"
},
"prefs_Connection_type_ChatGPT_API": {
"message": "ChatGPT OpenAI API"
},
"prefs_ChatGPT_API_Key": {
"message": "Klíč ChatGPT API"
},
"Loading": {
"message": "Načítání..."
},
"error": {
"message": "Chyba ThunderAI!"
},
"chatgpt_empty_apikey": {
"message": "Nezadali jste klíč API pro ChatGPT API. Vložte jej prosím na stránce s možnostmi."
},
"chatgpt_empty_model": {
"message": "Nevybrali jste model pro ChatGPT API. Vyberte jej prosím na stránce s možnostmi."
},
"chagpt_api_connecting": {
"message": "Pokouším se připojit k OpenAI ChatGPT pomocí poskytnutého klíče API"
},
"chagpt_api_send_button": {
"message": "Používám model"
},
"prefs_OptionText_do_debug_info": {
"message": "Zapnout ladění"
},
"Debug": {
"message": "Ladění"
},
"prefs_Connection_type_OpenAI_Comp_API": {
"message": "API kompatibilní s OpenAI"
},
"prefs_Connection_type_Ollama_API": {
"message": "Ollama API (Lokální LLM)"
},
"Ollama_Models": {
"message": "Modely Ollama"
},
"Ollama_Models_Fetch": {
"message": "Aktualizovat seznam modelů Ollama"
},
"Ollama_Models_Error_fetching": {
"message": "Chyba při pokusu o načtení modelů Ollama"
},
"API_Models_Error_NoModels": {
"message": "Nebyly nalezeny žádné modely"
},
"ollama_empty_host": {
"message": "Nezadali jste adresu hostitele pro Ollama API. Prosím, vložte ji na stránce s nastavením."
},
"prefs_API_Host": {
"message": "Adresa hostitele"
},
"ollama_empty_model": {
"message": "Nevybrali jste model pro Ollama API. Prosím, vyberte jej na stránce s nastavením."
},
"ollama_api_connecting": {
"message": "Pokouším se připojit k lokálnímu serveru Ollama pomocí hostitele"
},
"andModel": {
"message": "a model"
},
"error_connection_interrupted": {
"message": "Spojení se serverem bylo neočekávaně přerušeno"
},
"chatgpt_api_request_failed": {
"message": "Požadavek na OpenAI ChatGPT API selhal"
},
"WaitingServerReponse": {
"message": "Čekám na odpověď serveru"
},
"prefs_API_Host_Info": {
"message": "Něco jako"
},
"OpenAIComp_Models": {
"message": "odely kompatibilní s OpenAI API"
},
"OpenAIComp_Models_Fetch": {
"message": "Aktualizovat seznam modelů kompatibilních s OpenAI API"
},
"OpenAIComp_Models_Error_fetching": {
"message": "Chyba při pokusu o načtení modelů kompatibilních s OpenAI API"
},
"OpenAIComp_empty_host": {
"message": "Nezadali jste adresu hostitele pro API kompatibilní s OpenAI. Prosím, vložte ji na stránce s nastavením."
},
"OpenAIComp_empty_model": {
"message": "Nevybrali jste model pro API kompatibilní s OpenAI. Prosím, vyberte jej na stránce s nastavením."
},
"OpenAIComp_api_connecting": {
"message": "Pokouším se připojit k lokálnímu serveru API kompatibilního s OpenAI pomocí hostitele"
},
"OpenAIComp_api_request_failed": {
"message": "Požadavek na OpenAI Comp API selhal"
},
"prefs_OpenAIComp_ChatName": {
"message": "Jméno chatu"
},
"prefs_OpenAIComp_ChatName_Info": {
"message": "Toto je jméno, které bude použito v AI chatu."
},
"OpenChatGPTTab_Info": {
"message": "V případě problémů s přihlášením v okně ThunderAI otevřete ChatGPT na nové kartě pomocí tlačítka vpravo, přihlaste se, poté kartu zavřete a pokračujte v používání ThunderAI."
},
"placeholder_mail_text_body": {
"message": "Tělo e-mailu"
},
"placeholder_mail_html_body": {
"message": "HTML tělo e-mailu"
},
"placeholder_mail_subject": {
"message": "Předmět e-mailu"
},
"placeholder_folder_name": {
"message": "Název složky"
},
"placeholder_folder_path": {
"message": "Cesta ke složce"
},
"placeholder_selected_text": {
"message": "Vybraný text"
},
"prefs_OptionText_chatgpt_web_tempchat_info": {
"message": "Pokud je zaškrtnuto, bude ve webovém rozhraní ChatGPT použit dočasný chat."
},
"chatgpt_btn_model": {
"message": "Použít aktuální model"
},
"SendingPrompt": {
"message": "Odesílání výzvy..."
},
"AddTags_prompt_text_title": {
"message": "Aktuální text výzvy"
},
"AddTags_excl_list_title": {
"message": "Seznam vyloučení"
},
"addtags_no_valid_tags": {
"message": "Po filtrování se seznamem vyloučení nebyly nalezeny žádné platné štítky."
},
"thunderai_error_title": {
"message": "Chyba ThunderAI"
},
"thunderai_warning_title": {
"message": "Varování ThunderAI"
},
"GoogleGemini_Models_Error_fetching": {
"message": "Chyba při pokusu o načtení modelů Google Gemini"
},
"google_gemini_api_request_failed": {
"message": "Požadavek Google Gemini API selhal"
},
"prefs_OptionText_btnManagePrompts_infoline3": {
"message": "V zástupném symbolu dat {%tags_full_list%} můžete ve výzvě uvést seznam dostupných štítků. S vhodnou výzvou pak můžete vynutit, aby byly štítky vybrány pouze ze seznamu již existujících."
},
"prefs_OptionText_get_calendar_event_Info": {
"message": "Pokud je zaškrtnuto, bude do nabídky přidána položka pro získání informací o události kalendáře z vybraného textu."
},
"prefs_OptionText_add_tags_auto_force_existing_Info": {
"message": "Pokud je zaškrtnuto, AI bude nově přijatým e-mailům přidávat pouze existující štítky a nebude vytvářet nové."
},
"prompt_spamfilter": {
"message": "Detekovat spamové e-maily"
},
"placeholder_thunderai_def_sign": {
"message": "Výchozí podpis podle nastavení ThunderAI."
},
"prefs_OptionText_spamfilter": {
"message": "Automatický filtr spamu"
},
"prefs_OptionText_spamfilter_Info": {
"message": "Pokud je zaškrtnuto, ThunderAI automaticky přesune spamové e-maily do složky se spamem."
},
"SpamFilter_PageTitle": {
"message": "Spravovat nastavení filtru spamu"
},
"SpamFilter_info_default": {
"message": "Na této stránce můžete upravit výchozí výzvu používanou k detekci spamových e-mailů."
},
"SpamFilter_prompt_text_title": {
"message": "Aktuální text přikazu"
},
"prefs_OptionText_spamfilter_infoline": {
"message": "Příkaz můžete změnit, jak chcete, ale odpověď přijatá z AI musí být ve formátu JSON, jak je uvedeno ve výchozím příkazu!"
},
"Moved_to_Spam": {
"message": "Přesunuto do Spamu"
},
"Subject": {
"message": "Předmět"
},
"From": {
"message": "Od"
},
"SpamReport_Title": {
"message": "Hlášení spamového filtru"
},
"spamfilter_threshold_zero": {
"message": "Práh spamu je nula! Označíte všechny e-maily jako spam!"
},
"Spam_Value": {
"message": "Hodnota spamu"
},
"spamfilter_not_moved": {
"message": "Ne"
},
"prefsInfoDesc_4": {
"message": "Pro použití této integrace je nutné nastavit místní server kompatibilní s OpenAI API, jako je LM Studio. Jakmile server běží, zadejte jeho adresu do určeného pole v aplikaci. Pro zajištění správné komunikace mezi ThunderAI a místním serverem nezapomeňte správně nastavit nastavení CORS."
},
"prefs_OptionText_add_tags_auto_only_inbox": {
"message": "Přidávat štítky pouze e-mailům v doručené poště"
},
"prefs_OptionText_add_tags": {
"message": "Přidat štitky k e-mailům"
},
"ollama_api_request_failed": {
"message": "Požadavek na Ollama API selhal"
},
"prefs_OptionText_add_tags_first_uppercase": {
"message": "První písmeno velké"
},
"TranslateLink": {
"message": "Zjistěte, jak na to!"
},
"prefsInfoDesc_1": {
"message": "Může se stát, že se webové rozhraní ChatGPT změní způsobem, který naruší funkčnost doplňku. Zkontrolujte stránku „Stav služby“, která je odkazovaná ve spodní části této stránky. Také si pamatujte, že při prvním použití ThunderAI se musíte přihlásit do ChatGPT."
},
"prefs_OptionText_btnManageSpamFilterInfo": {
"message": "Spravovat nastavení filtru spamu"
},
"ChatGPT_Models": {
"message": "Modely ChatGPT"
},
"spamfilter_no_reports": {
"message": "Zatím nebyly žádné zprávy zkontrolovány na spam. Zde naleznete seznam posledních 100 hlášení spamu pouze pro aktuální relaci."
},
"SpamFilter_prompt_prefs_title": {
"message": "\"Možnosti filtru spamu\""
},
"spamfilter_threshold_too_low": {
"message": "Práh spamu je příliš nízký! Pravděpodobně označíte příliš mnoho e-mailů jako spam!"
},
"importPrompts_invalidFile": {
"message": "Soubor, který se snažíte importovat, není platný soubor vlastních příkazů."
},
"Explanation": {
"message": "Vysvětlení"
},
"customPrompts_start_import": {
"message": "Spouštím import vlastních příkazů..."
},
"currently_used_prompt": {
"message": "Aktuálně používaný název přikazu"
},
"ChatGPT_Models_Fetch": {
"message": "Aktualizovat seznam modelů ChatGPT"
},
"ChatGPT_Models_Error_fetching": {
"message": "Chyba při pokusu o načtení modelů ChatGPT"
},
"Date": {
"message": "Datum"
},
"spamfilter_moved": {
"message": "Ano"
},
"Report_Date": {
"message": "Datum hlášení"
},
"prefs_OptionText_spamfilter_threshold_Info": {
"message": "Pokud je hodnota vrácená umělou inteligencí nad tímto prahem, e-mail bude přesunut do složky se spamem."
},
"prefs_OptionText_spamfilter_threshold": {
"message": "Práh spamu"
},
"prefs_OptionText_add_tags_first_uppercase_Info": {
"message": "Pokud je zaškrtnuto, štítek bude nastaven na malá písmena s pouze prvním písmenem velkým."
},
"AddTags_prompt_prefs_title": {
"message": "Možnosti přidávání štítků"
},
"prefs_SurveyLinkText": {
"message": "Podělte se o svůj názor a pomozte vylepšit ThunderAI!"
},
"prefs_SurveyLinkText2": {
"message": "Klikněte zde, zabere to jen minutu!"
},
"prefs_OpenAIComp_ForceModel": {
"message": "Ručně vložit model"
},
"OpenAIComp_force_model_ask": {
"message": "Zde vložte název modelu, který chcete použít."
},
"prefs_OptionText_add_tags_force_lang": {
"message": "Vynutit jazyk"
},
"prefs_OptionText_add_tags_force_lang_Info": {
"message": "Pokud je zaškrtnuto, jazyk štítků bude vynucen tak, aby odpovídal jazyku definovanému na stránce možností ThunderAI, pokud je zadán."
},
"prompt_add_tags_force_lang": {
"message": "Štítky musí být napsány v"
},
"prefs_Connection_type_Google_Gemini_API": {
"message": "Google Gemini API"
},
"prefs_GoogleGemini_API_Key": {
"message": "API klíč"
},
"GoogleGemini_Models": {
"message": "Modely Google Gemini API"
},
"GoogleGemini_Models_Fetch": {
"message": "Aktualizovat seznam modelů Google Gemini"
},
"google_gemini_api_connecting": {
"message": "Probíhá pokus o připojení ke Google Gemini pomocí zadaného API klíče"
},
"google_gemini_empty_apikey": {
"message": "Nezadali jste API klíč pro Google Gemini API. Vložte jej na stránce možností."
},
"google_gemini_empty_model": {
"message": "Nevybrali jste model pro Google Gemini API. Vyberte jej na stránce možností."
},
"GoogleGemini_SystemInstruction": {
"message": "Systémová instrukce"
},
"GoogleGemini_SystemInstruction_Info": {
"message": "Když nastavíte systémovou instrukci, poskytnete modelu další kontext pro pochopení úkolu, poskytnutí přizpůsobenějších odpovědí a dodržování specifických pokynů nad rámec odeslané výzvy."
},
"ChatGPT_Developer_Messages": {
"message": "Zprávy pro vývojáře"
},
"AddTags_excl_list_infoline": {
"message": "Toto je seznam štítků, které není povoleno přidávat do e-mailů."
},
"save": {
"message": "Uložit"
},
"addtags_info_additional_statements": {
"message": "Toto prohlášení bude přidáno na konec výzvy:"
},
"reset_default": {
"message": "Obnovit výchozí"
},
"addtags_excl_list_infoline2": {
"message": "Přidejte slovo na řádek nebo oddělené čárkou."
},
"addtags_dialog_title": {
"message": "Přidat štítky do e-mailu"
},
"addtags_exclude_tag": {
"message": "Vyloučit štítek"
},
"addtags_no_tags_received": {
"message": "Z AI nebyly přijaty žádné štítky."
},
"ChatGPT_Developer_Messages_Info": {
"message": "Když nastavíte zprávy pro vývojáře, poskytnete modelu další kontext pro pochopení úkolu, poskytnutí přizpůsobenějších odpovědí a dodržování specifických pokynů nad rámec odeslané výzvy."
},
"placeholder_mail_typed_text": {
"message": "Text napsaný před citovaným tělem e-mailu"
},
"prompt_get_calendar_event": {
"message": "Přidej novou událost do kalendáře"
},
"prefs_OptionText_btnManagePrompts_infoline2": {
"message": "Výzvu můžete změnit, jak chcete, ale odpověď obdržená od AI musí být seznam štítků oddělených čárkou!"
},
"prefs_OptionText_add_tags_auto_only_inbox_Info": {
"message": "Pokud je zaškrtnuto, AI bude přidávat štítky pouze e-mailům přijatým ve složce Doručená pošta."
},
"thunderai_def_lang": {
"message": "Výchozí jazyk podle nastavení ThunderAI."
},
"StorageSpace": {
"message": "Celkový obsazený úložný prostor"
},
"SearchPrompt": {
"message": "Hledat výzvy"
},
"prefs_OptionText_dynamic_menu_force_enter": {
"message": "Menu: okamžité odeslání výzvy"
},
"prefs_OptionText_dynamic_menu_force_enter_info": {
"message": "Pokud je zaškrtnuto, použití klávesové zkratky CTRL+ALT+A automaticky odešle zvýrazněnou výzvu z menu. Jinak se uživateli zobrazí název výzvy a pro její odeslání bude nutné znovu stisknout klávesu Enter."
},
"prefs_OptionText_dynamic_menu_order_alphabet": {
"message": "Menu: seřadit abecedně"
},
"prefs_OptionText_dynamic_menu_order_alphabet_info": {
"message": "Pokud je zaškrtnuto, výzvy v menu budou seřazeny abecedně."
},
"prefs_OptionText_chatgpt_win_dims_info": {
"message": "Nastavte na 0, pokud nechcete specifikovat velikost okna."
},
"prefs_OpenAIComp_API_Key": {
"message": "OpenAI Comp API klíč"
},
"Optional": {
"message": "Volitelné"
},
"OpenChatGPTTab": {
"message": "Otevřít kartu ChatGPT"
},
"placeholder_additional_text": {
"message": "Dodatečný text"
},
"placeholder_junk_score": {
"message": "Skóre nevyžádané pošty"
},
"placeholder_recipients": {
"message": "Příjemci"
},
"placeholder_cc_list": {
"message": "Seznam kopií"
},
"placeholder_author": {
"message": "Autor"
},
"placeholder_account_email_address": {
"message": "E-mailová adresa účtu"
},
"prefs_OptionText_placeholders_use_default_value": {
"message": "Zástupné symboly: použít výchozí hodnotu"
},
"prefs_OptionText_placeholders_use_default_value_info": {
"message": "Pokud je zaškrtnuto, zástupné symboly budou vyplněny výchozími hodnotami, pokud není zadána žádná hodnota. Jinak zůstanou zástupné symboly na svém místě."
},
"prefs_OptionText_max_prompt_length": {
"message": "Maximální délka výzvy"
},
"prefs_OptionText_max_prompt_length_Info": {
"message": "Toto je maximální počet znaků, které lze použít ve výzvě. V opačném případě se zobrazí chybová zpráva. Tato hodnota není upravitelná pro webové rozhraní ChatGPT."
},
"prefs_OptionText_chatgpt_web_model": {
"message": "Webový model ChatGPT"
},
"prefs_OptionText_chatgpt_web_model_info": {
"message": "Toto je model, který bude vynucen pro webové rozhraní ChatGPT. Pokud není zadán žádný model nebo je zadán nesprávný, výchozí model bude nastaven ChatGPT na webové stránce."
},
"prefs_OptionText_chatgpt_web_tempchat": {
"message": "Dočasný chat ChatGPT Web"
},
"AllowedValues": {
"message": "Povolené hodnoty"
},
"prefs_OptionText_btnManagePrompts_infoline": {
"message": "Můžete použít další zástupné symboly dat."
},
"prefs_OptionText_openai_comp_use_v1": {
"message": "Zachovat kompatibilitu \"v1\""
},
"prefs_OptionText_openai_comp_use_v1_info": {
"message": "Pokud je zaškrtnuto, segment \"v1\" v cestě volání API bude zachován, například \"http://localhost:1234/v1/chat/completions\"."
},
"prefs_OptionText_openai_comp_info_remote": {
"message": "Zde můžete také vložit adresu vzdáleného serveru."
},
"prefs_OptionText_owl_warning": {
"message": "Zdá se, že alespoň jeden z vašich účtů používá doplněk Owl for Exchange. Mezi Thunderbirdem a Owlem je známý problém, který se v současné době řeší. V tuto chvíli můžete používat ThunderAI při psaní e-mailů, ale ne při jejich čtení."
},
"prefs_OptionText_chatgpt_web_model_tooltip": {
"message": "Kliknutím na hodnotu ji nastavíte."
},
"prompt_reply_full_text": {
"message": "Odpovězte na následující e-mail. Odpovězte pouze potřebným textem a bez dalších komentářů nebo jiného textu."
},
"prompt_reply_additional_text": {
"message": "Nepřidávejte řádek předmětu do odpovědi."
},
"reply_same_lang": {
"message": "Odpovězte ve stejném jazyce."
},
"sign_msg_as": {
"message": "Podepište zprávu jako"
},
"prompt_reply_advanced_full_text": {
"message": "Odpovězte na následující e-mail \"{%selected_text%}\", s ohledem na to, že se jedná o celé vlákno e-mailů \"{%mail_html_body%}\". Odpovězte pouze potřebným textem a bez dalších komentářů nebo jiného textu."
},
"prompt_rewrite_full_text": {
"message": "Přepište následující text, aby byl zdvořilejší. Odpovězte pouze přepsaným textem a bez dalších komentářů nebo jiného textu."
},
"prompt_rewrite_formal_full_text": {
"message": "Přepište následující text, aby byl formálnější. Odpovězte pouze přepsaným textem a bez dalších komentářů nebo jiného textu."
},
"prompt_classify_full_text": {
"message": "Klasifikujte následující text z hlediska zdvořilosti, vřelosti, formálnosti, asertivity, urážlivosti a uveďte procento pro každou kategorii. Odpovězte pouze kategorií a skóre bez dalších komentářů nebo jiného textu."
},
"prompt_summarize_this_full_text": {
"message": "Shrňte následující e-mail do seznamu s odrážkami."
},
"prompt_translate_this_full_text": {
"message": "Přeložte následující e-mail do"
},
"prompt_this_full_text": {
"message": "Odpovězte pouze potřebným textem a bez dalších komentářů nebo jiného textu."
},
"prompt_add_tags": {
"message": "Přidat štitky k tomuto e-mailu"
},
"prefs_OptionText_add_tags_Info": {
"message": "Pokud je zaškrtnuto, do menu bude přidána položka pro aplikaci štítků na e-maily."
},
"placeholder_tags_current_email": {
"message": "Štitky e-mailu"
},
"placeholder_tags_full_list": {
"message": "Existující štitky"
},
"prefs_OptionText_add_tags_hide_exclusions": {
"message": "Skrýt vyloučené štitky"
},
"prefs_OptionText_add_tags_hide_exclusions_Info": {
"message": "Pokud je zaškrtnuto, štitky, které jsou přítomny v seznamu vyloučení, budou skryty v potvrzovacím dialogu."
},
"prompt_add_tags_full_text": {
"message": "Analyzuj následující text e-mailu a vygeneruj seznam štítků oddělených čárkou, které shrnují jeho obsah. Použij témata, klíčová témata a relevantní deskriptory jako štitky. Zajisti, aby štitky byly stručné a relevantní k obsahu e-mailu.\nText e-mailu: {%mail_text_body%}\nPro kontext zvaž následující podrobnosti:\n- Odesílatel: {%author%}\n- Příjemci: {%recipients%}\n- Seznam kopií: {%cc_list%}\n- Předmět e-mailu: {%mail_subject%}\nZalož své štitky na textu a kontextu e-mailu, ignoruj zbytečné informace nebo triviální detaily. Výstup by měl být pouze seznam štítků oddělených čárkou bez jakéhokoli dalšího komentáře nebo textu."
},
"prefs_OptionText_add_tags_maxnum": {
"message": "Maximální počet štítků"
},
"prompt_add_tags_maxnum": {
"message": "Omezit počet štítků na"
},
"prefs_OptionText_add_tags_maxnum_Info": {
"message": "Maximální počet štítků navržených AI. Nastavte na 0, pokud nechcete omezit počet štítků."
},
"prefs_OptionText_btnManageTagsInfo": {
"message": "Spravovat nastavení štítků"
},
"AddTags_info_default": {
"message": "Na této stránce můžete upravit výchozí výzvu použitou k přidání štítků k e-mailům a spravovat seznam vyloučení."
},
"AddTags_PageTitle": {
"message": "Spravovat nastavení štítků"
},
"prompt_get_calendar_event_full_text": {
"message": "Z následujícího textu extrahuj všechny relevantní podrobnosti potřebné k vygenerování události kalendáře. Extrahované informace by měly zahrnovat:\n- Název události\n- Datum a čas zahájení (včetně časového pásma, pokud je uvedeno)\n- Datum a čas ukončení (včetně časového pásma, pokud je uvedeno)\n- Celý den (pokud je zmíněn)\n- Účastníci\nZajisti, aby byla data formátována jasně a konzistentně, aby je bylo možné přímo použít k vytvoření události kalendáře.\nPokud existují relativní časové odkazy, vezmi v úvahu, že datum a čas e-mailu jsou \"{%mail_datetime%}\". Vypočítej datum a čas zahájení na základě tohoto odkazu. Pokud jsou vypočítané datum a čas zahájení dřívější než \"{%current_datetime%}\", přepočti datum a čas zahájení pomocí \"{%current_datetime%}\" jako základu.\nPokud není zadána doba trvání, nastav ji na jednu hodinu.\nToto jsou účastníci: {%author%}, {%recipients%}, {%cc_list%}. Pokud je přítomna, nezahrnuj mou adresu: {%account_email_address%}.\nPokud nejsi schopen získat jednu nebo více požadovaných informací, odpověz prázdným řetězcem.\nVygeneruj odpověď pouze ve formátu JSON. Nezahrnuj žádný další text ani vysvětlení; poskytni pouze JSON. Zde je formát, který se má použít:\n{\n\"startDate\": \"YYYYMMDDTHHMMSS\",\n\"endDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"Zde je souhrn události kalendáře\",\n\"forceAllDay\": false,\n\"attendees\": [attendee1@example.com,attendee2@example.com,attendee3@example.com]\n}\nZde je text:\"{%selected_text%}\""
},
"prefs_OptionText_get_calendar_event": {
"message": "Přidat novou událost do kalendáře z vybraného textu"
},
"prefs_OptionText_btnManageCalendarEventInfo": {
"message": "Spravovat nastavení událostí kalendáře"
},
"GetCalendarEvent_PageTitle": {
"message": "Spravovat nastavení událostí kalendáře"
},
"GetCalendarEvent_info_default": {
"message": "Na této stránce můžete upravit výchozí výzvu použitou k získání události kalendáře z vybraného textu."
},
"GetCalendarEvent_prompt_text_title": {
"message": "Aktuální text výzvy"
},
"prefs_OptionText_GetCalendarEvent_infoline2": {
"message": "Výzvu můžete změnit, jak si přejete, ale odpověď přijatá od AI musí být ve formátu JSON, jak je uvedeno ve výchozí výzvě!"
},
"prefs_OptionText_get_calendar_event_Sparks_not_present": {
"message": "Chcete-li používat funkci události kalendáře, nainstalujte si doplněk ThunderAI Sparks."
},
"prefs_OptionText_download_now": {
"message": "Stáhnout ThunderAI Sparks nyní!"
},
"placeholder_mail_datetime": {
"message": "Datum a čas e-mailu"
},
"placeholder_current_datetime": {
"message": "Aktuální datum a čas"
},
"calendar_getting_data_error": {
"message": "Chyba při získávání dat události kalendáře"
},
"calendar_opening_dialog_error": {
"message": "Chyba při otevírání dialogu události kalendáře"
},
"sparks_not_installed": {
"message": "ThunderAI Sparks není nainstalován!"
},
"prefs_OptionText_add_tags_auto": {
"message": "Přidávat štítky automaticky"
},
"prefs_OptionText_add_tags_auto_Info": {
"message": "Pokud je zaškrtnuto, AI automaticky přidá štítky k nově přijatým e-mailům."
},
"prefs_OptionText_add_tags_auto_force_existing": {
"message": "Vynutit existující štítky při automatickém označování"
},
"prompt_spamfilter_full_text": {
"message": "Analyzuj následující e-mail a urči, zda se jedná o spam či nikoli. Zvaž faktory, jako jsou podezřelá klíčová slova, nadměrné propagační výrazy, zavádějící řádky předmětu, žádosti o osobní informace a neobvyklé adresy odesílatele.\nZadej hodnotu od 0 (není spam) do 100 (spam) a vysvětlení o maximálně 10 slovech. \nVygeneruj odpověď pouze ve formátu JSON. Neuváděj žádný další text nebo vysvětlení; uveď pouze JSON. Zde je formát, který se má použít:\n{\n\"spamValue\": <celé číslo od 0 do 100>,\n\"explanation\": \"Stručné vysvětlení vašeho zdůvodnění\",\n}\nZde jsou informace o e-mailu:\nOdesílatel: \"{%author%}\"\nPředmět: \"{%mail_subject%}\"\nText HTML: \"{%mail_html_body%}\""
},
"context_menu_mzta-add-tags": {
"message": "Přidat štítky"
},
"context_menu_mzta-spamfilter": {
"message": "Analýza spamu"
},
"prefs_OptionText_add_tags_context_menu": {
"message": "Zobrazit v nabídce položku „Přidat štítky“"
},
"prefs_OptionText_spamfilter_context_menu": {
"message": "Zobrazit v nabídce položku „Analýza spamu“"
},
"prefs_OptionText_spamfilter_context_menu_Info": {
"message": "Po zaškrtnutí bude po kliknutí pravým tlačítkem na e-mail v seznamu zpráv v kontextové nabídce zobrazena položka „Analýza spamu“."
},
"prefs_OptionText_add_tags_context_menu_Info": {
"message": "Po zaškrtnutí bude po kliknutí pravým tlačítkem na e-mail v seznamu zpráv v kontextové nabídce zobrazena položka „Přidat štítky“."
},
"get_calendar_event_prompt_prefs_title": {
"message": "Možnosti události kalendáře"
},
"prefs_OptionText_calendar_enforce_timezone": {
"message": "Vynutit zvolené časové pásmo"
},
"Select_your_timezone": {
"message": "Vyberte své časové pásmo"
},
"prefs_OptionText_calendar_enforce_timezone_Info": {
"message": "Pokud je zaškrtnuto, bude pro události kalendáře vynuceno zvolené časové pásmo."
},
"noActiveCalendar": {
"message": "Nenalezen žádný aktivní kalendář!"
}
}

View file

@ -652,7 +652,7 @@
"message": "Optionen zum Hinzufügen von Tags"
},
"prefs_SurveyLinkText": {
"message": "Teilen Sie Ihr Feedback und helfen Sie uns, ThunderAI zu verbessern!"
"message": "Teilen Sie Ihr Feedback und helfen Sie, ThunderAI zu verbessern!"
},
"prefs_SurveyLinkText2": {
"message": "Klicken Sie hier, es dauert nur eine Minute!"
@ -721,7 +721,7 @@
"message": "Ein neues Kalenderevent hinzufügen"
},
"prompt_get_calendar_event_full_text": {
"message": "Extrahieren Sie alle relevanten Details, die erforderlich sind, um ein Kalenderevent aus dem folgenden Text zu erstellen. Die extrahierten Informationen sollten Folgendes enthalten:\n- Ereignistitel\n- Startdatum und -uhrzeit (einschließlich Zeitzone, falls angegeben)\n- Enddatum und -uhrzeit (einschließlich Zeitzone, falls angegeben)\n- Ganztägig (falls erwähnt)\nStellen Sie sicher, dass die Daten klar und konsistent formatiert sind, sodass sie direkt für die Erstellung eines Kalenderevents verwendet werden können.\nFalls relative Zeitangaben enthalten sind, beachten Sie, dass Datum und Uhrzeit der E-Mail \"{%mail_datetime%}\" sind. Berechnen Sie das Startdatum und die Startzeit basierend auf diesem Bezugspunkt. Falls das berechnete Startdatum und die Startzeit vor \"{%current_datetime%}\" liegen, berechnen Sie Startdatum und -zeit erneut, wobei Sie \"{%current_datetime%}\" als Grundlage verwenden.\nFalls keine Dauer angegeben ist, setzen Sie sie auf eine Stunde.\nFalls Sie eine oder mehrere der erforderlichen Informationen nicht erhalten können, antworten Sie mit einem leeren String.\nErstellen Sie eine Antwort ausschließlich im JSON-Format. Fügen Sie keinen zusätzlichen Text oder Erklärungen hinzu; geben Sie nur das JSON an. Verwenden Sie folgendes Format:\n{\n \"startDate\": \"YYYYMMDDTHHMMSS\",\n \"endDate\": \"YYYYMMDDTHHMMSS\",\n \"summary\": \"Zusammenfassung des Kalenderevents hier\",\n \"forceAllDay\": false\n}\nHier ist der Text: \"{%selected_text%}\""
"message": "Extrahieren Sie alle relevanten Details, die erforderlich sind, um ein Kalenderevent aus dem folgenden Text zu erstellen. Die extrahierten Informationen sollten Folgendes enthalten:\n- Ereignistitel\n- Startdatum und -uhrzeit (einschließlich Zeitzone, falls angegeben)\n- Enddatum und -uhrzeit (einschließlich Zeitzone, falls angegeben)\n- Ganztägig (falls erwähnt)\n- Teilnehmer\nStellen Sie sicher, dass die Daten klar und konsistent formatiert sind, sodass sie direkt für die Erstellung eines Kalenderevents verwendet werden können.\nFalls relative Zeitangaben enthalten sind, beachten Sie, dass Datum und Uhrzeit der E-Mail \"{%mail_datetime%}\" sind. Berechnen Sie das Startdatum und die Startzeit basierend auf diesem Bezugspunkt. Falls das berechnete Startdatum und die Startzeit vor \"{%current_datetime%}\" liegen, berechnen Sie Startdatum und -zeit erneut, wobei Sie \"{%current_datetime%}\" als Grundlage verwenden.\nFalls keine Dauer angegeben ist, setzen Sie sie auf eine Stunde.\nDas sind die Teilnehmer: {%author%}, {%recipients%}, {%cc_list%}. Falls vorhanden, meine Adresse ausschließen: {%account_email_address%}.\nFalls Sie eine oder mehrere der erforderlichen Informationen nicht erhalten können, antworten Sie mit einem leeren String.\nErstellen Sie eine Antwort ausschließlich im JSON-Format. Fügen Sie keinen zusätzlichen Text oder Erklärungen hinzu; geben Sie nur das JSON an. Verwenden Sie folgendes Format:\n{\n \"startDate\": \"YYYYMMDDTHHMMSS\",\n \"endDate\": \"YYYYMMDDTHHMMSS\",\n \"summary\": \"Zusammenfassung des Kalenderevents hier\",\n \"forceAllDay\": false\n\"attendees\": [attendee1@example.com,attendee2@example.com,attendee3@example.com]\n}\nHier ist der Text: \"{%selected_text%}\""
},
"prefs_OptionText_get_calendar_event": {
"message": "Ein neues Kalenderevent aus ausgewähltem Text hinzufügen"
@ -866,5 +866,74 @@
},
"prefs_OptionText_openai_comp_info_remote": {
"message": "Hier können Sie auch die Adresse eines entfernten Servers eingeben."
},
"prefs_OptionText_add_tags_context_menu_Info": {
"message": "Wenn aktiviert, wird beim Rechtsklick auf eine E-Mail in der Nachrichtenliste der Eintrag \"Tags hinzufügen\" angezeigt."
},
"prefs_OptionText_spamfilter_context_menu_Info": {
"message": "Wenn aktiviert, wird beim Rechtsklick auf eine E-Mail in der Nachrichtenliste der Eintrag \"Auf Spam analysieren\" angezeigt."
},
"prefs_OptionText_calendar_enforce_timezone": {
"message": "Erzwinge die angegebene Zeitzone"
},
"context_menu_mzta-add-tags": {
"message": "Tags hinzufügen"
},
"context_menu_mzta-spamfilter": {
"message": "Auf Spam analysieren"
},
"noActiveCalendar": {
"message": "Kein bearbeitbarer Kalender gefunden!"
},
"get_calendar_event_prompt_prefs_title": {
"message": "Kalenderereignisoptionen"
},
"Select_your_timezone": {
"message": "Wähle deine Zeitzone"
},
"prefs_OptionText_calendar_enforce_timezone_Info": {
"message": "Wenn aktiviert, wird die angegebene Zeitzone für die Kalenderereignisse erzwungen."
},
"prefs_OptionText_add_tags_context_menu": {
"message": "\"Tags hinzufügen\" im Kontextmenü anzeigen"
},
"prefs_OptionText_spamfilter_context_menu": {
"message": "\"Auf Spam analysieren\" im Kontextmenü anzeigen"
},
"apiwebchat_you": {
"message": "Du"
},
"apiwebchat_info": {
"message": "Information"
},
"apiwebchat_error": {
"message": "Fehler"
},
"apiwebchat_stopping": {
"message": "Wird gestoppt"
},
"apiwebchat_receiving_data": {
"message": "Empfange Daten"
},
"customPrompts_form_label_use_diff_viewer": {
"message": "Aktiviere den Unterschiedsbetrachter"
},
"btn_show_differences": {
"message": "Unterschiede anzeigen"
},
"apiwebchat_use_this_answer": {
"message": "Diese Antwort verwenden"
},
"chatgpt_win_diff_title": {
"message": "Unterschiede zwischen dem Originaltext und dem geänderten Text"
},
"placeholder_folder_name": {
"message": "Ordnername"
},
"placeholder_folder_path": {
"message": "Ordnerpfad"
},
"placeholder_account_email_address": {
"message": "E-Mail-Adresse des Kontos"
}
}

View file

@ -1,6 +1,6 @@
{
"extensionDescription": {
"message": "Use ChatGPT, Goolge Gemini or Ollama to enhance you emails!",
"message": "Use ChatGPT, Goolge Gemini or Ollama to enhance your emails!",
"description": "Description of the extension."
},
"menu_title": {
@ -131,6 +131,10 @@
"message": "Enabled",
"description": ""
},
"customPrompts_form_label_use_diff_viewer": {
"message": "Enable the diff viewer",
"description": ""
},
"customPrompts_form_required_fields": {
"message": "Required fields",
"description": ""
@ -611,6 +615,14 @@
"message": "Mail subject",
"description": ""
},
"placeholder_folder_name": {
"message": "Folder name",
"description": ""
},
"placeholder_folder_path": {
"message": "Folder path",
"description": ""
},
"placeholder_selected_text": {
"message": "Selected text",
"description": ""
@ -635,6 +647,10 @@
"message": "Author",
"description": ""
},
"placeholder_account_email_address": {
"message": "Account email address",
"description": ""
},
"prefs_OptionText_placeholders_use_default_value": {
"message": "Placeholders: use default value",
"description": ""
@ -872,7 +888,7 @@
"description": ""
},
"prefs_SurveyLinkText": {
"message": "Share your feedback and help us improve ThunderAI!",
"message": "Share your feedback and help improve ThunderAI!",
"description": ""
},
"prefs_SurveyLinkText2": {
@ -964,7 +980,7 @@
"description": ""
},
"prompt_get_calendar_event_full_text": {
"message": "Extract all relevant details required to generate a calendar event from the following text. The extracted information should include:\n- Event Title\n- Start Date and Time (including timezone, if specified)\n- End Date and Time (including timezone, if specified)\n- Full day (if mentioned)\nEnsure the data is formatted clearly and consistently so that it can be directly used for creating a calendar event.\nIf there are relative time references, consider that the date and time of the email are \"{%mail_datetime%}\". Calculate the start date and time based on this reference. If the calculated start date and time are earlier than \"{%current_datetime%}\", recalculate the start date and time using \"{%current_datetime%}\" as the base.\nIf the duration is not specified, set it to one hour.\nIf you're not able to get one or more of the required information, please respond with an empty string.\nGenerate a response in JSON format only. Do not include any additional text or explanations; provide only the JSON. Here is the format to be used:\n{\n\"startDate\": \"YYYYMMDDTHHMMSS\",\n\"endDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"Calendar event summary here\",\n\"forceAllDay\": false\n}\nHere's the text:\"{%selected_text%}\"",
"message": "Extract all relevant details required to generate a calendar event from the following text. The extracted information should include:\n- Event Title\n- Start Date and Time (including timezone, if specified)\n- End Date and Time (including timezone, if specified)\n- Full day (if mentioned)\n- Attendees\nEnsure the data is formatted clearly and consistently so that it can be directly used for creating a calendar event.\nIf there are relative time references, consider that the date and time of the email are \"{%mail_datetime%}\". Calculate the start date and time based on this reference. If the calculated start date and time are earlier than \"{%current_datetime%}\", recalculate the start date and time using \"{%current_datetime%}\" as the base.\nIf the duration is not specified, set it to one hour.\nThese are the attendees: {%author%}, {%recipients%}, {%cc_list%}. If present, exclude my address: {%account_email_address%}.\nIf you're not able to get one or more of the required information, please respond with an empty string.\nGenerate a response in JSON format only. Do not include any additional text or explanations; provide only the JSON. Here is the format to be used:\n{\n\"startDate\": \"YYYYMMDDTHHMMSS\",\n\"endDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"Calendar event summary here\",\n\"forceAllDay\": false,\n\"attendees\": [attendee1@example.com,attendee2@example.com,attendee3@example.com]\n}\nHere's the text:\"{%selected_text%}\"",
"description": ""
},
"prefs_OptionText_get_calendar_event": {
@ -975,6 +991,22 @@
"message": "If checked, an item will be included in the menu to get a calendar event information from selected text.",
"description": ""
},
"get_calendar_event_prompt_prefs_title": {
"message": "Calendar Events Options",
"description": ""
},
"Select_your_timezone": {
"message": "Select your timezone",
"description": ""
},
"prefs_OptionText_calendar_enforce_timezone": {
"message": "Force the specified timezone",
"description": ""
},
"prefs_OptionText_calendar_enforce_timezone_Info": {
"message": "If checked, the specified timezone will be enforced for the calendar events.",
"description": ""
},
"prefs_OptionText_btnManageCalendarEventInfo": {
"message": "Manage calendar events settings",
"description": ""
@ -1154,5 +1186,65 @@
"spamfilter_not_moved": {
"message": "No",
"description": ""
},
"context_menu_mzta-add-tags": {
"message": "Add tags",
"description": ""
},
"context_menu_mzta-spamfilter": {
"message": "Analyze for spam",
"description": ""
},
"prefs_OptionText_add_tags_context_menu": {
"message": "Show the \"Add tags\" context menu item",
"description": ""
},
"prefs_OptionText_add_tags_context_menu_Info": {
"message": "If checked, the \"Add tags\" context menu item will be shown when right-clicking on an email in the messages list.",
"description": ""
},
"prefs_OptionText_spamfilter_context_menu": {
"message": "Show the \"Analyze for spam\" context menu item",
"description": ""
},
"prefs_OptionText_spamfilter_context_menu_Info": {
"message": "If checked, the \"Analyze for spam\" context menu item will be shown when right-clicking on an email in the messages list.",
"description": ""
},
"noActiveCalendar": {
"message": "No editable calendar found!",
"description": ""
},
"btn_show_differences": {
"message": "Show differences",
"description": ""
},
"chatgpt_win_diff_title": {
"message": "Differences between the original and the modified text",
"description": ""
},
"apiwebchat_you": {
"message": "You",
"description": ""
},
"apiwebchat_info": {
"message": "Information",
"description": ""
},
"apiwebchat_error": {
"message": "Error",
"description": ""
},
"apiwebchat_use_this_answer": {
"message": "Use this answer",
"description": ""
},
"apiwebchat_stopping": {
"message": "Stopping",
"description": ""
},
"apiwebchat_receiving_data": {
"message": "Receiving data",
"description": ""
}
}

View file

@ -652,7 +652,7 @@
"message": "Options dajout de tags"
},
"prefs_SurveyLinkText": {
"message": "Partagez vos commentaires et aidez-nous à améliorer ThunderAI !"
"message": "Partagez vos commentaires et aidez à améliorer ThunderAI!"
},
"prefs_SurveyLinkText2": {
"message": "Cliquez ici, cela ne prend qu'une minute !"
@ -721,7 +721,7 @@
"message": "Ajouter un nouvel événement au calendrier"
},
"prompt_get_calendar_event_full_text": {
"message": "Extrayez tous les détails pertinents nécessaires pour générer un événement de calendrier à partir du texte suivant. Les informations extraites doivent inclure :\n- Titre de l'événement\n- Date et heure de début (y compris le fuseau horaire, si spécifié)\n- Date et heure de fin (y compris le fuseau horaire, si spécifié)\n- Journée entière (si mentionnée)\nAssurez-vous que les données sont formatées clairement et de manière cohérente afin qu'elles puissent être utilisées directement pour créer un événement de calendrier.\nS'il y a des références temporelles relatives, considérez que la date et l'heure de l'email sont \"{%mail_datetime%}\". Calculez la date et l'heure de début sur cette base. Si la date et l'heure de début calculées sont antérieures à \"{%current_datetime%}\", recalculez-les en utilisant \"{%current_datetime%}\" comme base.\nSi la durée n'est pas spécifiée, définissez-la sur une heure.\nSi vous n'êtes pas en mesure d'obtenir une ou plusieurs des informations requises, répondez avec une chaîne vide.\nGénérez une réponse uniquement au format JSON. N'incluez aucun texte ou explication supplémentaire; fournissez uniquement le JSON. Voici le format à utiliser :\n{\n\"startDate\" : \"YYYYMMDDTHHMMSS\",\n\"endDate\" : \"YYYYMMDDTHHMMSS\",\n\"summary\" : \"Résumé de l'événement du calendrier ici\",\n\"forceAllDay\" : false\n}\nVoici le texte : \"{%selected_text%}\""
"message": "Extrayez tous les détails pertinents nécessaires pour générer un événement de calendrier à partir du texte suivant. Les informations extraites doivent inclure :\n- Titre de l'événement\n- Date et heure de début (y compris le fuseau horaire, si spécifié)\n- Date et heure de fin (y compris le fuseau horaire, si spécifié)\n- Journée entière (si mentionnée)\n- Participants\nAssurez-vous que les données sont formatées clairement et de manière cohérente afin qu'elles puissent être utilisées directement pour créer un événement de calendrier.\nS'il y a des références temporelles relatives, considérez que la date et l'heure de l'email sont \"{%mail_datetime%}\". Calculez la date et l'heure de début sur cette base. Si la date et l'heure de début calculées sont antérieures à \"{%current_datetime%}\", recalculez-les en utilisant \"{%current_datetime%}\" comme base.\nSi la durée n'est pas spécifiée, définissez-la sur une heure.\nVoici les participants : {%author%}, {%recipients%}, {%cc_list%}. Si elle est présente, exclure mon adresse : {%account_email_address%}.\nSi vous n'êtes pas en mesure d'obtenir une ou plusieurs des informations requises, répondez avec une chaîne vide.\nGénérez une réponse uniquement au format JSON. N'incluez aucun texte ou explication supplémentaire; fournissez uniquement le JSON. Voici le format à utiliser :\n{\n\"startDate\" : \"YYYYMMDDTHHMMSS\",\n\"endDate\" : \"YYYYMMDDTHHMMSS\",\n\"summary\" : \"Résumé de l'événement du calendrier ici\",\n\"forceAllDay\" : false\n\"attendees\" : [attendee1@example.com,attendee2@example.com,attendee3@example.com]\n}\nVoici le texte : \"{%selected_text%}\""
},
"prefs_OptionText_get_calendar_event": {
"message": "Ajouter un nouvel événement au calendrier à partir du texte sélectionné"
@ -866,5 +866,74 @@
},
"prompt_spamfilter_full_text": {
"message": "Analysez l'e-mail suivant et déterminez s'il s'agit d'un spam ou non. Prenez en compte des facteurs tels que des mots-clés suspects, un langage promotionnel excessif, des lignes d'objet trompeuses, des demandes d'informations personnelles et des adresses d'expéditeurs inhabituelles.\nFournissez une valeur de 0 (non spam) à 100 (spam) et une explication de 10 mots maximum.\nGénérez une réponse uniquement au format JSON. N'incluez aucun texte ou explication supplémentaire; fournissez uniquement le JSON. Voici le format à utiliser :\n{\n\"spamValue\" : <entier de 0 à 100>,\n\"explanation\" : \"Brève explication de votre raisonnement\",\n}\nVoici les informations de l'e-mail :\nExpéditeur : \"{%author%}\"\nObjet : \"{%mail_subject%}\"\nCorps HTML : \"{%mail_html_body%}\""
},
"context_menu_mzta-add-tags": {
"message": "Ajouter des étiquettes"
},
"prefs_OptionText_spamfilter_context_menu": {
"message": "Afficher l'option \"Analyser comme spam\" dans le menu contextuel"
},
"prefs_OptionText_spamfilter_context_menu_Info": {
"message": "Si coché, l'option \"Analyser comme spam\" apparaîtra lors dun clic droit sur un e-mail dans la liste des messages."
},
"noActiveCalendar": {
"message": "Aucun calendrier modifiable trouvé!"
},
"get_calendar_event_prompt_prefs_title": {
"message": "Options des événements du calendrier"
},
"apiwebchat_you": {
"message": "Vous"
},
"prefs_OptionText_calendar_enforce_timezone_Info": {
"message": "Si coché, le fuseau horaire spécifié sera appliqué aux événements du calendrier."
},
"prefs_OptionText_calendar_enforce_timezone": {
"message": "Forcer le fuseau horaire spécifié"
},
"prefs_OptionText_add_tags_context_menu_Info": {
"message": "Si coché, l'option \"Ajouter des étiquettes\" apparaîtra lors dun clic droit sur un e-mail dans la liste des messages."
},
"chatgpt_win_diff_title": {
"message": "Différences entre le texte original et le texte modifié"
},
"apiwebchat_stopping": {
"message": "Arrêt en cours"
},
"Select_your_timezone": {
"message": "Sélectionnez votre fuseau horaire"
},
"btn_show_differences": {
"message": "Afficher les différences"
},
"apiwebchat_error": {
"message": "Erreur"
},
"prefs_OptionText_add_tags_context_menu": {
"message": "Afficher l'option \"Ajouter des étiquettes\" dans le menu contextuel"
},
"apiwebchat_use_this_answer": {
"message": "Utiliser cette réponse"
},
"apiwebchat_receiving_data": {
"message": "Réception des données"
},
"customPrompts_form_label_use_diff_viewer": {
"message": "Activer le visualiseur de différences"
},
"context_menu_mzta-spamfilter": {
"message": "Analyser comme spam"
},
"apiwebchat_info": {
"message": "Information"
},
"placeholder_folder_name": {
"message": "Nom du dossier"
},
"placeholder_folder_path": {
"message": "Chemin du dossier"
},
"placeholder_account_email_address": {
"message": "Adresse e-mail du compte"
}
}

View file

@ -721,7 +721,7 @@
"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%}\""
"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)\n- Sudionici\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.\nOvo su sudionici: {%author%}, {%recipients%}, {%cc_list%}. Ako je prisutna, isključi moju adresu: {%account_email_address%}.\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\"attendees\": [attendee1@example.com,attendee2@example.com,attendee3@example.com]\n}\nOvo je tekst:\"{%selected_text%}\""
},
"prefs_OptionText_get_calendar_event": {
"message": "Dodaj novi kalendarski događaj iz odabranog teksta"

View file

@ -652,7 +652,7 @@
"message": "Opzioni per aggiungere tag"
},
"prefs_SurveyLinkText": {
"message": "Condividi il tuo feedback e aiutaci a migliorare ThunderAI!"
"message": "Condividi il tuo feedback e aiuta a migliorare ThunderAI!"
},
"prefs_SurveyLinkText2": {
"message": "Clicca qui, ci vuole solo un minuto!"
@ -721,7 +721,7 @@
"message": "Aggiungi un nuovo evento al calendario"
},
"prompt_get_calendar_event_full_text": {
"message": "Estrai tutti i dettagli rilevanti necessari per generare un evento del calendario dal seguente testo. Le informazioni estratte devono includere:\n- Titolo dell'evento\n- Data e ora di inizio (incluso il fuso orario, se specificato)\n- Data e ora di fine (incluso il fuso orario, se specificato)\n- Giornata intera (se menzionato)\nAssicurati che i dati siano formattati in modo chiaro e coerente in modo che possano essere utilizzati direttamente per creare un evento del calendario.\nSe ci sono riferimenti temporali relativi, considera che la data e l'ora dell'email sono \"{%mail_datetime%}\". Calcola la data e l'ora di inizio in base a questo riferimento. Se la data e l'ora di inizio calcolate sono precedenti a \"{%current_datetime%}\", ricalcolale utilizzando \"{%current_datetime%}\" come base.\nSe la durata non è specificata, impostala a un'ora.\nSe non riesci a ottenere una o più delle informazioni richieste, rispondi con una stringa vuota.\nGenera una risposta solo in formato JSON. Non includere testo o spiegazioni aggiuntive; fornisci solo il JSON. Ecco il formato da utilizzare:\n{\n\"startDate\": \"YYYYMMDDTHHMMSS\",\n\"endDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"Riassunto evento calendario qui\",\n\"forceAllDay\": false\n}\nEcco il testo: \"{%selected_text%}\""
"message": "Estrai tutti i dettagli rilevanti necessari per generare un evento del calendario dal seguente testo. Le informazioni estratte devono includere:\n- Titolo dell'evento\n- Data e ora di inizio (incluso il fuso orario, se specificato)\n- Data e ora di fine (incluso il fuso orario, se specificato)\n- Giornata intera (se menzionato)\n- I partecipanti\nAssicurati che i dati siano formattati in modo chiaro e coerente in modo che possano essere utilizzati direttamente per creare un evento del calendario.\nSe ci sono riferimenti temporali relativi, considera che la data e l'ora dell'email sono \"{%mail_datetime%}\". Calcola la data e l'ora di inizio in base a questo riferimento. Se la data e l'ora di inizio calcolate sono precedenti a \"{%current_datetime%}\", ricalcolale utilizzando \"{%current_datetime%}\" come base.\nSe la durata non è specificata, impostala a un'ora.\nQuesti sono i partecipanti: {%author%}, {%recipients%}, {%cc_list%}. Se presente, escludi il mio indirizzo: {%account_email_address%}.\nSe non riesci a ottenere una o più delle informazioni richieste, rispondi con una stringa vuota.\nGenera una risposta solo in formato JSON. Non includere testo o spiegazioni aggiuntive; fornisci solo il JSON. Ecco il formato da utilizzare:\n{\n\"startDate\": \"YYYYMMDDTHHMMSS\",\n\"endDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"Riassunto evento calendario qui\",\n\"forceAllDay\": false\n\"attendees\": [attendee1@example.com,attendee2@example.com,attendee3@example.com]\n}\nEcco il testo: \"{%selected_text%}\""
},
"prefs_OptionText_get_calendar_event": {
"message": "Aggiungi un nuovo evento al calendario dal testo selezionato"
@ -866,5 +866,77 @@
},
"spamfilter_threshold_zero": {
"message": "La soglia di spam è zero! Considererai tutte le email come spam!"
},
"placeholder_folder_name": {
"message": "Nome cartella"
},
"placeholder_folder_path": {
"message": "Percorso cartella"
},
"placeholder_account_email_address": {
"message": "Indirizzo email dell'account"
},
"context_menu_mzta-spamfilter": {
"message": "Analizza come spam"
},
"context_menu_mzta-add-tags": {
"message": "Aggiungi etichette"
},
"noActiveCalendar": {
"message": "Non è stato trovato alcun calendario modificabile!"
},
"get_calendar_event_prompt_prefs_title": {
"message": "Opzioni Eventi del Calendario"
},
"btn_show_differences": {
"message": "Mostra le differenze"
},
"apiwebchat_show_differences": {
"message": "Mostra le differenze"
},
"apiwebchat_error": {
"message": "Errore"
},
"apiwebchat_you": {
"message": "Tu"
},
"chatgpt_win_diff_title": {
"message": "Differenze tra il testo originale e quello modificato"
},
"prefs_OptionText_calendar_enforce_timezone": {
"message": "Forza il fuso orario specificato"
},
"prefs_OptionText_add_tags_context_menu_Info": {
"message": "Se selezionato, la voce \"Aggiungi etichette\" verrà mostrata facendo clic con il pulsante destro del mouse su un'email nell'elenco dei messaggi."
},
"apiwebchat_use_this_answer": {
"message": "Usa questa risposta"
},
"prefs_OptionText_spamfilter_context_menu_Info": {
"message": "Se selezionato, la voce \"Analizza come spam\" verrà mostrata facendo clic con il pulsante destro del mouse su un'email nell'elenco dei messaggi."
},
"prefs_OptionText_spamfilter_context_menu": {
"message": "Mostra la voce \"Analizza come spam\" nel menu contestuale"
},
"prefs_OptionText_add_tags_context_menu": {
"message": "Mostra la voce \"Aggiungi etichette\" nel menu contestuale"
},
"apiwebchat_info": {
"message": "Informazioni"
},
"Select_your_timezone": {
"message": "Seleziona il tuo fuso orario"
},
"prefs_OptionText_calendar_enforce_timezone_Info": {
"message": "Se selezionato, il fuso orario specificato verrà applicato agli eventi del calendario."
},
"customPrompts_form_label_use_diff_viewer": {
"message": "Abilita il visualizzatore delle differenze"
},
"apiwebchat_stopping": {
"message": "Interruzione in corso"
},
"apiwebchat_receiving_data": {
"message": "Ricezione dati"
}
}

View file

@ -712,7 +712,7 @@
"message": "Dodaj nowe wydarzenie w kalendarzu"
},
"prompt_get_calendar_event_full_text": {
"message": "Wyodrębnij wszystkie istotne szczegóły wymagane do wygenerowania wydarzenia w kalendarzu z poniższego tekstu. Wyodrębnione informacje powinny obejmować:\n- Tytuł wydarzenia\n- Datę i godzinę rozpoczęcia (w tym strefę czasową, jeśli została określona)\n- Datę i godzinę zakończenia (w tym strefę czasową, jeśli została określona)\n- Cały dzień (jeśli jest podany)\nUpewnij się, że dane są sformatowane w sposób jasny i spójny, tak aby można go bezpośrednio wykorzystać do utworzenia wydarzenia w kalendarzu.\nJeśli istnieją odniesienia do czasu względnego, pamiętaj, że data i godzina wysłania wiadomości e-mail to „{%mail_datetime%}”. Oblicz datę i godzinę rozpoczęcia na podstawie tego odniesienia. Jeśli obliczona data i godzina rozpoczęcia są wcześniejsze niż „{%current_datetime%}”, oblicz ponownie datę i godzinę rozpoczęcia, stosując jako podstawę „{%current_datetime%}”.\nJeśli czas trwania nie jest określony, ustaw go na jedną godzinę.\nJeśli nie możesz uzyskać co najmniej jednej z wymaganych informacji, w odpowiedzi wpisz pusty ciąg znaków.\nWygeneruj odpowiedź tylko w formacie JSON. Nie dołączaj żadnego dodatkowego tekstu ani wyjaśnień; podaj tylko JSON. Oto format, którego należy użyć:\n{\n\"startDate\": \"YYYYMMDDTHHMMSS\",\n\"endDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"Tutaj podsumowanie wydarzenia w kalendarzu\",\n\"forceAllDay\": false\n}\nOto tekst:\"{%selected_text %}\""
"message": "Wyodrębnij wszystkie istotne szczegóły wymagane do wygenerowania wydarzenia w kalendarzu z poniższego tekstu. Wyodrębnione informacje powinny obejmować:\n- Tytuł wydarzenia\n- Datę i godzinę rozpoczęcia (w tym strefę czasową, jeśli została określona)\n- Datę i godzinę zakończenia (w tym strefę czasową, jeśli została określona)\n- Cały dzień (jeśli jest podany)\n- Uczestnicy\nUpewnij się, że dane są sformatowane w sposób jasny i spójny, tak aby można go bezpośrednio wykorzystać do utworzenia wydarzenia w kalendarzu.\nJeśli istnieją odniesienia do czasu względnego, pamiętaj, że data i godzina wysłania wiadomości e-mail to „{%mail_datetime%}”. Oblicz datę i godzinę rozpoczęcia na podstawie tego odniesienia. Jeśli obliczona data i godzina rozpoczęcia są wcześniejsze niż „{%current_datetime%}”, oblicz ponownie datę i godzinę rozpoczęcia, stosując jako podstawę „{%current_datetime%}”.\nJeśli czas trwania nie jest określony, ustaw go na jedną godzinę.\nOto uczestnicy: {%author%}, {%recipients%}, {%cc_list%}. Jeśli jest obecny, wyklucz mój adres: {%account_email_address%}.\nJeśli nie możesz uzyskać co najmniej jednej z wymaganych informacji, w odpowiedzi wpisz pusty ciąg znaków.\nWygeneruj odpowiedź tylko w formacie JSON. Nie dołączaj żadnego dodatkowego tekstu ani wyjaśnień; podaj tylko JSON. Oto format, którego należy użyć:\n{\n\"startDate\": \"YYYYMMDDTHHMMSS\",\n\"endDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"Tutaj podsumowanie wydarzenia w kalendarzu\",\n\"forceAllDay\": false\n\"attendees\": [attendee1@example.com,attendee2@example.com,attendee3@example.com]\n}\nOto tekst:\"{%selected_text %}\""
},
"prefs_OptionText_get_calendar_event": {
"message": "Dodaj nowe wydarzenie w kalendarzu z zaznaczonego tekstu"

View file

@ -721,7 +721,7 @@
"message": "Adicionar um novo evento ao calendário"
},
"prompt_get_calendar_event_full_text": {
"message": "Extraia todos os detalhes relevantes necessários para gerar um evento de calendário a partir do texto a seguir. As informações extraídas devem incluir:\n- Título do evento\n- Data e hora de início (incluindo fuso horário, se especificado)\n- Data e hora de término (incluindo fuso horário, se especificado)\n- Dia inteiro (se mencionado)\nCertifique-se de que os dados estejam formatados de maneira clara e consistente para que possam ser usados diretamente para criar um evento de calendário.\nSe houver referências de tempo relativas, considere que a data e a hora do e-mail são \"{%mail_datetime%}\". Calcule a data e a hora de início com base nessa referência. Se a data e a hora de início calculadas forem anteriores a \"{%current_datetime%}\", recalcule a data e a hora de início usando \"{%current_datetime%}\" como base.\nSe a duração não for especificada, defina-a como uma hora.\nSe você não conseguir obter uma ou mais informações necessárias, responda com uma string vazia.\nGere uma resposta apenas no formato JSON. Não inclua texto ou explicações adicionais; forneça apenas o JSON. Aqui está o formato a ser usado:\n{\n\"startDate\": \"YYYYMMDDTHHMMSS\",\n\"endDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"Resumo do evento do calendário aqui\",\n\"forceAllDay\": false\n}\nAqui está o texto: \"{%selected_text%}\""
"message": "Extraia todos os detalhes relevantes necessários para gerar um evento de calendário a partir do texto a seguir. As informações extraídas devem incluir:\n- Título do evento\n- Data e hora de início (incluindo fuso horário, se especificado)\n- Data e hora de término (incluindo fuso horário, se especificado)\n- Dia inteiro (se mencionado)\n- Participantes\nCertifique-se de que os dados estejam formatados de maneira clara e consistente para que possam ser usados diretamente para criar um evento de calendário.\nSe houver referências de tempo relativas, considere que a data e a hora do e-mail são \"{%mail_datetime%}\". Calcule a data e a hora de início com base nessa referência. Se a data e a hora de início calculadas forem anteriores a \"{%current_datetime%}\", recalcule a data e a hora de início usando \"{%current_datetime%}\" como base.\nSe a duração não for especificada, defina-a como uma hora.\nEstes são os participantes: {%author%}, {%recipients%}, {%cc_list%}. Se estiver presente, exclua meu endereço: {%account_email_address%}.\nSe você não conseguir obter uma ou mais informações necessárias, responda com uma string vazia.\nGere uma resposta apenas no formato JSON. Não inclua texto ou explicações adicionais; forneça apenas o JSON. Aqui está o formato a ser usado:\n{\n\"startDate\": \"YYYYMMDDTHHMMSS\",\n\"endDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"Resumo do evento do calendário aqui\",\n\"forceAllDay\": false\n\"attendees\": [attendee1@example.com,attendee2@example.com,attendee3@example.com]\n}\nAqui está o texto: \"{%selected_text%}\""
},
"prefs_OptionText_get_calendar_event": {
"message": "Adicionar um novo evento ao calendário a partir do texto selecionado"

View file

@ -0,0 +1,932 @@
{
"prompt_summarize_this": {
"message": "总结一下这个"
},
"prompt_reply": {
"message": "回复此电子邮件"
},
"customPrompts_btnOK": {
"message": "OK"
},
"customPrompts_close_button": {
"message": "关闭按钮"
},
"prompt_reply_advanced": {
"message": "回复此主题"
},
"customPrompts_form_label_Text": {
"message": "提示文字"
},
"customPrompts_filtering_prompts": {
"message": "过滤提示词..."
},
"customPrompts_btnAddNewCommit": {
"message": "添加提示词"
},
"customPrompts_reloading_menus": {
"message": "正在重新加载菜单..."
},
"customPrompts_form_label_ID": {
"message": "ID"
},
"customPrompts_form_label_need_selected": {
"message": "需要选择文本"
},
"customPrompts_form_label_Action": {
"message": "操作"
},
"customPrompts_form_label_need_signature": {
"message": "始终添加签名"
},
"customPrompts_btnNew": {
"message": "新增"
},
"chatgpt_win_job_completed": {
"message": "完成了!"
},
"customPrompts_btnSaveAll": {
"message": "保存所有变动"
},
"extensionDescription": {
"message": "使用ChatGPT、Google Gemini 或Ollama 来增强你的邮件!"
},
"menu_title": {
"message": "AI"
},
"prompt_translate_this": {
"message": "翻译这个"
},
"prompt_this": {
"message": "提示这个"
},
"prompt_selection_needed": {
"message": "要继续,请先选择一些文本!"
},
"customPrompts_managePrompts": {
"message": "管理提示词"
},
"customPrompts_managePrompts_help": {
"message": "更多信息"
},
"customPrompts_managePrompts_info_default": {
"message": "默认的提示词无法直接编辑。你可以先禁用它们,然后将提示文本复制并粘贴到新提示中,从而创建修改后的版本。"
},
"customPrompts_managePrompts_info_default_2": {
"message": "你可以导入和导出提示。具有相同ID的现有提示将会被覆盖。具有新ID的提示会被添加。"
},
"customPrompts_btnDelete": {
"message": "删除"
},
"customPrompts_btnDelete_confirmText": {
"message": "您确实要删除此项吗?"
},
"backToOptionsText": {
"message": "选项"
},
"prefs_OptionText_placeholders_use_default_value_info": {
"message": "如果选中,则当未提供任何值时,占位符将用默认值填充。否则,占位符将保留在原处。"
},
"prefs_OptionText_max_prompt_length": {
"message": "最大提示词长度"
},
"prefs_OptionText_max_prompt_length_Info": {
"message": "这是提示中可以使用的最大字符数。否则,将显示错误消息。该值在 ChatGPT Web 界面中不可编辑。"
},
"prefs_OptionText_chatgpt_web_model": {
"message": "ChatGPT Web 模型"
},
"prefs_OptionText_chatgpt_web_model_info": {
"message": "这是将为 ChatGPT Web 界面强制使用的模型。如果未指定或提供了不正确的模型ChatGPT 将在网页上设置默认模型。"
},
"prefs_OptionText_chatgpt_web_tempchat": {
"message": "ChatGPT Web 临时聊天"
},
"prefs_OptionText_chatgpt_web_tempchat_info": {
"message": "如果勾选此项,将在 ChatGPT Web 界面中使用临时聊天功能。"
},
"chatgpt_btn_model": {
"message": "使用当前模型"
},
"SendingPrompt": {
"message": "正在发送提示词..."
},
"AllowedValues": {
"message": "允许的值"
},
"prefs_OptionText_btnManagePrompts_infoline": {
"message": "您可以使用额外的数据占位符。"
},
"prefs_OptionText_btnManagePrompts_infoline2": {
"message": "您可以根据需要更改提示,但从 AI 收到的响应必须是以逗号分隔的标签列表!"
},
"prefs_OptionText_openai_comp_use_v1": {
"message": "保持“v1”兼容性"
},
"prompt_reply_full_text": {
"message": "请提供您希望回复的邮件内容,我将根据要求仅提供所需的回复文本,不添加任何额外评论或其他文字。"
},
"prompt_reply_additional_text": {
"message": "不要在回复中添加主题行。"
},
"addtags_exclude_tag": {
"message": "排除标签"
},
"spamfilter_no_reports": {
"message": "尚未筛选出垃圾邮件。此处您只能找到当前会话的最近 100 条垃圾邮件报告的列表。"
},
"SpamReport_Title": {
"message": "垃圾邮件过滤报告"
},
"spamfilter_not_moved": {
"message": "否"
},
"spamfilter_moved": {
"message": "是"
},
"prompt_rewrite_polite": {
"message": "礼貌地重写"
},
"prompt_classify": {
"message": "分类"
},
"prompt_rewrite_formal": {
"message": "正式地重写"
},
"customPrompts_form_label_ID_rules": {
"message": "必须是唯一的、小写且没有空格"
},
"customPrompts_saving_default_prompts": {
"message": "正在保存默认提示词..."
},
"customPrompts_reindexing_list": {
"message": "重新索引列表..."
},
"customPrompts_form_label_enabled": {
"message": "启用"
},
"customPrompts_start_saving": {
"message": "正在保存提示词..."
},
"customPrompts_managePrompts_info_default_3": {
"message": "如果一切正确,在导入完成后点击“保存所有”按钮。"
},
"customPrompts_btnEdit": {
"message": "编辑"
},
"customPrompts_saving_custom_prompts": {
"message": "正在保存自定义提示词..."
},
"customPrompts_saved": {
"message": "提示词已保存!"
},
"customPrompts_unsaved_changes": {
"message": "有未保存的更改!"
},
"customPrompts_add_to_menu_always": {
"message": "始终"
},
"customPrompts_form_label_Name": {
"message": "名称"
},
"customPrompts_form_label_need_custom_text": {
"message": "要求补充文字"
},
"customPrompts_form_required_fields": {
"message": "必填字段"
},
"customPrompts_btnCancel": {
"message": "取消"
},
"customPrompts_save_button": {
"message": "保存"
},
"customPrompts_add_to_menu": {
"message": "添加到菜单"
},
"customPrompts_add_to_menu_composing": {
"message": "撰写电子邮件"
},
"customPrompts_do_reply": {
"message": "请回复"
},
"chatgpt_btn_retry": {
"message": "重试"
},
"customPrompts_add_to_menu_reading": {
"message": "阅读电子邮件"
},
"chatgpt_win_job_completed_select": {
"message": "选择您想要使用的文本并单击按钮。"
},
"chatgpt_sendbutton_not_found_error": {
"message": "单击发送按钮提交提示词。"
},
"customPrompts_substitute_text": {
"message": "替换文本"
},
"chatgpt_win_working": {
"message": "工作正在进行中..."
},
"prompt_spamfilter": {
"message": "检测垃圾邮件"
},
"chatgpt_win_get_answer": {
"message": "使用选定的答案"
},
"chatgpt_win_close": {
"message": "关闭"
},
"prefs_OptionText_add_tags_auto": {
"message": "自动添加标签"
},
"prefs_OptionText_spamfilter_Info": {
"message": "如果选中ThunderAI将自动将垃圾邮件移至垃圾邮件文件夹。"
},
"sparks_not_installed": {
"message": "ThunderAI Sparks 未安装!"
},
"chatgpt_textarea_not_found_error": {
"message": "看起来 ChatGPT 页面加载时间太长。如果加载完成,请点击右边的按钮。如果问题仍然存在,请检查服务状态。"
},
"prefs_OptionText_add_tags_auto_Info": {
"message": "如果选中AI将自动为新收到的电子邮件添加标签。"
},
"prefs_OptionText_add_tags_auto_force_existing_Info": {
"message": "如果选中AI 将仅向新收到的电子邮件添加现有标签,而不会创建新标签。"
},
"prefs_OptionText_add_tags_auto_only_inbox": {
"message": "仅向收件箱电子邮件添加标签"
},
"placeholder_thunderai_def_sign": {
"message": "ThunderAI 选项中定义的默认签名。"
},
"SpamFilter_prompt_prefs_title": {
"message": "垃圾邮件过滤选项"
},
"prefs_OptionText_spamfilter_threshold": {
"message": "垃圾阈值"
},
"Subject": {
"message": "主题"
},
"chatgpt_user_not_logged_in": {
"message": "您尚未登录ChatGPT。请使用您的凭据登录关闭ChatGPT窗口然后重复您尝试的操作。随后您将保持登录状态。"
},
"prefs_OptionText_default_chatgpt_lang": {
"message": "默认回复语言"
},
"customPrompts_ExportAll": {
"message": "导出所有提示词"
},
"ollama_empty_model": {
"message": "您尚未选择 Ollama API 的模型。请在选项页面中选择一个。"
},
"prefs_OptionText_default_sign_name": {
"message": "默认签名名称"
},
"prefs_OptionText_reply_all": {
"message": "回复全部"
},
"prefsInfoDesc_6": {
"message": "您可以通过单击此页面右上角的齿轮图标并选择“管理扩展快捷方式”来更改快捷方式。"
},
"chatgpt_win_model_warning": {
"message": "您已设置使用特定模型的选项,但似乎无法正确加载。请检查值并重试。目前,您可以按蓝色按钮继续。"
},
"prefs_Connection_type_ChatGPT_API": {
"message": "ChatGPT OpenAI API"
},
"Debug": {
"message": "调试"
},
"AddTags_info_default": {
"message": "在此页面中,您可以修改用于向电子邮件添加标签的默认提示词并管理排除列表。"
},
"OpenAIComp_api_request_failed": {
"message": "OpenAI 兼容 API 请求失败"
},
"StorageSpace": {
"message": "占用的总存储空间"
},
"addtags_excl_list_infoline2": {
"message": "每行添加一个词,或用逗号分隔。"
},
"google_gemini_api_request_failed": {
"message": "Google Gemini API 请求失败"
},
"placeholder_junk_score": {
"message": "垃圾评分"
},
"chatgpt_win_custom_text": {
"message": "在此处插入提示词的附加文本。"
},
"prefs_status_page": {
"message": "服务状态"
},
"chatgpt_empty_model": {
"message": "您尚未选择 ChatGPT API 的模型。请在选项页面中选择一个。"
},
"prefs_Connection_type_OpenAI_Comp_API": {
"message": "OpenAI 兼容的 API"
},
"prefs_OptionText_dynamic_menu_order_alphabet_info": {
"message": "如果勾选此项,菜单中的提示将按字母顺序排列。"
},
"chatgpt_win_send": {
"message": "发送"
},
"prefs_OptionText_reply_sender": {
"message": "回复发件人"
},
"chatgpt_force_completion_title": {
"message": "如果ChatGPT已完成处理但按钮未显示请点击此处启用“使用最后答案”按钮。"
},
"prefsInfoTitle": {
"message": "重要信息"
},
"prefs_ChatGPT_API_Key": {
"message": "ChatGPT API 密钥"
},
"chagpt_api_connecting": {
"message": "尝试使用提供的 API 密钥连接到 OpenAI ChatGPT"
},
"prefs_OptionText_release_notes": {
"message": "发行说明"
},
"prefsDonation_1": {
"message": "你喜欢这个插件吗?"
},
"prefsDonation_2": {
"message": "考虑捐款!"
},
"WaitingServerReponse": {
"message": "正在等待服务器响应"
},
"OpenAIComp_Models_Error_fetching": {
"message": "尝试获取 OpenAI 兼容 API 模型时出错"
},
"chatgpt_use_gpt35": {
"message": "使用 GPT3.5"
},
"customPrompts_Import": {
"message": "导入新提示词"
},
"error_connection_interrupted": {
"message": "与服务器的连接意外中断"
},
"OpenAIComp_Models": {
"message": "OpenAI 兼容 API 模型"
},
"OpenAIComp_empty_model": {
"message": "您尚未选择 OpenAI Compatible API 的模型。请在选项页面中选择一个。"
},
"OpenAIComp_api_connecting": {
"message": "尝试使用主机连接到 OpenAI 兼容 API 本地服务器"
},
"prefs_OpenAIComp_ChatName": {
"message": "对话名称"
},
"placeholder_folder_path": {
"message": "文件夹路径"
},
"placeholder_selected_text": {
"message": "选定的文本"
},
"placeholder_account_email_address": {
"message": "帐户电子邮件地址"
},
"chatgpt_force_completion": {
"message": "强制完成"
},
"prefs_OptionText_chatgpt_win_height": {
"message": "高度"
},
"prefs_OptionText_btnManagePrompts": {
"message": "管理您的提示词"
},
"prefsInfoDesc_5": {
"message": "请记住,您可以使用键盘快捷键 CTRL+ALT+A 打开 ThunderAI 菜单。"
},
"importPrompts_invalidFile": {
"message": "您尝试导入的文件不是有效的自定义提示文件。"
},
"prefsInfoDesc_4": {
"message": "若要使用此集成功能您需要搭建一台兼容OpenAI API的本地服务器如LM Studio。服务器启动后请在应用程序中的指定字段填入其地址。为确保ThunderAI与本地服务器之间通信正常请务必正确配置CORS设置。"
},
"prefs_OptionText_chatgpt_win_text": {
"message": "ChatGPT 窗口尺寸"
},
"prefs_OptionText_chatgpt_win_width": {
"message": "宽度"
},
"prefsInfoDesc_3": {
"message": "若要使用与Ollama的集成功能您需要先搭建本地Ollama服务器。服务器运行后在应用程序中的指定字段输入其地址。为确保ThunderAI与Ollama服务器之间通信正常请记得设置环境变量OLLAMA_ORIGINS=moz-extension://*。"
},
"importPrompts_invalidPrompts": {
"message": "您尝试导入的文件不包含任何有效提示词。"
},
"andModel": {
"message": "和模型"
},
"ChatGPT_Models_Error_fetching": {
"message": "尝试获取 ChatGPT 模型时出错"
},
"prefs_OptionText_dynamic_menu_order_alphabet": {
"message": "菜单:按字母顺序排列"
},
"prefsInfoDesc_2": {
"message": "要使用 ChatGPT API您需要一个 OpenAI ChatGPT API 密钥并且必须选择一个模型。"
},
"TranslateText": {
"message": "你想帮助翻译这个插件吗?"
},
"importPrompts_confirmText": {
"message": "您即将导入新的提示。"
},
"customPrompts_start_import": {
"message": "开始导入自定义提示词..."
},
"customPrompts_import_completed": {
"message": "自定义提示词导入完成!您需要点击“全部保存”按钮来保存您的更改。"
},
"prefs_Connection_type": {
"message": "连接类型"
},
"prefs_OptionText_reply_type": {
"message": "回复类型"
},
"msg_prompt_too_long": {
"message": "您提供的文本太长。您需要缩短它。"
},
"TranslateLink": {
"message": "了解详情!"
},
"Loading": {
"message": "加载中..."
},
"prefsInfoDesc_1": {
"message": "有时ChatGPT的网页界面可能会发生更改导致插件功能无法正常运行。请查看本页底部的“服务状态”页面链接以获取最新信息。此外请记住首次使用ThunderAI时您需要先登录ChatGPT。"
},
"prefs_OptionText_do_debug_info": {
"message": "激活调试系统"
},
"prefs_API_Host": {
"message": "主机地址"
},
"placeholder_author": {
"message": "作者"
},
"Ollama_Models_Error_fetching": {
"message": "尝试获取 Ollama 模型时出错"
},
"Optional": {
"message": "可选的"
},
"placeholder_mail_text_body": {
"message": "邮件正文"
},
"placeholder_additional_text": {
"message": "附加文本"
},
"Ollama_Models_Fetch": {
"message": "更新 Ollama 模型列表"
},
"currently_used_prompt": {
"message": "当前使用的提示词名称"
},
"ChatGPT_Models": {
"message": "ChatGPT 模型"
},
"chatgpt_api_request_failed": {
"message": "OpenAI ChatGPT API 请求失败"
},
"prefs_API_Host_Info": {
"message": "类似于"
},
"OpenAIComp_empty_host": {
"message": "您尚未添加 OpenAI 兼容 API 的主机地址。请在选项页面中添加一个。"
},
"OpenChatGPTTab_Info": {
"message": "如果在 ThunderAI 窗口中遇到登录问题,请使用右侧的按钮在新标签页中打开 ChatGPT完成登录后关闭该标签页然后继续使用 ThunderAI。"
},
"prompt_translate_this_full_text": {
"message": "将以下电子邮件翻译成"
},
"prompt_add_tags": {
"message": "为这封电子邮件添加标签"
},
"prefs_OptionText_add_tags_maxnum_Info": {
"message": "AI 建议的最大标签数量。如果不想限制标签数量,请设置为 0。"
},
"prompt_rewrite_full_text": {
"message": "重写以下文字以使其更加礼貌。仅使用重写的文字进行回复,不要添加额外的评论或其他文字。"
},
"customprompts_form_label_define_response_lang": {
"message": "在提示词中定义响应语言"
},
"prefs_OptionText_dynamic_menu_force_enter": {
"message": "菜单:立即发送提示词"
},
"prefs_OptionText_dynamic_menu_force_enter_info": {
"message": "如果勾选此项,使用键盘快捷键 CTRL+ALT+A 将自动从菜单中发送高亮显示的提示。否则,会向用户显示提示名称,需要再次按下 Enter 键才能发送。"
},
"OpenChatGPTTab": {
"message": "打开 ChatGPT 标签"
},
"placeholder_recipients": {
"message": "收件人"
},
"prefs_OptionText_owl_warning": {
"message": "看来您的至少一个账户正在使用 Owl for Exchange 插件。Thunderbird 和 Owl 之间存在一个已知问题,目前正在解决中。在此期间,您可以在撰写邮件时使用 ThunderAI但在阅读邮件时无法使用。"
},
"prefs_Connection_type_ChatGPT_Web": {
"message": "ChatGPT Web 界面"
},
"ChatGPT_Models_Fetch": {
"message": "更新 ChatGPT 模型列表"
},
"SearchPrompt": {
"message": "搜索提示词"
},
"error": {
"message": "ThunderAI 错误!"
},
"ollama_empty_host": {
"message": "您尚未为 Ollama API 添加主机地址。请在选项页面中增加一个。"
},
"chatgpt_empty_apikey": {
"message": "您尚未添加 ChatGPT API 的 API 密钥。请在选项页面中添加一个。"
},
"chagpt_api_send_button": {
"message": "使用中的模型"
},
"GoogleGemini_Models": {
"message": "Google Gemini API 模型"
},
"google_gemini_empty_apikey": {
"message": "您尚未添加 Google Gemini API 的 API 密钥。请在选项页面中填入一个。"
},
"API_Models_Error_NoModels": {
"message": "未找到任何模型"
},
"prefs_Connection_type_Ollama_API": {
"message": "Ollama API (本地模型)"
},
"placeholder_mail_html_body": {
"message": "HTML 邮件正文"
},
"placeholder_cc_list": {
"message": "抄送列表"
},
"prefs_OptionText_chatgpt_web_model_tooltip": {
"message": "单击一个值进行设置。"
},
"prefs_OpenAIComp_ForceModel": {
"message": "手动填入模型"
},
"Ollama_Models": {
"message": "Ollama 模型"
},
"OpenAIComp_force_model_ask": {
"message": "在此处填入您想要使用的模型名称。"
},
"ollama_api_connecting": {
"message": "尝试使用主机连接到 Ollama 本地服务器"
},
"ollama_api_request_failed": {
"message": "Ollama API 请求失败"
},
"prefs_OpenAIComp_API_Key": {
"message": "OpenAI 兼容 API 密钥"
},
"OpenAIComp_Models_Fetch": {
"message": "更新 OpenAI 兼容 API 模型列表"
},
"prefs_OptionText_chatgpt_win_dims_info": {
"message": "如果不想指定窗口大小,请设置为 0。"
},
"placeholder_tags_current_email": {
"message": "邮件标签"
},
"prefs_GoogleGemini_API_Key": {
"message": "API 密钥"
},
"prompt_reply_advanced_full_text": {
"message": "回复以下邮件“{%selected_text%}”,并思考整个邮件主题“{%mail_html_body%}”。仅回复所需文本,不添加任何额外评论或其他文字。"
},
"addtags_info_additional_statements": {
"message": "该声明将添加到提示词的末尾:"
},
"prefs_Connection_type_Google_Gemini_API": {
"message": "Google Gemini API"
},
"prefs_OpenAIComp_ChatName_Info": {
"message": "这是将在 AI 聊天中使用的名字。"
},
"prefs_OptionText_openai_comp_use_v1_info": {
"message": "如果选中API 调用路径中的“v1”段将被保留例如“http://localhost:1234/v1/chat/completions”。"
},
"placeholder_mail_subject": {
"message": "邮件主题"
},
"placeholder_folder_name": {
"message": "文件夹名称"
},
"prefs_OptionText_placeholders_use_default_value": {
"message": "占位符:使用默认值"
},
"thunderai_def_lang": {
"message": "ThunderAI 选项中定义的默认语言。"
},
"prefs_OptionText_openai_comp_info_remote": {
"message": "您还可以在此处插入远程服务器地址。"
},
"thunderai_warning_title": {
"message": "ThunderAI 警告"
},
"google_gemini_api_connecting": {
"message": "尝试使用提供的 API 密钥连接到 Google Gemini"
},
"prefs_SurveyLinkText2": {
"message": "单击此处,只需一分钟!"
},
"prompt_add_tags_full_text": {
"message": "分析以下邮件文本,并生成一个用逗号分隔的标签列表,以概括其内容。使用主题、关键话题和相关描述词作为标签。确保标签简洁且与邮件内容相关。\n邮件文本{%mail_text_body%}\n考虑以下细节以获取上下文\n- 发件人:{%author%}\n- 收件人:{%recipients%}\n- 抄送列表:{%cc_list%}\n- 邮件主题:{%mail_subject%}\n请根据邮件文本和上下文生成标签忽略不必要的信息或琐碎的细节。输出应仅为逗号分隔的标签列表不包含任何额外评论或文字。"
},
"placeholder_tags_full_list": {
"message": "现有标签"
},
"addtags_dialog_title": {
"message": "为电子邮件添加标签"
},
"prompt_summarize_this_full_text": {
"message": "将以下电子邮件总结为要点列表。"
},
"prompt_rewrite_formal_full_text": {
"message": "重写以下文字,使其更加正式。回复时只使用重写的文字,不要添加任何额外的评论或其他文字。"
},
"prompt_this_full_text": {
"message": "仅使用所需的文本进行回复,不需要额外的评论或其他文本。"
},
"prefs_OptionText_btnManageTagsInfo": {
"message": "管理标签设置"
},
"prompt_add_tags_maxnum": {
"message": "将标签数量限制为"
},
"AddTags_PageTitle": {
"message": "管理标签设置"
},
"reply_same_lang": {
"message": "用相同的语言回复。"
},
"prompt_classify_full_text": {
"message": "按照礼貌、热情、正式、自信、冒犯性对以下文本进行分类,并为每个类别给出百分比。仅回复类别并评分,不要添加额外评论或其他文本。"
},
"prefs_OptionText_add_tags": {
"message": "为电子邮件添加标签"
},
"prefs_OptionText_add_tags_Info": {
"message": "如果选中,菜单中将包含一项用于将标签应用于电子邮件的项目。"
},
"prefs_OptionText_add_tags_maxnum": {
"message": "最大标签数"
},
"prefs_OptionText_add_tags_hide_exclusions": {
"message": "隐藏排除的标签"
},
"prefs_OptionText_add_tags_hide_exclusions_Info": {
"message": "如果选中,位于排除列表中的标签将在确认对话框中隐藏。"
},
"AddTags_prompt_text_title": {
"message": "当前提示文字"
},
"save": {
"message": "保存"
},
"prefs_OptionText_add_tags_force_lang_Info": {
"message": "如果选中,标签语言将被强制与 ThunderAI 选项页面上定义的语言匹配(如果指定)。"
},
"GoogleGemini_SystemInstruction_Info": {
"message": "当您设置系统指令时,您为模型提供了额外的上下文,以帮助其理解任务、提供更个性化的响应,并遵循将在提示中发送的具体准则。"
},
"prompt_get_calendar_event": {
"message": "添加新日历事件"
},
"AddTags_excl_list_title": {
"message": "排除列表"
},
"google_gemini_empty_model": {
"message": "您尚未选择 Google Gemini API 的模型。请在选项页面中选择一个。"
},
"From": {
"message": "来自"
},
"prefs_OptionText_add_tags_first_uppercase": {
"message": "首字母大写"
},
"GoogleGemini_SystemInstruction": {
"message": "系统指令"
},
"reset_default": {
"message": "重置为默认值"
},
"AddTags_excl_list_infoline": {
"message": "这是一份禁止添加到邮件中的标签列表。"
},
"prefs_OptionText_btnManageSpamFilterInfo": {
"message": "管理垃圾邮件过滤器设置"
},
"addtags_no_tags_received": {
"message": "未收到来自 AI 的标签。"
},
"addtags_no_valid_tags": {
"message": "使用排除列表过滤后,未找到有效标签。"
},
"prefs_SurveyLinkText": {
"message": "分享您的反馈并帮助改进 ThunderAI"
},
"GoogleGemini_Models_Error_fetching": {
"message": "尝试获取 Google Gemini 模型时出错"
},
"ChatGPT_Developer_Messages": {
"message": "开发者消息"
},
"prefs_OptionText_download_now": {
"message": "立即下载ThunderAI Sparks"
},
"thunderai_error_title": {
"message": "ThunderAI 错误"
},
"prefs_OptionText_add_tags_first_uppercase_Info": {
"message": "如果选中,标签标签将设置为小写字母,但只有首字母大写。"
},
"AddTags_prompt_prefs_title": {
"message": "添加标签选项"
},
"prefs_OptionText_add_tags_force_lang": {
"message": "强制语言"
},
"GoogleGemini_Models_Fetch": {
"message": "更新 Google Gemini 模型列表"
},
"ChatGPT_Developer_Messages_Info": {
"message": "当您设置开发者消息时,您为模型提供了额外的上下文,以帮助其理解任务、提供更个性化的响应,并遵循将在提示中发送的具体准则。"
},
"SpamFilter_info_default": {
"message": "在此页面中您可以修改用于检测垃圾邮件的默认提示词。"
},
"prefs_OptionText_btnManagePrompts_infoline3": {
"message": "您可以在提示中使用 {%tags_full_list%} 数据占位符来列出可用的标签。通过适当的提示,您可以强制仅从现有标签列表中选择标签。"
},
"placeholder_mail_typed_text": {
"message": "在引用的邮件正文前输入文本"
},
"calendar_opening_dialog_error": {
"message": "打开日历事件对话框时出错"
},
"prefs_OptionText_spamfilter": {
"message": "自动垃圾邮件过滤器"
},
"SpamFilter_PageTitle": {
"message": "管理垃圾邮件过滤器设置"
},
"prompt_get_calendar_event_full_text": {
"message": "从以下文本中提取生成日历事件所需的所有相关细节。提取的信息应包括:\n- 事件标题\n- 开始日期和时间(如果指定时区,则包括时区)\n- 结束日期和时间(如果指定时区,则包括时区)\n- 全天事件(如果提及)\n- 参与者 \n确保数据格式清晰且一致以便可以直接用于创建日历事件。\n如果存在相对时间的引用请注意邮件的日期和时间为“{%mail_datetime%}”。基于此参考计算开始日期和时间。如果计算出的开始日期和时间早于“{%current_datetime%}”,则使用“{%current_datetime%}”作为基准重新计算开始日期和时间。\n如果未指定持续时间请将其设置为一小时。\n以下是参与者{%author%}, {%recipients%}, {%cc_list%}。如有,请排除我的地址:{%account_email_address%}。\n如果无法获取一个或多个所需信息请以空字符串响应。\n仅以 JSON 格式生成响应。不要包含任何额外的文本或说明,仅提供 JSON。以下是使用的格式\n{\n\"startDate\": \"YYYYMMDDTHHMMSS\",\n\"endDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"日历事件摘要\",\n\"forceAllDay\": false\n\"attendees\": [attendee1@example.com,attendee2@example.com,attendee3@example.com]\n}\n以下是文本“{%selected_text%}”"
},
"prefs_OptionText_get_calendar_event": {
"message": "从所选文本添加新日历事件"
},
"prefs_OptionText_get_calendar_event_Info": {
"message": "如果选中,菜单中将包含一个项目,以从选定的文本中获取日历事件信息。"
},
"prefs_OptionText_btnManageCalendarEventInfo": {
"message": "管理日历活动设置"
},
"GetCalendarEvent_info_default": {
"message": "在此页面中,您可以修改用于从选定文本获取日历事件的默认提示。"
},
"prefs_OptionText_add_tags_auto_force_existing": {
"message": "自动标记时强制使用现有标签"
},
"prefs_OptionText_add_tags_auto_only_inbox_Info": {
"message": "如果选中AI 将仅向收件箱文件夹中收到的电子邮件添加标签。"
},
"GetCalendarEvent_PageTitle": {
"message": "管理日历活动设置"
},
"prefs_OptionText_get_calendar_event_Sparks_not_present": {
"message": "要使用日历事件功能,请安装 ThunderAI Sparks 插件。"
},
"placeholder_mail_datetime": {
"message": "电子邮件的日期和时间"
},
"SpamFilter_prompt_text_title": {
"message": "当前提示词"
},
"placeholder_current_datetime": {
"message": "当前日期和时间"
},
"GetCalendarEvent_prompt_text_title": {
"message": "当前提示词文字"
},
"prefs_OptionText_GetCalendarEvent_infoline2": {
"message": "您可以根据需要更改提示,但从 AI 收到的响应必须采用默认提示中指定的 JSON 格式!"
},
"calendar_getting_data_error": {
"message": "获取日历事件数据时出错"
},
"prefs_OptionText_spamfilter_infoline": {
"message": "您可以根据需要更改提示词,但从 AI 收到的响应必须采用默认提示中指定的 JSON 格式!"
},
"prompt_spamfilter_full_text": {
"message": "分析以下邮件并判断它是否为垃圾邮件。考虑因素包括可疑关键词、过多的宣传语言、误导性的主题行、索取个人信息的请求以及异常的发件人地址。\n提供一个从 0非垃圾邮件到 100垃圾邮件的值并附上不超过 10 个单词的解释。\n仅以 JSON 格式生成响应。不要包含任何额外文本或解释;仅提供 JSON。以下是使用的格式\n{\n\"spamValue\": <0 到 100 的整数>,\n\"explanation\": \"简要说明您的判断理由\",\n}\n以下是邮件信息\n发件人“{%author%}”\n主题“{%mail_subject%}”\nHTML 正文:“{%mail_html_body%}”"
},
"prefs_OptionText_spamfilter_threshold_Info": {
"message": "如果 AI 返回的值高于此阈值,电子邮件将被移至垃圾邮件文件夹。"
},
"spamfilter_threshold_too_low": {
"message": "垃圾邮件阈值太低!您可能会将太多邮件标记为垃圾邮件!"
},
"Spam_Value": {
"message": "垃圾指数"
},
"spamfilter_threshold_zero": {
"message": "垃圾邮件阈值为零!您将把所有邮件标记为垃圾邮件!"
},
"Date": {
"message": "日期"
},
"Moved_to_Spam": {
"message": "移至垃圾邮件箱"
},
"Report_Date": {
"message": "报告日期"
},
"context_menu_mzta-add-tags": {
"message": "添加标签"
},
"prefs_OptionText_add_tags_context_menu": {
"message": "显示“添加标签”上下文菜单项"
},
"prefs_OptionText_spamfilter_context_menu": {
"message": "显示“分析垃圾邮件”上下文菜单项"
},
"prefs_OptionText_spamfilter_context_menu_Info": {
"message": "如果选中,则在邮件列表中右键单击电子邮件时,将显示“分析垃圾邮件”上下文菜单项。"
},
"context_menu_mzta-spamfilter": {
"message": "分析垃圾邮件"
},
"prefs_OptionText_add_tags_context_menu_Info": {
"message": "如果选中,“添加标签”上下文菜单项将在消息列表中右键单击电子邮件时显示。"
},
"noActiveCalendar": {
"message": "未找到激活的日历!"
},
"customPrompts_form_label_use_diff_viewer": {
"message": "启用差异查看器"
},
"get_calendar_event_prompt_prefs_title": {
"message": "日历事件选项"
},
"Select_your_timezone": {
"message": "选择您的时区"
},
"prefs_OptionText_calendar_enforce_timezone": {
"message": "强制指定的时区"
},
"prefs_OptionText_calendar_enforce_timezone_Info": {
"message": "如果选中,将强制对日历事件使用指定的时区。"
},
"btn_show_differences": {
"message": "显示差异"
},
"chatgpt_win_diff_title": {
"message": "原始文本与修改文本之间的差异"
},
"apiwebchat_you": {
"message": "您"
},
"apiwebchat_info": {
"message": "信息"
},
"apiwebchat_error": {
"message": "错误"
},
"apiwebchat_use_this_answer": {
"message": "使用这个回答"
},
"apiwebchat_stopping": {
"message": "停止中"
},
"apiwebchat_receiving_data": {
"message": "正在接收数据"
},
"prompt_lang": {
"message": "使用此语言回复"
},
"Explanation": {
"message": "说明"
}
}

View file

@ -126,7 +126,7 @@ worker.onmessage = function(event) {
break;
case 'newToken':
messagesArea.handleNewToken(payload.token);
messageInput.setStatusMessage('Receiving data...');
messageInput.setStatusMessage(browser.i18n.getMessage("apiwebchat_receiving_data") + '...');
break;
case 'tokensDone':
messagesArea.handleTokensDone(promptData);

View file

@ -17,6 +17,7 @@
<!-- Include the JavaScript files at bottom to avoid blocking UI -->
<script src="messageInput.js" type="module" defer></script>
<script src="markdown-it.min.js"></script>
<script src="../js/lib/diff.js"></script>
<script src="messagesArea.js" type="module" defer></script>
<script src="controller.js" type="module" defer></script>
</body>

View file

@ -216,7 +216,7 @@ class MessageInput extends HTMLElement {
_handleStopClick() {
this.worker.postMessage({ type: 'stop' });
this._stopButton.setAttribute('disabled', 'disabled');
this._stopButton.title = 'Stopping...';
this._stopButton.title = browser.i18n.getMessage("apiwebchat_stopping") + '...';
}
_handleNewChatMessage() {

View file

@ -45,7 +45,6 @@ messagesAreaStyle.textContent = `
line-height: 1.3;
padding: 5px;
border-radius: 10px;
}
.message p{
margin: 0;
@ -90,6 +89,24 @@ messagesAreaStyle.textContent = `
color: navy;
margin-bottom: var(--margin);
}
/* diff viewer */
.added {
background-color: #d4fcdc;
display: inline;
}
.removed {
background-color: #fddddd;
display: inline;
text-decoration: line-through;
}
@media (prefers-color-scheme: dark) {
.added {
background-color:rgb(0, 94, 0);
}
.removed {
background-color:rgb(90, 0, 0);
}
}
`;
messagesAreaTemplate.content.appendChild(messagesAreaStyle);
@ -145,13 +162,13 @@ class MessagesArea extends HTMLElement {
this.fullTextHTML = "";
// console.log("[ThunderAI] appendUserMessage: " + messageText);
const header = document.createElement('h2');
let source = "You";
let source = browser.i18n.getMessage("apiwebchat_you");
switch (type) {
case "user":
source = "You";
source = browser.i18n.getMessage("apiwebchat_you");;
break;
case "info":
source = "Information";
source = browser.i18n.getMessage("apiwebchat_info");
break;
}
header.textContent = source;
@ -174,7 +191,7 @@ class MessagesArea extends HTMLElement {
if (isLastMessageFromUser) {
const header = document.createElement('h2');
header.textContent = this.llmName + (type=='error' ? " - Error" : "");
header.textContent = this.llmName + (type=='error' ? " - " + browser.i18n.getMessage("apiwebchat_error") : "");
this.messages.appendChild(header);
}
@ -207,33 +224,11 @@ class MessagesArea extends HTMLElement {
}
addActionButtons(promptData = null) {
// ============================== TESTING
// promptData = {
// action: "1",
// tabId: 1,
// mailMessageId: 1
// }
// let browser = {
// i18n: {
// getMessage: async function(key) {
// return key;
// }
// },
// storage: {
// sync: {
// get: async function(key) {
// return 'apitest';
// }
// }
// }
// }
// ============================== TESTING - END
if(promptData == null) { return; }
const actionButtons = document.createElement('div');
actionButtons.classList.add('action-buttons');
const actionButton = document.createElement('button');
actionButton.textContent = 'Use this answer';
//actionButton.textContent = browser.i18n.getMessage("chatgpt_win_get_answer");
actionButton.textContent = browser.i18n.getMessage("apiwebchat_use_this_answer");
const fullTextHTMLAtAssignment = this.fullTextHTML.trim().replace(/^"|"$/g, '').replace(/^<p>&quot;/, '<p>').replace(/&quot;<\/p>$/, '</p>'); // strip quotation marks
//console.log(">>>>>>>>>>>> fullTextHTMLAtAssignment: " + fullTextHTMLAtAssignment);
actionButton.addEventListener('click', async () => {
@ -257,6 +252,23 @@ class MessagesArea extends HTMLElement {
browser.runtime.sendMessage({command: "chatgpt_close", window_id: (await browser.windows.getCurrent()).id}); // close window
});
if(promptData.action != 0) { actionButtons.appendChild(actionButton); }
// diff viewer button
if(promptData.prompt_info?.use_diff_viewer == "1") {
const diffvButton = document.createElement('button');
diffvButton.textContent = browser.i18n.getMessage("btn_show_differences");
diffvButton.addEventListener('click', async () => {
let strippedText = fullTextHTMLAtAssignment.replace(/<\/?[^>]+(>|$)/g, "");
let originalText = promptData.prompt_info?.selection_text;
if((originalText == null) || (originalText == "")) {
originalText = promptData.prompt_info?.body_text;
}
this.appendDiffViewer(originalText, strippedText);
diffvButton.disabled = true;
});
actionButtons.appendChild(diffvButton);
}
actionButtons.appendChild(closeButton);
this.messages.appendChild(actionButtons);
this.scrollToBottom();
@ -268,6 +280,40 @@ class MessagesArea extends HTMLElement {
this.scrollToBottom();
}
appendDiffViewer(originalText, newText) {
const wordDiff = Diff.diffWords(originalText, newText);
const messageElement = document.createElement('div');
messageElement.classList.add('message', 'bot');
// Iterate over each part of the diff to create the HTML output
wordDiff.forEach(part => {
const diffElement = document.createElement("span");
// Apply a different class depending on whether the word is added, removed, or unchanged
if (part.added) {
diffElement.className = "added";
diffElement.textContent = part.value;
} else if (part.removed) {
diffElement.className = "removed";
diffElement.textContent = part.value;
} else {
diffElement.textContent = part.value;
}
// Add the element to the container
messageElement.appendChild(diffElement);
});
const header = document.createElement('h2');
header.textContent = browser.i18n.getMessage("chatgpt_win_diff_title");
this.messages.appendChild(header);
this.messages.appendChild(messageElement);
this.addDivider();
this.scrollToBottom();
}
flushAccumulatingMessage() {
if (this.accumulatingMessageEl) {
// Collect all tokens in a full text

17
images/icon-loading.svg Normal file
View file

@ -0,0 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" style="shape-rendering: auto; display: block; background: transparent;" width="200" height="200" xmlns:xlink="http://www.w3.org/1999/xlink"><g><rect fill="#7ddfde" height="20" width="20" y="19" x="19">
<animate calcMode="discrete" begin="0s" repeatCount="indefinite" dur="1s" keyTimes="0;0.125;1" values="#ffe5c9;#7ddfde;#7ddfde" attributeName="fill"></animate>
</rect><rect fill="#7ddfde" height="20" width="20" y="19" x="40">
<animate calcMode="discrete" begin="0.125s" repeatCount="indefinite" dur="1s" keyTimes="0;0.125;1" values="#ffe5c9;#7ddfde;#7ddfde" attributeName="fill"></animate>
</rect><rect fill="#7ddfde" height="20" width="20" y="19" x="61">
<animate calcMode="discrete" begin="0.25s" repeatCount="indefinite" dur="1s" keyTimes="0;0.125;1" values="#ffe5c9;#7ddfde;#7ddfde" attributeName="fill"></animate>
</rect><rect fill="#7ddfde" height="20" width="20" y="40" x="19">
<animate calcMode="discrete" begin="0.875s" repeatCount="indefinite" dur="1s" keyTimes="0;0.125;1" values="#ffe5c9;#7ddfde;#7ddfde" attributeName="fill"></animate>
</rect><rect fill="#7ddfde" height="20" width="20" y="40" x="61">
<animate calcMode="discrete" begin="0.375s" repeatCount="indefinite" dur="1s" keyTimes="0;0.125;1" values="#ffe5c9;#7ddfde;#7ddfde" attributeName="fill"></animate>
</rect><rect fill="#7ddfde" height="20" width="20" y="61" x="19">
<animate calcMode="discrete" begin="0.75s" repeatCount="indefinite" dur="1s" keyTimes="0;0.125;1" values="#ffe5c9;#7ddfde;#7ddfde" attributeName="fill"></animate>
</rect><rect fill="#7ddfde" height="20" width="20" y="61" x="40">
<animate calcMode="discrete" begin="0.625s" repeatCount="indefinite" dur="1s" keyTimes="0;0.125;1" values="#ffe5c9;#7ddfde;#7ddfde" attributeName="fill"></animate>
</rect><rect fill="#7ddfde" height="20" width="20" y="61" x="61">
<animate calcMode="discrete" begin="0.5s" repeatCount="indefinite" dur="1s" keyTimes="0;0.125;1" values="#ffe5c9;#7ddfde;#7ddfde" attributeName="fill"></animate>
</rect><g></g></g><!-- [ldio] generated by https://loading.io --></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

2071
js/lib/diff.js Normal file

File diff suppressed because it is too large Load diff

View file

@ -99,7 +99,7 @@ function chatpgt_scrollToBottom () {
function addCustomDiv(prompt_action,tabId,mailMessageId) {
// Create <style> element for the CSS
var style = document.createElement('style');
style.textContent = ".mzta-header-fixed {position: fixed;bottom: 0;left: 0;height:100px;width: 100%;background-color: #333;color: white;text-align: center;padding: 10px 0;z-index: 1000;border-top: 3px solid white;}"
style.textContent = ".mzta-header-fixed {position:fixed;bottom:0;left: 0;height:100px;width:100%;background-color: #333;color: white;text-align: center;padding: 10px 0;z-index: 1000;border-top: 3px solid white;}"
style.textContent += "body {padding-bottom: 100px !important;} [id^='headlessui-dialog-panel-:r']{padding-bottom: 100px !important;} [data-testid='screen-thread']{padding-bottom: 100px !important;} [slot='content']{padding-bottom: 100px !important;}";
style.textContent += ".mzta-btn {background-color: #007bff;border: none;color: white;padding: 8px 15px;text-align: center;text-decoration: none;display: inline-block;font-size: 16px;margin: 4px 2px;transition-duration: 0.4s;cursor: pointer;border-radius: 5px;}";
style.textContent += ".mzta-btn:hover {background-color:#0056b3;color:white;}";
@ -116,6 +116,12 @@ function addCustomDiv(prompt_action,tabId,mailMessageId) {
style.textContent += "#mzta-custom_textarea{color:black;padding:1px;font-size:15px;width:100%;}";
style.textContent += "#mzta-custom_info{text-align:center;width:100%;padding-bottom:10px;font-size:15px;}";
style.textContent += "#mzta-prompt-name{font-size:13px;font-style:italic;color:#919191;position:fixed;bottom:75px;;left:0;padding-left:5px;}";
style.textContent += "#mzta-diff-overlay{position: fixed;top:0;left:0;width:100vw;height:100vh;background: rgba(0, 0, 0, 0.5);display:flex;justify-content:center;align-items:center;z-index:999;}";
style.textContent += "#mzta-diff{padding:10px;border:2px solid white;border-radius:1em;position:fixed;top:50%;left:50%;width:80%;height:30em;transform:translate(-50%,-50%);z-index:9999;background-color: #333;color: white;}";
style.textContent += "#mzta-diff_title{font-size:16px;font-weight:bold;text-align:center;padding-bottom:10px;}";
style.textContent += "#mzta-diff_content{overflow-y:scroll;text-align:justify;width:100%;height:22.5em;}";
style.textContent += "#mzta-diff span.added{background-color: rgb(0, 94, 0);display:inline;} #mzta-diff span.removed{background-color: rgb(90, 0, 0);display:inline;text-decoration:line-through;}";
style.textContent += "#mzta-btn_close_diff{position:absolute;bottom:10px;left:50%;transform:translateX(-50%);}";
// Add <style> to the page's <head>
document.head.appendChild(style);
@ -170,11 +176,13 @@ function addCustomDiv(prompt_action,tabId,mailMessageId) {
curr_msg.style.display = 'block';
fixedDiv.appendChild(curr_msg);
// loading gif
var loading = document.createElement('img');
loading.src = browser.runtime.getURL("/images/loading.gif");
loading.id = "mzta-loading";
fixedDiv.appendChild(loading);
// OK button
var btn_ok = document.createElement('button');
btn_ok.id="mzta-btn_ok";
btn_ok.classList.add('mzta-btn');
@ -210,6 +218,68 @@ function addCustomDiv(prompt_action,tabId,mailMessageId) {
btn_ok.style.display = 'none';
fixedDiv.appendChild(btn_ok);
if(mztaUseDiffViewer == '1'){
// diff overlay div
var diffOverlay = document.createElement('div');
diffOverlay.id = 'mzta-diff-overlay';
diffOverlay.style.display = 'none';
// diff div
var diffDiv = document.createElement('div');
diffDiv.id = 'mzta-diff';
// diff div title
var diffTitle = document.createElement('div');
diffTitle.id = 'mzta-diff_title';
diffTitle.textContent = browser.i18n.getMessage('chatgpt_win_diff_title');
diffDiv.appendChild(diffTitle);
// diff div content
var diffContent = document.createElement('div');
diffContent.id = 'mzta-diff_content';
diffDiv.appendChild(diffContent);
// diff div close button
var btn_close_diff = document.createElement('button');
btn_close_diff.id = 'mzta-btn_close_diff';
btn_close_diff.classList.add('mzta-btn');
btn_close_diff.textContent = browser.i18n.getMessage('chatgpt_win_close');
btn_close_diff.onclick = function() {
document.getElementById('mzta-diff-overlay').style.display = 'none';
};
diffDiv.appendChild(btn_close_diff);
diffOverlay.appendChild(diffDiv);
fixedDiv.appendChild(diffOverlay);
// diff viewer button
var btn_diff = document.createElement('button');
btn_diff.id='mzta-btn_diff';
btn_diff.classList.add('mzta-btn');
btn_diff.textContent = browser.i18n.getMessage('btn_show_differences');
btn_diff.style.display = 'none';
btn_diff.disabled = true;
btn_diff.onclick = async function() {
diffContent.innerHTML = '';
const response = getSelectedHtml();
const wordDiff = Diff.diffWords(mztaOriginalText, response.replace(/<\\/?[^>]+(>|$)/g, ''));
wordDiff.forEach(part => {
const diffElement = document.createElement('span');
// Apply a different class depending on whether the word is added, removed, or unchanged
if (part.added) {
diffElement.className = 'added';
diffElement.textContent = part.value;
} else if (part.removed) {
diffElement.className = 'removed';
diffElement.textContent = part.value;
} else {
diffElement.textContent = part.value;
}
// Add the element to the container
diffContent.appendChild(diffElement);
diffOverlay.style.display = 'block';
});
};
fixedDiv.appendChild(btn_diff);
}
//div per custom text
let customDiv = document.createElement('div');
customDiv.id = 'mzta-custom_text';
@ -246,7 +316,7 @@ function customTextBtnClick(args) {
args.customDiv.style.display = 'none';
}
function checkGPTModel(model) { //TODO
function checkGPTModel(model) {
if(model == '') return;
doLog("checkGPTModel model: " + model);
return new Promise((resolve, reject) => {
@ -291,6 +361,9 @@ function operation_done(){
}
curr_msg.style.display = 'block';
document.getElementById('mzta-btn_ok').style.display = 'inline';
if(mztaUseDiffViewer == '1'){
document.getElementById('mzta-btn_diff').style.display = 'inline';
}
document.getElementById('mzta-loading').style.display = 'none';
document.getElementById('mzta-force-completion').style.display = 'none';
chatpgt_scrollToBottom();
@ -459,12 +532,21 @@ document.addEventListener("selectionchange", function() {
// Set a timeout to delay the execution of the callback
selectionChangeTimeout = setTimeout(function() {
let btn_ok = document.getElementById('mzta-btn_ok');
let btn_diff = document.getElementById('mzta-btn_diff');
if (isSomethingSelected()) {
btn_ok.disabled = false;
btn_ok.classList.remove('btn_disabled');
if(mztaUseDiffViewer == '1'){
btn_diff.disabled = false;
btn_diff.classList.remove('btn_disabled');
}
} else {
btn_ok.disabled = true;
btn_ok.classList.add('btn_disabled');
if(mztaUseDiffViewer == '1'){
btn_diff.disabled = true;
btn_diff.classList.add('btn_disabled');
}
}
}, 300); // Delay in milliseconds
});

View file

@ -19,11 +19,12 @@
// 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 } from './mzta-utils.js'
import { getLanguageDisplayName, getMenuContextCompose, getMenuContextDisplay, i18nConditionalGet, getMailSubject, getTagsList, extractJsonObject } 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';
import { taWorkingStatus } from './mzta-working-status.js';
export class mzta_Menus {
@ -88,6 +89,7 @@ export class mzta_Menus {
};
curr_menu_entry.act = async () => {
taWorkingStatus.startWorking();
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
const msg_text = await getMailBody(tabs, placeholdersUtils.hasPlaceholder(curr_prompt.text,'mail_typed_text'));
@ -96,6 +98,7 @@ export class mzta_Menus {
//A selection is needed, but nothing is selected!
//alert(browser.i18n.getMessage('prompt_selection_needed'));
browser.tabs.sendMessage(tabs[0].id, { command: "sendAlert", curr_tab_type: tabs[0].type, message : browser.i18n.getMessage('prompt_selection_needed') });
taWorkingStatus.stopWorking();
return {ok:'0'};
}
@ -103,7 +106,9 @@ export class mzta_Menus {
let selection_text = '';
let only_typed_text = '';
selection_text = msg_text.selection.replace(/\s+/g, ' ').trim();
curr_prompt.selection_text = selection_text;
body_text = msg_text.text.replace(/\s+/g, ' ').trim();
curr_prompt.body_text = body_text;
only_typed_text = msg_text.only_typed_text.replace(/\s+/g, ' ').trim();
//open chatgpt window
//console.log("Click menu item...");
@ -156,6 +161,7 @@ export class mzta_Menus {
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);
taWorkingStatus.stopWorking();
return {ok:'0'};
}
fullPrompt = taPromptUtils.finalizePrompt_add_tags(fullPrompt, prefs_at.add_tags_maxnum, prefs_at.add_tags_force_lang, prefs_at.default_chatgpt_lang);
@ -171,19 +177,22 @@ export class mzta_Menus {
}catch(err){
console.error("[ThunderAI] Error getting tags: ", err);
browser.tabs.sendMessage(tabs[0].id, { command: "sendAlert", curr_tab_type: tabs[0].type, message: "Error getting tags: " + err });
taWorkingStatus.stopWorking();
return {ok:'0'};
}
this.logger.log("tags_current_email: " + tags_current_email);
this.logger.log("tags_full_list: " + JSON.stringify(tags_full_list));
browser.tabs.sendMessage(tabs[0].id, {command: "getTags", tags: tags_current_email, messageId: curr_message.id});
taWorkingStatus.stopWorking();
return {ok:'1'};
break; // Add tags to the email - END
}
case 'prompt_get_calendar_event': { // Get a calendar event info
let calendar_event_data = '';
let prefs_at = await browser.storage.sync.get({connection_type: ''});
let prefs_at = await browser.storage.sync.get({connection_type: '', calendar_enforce_timezone: false, calendar_timezone: '',});
if((prefs_at.connection_type === '')||(prefs_at.connection_type === null)||(prefs_at.connection_type === undefined)||(prefs_at.connection_type === 'chatgpt_web')){
console.error("[ThunderAI | GetCalendarEvent] Invalid connection type: " + prefs_at.connection_type);
taWorkingStatus.stopWorking();
return {ok:'0'};
}
/* We expect to receive from the AI a JSON object like this:
@ -191,9 +200,11 @@ export class mzta_Menus {
* "startDate": "20250104T183000Z",
* "endDate": "20250104T193000Z",
* "summary": "ThunderAI Sparks",
* "forceAllDay": false
* "forceAllDay": false,
* "attendees": [attendee1@example.com,attendee2@example.com,attendee3@example.com]"
* }
*/
fullPrompt = taPromptUtils.finalizePrompt_get_calendar_event(fullPrompt);
this.logger.log("fullPrompt: " + fullPrompt);
let cmd_GetCalendarEvent = new mzta_specialCommand(fullPrompt,prefs_at.connection_type,true);
await cmd_GetCalendarEvent.initWorker();
@ -201,32 +212,61 @@ export class mzta_Menus {
calendar_event_data = await cmd_GetCalendarEvent.sendPrompt();
// console.log(">>>>>>>>>>> calendar_event_data: " + calendar_event_data);
}catch(err){
console.error("[ThunderAI] Error getting calendar event data: ", JSON.stringify(err));
browser.tabs.sendMessage(tabs[0].id, { command: "sendAlert", curr_tab_type: tabs[0].type, message: browser.i18n.getMessage("calendar_getting_data_error") + ": " + JSON.stringify(err) });
console.error("[ThunderAI] Error getting calendar event data: ", err.message);
browser.tabs.sendMessage(tabs[0].id, { command: "sendAlert", curr_tab_type: tabs[0].type, message: browser.i18n.getMessage("calendar_getting_data_error") + ": " + err.message });
taWorkingStatus.stopWorking();
return {ok:'0'};
}
this.logger.log("calendar_event_data: " + calendar_event_data);
let calendar_event_data_obj = {};
try{
let result_openCalendarEventDialog = await browser.runtime.sendMessage('thunderai-sparks@micz.it',{action: "openCalendarEventDialog", calendar_event_data: calendar_event_data})
calendar_event_data_obj = extractJsonObject(calendar_event_data);
}catch(err){
console.error("[ThunderAI] Error extracting JSON object from calendar event data: ", err.message);
browser.tabs.sendMessage(tabs[0].id, { command: "sendAlert", curr_tab_type: tabs[0].type, message: browser.i18n.getMessage("calendar_getting_data_error") + ": " + err.message });
taWorkingStatus.stopWorking();
return {ok:'0'};
}
// Timezone management
calendar_event_data_obj.use_timezone = false;
if(prefs_at.calendar_enforce_timezone){
calendar_event_data_obj.use_timezone = true;
calendar_event_data_obj.timezone = prefs_at.calendar_timezone;
}
let calendar_event_data_str = JSON.stringify(calendar_event_data_obj);
// Timezone management - END
this.logger.log("calendar_event_data: " + calendar_event_data);
this.logger.log("calendar_event_data_obj: " + calendar_event_data_str);
try{
let result_openCalendarEventDialog = await browser.runtime.sendMessage('thunderai-sparks@micz.it',{action: "openCalendarEventDialog", calendar_event_data: calendar_event_data_str})
if(result_openCalendarEventDialog == 'ok'){
taWorkingStatus.stopWorking();
return {ok:'1'};
} else {
let err = result_openCalendarEventDialog.error;
if (err && typeof err === 'string' && err.startsWith('|>>')) {
result_openCalendarEventDialog.error = browser.i18n.getMessage(result_openCalendarEventDialog.error.substring(3));
}
browser.tabs.sendMessage(tabs[0].id, { command: "sendAlert", curr_tab_type: tabs[0].type, message: browser.i18n.getMessage("calendar_opening_dialog_error") + ": " + result_openCalendarEventDialog.error });
taWorkingStatus.stopWorking();
return {ok:'0'};
}
}catch(err){
console.error("[ThunderAI] Error opening calendar event dialog: ", JSON.stringify(err));
console.error("[ThunderAI] Error opening calendar event dialog: ", err);
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") });
taWorkingStatus.stopWorking();
return {ok:'0'};
}
break; // Get a calendar event info - END
}
default:
console.error("[ThunderAI] Unknown special prompt id: " + curr_prompt.id);
taWorkingStatus.stopWorking();
return {ok:'0'};
break;
}
}else{ // Classic prompts for the API webchat
this.openChatGPT(fullPrompt, curr_prompt.action, tabs[0].id, curr_prompt.name, curr_prompt.need_custom_text);
this.openChatGPT(fullPrompt, curr_prompt.action, tabs[0].id, curr_prompt.name, curr_prompt.need_custom_text, curr_prompt);
taWorkingStatus.stopWorking();
return {ok:'1'};
}
};

View file

@ -32,7 +32,7 @@
*/
import { transformTagsLabels } from './mzta-utils.js';
import { transformTagsLabels, getCurrentIdentity } from './mzta-utils.js';
const defaultPlaceholders = [
{
@ -63,6 +63,20 @@ const defaultPlaceholders = [
type: 0,
is_default: "1",
},
{
id: 'mail_folder_name',
name: "__MSG_placeholder_folder_name__",
default_value: "",
type: 1,
is_default: "1",
},
{
id: 'mail_folder_path',
name: "__MSG_placeholder_folder_path__",
default_value: "",
type: 1,
is_default: "1",
},
{
id: 'selected_text',
name: "__MSG_placeholder_selected_text__",
@ -119,6 +133,13 @@ const defaultPlaceholders = [
type: 0,
is_default: "1",
},
{
id: 'account_email_address',
name: "__MSG_placeholder_account_email_address__",
default_value: "",
type: 0,
is_default: "1",
},
{
id: 'tags_current_email',
name: "__MSG_placeholder_tags_current_email__",
@ -270,52 +291,62 @@ export const placeholdersUtils = {
for(let currPH of currPHs){
switch(currPH.id){
case 'mail_text_body':
finalSubs['mail_text_body'] = body_text;
finalSubs['mail_text_body'] = placeholdersUtils.failSafePlaceholders(body_text);
break;
case 'mail_html_body':
finalSubs['mail_html_body'] = msg_text.html;
finalSubs['mail_html_body'] = placeholdersUtils.failSafePlaceholders(msg_text?.html);
break;
case 'mail_typed_text':
finalSubs['mail_typed_text'] = only_typed_text;
finalSubs['mail_typed_text'] = placeholdersUtils.failSafePlaceholders(only_typed_text);
break;
case 'mail_subject':
finalSubs['mail_subject'] = mail_subject;
finalSubs['mail_subject'] = placeholdersUtils.failSafePlaceholders(mail_subject);
break;
case 'mail_folder_name':
finalSubs['mail_folder_name'] = placeholdersUtils.failSafePlaceholders(curr_message.folder?.name);
break;
case 'mail_folder_path':
finalSubs['mail_folder_path'] = placeholdersUtils.failSafePlaceholders(curr_message.folder?.path);
break;
case 'selected_text':
finalSubs['selected_text'] = selection_text;
finalSubs['selected_text'] = placeholdersUtils.failSafePlaceholders(selection_text);
break;
case 'author':
finalSubs['author'] = curr_message.author;
finalSubs['author'] = placeholdersUtils.failSafePlaceholders(curr_message.author);
break;
case 'recipients':
finalSubs['recipients'] = curr_message.recipients.join(", ");
finalSubs['recipients'] = placeholdersUtils.failSafePlaceholders(curr_message.recipients?.join(", "));
break;
case 'cc_list':
finalSubs['cc_list'] = curr_message.ccList.join(", ");
finalSubs['cc_list'] = placeholdersUtils.failSafePlaceholders(curr_message.ccList?.join(", "));
break;
case 'junk_score':
finalSubs['junk_score'] = curr_message.junkScore;
finalSubs['junk_score'] = placeholdersUtils.failSafePlaceholders(curr_message.junkScore);
break;
case 'mail_datetime':
finalSubs['mail_datetime'] = curr_message.date;
finalSubs['mail_datetime'] = placeholdersUtils.failSafePlaceholders(curr_message.date);
break;
case 'current_datetime':
finalSubs['current_datetime'] = new Date().toString();
finalSubs['current_datetime'] = placeholdersUtils.failSafePlaceholders(new Date().toString());
break;
case 'account_email_address':
let current_identity = await getCurrentIdentity(curr_message, true);
finalSubs['account_email_address'] = placeholdersUtils.failSafePlaceholders(current_identity.email);
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(", ");
finalSubs['tags_current_email'] = placeholdersUtils.failSafePlaceholders(tags_current_email_array.join(", "));
break;
case 'tags_full_list':
finalSubs['tags_full_list'] = tags_full_list[0];
finalSubs['tags_full_list'] = placeholdersUtils.failSafePlaceholders(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;
finalSubs['thunderai_def_sign'] = placeholdersUtils.failSafePlaceholders(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;
finalSubs['thunderai_def_lang'] = placeholdersUtils.failSafePlaceholders(prefs_def_lang.default_chatgpt_lang);
break;
default: // TODO Manage custom placeholders https://github.com/micz/ThunderAI/issues/156
break;
@ -323,6 +354,14 @@ export const placeholdersUtils = {
}
return finalSubs;
},
failSafePlaceholders(element){
//console.log(">>>>>>>>>> failSafePlaceholders element: " + JSON.stringify(element));
if(element === null || element === undefined){
return '';
}
return element;
}
}

View file

@ -45,8 +45,12 @@
1: Custom text needed
Define response language (define_response_lang attribute):
0: Do not include a statement about the response language in the prompt.
1: Include a statement about the response language in the prompt.
0: Do not include a statement about the response language in the prompt
1: Include a statement about the response language in the prompt
Use the diff viewer (use_diff_viewer attribute):
0: Do not use the diff viewer
1: Use the diff viewer
================ USER PROPERTIES
Enabled (enabled attribute):
@ -72,6 +76,7 @@ const defaultPrompts = [
need_signature: "1",
need_custom_text: "0",
define_response_lang: "1",
use_diff_viewer: "0",
is_default: "1",
is_special: "0",
},
@ -85,6 +90,7 @@ const defaultPrompts = [
need_signature: "1",
need_custom_text: "0",
define_response_lang: "1",
use_diff_viewer: "0",
is_default: "1",
is_special: "0",
},
@ -98,6 +104,7 @@ const defaultPrompts = [
need_signature: "0",
need_custom_text: "0",
define_response_lang: "1",
use_diff_viewer: "1",
is_default: "1",
is_special: "0",
},
@ -111,6 +118,7 @@ const defaultPrompts = [
need_signature: "0",
need_custom_text: "0",
define_response_lang: "1",
use_diff_viewer: "1",
is_default: "1",
is_special: "0",
},
@ -124,6 +132,7 @@ const defaultPrompts = [
need_signature: "0",
need_custom_text: "0",
define_response_lang: "1",
use_diff_viewer: "0",
is_default: "1",
is_special: "0",
},
@ -137,6 +146,7 @@ const defaultPrompts = [
need_signature: "0",
need_custom_text: "0",
define_response_lang: "1",
use_diff_viewer: "0",
is_default: "1",
is_special: "0",
},
@ -150,6 +160,7 @@ const defaultPrompts = [
need_signature: "0",
need_custom_text: "0",
define_response_lang: "0",
use_diff_viewer: "0",
is_default: "1",
is_special: "0",
},
@ -163,6 +174,7 @@ const defaultPrompts = [
need_signature: "0",
need_custom_text: "0",
define_response_lang: "0",
use_diff_viewer: "0",
is_default: "1",
is_special: "0",
},
@ -179,6 +191,7 @@ const specialPrompts = [
need_signature: "0",
need_custom_text: "0",
define_response_lang: "0",
use_diff_viewer: "0",
is_default: "1",
is_special: "1",
},
@ -192,6 +205,7 @@ const specialPrompts = [
need_signature: "0",
need_custom_text: "0",
define_response_lang: "0",
use_diff_viewer: "0",
is_default: "1",
is_special: "1",
},
@ -205,6 +219,7 @@ const specialPrompts = [
need_signature: "0",
need_custom_text: "0",
define_response_lang: "0",
use_diff_viewer: "0",
is_default: "1",
is_special: "1",
},
@ -324,6 +339,11 @@ async function getCustomPrompts() {
if(prefs._custom_prompt === null){
return [];
} else {
prefs._custom_prompt.forEach(prompt => {
if (prompt.use_diff_viewer === undefined) {
prompt.use_diff_viewer = "0";
}
});
return prefs._custom_prompt;
}
}

View file

@ -57,6 +57,13 @@ export const taPromptUtils = {
return fullPrompt;
},
finalizePrompt_get_calendar_event(fullPrompt){
fullPrompt = fullPrompt.replace("{%cc_list%}", "");
fullPrompt = fullPrompt.replace("{%recipients%}", "");
return fullPrompt;
},
async getDefaultLang(curr_prompt){
let chatgpt_lang = '';
if(String(curr_prompt.define_response_lang) == "1"){

View file

@ -19,6 +19,8 @@
export const getMenuContextCompose = () => 'compose_action_menu';
export const getMenuContextDisplay = () => 'message_display_action_menu';
export const contextMenuID_AddTags = 'mzta-add-tags';
export const contextMenuID_Spamfilter = 'mzta-spamfilter';
export function getLanguageDisplayName(languageCode) {
const languageDisplay = new Intl.DisplayNames([languageCode], {type: 'language'});
@ -26,15 +28,30 @@ export function getLanguageDisplayName(languageCode) {
return lang_string.charAt(0).toUpperCase() + lang_string.slice(1);
}
export async function getCurrentIdentity(msgHeader) {
function fixMsgHeader(msgHeader) {
if (!msgHeader.bccList) {
msgHeader.bccList = [];
}
if (!msgHeader.ccList) {
msgHeader.ccList = [];
}
if (!msgHeader.recipients) {
msgHeader.recipients = [];
}
return msgHeader;
}
export async function getCurrentIdentity(msgHeader, getFull = false) {
let identities_array = [];
let fallback_identity = '';
msgHeader = fixMsgHeader(msgHeader);
let accounts = await browser.accounts.list();
for (let account of accounts) {
for (let identity of account.identities) {
identities_array.push({id: identity.id, email:identity.email})
if(fallback_identity === '') {
fallback_identity = {id: identity.id, email:identity.email}
// console.log(">>>>>>>>>> getCurrentIdentity fallback_identity: " + JSON.stringify(fallback_identity));
}
}
}
@ -42,22 +59,30 @@ export async function getCurrentIdentity(msgHeader) {
let author = extractEmail(msgHeader.author);
let author_identity = identities_array.find(identity => identity.email === author);
if (author_identity) {
return author_identity.id;
// console.log(">>>>>>>>>> getCurrentIdentity author_identity: " + JSON.stringify(author_identity));
return getFull ? author_identity : author_identity.id;
}
let correspondents_array = msgHeader.bccList.concat(msgHeader.ccList, msgHeader.recipients);
correspondents_array = correspondents_array.map(correspondent => {
correspondent = extractEmail(correspondent);
return correspondent;
let correspondent_identity = identities_array.find(identity => identity.email === author);
if (correspondent_identity) {
// console.log(">>>>>>>>>> getCurrentIdentity correspondent_identity: " + JSON.stringify(correspondent_identity));
return getFull ? correspondent_identity : correspondent_identity.id;
}
});
const matching_identity = correspondents_array.map(correspondent => identities_array.find(identity => identity.email === correspondent)).find(identity => identity !== undefined);
if(matching_identity) {
return matching_identity.id;
// console.log(">>>>>>>>>> getCurrentIdentity matching_identity: " + JSON.stringify(matching_identity));
return getFull ? matching_identity : matching_identity.id;
} else { // no identity found. using the fallback one
return fallback_identity.id;
// console.log(">>>>>>>>>> getCurrentIdentity fallback_identity: " + JSON.stringify(fallback_identity));
return getFull ? fallback_identity : fallback_identity.id;
}
}
function extractEmail(text) {
if((text=='')||(text==undefined)) return '';
const emailRegex = /[\w.-]+@[\w.-]+\.\w+/;
const match = text.match(emailRegex);
return match ? match[0] : '';
@ -315,10 +340,12 @@ export function extractJsonObject(inputString) {
return jsonObject;
} else {
console.error("[ThunderAI] No JSON object found in the input string.");
throw new Error("No JSON object found in the input string.");
return null;
}
} catch (error) {
console.error("[ThunderAI] Error extracting JSON object:", error);
throw new Error("Error extracting JSON object: " + error.message);
return null;
}
}

41
js/mzta-working-status.js Normal file
View file

@ -0,0 +1,41 @@
/*
* 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 taWorkingStatus = {
WorkingLevel: 0,
taLog: console,
startWorking(){
this.WorkingLevel++;
this.taLog.log("[startWorking] WorkingLevel: " + this.WorkingLevel);
browser.messageDisplayAction.setIcon({path: "/images/icon-loading.svg"});
browser.composeAction.setIcon({path: "/images/icon-loading.svg"});
},
stopWorking(){
this.WorkingLevel--;
this.taLog.log("[stopWorking] WorkingLevel: " + this.WorkingLevel);
if(this.WorkingLevel<=0){
this.WorkingLevel = 0;
browser.messageDisplayAction.setIcon({path: "/images/icon-32px.png"});
browser.composeAction.setIcon({path: "/images/icon-32px.png"});
}
}
};

View file

@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "ThunderAI",
"description": "__MSG_extensionDescription__",
"version": "3.2.3",
"version": "3.3.0",
"author": "Mic (m@micz.it)",
"homepage_url": "https://micz.it/thunderbird-addon-thunderai/",
"browser_specific_settings": {
@ -59,7 +59,7 @@
"content_scripts": [
{
"matches": ["https://*.chatgpt.com/*"],
"js": ["js/tb115_segmenter/tb115_loader.js"],
"js": ["js/tb115_segmenter/tb115_loader.js","js/lib/diff.js"],
"all_frames": true,
"run_at": "document_start"
}

View file

@ -20,11 +20,23 @@ 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, getMessages, getMailBody, extractJsonObject } from './js/mzta-utils.js';
import { getCurrentIdentity, getOriginalBody, replaceBody, setBody, i18nConditionalGet, generateCallID, migrateCustomPromptsStorage, migrateDefaultPromptsPropStorage, getGPTWebModelString, getTagsList, createTag, assignTagsToMessage, checkIfTagExists, getActiveSpecialPromptsIDs, checkSparksPresence, getMessages, getMailBody, extractJsonObject, contextMenuID_AddTags, contextMenuID_Spamfilter } 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';
import { taWorkingStatus } from './js/mzta-working-status.js';
browser.runtime.onInstalled.addListener(({ reason, previousVersion }) => {
// console.log(">>>>>>>>>>> onInstalled: " + JSON.stringify(reason) + ", previousVersion: " + previousVersion);
if (reason === "install"
|| (reason === "update" && (previousVersion.startsWith("2.") || previousVersion.startsWith("1.")))
|| (reason === "update" && ((previousVersion.startsWith("3.") && parseInt(previousVersion.split(".")[1]) <= 2)))
//|| (reason === "update") // only for testing
) {
browser.tabs.create({ url: "/pages/onboarding/onboarding.html" });
}
});
await migrateCustomPromptsStorage();
await migrateDefaultPromptsPropStorage();
@ -36,6 +48,7 @@ let prefs_init = {};
await reload_pref_init();
let taLog = new taLogger("mzta-background",prefs_init.do_debug);
taWorkingStatus.taLog = taLog;
let special_prompts_ids = getActiveSpecialPromptsIDs(prefs_init.add_tags, await doGetCalendarEvent(prefs_init.get_calendar_event), (prefs_init.connection_type === "chatgpt_web"));
@ -283,7 +296,7 @@ browser.runtime.onMessageExternal.addListener((message, sender, sendResponse) =>
}
});
async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_custom_text = 0) {
async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_custom_text = 0, prompt_info = {}) {
let prefs = await browser.storage.sync.get(prefs_default);
taLog.changeDebug(prefs.do_debug);
prefs = checkScreenDimensions(prefs);
@ -335,6 +348,11 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_
taLog.log("prefs.chatgpt_web_model: " + prefs.chatgpt_web_model);
taLog.log("_gpt_model: " + _gpt_model);
let originalText = prompt_info.selection_text;
if((originalText == null) || (originalText == "")) {
originalText = prompt_info.body_text;
}
let pre_script = `let mztaWinId = `+ createdTab.windowId +`;
let mztaStatusPageDesc="`+ browser.i18n.getMessage("prefs_status_page") +`";
@ -345,6 +363,8 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_
let mztaPhDefVal="`+(prefs.placeholders_use_default_value?'1':'0')+`";
let mztaGPTModel="`+ _gpt_model +`";
let mztaDoDebug="`+(prefs.do_debug?'1':'0')+`";
let mztaUseDiffViewer="`+(prompt_info.use_diff_viewer?'1':'0')+`";
let mztaOriginalText="`+ originalText +`";
`;
taLog.log("Waiting 1 sec");
@ -392,7 +412,7 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_
return;
}
//console.log(">>>>>>>>>> sender: " + JSON.stringify(sender));
browser.tabs.sendMessage(createdTab.id, { command: "api_send", prompt: promptText, action: action, tabId: curr_tabId, mailMessageId: mailMessageId2, do_custom_text: do_custom_text});
browser.tabs.sendMessage(createdTab.id, { command: "api_send", prompt: promptText, action: action, tabId: curr_tabId, mailMessageId: mailMessageId2, do_custom_text: do_custom_text, prompt_info: prompt_info});
taLog.log('[OpenAI ChatGPT] Connection succeded!');
browser.runtime.onMessage.removeListener(listener2);
}
@ -442,7 +462,7 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_
return;
}
//console.log(">>>>>>>>>> sender: " + JSON.stringify(sender));
browser.tabs.sendMessage(createdTab.id, { command: "api_send", prompt: promptText, action: action, tabId: curr_tabId, mailMessageId: mailMessageId5, do_custom_text: do_custom_text});
browser.tabs.sendMessage(createdTab.id, { command: "api_send", prompt: promptText, action: action, tabId: curr_tabId, mailMessageId: mailMessageId5, do_custom_text: do_custom_text, prompt_info: prompt_info});
taLog.log('[Google Gemini] Connection succeded!');
browser.runtime.onMessage.removeListener(listener5);
}
@ -498,7 +518,7 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_
browser.tabs.sendMessage(createdTab3.id, { command: "api_error", error: browser.i18n.getMessage('ollama_empty_model')});
return;
}
browser.tabs.sendMessage(createdTab3.id, { command: "api_send", prompt: promptText, action: action, tabId: curr_tabId, mailMessageId: mailMessageId3, do_custom_text: do_custom_text});
browser.tabs.sendMessage(createdTab3.id, { command: "api_send", prompt: promptText, action: action, tabId: curr_tabId, mailMessageId: mailMessageId3, do_custom_text: do_custom_text, prompt_info: prompt_info});
taLog.log('[Ollama API] Connection succeded!');
browser.runtime.onMessage.removeListener(listener3);
}
@ -550,7 +570,7 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_
return;
}
browser.tabs.sendMessage(createdTab.id, { command: "api_send", prompt: promptText, action: action, tabId: curr_tabId, mailMessageId: mailMessageId4, do_custom_text: do_custom_text});
browser.tabs.sendMessage(createdTab.id, { command: "api_send", prompt: promptText, action: action, tabId: curr_tabId, mailMessageId: mailMessageId4, do_custom_text: do_custom_text, prompt_info: prompt_info});
taLog.log('[OpenAI Comp API] Connection succeded!');
browser.runtime.onMessage.removeListener(listener4);
}
@ -603,7 +623,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', 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});
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, add_tags_context_menu: true, spamfilter_context_menu: true});
}
@ -637,6 +657,45 @@ function setupStorageChangeListener() {
const special_prompts_ids = getActiveSpecialPromptsIDs(prefs_init.add_tags, calendarEvent, (newConnectionType === "chatgpt_web"));
menus.reload(special_prompts_ids);
});
if(newConnectionType === "chatgpt_web"){
removeContextMenu(contextMenuID_AddTags);
removeContextMenu(contextMenuID_Spamfilter);
}
}
// context menu changes for add_tags and spamfilter
if (changes.add_tags_context_menu) {
if(changes.add_tags_context_menu.newValue){
addContextMenu(contextMenuID_AddTags);
}else{
removeContextMenu(contextMenuID_AddTags);
}
}
if (changes.add_tags) {
if(changes.add_tags.newValue){
if(prefs_init.add_tags_context_menu){
addContextMenu(contextMenuID_AddTags);
}
}else{
removeContextMenu(contextMenuID_AddTags);
}
}
if (changes.spamfilter_context_menu) {
if(changes.spamfilter_context_menu.newValue){
addContextMenu(contextMenuID_Spamfilter);
}else{
removeContextMenu(contextMenuID_Spamfilter);
}
}
if (changes.spamfilter) {
if(changes.spamfilter.newValue){
if(prefs_init.spamfilter_context_menu){
addContextMenu(contextMenuID_Spamfilter);
}
}else{
removeContextMenu(contextMenuID_Spamfilter);
}
}
reload_pref_init();
}
@ -670,6 +729,47 @@ setupPermissionsRemovedListener();
const menus = new mzta_Menus(openChatGPT, prefs_init.do_debug);
menus.loadMenus(special_prompts_ids);
// Context Menus
function addContextMenu(menu_id) {
browser.menus.create({
id: menu_id,
title: browser.i18n.getMessage("context_menu_" + menu_id),
contexts: ["message_list"]
});
taLog.log("Context menu added: " + menu_id);
}
function removeContextMenu(menu_id) {
browser.menus.remove(menu_id);
taLog.log("Context menu removed: " + menu_id);
}
// Add Context menu: Add tags
if(prefs_init.add_tags && prefs_init.add_tags_context_menu){
addContextMenu(contextMenuID_AddTags);
}
// Add Context menu: Spamfilter
if(prefs_init.spamfilter && prefs_init.spamfilter_context_menu){
addContextMenu(contextMenuID_Spamfilter);
}
// Listen for context menu item clicks
browser.menus.onClicked.addListener( (info, tab) => {
let _add_tags = false
let _spamfilter = false
if(info.menuItemId === contextMenuID_AddTags){
_add_tags = true;
}
if(info.menuItemId === contextMenuID_Spamfilter){
_spamfilter = true;
}
if(_add_tags || _spamfilter){
processEmails(getMessages(info.selectedMessages), _add_tags, _spamfilter);
}
});
// Listening for new received emails
const newEmailListener = (folder, messagesList) => {
@ -681,132 +781,7 @@ const newEmailListener = (folder, 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);
}
}
await processEmails(messages, prefs_init.add_tags_auto, prefs_init.spamfilter);
if(prefs_init.spamfilter){
taSpamReport.truncReportData();
@ -816,9 +791,96 @@ const newEmailListener = (folder, messagesList) => {
return _newEmailListener();
}
async function processEmails(messages, addTagsAuto, spamFilter) {
taWorkingStatus.startWorking();
for await (let message of messages) {
let curr_fullMessage = null;
let msg_text = null;
let body_text = '';
if (addTagsAuto || spamFilter) {
curr_fullMessage = await browser.messages.getFull(message.id);
msg_text = await getMailBody(curr_fullMessage);
body_text = msg_text.text.replace(/\s+/g, ' ').trim();
}
if (addTagsAuto) {
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, '', body_text, curr_fullMessage.headers.subject, msg_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);
}
if (spamFilter) {
let curr_prompt_spamfilter = await getSpamFilterPrompt();
let chatgpt_lang = await taPromptUtils.getDefaultLang(curr_prompt_spamfilter);
let specialFullPrompt_spamfilter = await taPromptUtils.preparePrompt(curr_prompt_spamfilter, message, chatgpt_lang, '', body_text, curr_fullMessage.headers.subject, msg_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();
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;
if (jsonObj.spamValue >= prefs_init.spamfilter_threshold) {
taLog.log("Marking as spam [" + message.headerMessageId + "]");
messenger.messages.update(message.id, { junk: true });
let spamFolder = await messenger.folders.query({ accountId: message.folder.accountId, specialUse: ['junk'] });
messenger.messages.move([message.id], spamFolder[0].id);
report_data.moved = true;
taLog.log("Marked as spam [" + message.headerMessageId + "]");
}
taSpamReport.saveReportData(report_data, message.headerMessageId);
}
}
taWorkingStatus.stopWorking();
}
try {
browser.messages.onNewMailReceived.addListener(newEmailListener, !prefs_init.add_tags_auto_only_inbox);
} catch (e) {
taLog.log("Using browser.messages.onNewMailReceived.addListener with one agrument for Thunderbird 115.");
browser.messages.onNewMailReceived.addListener(newEmailListener);
}
}

View file

@ -50,7 +50,11 @@ export const prefs_default = {
add_tags_auto: false,
add_tags_auto_force_existing: false,
add_tags_auto_only_inbox: true,
add_tags_context_menu: true,
get_calendar_event: true,
calendar_enforce_timezone: false,
calendar_timezone: '',
spamfilter: false,
spamfilter_threshold: 70,
spamfilter_context_menu: true,
}

View file

@ -191,20 +191,23 @@ input.option-input[type="text"]{
}
#mzta_top_msg div{
color: white;
color: #212529;
font-style: italic;
background-color: rgb(3, 0, 180);
background-color: #e0e0e0;
border-radius: 4px;
padding: 3px;
padding: 15px;
font-weight: bold;
margin-bottom: 5px;
text-align: center;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
}
#mzta_top_msg div a{
background-color: white;
padding:0px 3px;
border-radius: 4px;
color: #007BFF;
}
#mzta_top_msg div a:hover{
color: #FF6600;
}
.conntype_chatgpt_web_option{
@ -251,7 +254,16 @@ input.option-input[type="text"]{
}
#mzta_top_msg div{
background-color: rgb(2, 0, 100);
color:#EEEEEE;
background-color: #313131;
}
#mzta_top_msg div a{
color: #00ADB5;
}
#mzta_top_msg div a:hover{
color: #FF5722;
}
#no_sparks td{

View file

@ -7,6 +7,21 @@
<body>
<div id="miczBackPrefs"><a href="mzta-options.html">__MSG_backToOptionsText__</a></div>
<div id="miczRelNotes"><h1>ThunderAI Release Notes</h1>
<h2>Version 3.3.0 - 31/03/2025</h2>
<ul>
<li>Added the <i>{%mail_folder_name%}</i> placeholder to get the mail folder name [<a href="https://github.com/micz/ThunderAI/issues/253">#253</a>].</li>
<li>Added the <i>{%mail_folder_path%}</i> placeholder to get the mail folder path [<a href="https://github.com/micz/ThunderAI/issues/253">#253</a>].</li>
<li>Added the <i>{%account_email_address%}</i> placeholder to get the current account mail address [<a href="https://github.com/micz/ThunderAI/issues/272">#272</a>].</li>
<li><i>[ChatGPT Web][All APIs]</i> Added a diff viewer to compare the old and new text. This feature could be activated at prompt level, and it's useful for "rewrite" prompts [<a href="https://github.com/micz/ThunderAI/issues/109">#109</a>].</li>
<li><i>[All APIs]</i> Added a context menu to automatically add tags and run the spam filter on selected messages. [<a href="https://github.com/micz/ThunderAI/issues/262">#262</a>].</li>
<li><i>[All APIs]</i> It's now possibile to define a timezone in the calendar event settings page [<a href="https://github.com/micz/ThunderAI/issues/250">#250</a>].</li>
<li><i>[All APIs]</i> It's now possibile to add the attendees in the calendar event, be sure to update the prompt in the settings [<a href="https://github.com/micz/ThunderAI/issues/258">#258</a>].</li>
<li>The button icon now shows a loading indicator when ThunderAI is performing an operation [<a href="https://github.com/micz/ThunderAI/issues/295">#295</a>].</li>
<li>Improved the handling of null or undefined placeholders [<a href="https://github.com/micz/ThunderAI/issues/288">#288</a>].</li>
<li>Czech (cs) translation added, thanks to <a href="https://hosted.weblate.org/user/jaroush/">Jaroslav Staněk</a> and <a href="https://hosted.weblate.org/user/Fjuro/">Fjuro</a>.</li>
<li>Simplified Chinese (zh_Hans) translation added, thanks to <a href="https://github.com/jeklau">jeklau</a>.</li>
<li>Some old strings are now translated in the API webchat [<a href="https://github.com/micz/ThunderAI/issues/298">#298</a>].</li>
</ul>
<h2>Version 3.2.3 - 06/03/2025</h2>
<ul>
<li><i>[ChatGPT Web]</i> Fixed hiding the Spam Filter options [<a href="https://github.com/micz/ThunderAI/issues/284">#284</a>].</li>

View file

@ -76,6 +76,15 @@
</label>
</td>
</tr>
<tr class="add_tags_tr">
<td><span>__MSG_prefs_OptionText_add_tags_context_menu__</span></td>
<td>
<label>
<input type="checkbox" id="add_tags_context_menu" name="add_tags_context_menu" class="option-input" />
__MSG_prefs_OptionText_add_tags_context_menu_Info__
</label>
</td>
</tr>
</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>

View file

@ -57,6 +57,8 @@
<span class="need_custom_text_span"><input type="checkbox" id="checkboxNeedCustomTextNew" name="need_custom_text" class="need_custom_text_new" value="1" tabindex="8"> <label for="checkboxNeedCustomTextNew">__MSG_customPrompts_form_label_need_custom_text__</label></span>
<br>
<input type="checkbox" id="checkboxDefineResponseLangNew" name="define_response_lang" value="1" tabindex="8"> <label for="checkboxDefineResponseLangNew">__MSG_customPrompts_form_label_define_response_lang__</label>
<br>
<input type="checkbox" id="checkboxUseDiffViewerNew" name="use_diff_viewer" value="1" tabindex="9"> <label for="checkboxUseDiffViewerNew">__MSG_customPrompts_form_label_use_diff_viewer__</label>
</td>
</tr>
<tr>

View file

@ -155,6 +155,7 @@ document.addEventListener('DOMContentLoaded', async () => {
var checkboxNeedSignatureNew = document.getElementById('checkboxNeedSignatureNew');
var checkboxNeedCustomTextNew = document.getElementById('checkboxNeedCustomTextNew');
var checkboxDefineResponseLangNew = document.getElementById('checkboxDefineResponseLangNew');
var checkboxUseDiffViewerNew = document.getElementById('checkboxUseDiffViewerNew');
const btnAddNew = document.getElementById('btnAddNew');
btnAddNew.addEventListener('click', (e) => {
@ -172,6 +173,7 @@ document.addEventListener('DOMContentLoaded', async () => {
need_signature: (checkboxNeedSignatureNew.checked) ? 1 : 0,
need_custom_text: (checkboxNeedCustomTextNew.checked) ? 1 : 0,
define_response_lang: (checkboxDefineResponseLangNew.checked) ? 1 : 0,
use_diff_viewer: (checkboxUseDiffViewerNew.checked) ? 1 : 0,
enabled: 1,
position_compose: positionMax_compose + 1,
position_display: positionMax_display + 1,
@ -318,6 +320,7 @@ function showItemRowEditor(tr) {
tr.querySelector('input.need_signature').disabled = false;
tr.querySelector('input.need_custom_text').disabled = false;
tr.querySelector('input.define_response_lang').disabled = false;
tr.querySelector('input.use_diff_viewer').disabled = false;
}
function hideItemRowEditor(tr) {
@ -335,6 +338,7 @@ function hideItemRowEditor(tr) {
tr.querySelector('input.need_signature').disabled = true;
tr.querySelector('input.need_custom_text').disabled = true;
tr.querySelector('input.define_response_lang').disabled = true;
tr.querySelector('input.use_diff_viewer').disabled = true;
}
// Confirm and log deletion action
@ -413,7 +417,7 @@ function handleInputChange(e) {
function loadPromptsList(values){
// console.log('>>>>>>>> loadPromptsList values: ' + JSON.stringify(values));
let options = {
valueNames: [ { data: ['idnum'] }, 'is_default', 'id', 'name', 'text', 'type', 'action', 'position_compose', 'position_display', { name: 'need_selected', attr: 'checked_val'}, { name: 'need_signature', attr: 'checked_val'}, { name: 'need_custom_text', attr: 'checked_val'}, { name: 'define_response_lang', attr: 'checked_val'}, { name: 'enabled', attr: 'checked_val'} ],
valueNames: [ { data: ['idnum'] }, 'is_default', 'id', 'name', 'text', 'type', 'action', 'position_compose', 'position_display', { name: 'need_selected', attr: 'checked_val'}, { name: 'need_signature', attr: 'checked_val'}, { name: 'need_custom_text', attr: 'checked_val'}, { name: 'define_response_lang', attr: 'checked_val'}, { name: 'use_diff_viewer', attr: 'checked_val'}, { name: 'enabled', attr: 'checked_val'} ],
item: function(values) {
let type_output = '';
switch(String(values.type)){
@ -471,6 +475,8 @@ function loadPromptsList(values){
<br>
<input type="checkbox" class="define_response_lang" disabled> __MSG_customPrompts_form_label_define_response_lang__
<br>
<input type="checkbox" class="use_diff_viewer" disabled> __MSG_customPrompts_form_label_use_diff_viewer__
<br>
<input type="checkbox" class="enabled input_mod"> __MSG_customPrompts_form_label_enabled__
<span class="is_default hiddendata"></span>
<span class="position_compose hiddendata"></span>
@ -609,6 +615,7 @@ function checkSelectedBoxes(checkboxes = null) {
...document.querySelectorAll('.need_signature[type="checkbox"]'),
...document.querySelectorAll('.need_custom_text[type="checkbox"]'),
...document.querySelectorAll('.define_response_lang[type="checkbox"]'),
...document.querySelectorAll('.use_diff_viewer[type="checkbox"]'),
...document.querySelectorAll('.enabled[type="checkbox"]'),
];
}

View file

@ -18,6 +18,38 @@
justify-content: space-between;
}
table#miczPrefs {
padding: 10px;
border-spacing: 0px;
width: 90%;
margin: 0px auto 40px auto;
border: 1px solid #ccc;
}
.get_calendar_event_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;
}

View file

@ -11,6 +11,50 @@
<h1 class="page_title">__MSG_GetCalendarEvent_PageTitle__</h1>
<p>__MSG_GetCalendarEvent_info_default__</p>
</div>
<div class="get_calendar_event_table_title section_title">__MSG_get_calendar_event_prompt_prefs_title__</div>
<table id="miczPrefs">
<tr class="get_calendar_event_tr">
<td><span>__MSG_prefs_OptionText_calendar_enforce_timezone__</span></td>
<td>
<label>
<input type="checkbox" id="calendar_enforce_timezone" name="calendar_enforce_timezone" class="option-input" /> __MSG_prefs_OptionText_calendar_enforce_timezone_Info__
<br><label for="timezone">__MSG_Select_your_timezone__:</label>
<select id="calendar_timezone" name="calendar_timezone" class="option-input">
<option value=""></option>
<option value="Pacific/Midway">(UTC-11:00) Atol Midway</option>
<option value="Pacific/Honolulu">(UTC-10:00) Honolulu</option>
<option value="America/Anchorage">(UTC-09:00) Anchorage</option>
<option value="America/Los_Angeles">(UTC-08:00) Los Angeles</option>
<option value="America/Denver">(UTC-07:00) Denver</option>
<option value="America/Mexico_City">(UTC-06:00) Ciudad de Mexico</option>
<option value="America/New_York">(UTC-05:00) Nueva York</option>
<option value="America/Caracas">(UTC-04:00) Caracas</option>
<option value="America/Sao_Paulo">(UTC-03:00) Sao Paulo</option>
<option value="Atlantic/South_Georgia">(UTC-02:00) South Georgia</option>
<option value="Atlantic/Azores">(UTC-01:00) Azores</option>
<option value="Europe/London">(UTC+00:00) London</option>
<option value="Europe/Rome">(UTC+01:00) Roma</option>
<option value="Africa/Johannesburg">(UTC+02:00) Johannesburg</option>
<option value="Europe/Moscow">(UTC+03:00) Moscow</option>
<option value="Asia/Dubai">(UTC+04:00) Dubai</option>
<option value="Asia/Karachi">(UTC+05:00) Karachi</option>
<option value="Asia/Dhaka">(UTC+06:00) Dhaka</option>
<option value="Asia/Yangon">(UTC+06:30) Yangon</option>
<option value="Asia/Bangkok">(UTC+07:00) Bangkok</option>
<option value="Asia/Shanghai">(UTC+08:00) Shanghai</option>
<option value="Asia/Tokyo">(UTC+09:00) Tokyo</option>
<option value="Australia/Adelaide">(UTC+09:30) Adelaide</option>
<option value="Australia/Sydney">(UTC+10:00) Sydney</option>
<option value="Pacific/Noumea">(UTC+11:00) Noumea</option>
<option value="Pacific/Fiji">(UTC+12:00) Suva</option>
<option value="Pacific/Chatham">(UTC+12:45) Chatham Islands</option>
<option value="Pacific/Tongatapu">(UTC+13:00) Nuku'alofa</option>
<option value="Pacific/Kiritimati">(UTC+14:00) Kiritimati</option>
</select>
</label>
</td>
</tr>
</table>
<div id="get_calendar_event_container">
<span class="section_title">__MSG_GetCalendarEvent_prompt_text_title__</span><span id="get_calendar_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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -0,0 +1,183 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* Portions Copyright (C) Philipp Kewisch
* This is a modified version of the original file of Quick Folder Move:
* https://github.com/kewisch/quickmove-extension/blob/v3.1.0/src/onboarding/onboarding.html */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html,
body {
color-scheme: light dark;
background-color: light-dark(#f4f4f4, #151516);
color: light-dark(#666, #f4f4f5);
}
body {
font-family: sans-serif;
line-height: 1.6;
width: 960px;
margin: 0 auto;
padding: 20px;
font-size: 18px;
}
body.platform-mac .platform-default,
body:not(.platform-mac) .platform-mac {
display: none;
}
h1,
h2 {
color: light-dark(#333, #fff);
}
.content {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-top: 2em;
padding: 2em;
background: light-dark(#fff, #27272a);
box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.1);
border-radius: 10px;
}
.section {
justify-content: space-between;
align-items: start;
width: 100%;
margin-bottom: 2em;
text-align: left;
padding: 1ex 0 0;
}
.section:not(:last-child) {
border-bottom: 1px solid #c4c4c4;
padding: 1ex 0;
}
.section.header,
.section.footer {
flex-direction: column;
z-index: 1;
position: relative;
}
.title-icon{
margin-right: 20px;
position: relative;
top: 12px;
}
.section.image-right img {
float: right;
margin: 15px 0 35px 35px;
}
.section.image-left img {
float: left;
margin: 15px 35px 45px 0;
}
.section ul {
padding-inline-start: 2em;
}
.section.image-left ul {
padding-inline-start: calc(50% + 2em);
}
.clear {
clear: both;
}
.section > img {
border-radius: 10px;
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.1);
margin-top: 15px;
}
.section p.warning {
border: 1px solid #eed936;
background: #fff7b8;
border-radius: 3px;
padding-inline-start: 90px;
padding-top: 4px;
padding-bottom: 4px;
position: relative;
}
.section p.warning::before {
content: "⚠️";
font-size: 50px;
display: block;
position: absolute;
top: calc(50% - 0.5em);
left: 20px;
line-height: 1;
}
.section p {
color: light-dark(#666, #ddd);
}
.section p.donatebutton {
text-align: center;
width: 100%;
margin-top: 3ex;
}
.section p.donatebutton .button {
padding: 20px;
border-radius: 30px;
}
.section p.donatebutton .button .icon-box {
background-color: light-dark(#fff, #27272a);
padding: 7px 5px 3px;
border-radius: 20px;
}
.section form {
display: flex;
flex-direction: column;
width: 90%;
margin: 0 auto 1em;
}
.section input[type="text"] {
padding: 10px;
margin-bottom: 1em;
border: 1px solid #ddd;
border-radius: 5px;
}
.section input[type="radio"] {
width: 16px;
height: 16px;
}
.section input[type="submit"],
.section .button {
padding: 10px;
color: #fff;
background-color: #0a84ff;
border: none;
border-radius: 5px;
cursor: pointer;
text-decoration: none;
transition:
0.3s background-color,
0.3s box-shadow,
0.3s margin;
}
.section .button:hover {
box-shadow: inset 4px 2px 5px rgba(0, 0, 0, 0.3);
}
.section .button img {
vertical-align: middle;
}
.section .button:active {
box-shadow: inset 5px 2px 5px rgba(0, 0, 0, 0.3);
}

View file

@ -0,0 +1,86 @@
<!DOCTYPE html>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/.
- Portions Copyright (C) Philipp Kewisch
- This is a modified version of the original file of Quick Folder Move:
- https://github.com/kewisch/quickmove-extension/blob/v3.1.0/src/onboarding/onboarding.html -->
<html>
<head>
<title>Welcome to ThunderAI!</title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="onboarding.css">
<link rel="icon" href="../../images/icon-16px.png">
</head>
<body>
<div class="content">
<div class="section header">
<h1><img src="../../images/icon.png" class="title-icon"/>ThunderAI</h1>
<p>
Welcome to ThunderAI!
<br>This add-on is designed to enhance your email management with the power of AI.
<br>With ThunderAI, you can streamline your inbox, generate smart replies, summarize emails, and much more—all with the help of artificial intelligence.
<br><br>On this page, you'll find an overview of the key features available to help you make the most of ThunderAI.
<br>Get ready to experience a smarter, more efficient way to handle your emails!
<br><br>Let's see how to make best use of this add-on!
</p>
</div>
<div class="section image-left">
<h2>Using Prompts</h2>
<img src="images/prompts-button.png" alt="Prompts menu button" />
<p>
On each message, there is a button that will allow you to open the prompts menu.
<br>Here you can choose the prompt in different ways:
<ul>
<li><b>Search box</b>: Use this to search for part of the prompt.</li>
<li><b>Down/Up Arrow</b>: Move through the prompts.</li>
<li><b>Press a number</b>: Press a number on the kayboard to choose the corresponding prompt.</li>
<li><b>Enter</b>: When you've picked the prompt you'd like, press enter to execute it.</li>
</ul>
In the ThunderAI options page you could find some option regarding this menu.
<br>The first two prompts are special ones, that are available only when using an API integration. They work directly without opening the AI Chat webpage.
</p>
</div>
<div class="section image-right">
<h2>Defining your Custom Prompts</h2>
<img src="images/customprompts.png" alt="Managing Custom Prompts"/>
<p>
From the options page you can open the Custom Prompts page.
<br>From there you can add your prompts, and also disable the default ones.
<br>You can find more info <a href="https://micz.it/thunderbird-addon-thunderai/custom-prompts/" target="_blank">here</a>.
</p>
<p>
While defining your own prompts you can also use data placeholders, that will be substituted with the corresponding information when using the prompt.
<br>You can find more info <a href="https://micz.it/thunderbird-addon-thunderai/data-placeholders/" target="_blank">here</a>.
</p>
<p class="clear">
For example, you can use the placeholder <i>{%mail_subject%}</i> to refer to the subject of the email or <i>{%tags_current_email%}</i> to refer to the tags of the current email.
</p>
</div>
<div class="section image-left">
<h2>Automatic features</h2>
<img src="images/autospamfilter.png" alt="Auto spam filter" />
<p>
There are also two automatic features available when using an API integration, which can be activated from the options page:
<br><br>
<ul>
<li><b>Auto Spam Filter</b>: automatically moves the email to the spam folder if it is detected as spam.</li>
<li><b>Auto Tagging</b>: automatically assigns tags to the email.</li>
</ul>
<br>For each of these features, there is an options page to specify the settings and the custom prompt to be used.
</p>
</div>
<div class="section footer">
<p style="text-align:center;">
If you have any questions or suggestions, please open an issue on the <a href="https://github.com/micz/ThunderAI/" target="_blank">GitHub page</a>.
</p>
<p style="text-align:center;"><br>
Do you enjoy ThunderAI?
</p>
<p class="donatebutton">
<a class="button" href="https://paypal.me/miczit" target="_blank">Make a donation!</a>
</p>
</div>
</div>
</body>
</html>

View file

@ -22,6 +22,15 @@
</label>
</td>
</tr>
<tr class="spamfilter_tr">
<td><span>__MSG_prefs_OptionText_spamfilter_context_menu__</span></td>
<td>
<label>
<input type="checkbox" id="spamfilter_context_menu" name="spamfilter_context_menu" class="option-input" />
__MSG_prefs_OptionText_spamfilter_context_menu_Info__
</label>
</td>
</tr>
</table>
<div id="spamfilter_container">
<span class="section_title">__MSG_GetCalendarEvent_prompt_text_title__</span><span id="spamfilter_event_prompt_unsaved" class="unsaved hidden"> __MSG_customPrompts_unsaved_changes__</span>