Merge pull request #371 from micz/v3.4.0

v3.4.0
This commit is contained in:
Mic 2025-05-07 22:42:50 +02:00 committed by GitHub
commit 4baa412e7a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 2660 additions and 407 deletions

View file

@ -4,10 +4,23 @@
<h2>Version 3.3.6 - ??/??/2025</h2>
<h2>Version 3.4.0 - 07/04/2025</h2>
<ul>
<li><i>[All APIs]</i> Added a special prompt to get tasks data from emails [<a href="https://github.com/micz/ThunderAI/issues/333">#333</a>]. To use this feature, you must install also the <a href="https://addons.thunderbird.net/it/thunderbird/addon/thunderai-sparks/">Sparks</a> add-on.</li>
<li><i>[ChatGPT Web]</i> It is now possible to define a Custom GPT or a Project in the options page to be used by default, or directly in a custom prompt to be used only for that prompt [<a href="https://github.com/micz/ThunderAI/issues/168">#168</a>, <a href="https://github.com/micz/ThunderAI/issues/277">#277</a>].</li>
<li>The chatgpt.com access permission is no more requested when installing the addon. It's mandatory to give this permission to use the ChatGPT Web Interface integration [<a href="https://github.com/micz/ThunderAI/issues/293">#293</a>].</li>
<li>Added the <i>{%mail_quoted_text%}</i> placeholder to get the quoted text when composing a new message [<a href="https://github.com/micz/ThunderAI/issues/324">#324</a>].</li>
<li>Fix: correctly choosing the right account when replying [<a href="https://github.com/micz/ThunderAI/issues/369">#369</a>].</li>
<li>Fix: In the <i>{%mail_typed_text%}</i> placeholder text on different lines is now separated by a space.</li>
<li>Fix: correctly showing text differences when using {%mail_typed_text%} placeholder.</li>
<li>Added a default proofread prompt [<a href="https://github.com/micz/ThunderAI/issues/21">#21</a>].</li>
<li>Added the <i>{%empty%}</i> placeholder to prevent the email body from being automatically appended at the end of the prompt [<a href="https://github.com/micz/ThunderAI/issues/345">#345</a>].</li>
<li>Added a check for the presence of the correct version of ThunderAI Sparks [<a href="https://github.com/micz/ThunderAI/issues/315">#315</a>].</li>
<li><i>[All APIs]</i> Improved the form asking for additional text [<a href="https://github.com/micz/ThunderAI/issues/97">#97</a>].</li>
<li><i>[All APIs]</i> Fix: Ensure HTML body is generated from plain text if no parts are available when processing incoming messages for tags or spam.</li>
<li>...</li>
<li>Fix a condition when using a prompt from the compose window with a "Do reply" action that is changed in "Substitute Text" [<a href="https://github.com/micz/ThunderAI/issues/353">#353</a>].</li>
<li>Custom Prompts form improved.</li>
<li>Various improvements.</li>
</ul>
<h2>Version 3.3.5 - 22/04/2025</h2>
<ul>

View file

@ -2,7 +2,7 @@
ThunderAI is a Thunderbird Addon that uses the capabilities of ChatGPT, Google Gemini or Ollama to enhance email management.
It enables users to analyse, write, correct, assign tags, create calendar events and optimize their emails, facilitating more effective and professional communication.
It enables users to analyse, write, correct, assign tags, create calendar events or tasks and optimize their emails, facilitating more effective and professional communication.
ThunderAI is a tool for anyone looking to improve their email quality, both in content and grammar, making the writing process quicker and more intuitive.
@ -86,7 +86,7 @@ Are you using this addon in your Thunderbird?
- French (fr): Generated automatically, [Noam](https://github.com/noam-sc)
- German (de): Generated automatically
- Italian (it): [Mic](https://github.com/micz/)
- Polski (pl): [neexpl](https://github.com/neexpl)
- Polski (pl): [neexpl](https://github.com/neexpl), [makkacprzak](https://github.com/makkacprzak)
- Português Brasileiro (pt-br): Bruno Pereira de Souza

View file

@ -745,7 +745,7 @@
"message": "Sie können den Prompt nach Belieben ändern, aber die von der KI erhaltene Antwort muss im JSON-Format sein, wie im Standard-Prompt angegeben!"
},
"prefs_OptionText_get_calendar_event_Sparks_not_present": {
"message": "Um die Kalenderevent-Funktion zu nutzen, installieren Sie bitte das ThunderAI Sparks-Addon."
"message": "Um die Funktionen für Kalenderereignisse und Aufgaben zu nutzen, installieren Sie bitte das ThunderAI Sparks Add-on."
},
"prefs_OptionText_download_now": {
"message": "Laden Sie jetzt ThunderAI Sparks herunter!"
@ -892,7 +892,7 @@
"message": "Wähle deine Zeitzone"
},
"prefs_OptionText_calendar_enforce_timezone_Info": {
"message": "Wenn aktiviert, wird die angegebene Zeitzone für die Kalenderereignisse erzwungen."
"message": "Wenn aktiviert, wird die angegebene Zeitzone für die Kalendereinträge und Aufgaben erzwungen."
},
"prefs_OptionText_add_tags_context_menu": {
"message": "\"Tags hinzufügen\" im Kontextmenü anzeigen"
@ -968,5 +968,119 @@
},
"prefs_OptionText_composing_plain_text_Info": {
"message": "Aktivieren Sie diese Option, wenn Sie E-Mails im Nur-Text-Format verfassen."
},
"placeholder_mail_quoted_text": {
"message": "Zitierter Text im E-Mail-Textkörper"
},
"prefs_OptionText_chatgpt_web_project_info": {
"message": "Dies ist das Projekt, das für die ChatGPT-Weboberfläche verwendet wird."
},
"prefs_OptionText_get_calendar_event_Sparks_wrong_version": {
"message": "Um Kalender- und Aufgabenfunktionen zu nutzen, installiere bitte eine aktualisierte Version des ThunderAI Sparks-Add-ons."
},
"prefs_OptionText_Project_No_temporary_chat_warn": {
"message": "Wenn ein Projekt in den Optionen oder im Prompt angegeben ist, wird der temporäre Chat nicht verwendet."
},
"customPrompts_form_label_use_diff_viewer_title": {
"message": "Der Differenz-Viewer kann ausgewählt werden, wenn die Aktion auf „Text ersetzen“ gesetzt ist."
},
"prefs_OptionText_CustomGPT_Warn": {
"message": "Wenn ein Projekt in den Optionen oder im Prompt angegeben ist, überschreibt es die benutzerdefinierte GPT-Einstellung."
},
"prefs_OptionText_btnManageTaskInfo": {
"message": "Aufgabeneinstellungen verwalten"
},
"prefs_OptionText_chatgpt_web_custom_gpt_info": {
"message": "Dies ist der benutzerdefinierte GPT, der für die ChatGPT-Weboberfläche verwendet wird."
},
"prefs_OptionText_chatgpt_web_project": {
"message": "ChatGPT-Webprojekt"
},
"empty": {
"message": "Dieser Platzhalter fügt keinen Text hinzu, verhindert jedoch, dass der E-Mail-Text automatisch am Ende des Prompts angehängt wird."
},
"OpenChatGPTTab_Info2": {
"message": "Das Öffnen von ChatGPT Web von hier aus übernimmt alle konfigurierten Einstellungen für Modell, Projekt und benutzerdefinierten GPT."
},
"task_getting_data_error": {
"message": "Fehler beim Abrufen der Aufgabendaten"
},
"task_opening_dialog_error": {
"message": "Fehler beim Öffnen des Aufgabenfensters"
},
"no_valid_data_received": {
"message": "Keine gültigen Daten von der KI empfangen."
},
"prefs_OptionText_add_tags_auto_Info2": {
"message": "Wähle am Ende dieser Seite aus, für welches Konto diese Funktion aktiviert werden soll."
},
"prompt_get_task": {
"message": "Neue Aufgabe hinzufügen"
},
"GetTask_PageTitle": {
"message": "Aufgabeneinstellungen verwalten"
},
"prefs_OptionText_get_task": {
"message": "Füge eine neue Aufgabe aus dem ausgewählten Text hinzu"
},
"prefs_OptionText_get_task_Info": {
"message": "Wenn ausgewählt, wird ein Element im Menü hinzugefügt, um Aufgabeninformationen aus dem ausgewählten Text zu erhalten."
},
"get_task_prompt_prefs_title": {
"message": "Aufgabenoptionen"
},
"GetTask_info_default": {
"message": "Auf dieser Seite kannst du den Standard-Prompt anpassen, der verwendet wird, um eine Aufgabe aus dem ausgewählten Text zu erstellen."
},
"ask_chatgptweb_permission_2": {
"message": "Klicke hier, um fortzufahren."
},
"ask_chatgptweb_permission_1": {
"message": "Um die ChatGPT-Web-Integration zu nutzen, musst du die erforderliche Berechtigung erteilen."
},
"ask_chatgptweb_permission_2_popup": {
"message": "Klicke hier, um einen neuen Tab zu öffnen und den Anweisungen zu folgen."
},
"ask_chatgptweb_permission_ok": {
"message": "Berechtigung erteilt. Du kannst hier klicken, um diesen Tab zu schließen und zum Hauptfenster zurückzukehren."
},
"AccountSelector_AutoTags": {
"message": "Wähle die Konten aus, bei denen die automatische Verschlagwortung aktiviert ist"
},
"AccountSelector_AutoTags_infoline": {
"message": "Jede Änderung wird sofort gespeichert."
},
"AccountSelector_Spamfilter": {
"message": "Wähle die Konten aus, bei denen der Spamfilter aktiviert ist"
},
"prompt_proofread_this": {
"message": "Korrigiere diese E-Mail"
},
"prefs_OptionText_chatgpt_web_custom_gpt": {
"message": "Benutzerdefinierter GPT für ChatGPT Web"
},
"prefs_OptionText_chatgpt_web_custom_data_info": {
"message": "Dies muss folgendes Format haben:"
},
"prefs_OptionText_chatgpt_web_custom_data_info2": {
"message": "Den richtigen Wert findest du im URL-Feld deines Browsers, wenn du die entsprechende ChatGPT-Seite öffnest."
},
"customPrompts_Properties": {
"message": "Eigenschaften"
},
"customPrompts_show_additional_info": {
"message": "Zusätzliche Eigenschaften anzeigen"
},
"customPrompts_hide_additional_info": {
"message": "Zusätzliche Eigenschaften ausblenden"
},
"customPrompts_show_additional_info_show": {
"message": "Zusätzliche Eigenschaften"
},
"prompt_get_task_full_text": {
"message": "Extrahiere alle relevanten Details, die erforderlich sind, um eine Aufgabe aus dem folgenden Text zu erstellen. Die extrahierten Informationen sollten Folgendes umfassen:\n- Fälligkeitsdatum und -uhrzeit (einschließlich Zeitzone, falls angegeben)\n- Aufgabenbeschreibung\n- Startdatum und -uhrzeit (einschließlich Zeitzone, falls angegeben)\nStelle sicher, dass die Daten klar und einheitlich formatiert sind, sodass sie direkt zur Erstellung einer Aufgabe verwendet werden können.\nWenn relative Zeitangaben vorhanden sind, beachte, dass das Datum und die Uhrzeit der E-Mail \"{%mail_datetime%}\" sind. Berechne das Startdatum und die Startzeit basierend auf diesem Bezugspunkt. Falls das berechnete Startdatum und die Startzeit vor \"{%current_datetime%}\" liegen, berechne das Startdatum und die Startzeit erneut unter Verwendung von \"{%current_datetime%}\" als Ausgangspunkt.\nWenn du eine oder mehrere der erforderlichen Informationen nicht erhalten kannst, gib bitte einen leeren String zurück.\nErzeuge eine Antwort ausschließlich im JSON-Format. Füge keinen zusätzlichen Text oder Erklärungen hinzu liefere nur das JSON. Verwende folgendes Format:\n{\n\"InitialDate\": \"YYYYMMDDTHHMMSS\",\n\"dueDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"Aufgabenbeschreibung hier\"\n}\nWenn keine Informationen über die Daten vorhanden sind, lasse sie weg.\nHier ist der Text: \"{%selected_text%}\""
},
"prompt_proofread_this_full_text": {
"message": "Bitte korrigieren Sie die folgende E-Mail und beheben Sie alle Rechtschreib- oder Grammatikfehler. Antworten Sie nur mit dem korrigierten Text, ohne zusätzliche Kommentare oder sonstigen Text.\n\n„{%mail_typed_text%}“"
}
}

View file

@ -135,6 +135,10 @@
"message": "Enable the diff viewer",
"description": ""
},
"customPrompts_form_label_use_diff_viewer_title": {
"message": "The diff viewer can be selected when the action is set to \"Substitute text\".",
"description": ""
},
"customPrompts_form_required_fields": {
"message": "Required fields",
"description": ""
@ -603,6 +607,10 @@
"message": "In case of login issues in the ThunderAI window, open ChatGPT in a new tab using the button on the right, log in, then close the tab and continue using ThunderAI.",
"description": ""
},
"OpenChatGPTTab_Info2": {
"message": "Opening ChatGPT Web from here will apply any configured settings for the model, project, and Custom GPT.",
"description": ""
},
"placeholder_mail_text_body": {
"message": "Mail body",
"description": ""
@ -668,11 +676,11 @@
"description": ""
},
"prefs_OptionText_chatgpt_web_model": {
"message": "ChatGPT Web model",
"message": "ChatGPT Web Model",
"description": ""
},
"prefs_OptionText_chatgpt_web_model_info": {
"message": "This is the model that will be enforced for the ChatGPT Web Interface. If none is specified or an incorrect one is provided, the default model will be set by ChatGPT on the webpage.",
"message": "This is the Model that will be enforced for the ChatGPT Web Interface. If none is specified or an incorrect one is provided, the default model will be set by ChatGPT on the webpage.",
"description": ""
},
"prefs_OptionText_chatgpt_web_tempchat": {
@ -783,6 +791,14 @@
"message": "Analyze the following email text and generate a comma-separated list of tags that summarize its content. Use themes, key topics, and relevant descriptors as tags. Ensure the tags are concise and relevant to the email's content.\nEmail text: {%mail_text_body%}\nConsider the following details for context:\n- Sender: {%author%}\n- Recipients: {%recipients%}\n- CC list: {%cc_list%}\n- Email subject: {%mail_subject%}\nPlease base your tags on the email's text and context, ignoring unnecessary information or trivial details. The output should be only a list of comma separated tags without any additional comment or text.",
"description": ""
},
"prompt_proofread_this": {
"message": "Proofread this email",
"description": ""
},
"prompt_proofread_this_full_text": {
"message": "Proofread the following email and also correct any spelling or grammar mistakes. Reply with only the corrected text and with no extra comments or other text.\n\n\"{%mail_typed_text%}\"",
"description": ""
},
"placeholder_tags_current_email": {
"message": "Mail tags",
"description": ""
@ -975,6 +991,10 @@
"message": "Typed text before the quoted mail body",
"description": ""
},
"placeholder_mail_quoted_text": {
"message": "Quoted text in the mail body",
"description": ""
},
"prompt_get_calendar_event": {
"message": "Add a new calendar event",
"description": ""
@ -983,18 +1003,38 @@
"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": ""
},
"prompt_get_task": {
"message": "Add a new task",
"description": ""
},
"prompt_get_task_full_text": {
"message": "Extract all relevant details required to generate a task from the following text. The extracted information should include:\n- Due Date and Time (including timezone, if specified)\n- Task summary\n- Initial Date and Time (including timezone, if specified)\nEnsure the data is formatted clearly and consistently so that it can be directly used for creating a task.\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 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\"InitialDate\": \"YYYYMMDDTHHMMSS\",\n\"dueDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"Task summary here\"\n}\nIf there are no information about the dates, remove them.\nHere's the text:\"{%selected_text%}\"",
"description": ""
},
"prefs_OptionText_get_calendar_event": {
"message": "Add a new calendar event from selected text",
"description": ""
},
"prefs_OptionText_get_calendar_event_Info": {
"message": "If checked, an item will be included in the menu to get a calendar event information from selected text.",
"message": "If checked, an item will be included in the menu to get calendar event information from selected text.",
"description": ""
},
"get_calendar_event_prompt_prefs_title": {
"message": "Calendar Events Options",
"description": ""
},
"prefs_OptionText_get_task": {
"message": "Add a new task from selected text",
"description": ""
},
"prefs_OptionText_get_task_Info": {
"message": "If checked, an item will be included in the menu to get task information from selected text.",
"description": ""
},
"get_task_prompt_prefs_title": {
"message": "Tasks Options",
"description": ""
},
"Select_your_timezone": {
"message": "Select your timezone",
"description": ""
@ -1004,7 +1044,7 @@
"description": ""
},
"prefs_OptionText_calendar_enforce_timezone_Info": {
"message": "If checked, the specified timezone will be enforced for the calendar events.",
"message": "If checked, the specified timezone will be enforced for the calendar events and the tasks.",
"description": ""
},
"prefs_OptionText_btnManageCalendarEventInfo": {
@ -1028,7 +1068,23 @@
"description": ""
},
"prefs_OptionText_get_calendar_event_Sparks_not_present": {
"message": "To use the calendar event feature, please install the ThunderAI Sparks addon.",
"message": "To use the calendar event and task features, please install the ThunderAI Sparks addon.",
"description": ""
},
"prefs_OptionText_get_calendar_event_Sparks_wrong_version": {
"message": "To use the calendar event and task features, please install an updated version of ThunderAI Sparks addon.",
"description": ""
},
"GetTask_PageTitle": {
"message": "Manage Tasks Settings",
"description": ""
},
"GetTask_info_default": {
"message": "In this page you can modify the default prompt used to get a task from selected text.",
"description": ""
},
"prefs_OptionText_btnManageTaskInfo": {
"message": "Manage tasks settings",
"description": ""
},
"prefs_OptionText_download_now": {
@ -1051,8 +1107,16 @@
"message": "Error opening the calendar event dialog",
"description": ""
},
"sparks_not_installed": {
"message": "ThunderAI Sparks not installed!",
"task_getting_data_error": {
"message": "Error getting task data",
"description": ""
},
"task_opening_dialog_error": {
"message": "Error opening the task dialog",
"description": ""
},
"no_valid_data_received": {
"message": "No valid data recevied from the AI.",
"description": ""
},
"prefs_OptionText_add_tags_auto": {
@ -1063,6 +1127,10 @@
"message": "If checked, the AI will automatically add tags to newly received emails.",
"description": ""
},
"prefs_OptionText_add_tags_auto_Info2": {
"message": "Choose which account to activate this feature for at the bottom of this page.",
"description": ""
},
"prefs_OptionText_add_tags_auto_force_existing": {
"message": "Force existing tags when autotagging",
"description": ""
@ -1087,6 +1155,10 @@
"message": "Default language as defined in ThunderAI options.",
"description": ""
},
"empty": {
"message": "This placeholder doesn't add any text, but it prevents the email body from being automatically appended at the end of the prompt.",
"description": ""
},
"prefs_OptionText_spamfilter": {
"message": "Automatic Spam Filter",
"description": ""
@ -1290,5 +1362,81 @@
"prefs_ollama_num_ctx_Info": {
"message": "The number of context tokens to use for the Ollama API. Set to 0 if you don't want to pass it as a parameter to the server.",
"description": ""
},
"ask_chatgptweb_permission_1": {
"message": "To use the ChatGPT Web Integration, you need to grant the required permission.",
"description": ""
},
"ask_chatgptweb_permission_2_popup": {
"message": "Click here to open a new tab and follow the instructions.",
"description": ""
},
"ask_chatgptweb_permission_2": {
"message": "Click here to proceed.",
"description": ""
},
"ask_chatgptweb_permission_ok": {
"message": "Permission granted. You can click here to close this tab and return to the main window.",
"description": ""
},
"AccountSelector_AutoTags": {
"message": "Choose the accounts where auto-tagging is enabled",
"description": ""
},
"AccountSelector_AutoTags_infoline": {
"message": "Each change is saved immediately.",
"description": ""
},
"AccountSelector_Spamfilter": {
"message": "Choose the accounts where the spam filter is enabled",
"description": ""
},
"prefs_OptionText_chatgpt_web_project": {
"message": "ChatGPT Web Project",
"description": ""
},
"prefs_OptionText_chatgpt_web_project_info": {
"message": "This is the Project that will be enforced for the ChatGPT Web Interface.",
"description": ""
},
"prefs_OptionText_chatgpt_web_custom_gpt": {
"message": "ChatGPT Web Custom GPT",
"description": ""
},
"prefs_OptionText_chatgpt_web_custom_gpt_info": {
"message": "This is the Custom GPT that will be enforced for the ChatGPT Web Interface.",
"description": ""
},
"prefs_OptionText_chatgpt_web_custom_data_info": {
"message": "This must be in the following form:",
"description": ""
},
"prefs_OptionText_chatgpt_web_custom_data_info2": {
"message": "You can find the correct value in the browser URL field when you open the related ChatGPT page.",
"description": ""
},
"customPrompts_Properties": {
"message": "Properties",
"description": ""
},
"customPrompts_show_additional_info": {
"message": "Show additional properties",
"description": ""
},
"customPrompts_hide_additional_info": {
"message": "Hide additional properties",
"description": ""
},
"customPrompts_show_additional_info_show": {
"message": "Additional properties",
"description": ""
},
"prefs_OptionText_CustomGPT_Warn": {
"message": "If a Project is specified in the options or in a prompt, it will override the Custom GPT setting.",
"description": ""
},
"prefs_OptionText_Project_No_temporary_chat_warn": {
"message": "If a Project is specified in the options or in a prompt, the temporary chat will not be used.",
"description": ""
}
}

158
_locales/eo/messages.json Normal file
View file

@ -0,0 +1,158 @@
{
"customPrompts_save_button": {
"message": "Konservi"
},
"prompt_lang": {
"message": "Respondi per"
},
"extensionDescription": {
"message": "Uzu ChatGPT, Google Gemini aŭ Ollama por poluri viajn retpoŝtajn mesaĝojn!"
},
"prompt_rewrite_formal": {
"message": "Reverki formale"
},
"customPrompts_managePrompts_help": {
"message": "Pliaj informoj"
},
"customPrompts_managePrompts": {
"message": "Administri instrukciojn"
},
"customPrompts_btnCancel": {
"message": "Nuligi"
},
"customPrompts_form_required_fields": {
"message": "Postulataj kampoj"
},
"customPrompts_btnSaveAll": {
"message": "Konservi ĉion"
},
"customPrompts_btnNew": {
"message": "Aldoni novan"
},
"chatgpt_btn_retry": {
"message": "Reprovi"
},
"customPrompts_close_button": {
"message": "Fermobutono"
},
"customPrompts_add_to_menu": {
"message": "Aldoni en menuon"
},
"From": {
"message": "De"
},
"spamfilter_not_moved": {
"message": "Ne"
},
"apiwebchat_stopping": {
"message": "Ĉesante"
},
"prompt_classify": {
"message": "Klasifiku"
},
"customPrompts_add_to_menu_always": {
"message": "Ĉiam"
},
"menu_title": {
"message": "AI"
},
"customPrompts_form_label_Text": {
"message": "Teksto de instrukcio"
},
"prompt_reply": {
"message": "Respondu al ĉi tiu retpoŝta mesaĝo"
},
"customPrompts_btnDelete": {
"message": "Forviŝi"
},
"prompt_reply_advanced": {
"message": "Respondu al ĉi tiu fadeno"
},
"prompt_summarize_this": {
"message": "Resumu ĉi tion"
},
"prompt_translate_this": {
"message": "Traduku ĉi tion"
},
"save": {
"message": "Konservi"
},
"customPrompts_form_label_ID": {
"message": "Identigilo"
},
"customPrompts_form_label_enabled": {
"message": "Ŝaltita"
},
"customPrompts_form_label_Name": {
"message": "Nomo"
},
"customPrompts_form_label_Action": {
"message": "Ago"
},
"chatgpt_win_send": {
"message": "Sendi"
},
"Date": {
"message": "Dato"
},
"customPrompts_btnEdit": {
"message": "Modifi"
},
"Loading": {
"message": "Ŝargante…"
},
"customPrompts_btnOK": {
"message": "Bone"
},
"chatgpt_win_job_completed": {
"message": "Finite!"
},
"chatgpt_win_close": {
"message": "Fermi"
},
"prefs_OptionText_chatgpt_win_height": {
"message": "Alto"
},
"prefs_OptionText_chatgpt_win_width": {
"message": "Larĝo"
},
"backToOptionsText": {
"message": "Opcioj"
},
"Subject": {
"message": "Temo"
},
"Explanation": {
"message": "Klarigo"
},
"spamfilter_moved": {
"message": "Jes"
},
"apiwebchat_you": {
"message": "Vi"
},
"apiwebchat_info": {
"message": "Informoj"
},
"apiwebchat_error": {
"message": "Eraro"
},
"prompt_rewrite_polite": {
"message": "Reverki ĝentile"
},
"customPrompts_start_saving": {
"message": "Konservante instrukciojn…"
},
"placeholder_recipients": {
"message": "Ricevantoj"
},
"placeholder_author": {
"message": "Aŭtoro"
},
"Ollama_Models": {
"message": "Modeloj de Ollama"
},
"Ollama_Models_Fetch": {
"message": "Ĝisdatigi liston de modeloj Ollama"
}
}

View file

@ -493,7 +493,7 @@
"message": "Modèle Web ChatGPT"
},
"prefs_OptionText_chatgpt_web_model_info": {
"message": "C'est le modèle qui sera appliqué pour l'interface Web de ChatGPT. Si aucun n'est spécifié ou si un modèle incorrect est fourni, le modèle par défaut sera défini par ChatGPT sur la page Web."
"message": "C'est le Modèle qui sera appliqué pour l'interface Web de ChatGPT. Si aucun n'est spécifié ou si un modèle incorrect est fourni, le modèle par défaut sera défini par ChatGPT sur la page Web."
},
"prefs_OptionText_chatgpt_web_tempchat": {
"message": "Chat temporaire Web ChatGPT"
@ -745,7 +745,7 @@
"message": "Vous pouvez modifier le prompt comme vous le souhaitez, mais la réponse reçue de l'IA doit être au format JSON tel que spécifié dans l'invite par défaut !"
},
"prefs_OptionText_get_calendar_event_Sparks_not_present": {
"message": "Pour utiliser la fonctionnalité d'événements de calendrier, veuillez installer l'addon ThunderAI Sparks."
"message": "Pour utiliser les fonctionnalités dévénements du calendrier et de tâches, veuillez installer lextension ThunderAI Sparks."
},
"prefs_OptionText_download_now": {
"message": "Téléchargez ThunderAI Sparks maintenant !"
@ -886,7 +886,7 @@
"message": "Vous"
},
"prefs_OptionText_calendar_enforce_timezone_Info": {
"message": "Si coché, le fuseau horaire spécifié sera appliqué aux événements du calendrier."
"message": "Si cette option est cochée, le fuseau horaire spécifié sera appliqué aux événements du calendrier et aux tâches."
},
"prefs_OptionText_calendar_enforce_timezone": {
"message": "Forcer le fuseau horaire spécifié"
@ -968,5 +968,119 @@
},
"prefs_OptionText_composing_plain_text": {
"message": "Rédaction en texte brut"
},
"task_opening_dialog_error": {
"message": "Erreur lors de louverture de la boîte de dialogue de la tâche"
},
"prefs_OptionText_get_calendar_event_Sparks_wrong_version": {
"message": "Pour utiliser les fonctionnalités dévénements de calendrier et de tâches, veuillez installer une version mise à jour de lextension ThunderAI Sparks."
},
"prefs_OptionText_chatgpt_web_custom_gpt": {
"message": "GPT personnalisé pour ChatGPT Web"
},
"customPrompts_form_label_use_diff_viewer_title": {
"message": "Le visualiseur de différences peut être sélectionné lorsque l'action est définie sur \"Remplacer le texte\"."
},
"ask_chatgptweb_permission_1": {
"message": "Pour utiliser l'intégration Web de ChatGPT, vous devez accorder l'autorisation requise."
},
"prefs_OptionText_chatgpt_web_custom_data_info": {
"message": "Cela doit être dans le format suivant :"
},
"ask_chatgptweb_permission_2_popup": {
"message": "Cliquez ici pour ouvrir un nouvel onglet et suivre les instructions."
},
"ask_chatgptweb_permission_2": {
"message": "Cliquez ici pour continuer."
},
"prefs_OptionText_Project_No_temporary_chat_warn": {
"message": "Si un projet est spécifié dans les options ou dans une invite, le chat temporaire ne sera pas utilisé."
},
"empty": {
"message": "Ce champ de remplacement najoute aucun texte, mais empêche que le corps de le-mail soit automatiquement ajouté à la fin de linvite."
},
"OpenChatGPTTab_Info2": {
"message": "Ouvrir ChatGPT Web depuis ici appliquera tous les paramètres configurés pour le modèle, le projet et le GPT personnalisé."
},
"GetTask_PageTitle": {
"message": "Gérer les paramètres des tâches"
},
"GetTask_info_default": {
"message": "Sur cette page, vous pouvez modifier linvite par défaut utilisée pour extraire une tâche du texte sélectionné."
},
"prefs_OptionText_btnManageTaskInfo": {
"message": "Gérer les paramètres des tâches"
},
"task_getting_data_error": {
"message": "Erreur lors de la récupération des données de la tâche"
},
"no_valid_data_received": {
"message": "Aucune donnée valide reçue de l'IA."
},
"prefs_OptionText_get_task": {
"message": "Ajouter une nouvelle tâche à partir du texte sélectionné"
},
"prefs_OptionText_get_task_Info": {
"message": "Si coché, un élément sera ajouté au menu pour obtenir des informations sur la tâche à partir du texte sélectionné."
},
"get_task_prompt_prefs_title": {
"message": "Options des tâches"
},
"prompt_get_task": {
"message": "Ajouter une nouvelle tâche"
},
"AccountSelector_AutoTags_infoline": {
"message": "Chaque modification est enregistrée immédiatement."
},
"AccountSelector_Spamfilter": {
"message": "Choisissez les comptes pour lesquels le filtre anti-spam est activé"
},
"ask_chatgptweb_permission_ok": {
"message": "Autorisation accordée. Vous pouvez cliquer ici pour fermer cet onglet et revenir à la fenêtre principale."
},
"prefs_OptionText_add_tags_auto_Info2": {
"message": "Choisissez pour quel compte activer cette fonctionnalité en bas de cette page."
},
"prompt_proofread_this": {
"message": "Relire cet e-mail"
},
"placeholder_mail_quoted_text": {
"message": "Texte cité dans le corps du message"
},
"AccountSelector_AutoTags": {
"message": "Choisissez les comptes pour lesquels le marquage automatique est activé"
},
"prefs_OptionText_chatgpt_web_project": {
"message": "Projet ChatGPT Web"
},
"prefs_OptionText_chatgpt_web_project_info": {
"message": "Cest le projet qui sera appliqué pour linterface Web de ChatGPT."
},
"prefs_OptionText_chatgpt_web_custom_gpt_info": {
"message": "Cest le GPT personnalisé qui sera appliqué pour linterface Web de ChatGPT."
},
"prefs_OptionText_chatgpt_web_custom_data_info2": {
"message": "Vous pouvez trouver la valeur correcte dans la barre dadresse du navigateur lorsque vous ouvrez la page ChatGPT correspondante."
},
"customPrompts_Properties": {
"message": "Propriétés"
},
"customPrompts_show_additional_info": {
"message": "Afficher les propriétés supplémentaires"
},
"customPrompts_hide_additional_info": {
"message": "Masquer les propriétés supplémentaires"
},
"customPrompts_show_additional_info_show": {
"message": "Propriétés supplémentaires"
},
"prefs_OptionText_CustomGPT_Warn": {
"message": "Si un projet est spécifié dans les options ou dans une invite, il remplacera le paramètre de GPT personnalisé."
},
"prompt_proofread_this_full_text": {
"message": "Veuillez relire le-mail suivant et corriger les éventuelles fautes dorthographe ou de grammaire. Répondez uniquement avec le texte corrigé, sans ajouter de commentaires ou de texte supplémentaire.\n\n\"{%mail_typed_text%}\""
},
"prompt_get_task_full_text": {
"message": "Extrait tous les détails pertinents nécessaires pour générer une tâche à partir du texte suivant. Les informations extraites doivent inclure :\n- Date et heure d'échéance (incluant le fuseau horaire, si précisé)\n- Résumé de la tâche\n- Date et heure de début (incluant le fuseau horaire, si précisé)\nAssure-toi que les données sont clairement et uniformément formatées afin quelles puissent être utilisées directement pour créer une tâche.\nS'il y a des références temporelles relatives, considère que la date et lheure de le-mail sont \"{%mail_datetime%}\". Calcule la date et lheure de début en te basant sur cette référence. Si la date et lheure de début calculées sont antérieures à \"{%current_datetime%}\", recalcule-les en utilisant \"{%current_datetime%}\" comme base.\nSi tu ne peux pas obtenir une ou plusieurs des informations requises, réponds par une chaîne vide.\nGénère une réponse uniquement au format JSON. Ninclus aucun texte ou explication supplémentaire fournis uniquement le JSON. Voici le format à utiliser :\n{\n\"InitialDate\" : \"YYYYMMDDTHHMMSS\",\n\"dueDate\" : \"YYYYMMDDTHHMMSS\",\n\"summary\" : \"Résumé de la tâche ici\"\n}\nS'il n'y a pas d'informations concernant les dates, supprime-les.\nVoici le texte : \"{%selected_text%}\""
}
}

View file

@ -88,7 +88,7 @@
"message": "Azione"
},
"customPrompts_form_label_need_selected": {
"message": "Necessaria la selezione di testo"
"message": "Devi selezionare del testo"
},
"customPrompts_form_label_need_signature": {
"message": "Aggiungi sempre la firma"
@ -493,7 +493,7 @@
"message": "Modello Web ChatGPT"
},
"prefs_OptionText_chatgpt_web_model_info": {
"message": "Questo è il modello che verrà utilizzato nell'interfaccia Web di ChatGPT. Se non viene specificato o ne viene fornito uno errato, ChatGPT imposterà il modello predefinito sulla pagina Web."
"message": "Questo è il Modello che verrà utilizzato nell'interfaccia Web di ChatGPT. Se non viene specificato o ne viene fornito uno errato, ChatGPT imposterà il modello predefinito sulla pagina Web."
},
"prefs_OptionText_chatgpt_web_tempchat": {
"message": "Chat temporanea di ChatGPT"
@ -727,7 +727,7 @@
"message": "Aggiungi un nuovo evento al calendario dal testo selezionato"
},
"prefs_OptionText_get_calendar_event_Info": {
"message": "Se selezionato, sarà inclusa una voce del menu per ottenere informazioni su un evento del calendario dal testo selezionato."
"message": "Se selezionato, sarà inclusa una voce del menu per ottenere informazioni dell'evento del calendario dal testo selezionato."
},
"prefs_OptionText_btnManageCalendarEventInfo": {
"message": "Gestisci le impostazioni degli eventi del calendario"
@ -745,7 +745,7 @@
"message": "Puoi modificare il prompt come preferisci, ma la risposta ricevuta dall'AI deve essere in formato JSON come specificato nel prompt predefinito!"
},
"prefs_OptionText_get_calendar_event_Sparks_not_present": {
"message": "Per utilizzare la funzionalità degli eventi del calendario, installa il componente aggiuntivo ThunderAI Sparks."
"message": "Per utilizzare le funzionalità degli eventi del calendario e delle attività, installa il componente aggiuntivo ThunderAI Sparks."
},
"prefs_OptionText_download_now": {
"message": "Scarica subito ThunderAI Sparks!"
@ -928,7 +928,7 @@
"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."
"message": "Se selezionato, il fuso orario specificato verrà applicato agli eventi del calendario e alle attività."
},
"customPrompts_form_label_use_diff_viewer": {
"message": "Abilita il visualizzatore delle differenze"
@ -971,5 +971,119 @@
},
"Replace_No_Selected_Text": {
"message": "Nessun testo selezionato, vuoi inserire la risposta dell'IA all'inizio dell'email?"
},
"customPrompts_form_label_use_diff_viewer_title": {
"message": "Il visualizzatore delle differenze può essere selezionato quando l'azione è impostata su \"Sostituisci testo\"."
},
"prefs_OptionText_get_calendar_event_Sparks_wrong_version": {
"message": "Per utilizzare le funzionalità di eventi del calendario e delle attività, installa una versione aggiornata del componente aggiuntivo ThunderAI Sparks."
},
"AccountSelector_AutoTags_infoline": {
"message": "Ogni modifica viene salvata immediatamente."
},
"OpenChatGPTTab_Info2": {
"message": "Aprire ChatGPT Web da qui applicherà tutte le impostazioni configurate per il modello, il progetto e il GPT personalizzato."
},
"AccountSelector_AutoTags": {
"message": "Scegli gli account per i quali l'etichettatura automatica è attivata"
},
"AccountSelector_Spamfilter": {
"message": "Scegli gli account per i quali è attivo il filtro antispam"
},
"prefs_OptionText_chatgpt_web_custom_data_info2": {
"message": "Puoi trovare il valore corretto nel campo URL del browser quando apri la pagina ChatGPT corrispondente."
},
"ask_chatgptweb_permission_1": {
"message": "Per utilizzare l'integrazione con ChatGPT Web, devi concedere l'autorizzazione richiesta."
},
"ask_chatgptweb_permission_2_popup": {
"message": "Clicca qui per aprire una nuova scheda e seguire le istruzioni."
},
"GetTask_info_default": {
"message": "In questa pagina puoi modificare il prompt predefinito utilizzato per ottenere un'attività dal testo selezionato."
},
"prefs_OptionText_btnManageTaskInfo": {
"message": "Gestisci le impostazioni delle attività"
},
"prefs_OptionText_add_tags_auto_Info2": {
"message": "Scegli per quale account attivare questa funzionalità in fondo a questa pagina."
},
"empty": {
"message": "Questo segnaposto non aggiunge testo, ma impedisce che il corpo dell'email venga automaticamente aggiunto alla fine del prompt."
},
"prompt_get_task": {
"message": "Aggiungi una nuova attività"
},
"prefs_OptionText_get_task": {
"message": "Aggiungi una nuova attività dal testo selezionato"
},
"prefs_OptionText_get_task_Info": {
"message": "Se selezionato, verrà aggiunto un elemento nel menu per ottenere informazioni sull'attività dal testo selezionato."
},
"get_task_prompt_prefs_title": {
"message": "Opzioni delle attività"
},
"GetTask_PageTitle": {
"message": "Gestisci le impostazioni delle attività"
},
"task_getting_data_error": {
"message": "Errore nel recupero dei dati dell'attività"
},
"task_opening_dialog_error": {
"message": "Errore nell'apertura della finestra di dialogo dell'attività"
},
"no_valid_data_received": {
"message": "Nessun dato valido ricevuto dall'IA."
},
"ask_chatgptweb_permission_2": {
"message": "Clicca qui per procedere."
},
"ask_chatgptweb_permission_ok": {
"message": "Autorizzazione concessa. Puoi cliccare qui per chiudere questa scheda e tornare alla finestra principale."
},
"prompt_proofread_this": {
"message": "Correggi questa email"
},
"prompt_proofread_this_full_text": {
"message": "Correggi la seguente email e correggi anche eventuali errori di ortografia o grammatica. Rispondi solo con il testo corretto e senza commenti o altro testo aggiuntivo.\n\n\"{%mail_typed_text%}\""
},
"prefs_OptionText_chatgpt_web_project": {
"message": "Progetto ChatGPT Web"
},
"prefs_OptionText_chatgpt_web_custom_gpt": {
"message": "GPT personalizzato per ChatGPT Web"
},
"prefs_OptionText_chatgpt_web_custom_gpt_info": {
"message": "Questo è il GPT personalizzato che verrà caricato nell'interfaccia Web di ChatGPT."
},
"prefs_OptionText_chatgpt_web_project_info": {
"message": "Questo è il progetto che verrà utilizzato nell'interfaccia Web di ChatGPT."
},
"prefs_OptionText_chatgpt_web_custom_data_info": {
"message": "Deve essere nel seguente formato:"
},
"customPrompts_Properties": {
"message": "Proprietà"
},
"customPrompts_show_additional_info": {
"message": "Mostra proprietà aggiuntive"
},
"customPrompts_hide_additional_info": {
"message": "Nascondi proprietà aggiuntive"
},
"customPrompts_show_additional_info_show": {
"message": "Proprietà aggiuntive"
},
"prefs_OptionText_CustomGPT_Warn": {
"message": "Se un Progetto è specificato nelle opzioni o in un prompt, sostituirà l'impostazione del GPT personalizzato."
},
"prompt_get_task_full_text": {
"message": "Estrai tutti i dettagli rilevanti necessari per generare un'attività dal testo seguente. Le informazioni estratte devono includere:\n- Data e ora di scadenza (incluso il fuso orario, se specificato)\n- Riepilogo dell'attività\n- Data e ora di inizio (incluso il fuso orario, se specificato)\nAssicurati che i dati siano formattati in modo chiaro e coerente, così da poter essere utilizzati direttamente per creare un'attività.\nSe ci sono riferimenti temporali relativi, considera che la data e l'ora dellemail sono \"{%mail_datetime%}\". Calcola la data e l'ora di inizio basandoti su questo riferimento. Se la data e ora di inizio calcolate risultano precedenti a \"{%current_datetime%}\", ricalcola la data e ora di inizio utilizzando \"{%current_datetime%}\" come riferimento.\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 alcun testo o spiegazione aggiuntiva; fornisci solo il JSON. Questo è il formato da utilizzare:\n{\n\"InitialDate\": \"YYYYMMDDTHHMMSS\",\n\"dueDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"Riepilogo dell'attività\"\n}\nSe non ci sono informazioni sulle date, rimuovile.\nEcco il testo: \"{%selected_text%}\""
},
"placeholder_mail_quoted_text": {
"message": "Testo citato nel corpo dell'email"
},
"prefs_OptionText_Project_No_temporary_chat_warn": {
"message": "Se un Progetto è specificato nelle opzioni o nel prompt, la chat temporanea non verrà utilizzata."
}
}

View file

@ -869,5 +869,53 @@
},
"spamfilter_no_reports": {
"message": "Nie przeskanowano jeszcze żadnych wiadomości pod kątem spamu. Tutaj znajdziesz listę ostatnich 100 raportów o spamie tylko dla bieżącej sesji."
},
"context_menu_mzta-add-tags": {
"message": "Dodaj tagi"
},
"customPrompts_form_label_use_diff_viewer_title": {
"message": "Widok zmian może zostać wybrany, kiedy wybrana akcja to \"Tekst zastępczy\"."
},
"empty": {
"message": "Ten tekst zastępczy nie dodaje żadnego tekstu, tylko zapobiega przed automatycznym wstawianiem treści emaila na końcu prompta."
},
"prefs_OptionText_calendar_enforce_timezone_Info": {
"message": "Jeżeli zaznaczone, określona strefa czasowa będzie wymuszana dla wydarzeń w kalendarzu."
},
"prefs_OptionText_get_calendar_event_Sparks_wrong_version": {
"message": "By używać wydarzeń w kalendarzu prosimy zainstalować zaktualizowaną wersję dodatku ThunderAI Sparks."
},
"customPrompts_form_label_use_diff_viewer": {
"message": "Włącz widok zmian"
},
"placeholder_folder_name": {
"message": "Nazwa folderu"
},
"placeholder_folder_path": {
"message": "Ścieżka folderu"
},
"Select_your_timezone": {
"message": "Wybierz swoją strefę czasową"
},
"get_calendar_event_prompt_prefs_title": {
"message": "Opcje Wydarzeń Kalendarza"
},
"prefs_OptionText_calendar_enforce_timezone": {
"message": "Wymuś konkretną strefę czasową"
},
"context_menu_mzta-spamfilter": {
"message": "Analizuj pod kątem spamu"
},
"placeholder_account_email_address": {
"message": "Adres email konta"
},
"prompt_proofread_this": {
"message": "Skoryguj ten email"
},
"prompt_proofread_this_full_text": {
"message": "Skoryguj poniższy email, oraz popraw wszelkie błędy ortograficzne lub gramatyczne. Niech twoja odpowiedź zawiera wyłącznie skorygowany tekst, bez żadnych komentarzy lub dodatkowego tekstu.\n\n\"{%mail_typed_text%}\""
},
"placeholder_mail_quoted_text": {
"message": "Zacytowany tekst w treści maila"
}
}

View file

@ -145,28 +145,37 @@ worker.onmessage = function(event) {
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
switch (message.command) {
case "api_send":
promptData = message;
//send the received prompt to the llm api
if(message.do_custom_text=="1") {
let userInput = prompt(browser.i18n.getMessage("chatgpt_win_custom_text"));
messageInput._showCustomTextField();
}else{
sendPrompt(message);
}
break;
case 'api_send_custom_text':
let userInput = message.custom_text;
if(userInput !== null) {
if(!placeholdersUtils.hasPlaceholder(message.prompt, 'additional_text')){
if(!placeholdersUtils.hasPlaceholder(promptData.prompt, 'additional_text')){
// no additional_text placeholder, do as usual
message.prompt += " " + userInput;
promptData.prompt += " " + userInput;
}else{
// we have the additional_text placeholder, do the magic!
let finalSubs = {};
finalSubs["additional_text"] = userInput;
message.prompt = placeholdersUtils.replacePlaceholders(message.prompt, finalSubs, ph_def_val==='1')
promptData.prompt = placeholdersUtils.replacePlaceholders(promptData.prompt, finalSubs, ph_def_val==='1')
}
sendPrompt(promptData);
}
}
promptData = message;
messageInput._setMessageInputValue(message.prompt);
messageInput._handleNewChatMessage();
break;
case "api_error":
messagesArea.appendBotMessage(message.error,'error');
messageInput.enableInput();
break;
}
});
});
function sendPrompt(message){
messageInput._setMessageInputValue(message.prompt);
messageInput._handleNewChatMessage();
}

View file

@ -23,7 +23,7 @@
const messageInputTemplate = document.createElement('template');
const messagesInputStyle = document.createElement('style');
messagesInputStyle .textContent = `
messagesInputStyle.textContent = `
:host {
display: flex;
justify-content: space-between;
@ -66,16 +66,49 @@ messagesInputStyle .textContent = `
padding: 5px;
background: #F2F2F2;
}
#mzta-custom_text{
padding:10px;
width:auto;
max-width:80%;
height:auto;
max-height:80%;
border-radius:5px;
overflow:auto;
position:fixed;
top:50%;
left:50%;
display:none;
transform:translate(-50%,-50%);
text-align:center;
background:#333;
color:white;
border:3px solid white;
}
#mzta-custom_loading{
height:50px;display:none;
}
#mzta-custom_textarea{
color:black;
padding:1px;
font-size:15px;
width:100%;
}
#mzta-custom_info{
text-align:center;
width:100%;
padding-bottom:10px;
font-size:15px;
}
@media (prefers-color-scheme: dark) {
#messageInputField {
background-color: #303030;
color: #ffffff;
#messageInputField {
background-color: #303030;
color: #ffffff;
}
#statusLogger{
background: #212121;
color: #ffffff;
}
}
#statusLogger{
background: #212121;
color: #ffffff;
}
}
`;
messageInputTemplate.content.appendChild(messagesInputStyle);
@ -135,6 +168,27 @@ statusLogger.textContent = '';
statusLogger.style.display = 'none';
messageInputTemplate.content.appendChild(statusLogger);
//div per custom text
const customDiv = document.createElement('div');
customDiv.id = 'mzta-custom_text';
const customInfo = document.createElement('div');
customInfo.id = 'mzta-custom_info';
customInfo.textContent = browser.i18n.getMessage("chatgpt_win_custom_text");
customDiv.appendChild(customInfo);
const customTextArea = document.createElement('textarea');
customTextArea.id = 'mzta-custom_textarea';
customDiv.appendChild(customTextArea);
const customLoading = document.createElement('img');
customLoading.src = browser.runtime.getURL("/images/loading.gif");
customLoading.id = "mzta-custom_loading";
customDiv.appendChild(customLoading);
const customBtn = document.createElement('button');
customBtn.id = 'mzta-custom_btn';
customBtn.textContent = browser.i18n.getMessage("chatgpt_win_send");
customBtn.classList.add('mzta-btn');
customDiv.appendChild(customBtn);
messageInputTemplate.content.appendChild(customDiv);
class MessageInput extends HTMLElement {
model = '';
@ -152,6 +206,13 @@ class MessageInput extends HTMLElement {
this._messageInputField.addEventListener('keydown', this._handleKeyDown.bind(this));
this._sendButton.addEventListener('click', this._handleClick.bind(this));
this._stopButton.addEventListener('click', this._handleStopClick.bind(this));
this._customText = shadowRoot.querySelector('#mzta-custom_text');
this._customTextArea = shadowRoot.querySelector('#mzta-custom_textarea');
this._customLoading = shadowRoot.querySelector('#mzta-custom_loading');
this._customBtn = shadowRoot.querySelector('#mzta-custom_btn');
this._customBtn.addEventListener("click", () => { this._customTextBtnClick({customBtn:this._customBtn,customLoading:this._customLoading,customDiv:this._customText}) });
this._customTextArea.addEventListener("keydown", (event) => { if(event.code == "Enter" && event.ctrlKey) this._customTextBtnClick({customBtn:this._customBtn,customLoading:this._customLoading,customDiv:this._customText}) });
}
connectedCallback() {
@ -243,6 +304,23 @@ class MessageInput extends HTMLElement {
_setMessageInputValue(msg) {
this._messageInputField.value = msg;
}
_showCustomTextField(){
this._customText.style.display = 'block';
this._customTextArea.focus();
}
async _customTextBtnClick(args) {
const customText = this._customTextArea.value;
// console.log(">>>>>>>>>>>>>>>> customText: " + customText);
args.customBtn.disabled = true;
args.customBtn.classList.add('disabled');
args.customLoading.style.display = 'inline-block';
args.customLoading.style.display = 'none';
let tab = await browser.tabs.query({ active: true, currentWindow: true });
browser.runtime.sendMessage({ command: "api_send_custom_text", custom_text: customText, tabId: tab[0].id });
args.customDiv.style.display = 'none';
}
}
customElements.define('message-input', MessageInput);

View file

@ -83,8 +83,16 @@ async function chatgpt_isIdle() {
function chatgpt_getRegenerateButton() {
for (const mainSVG of document.querySelectorAll('main svg.icon-md')) {
if (mainSVG.querySelector('path[d^="M3.06957"]')) // regen icon found
if (mainSVG.querySelector('path[d^="M3.06957"]')){ // regen icon found
//console.log(">>>>>>>>>> found regen icon!");
return mainSVG.parentNode.parentNode;
}
}
for (const mainSVG of document.querySelectorAll('main svg.icon-md-heavy')) {
if (mainSVG.querySelector('path[d^="M11 4.9099C11 4.47485"]')){ // read aloud icon found
//console.log(">>>>>>>>>> found read aloud icon!");
return mainSVG.parentNode.parentNode;
}
}
}
@ -186,7 +194,7 @@ function addCustomDiv(prompt_action,tabId,mailMessageId) {
var btn_ok = document.createElement('button');
btn_ok.id="mzta-btn_ok";
btn_ok.classList.add('mzta-btn');
//console.log('default: '+prompt_action)
//console.log('>>>>>>>>>>>>>>> default: '+prompt_action)
switch(String(prompt_action)){
default:
case "0": // close window
@ -317,13 +325,15 @@ function customTextBtnClick(args) {
}
function checkGPTModel(model) {
if(model == '') return;
if(model == '') return Promise.resolve();
doLog("checkGPTModel model: " + model);
return new Promise((resolve, reject) => {
// Set up an interval that shows the warning after 2 seconds
const intervalId2 = setTimeout(() => {
document.getElementById('mzta-model_warn').style.display = 'inline-block';
document.getElementById('mzta-btn_model').style.display = 'inline';
let modelWarn = document.getElementById('mzta-model_warn');
let btnModel = document.getElementById('mzta-btn_model');
if (modelWarn) modelWarn.style.display = 'inline-block';
if (btnModel) btnModel.style.display = 'inline';
}, 2000);
// Set up an interval that checks the value every 100 milliseconds
const intervalId = setInterval(() => {
@ -331,15 +341,13 @@ function checkGPTModel(model) {
// const element = document.querySelector('div#radix-\\\\:ri2\\\\: > div > span.text-token-text-secondary');
const elements = document.querySelectorAll('[id*=radix] span')
for(element of elements){
for(let element of elements){
// Check if the element exists and its content is '4' or '4o'
doLog("checkGPTModel model found in DOM: " + element.textContent);
if ((element && element.textContent === model)||(force_go)) {
doLog("The GPT Model is now " + model);
clearInterval(intervalId);
clearTimeout(intervalId2);
document.getElementById('mzta-model_warn').style.display = 'none';
document.getElementById('mzta-btn_model').style.display = 'none';
resolve(model);
break;
} else if (!element) {
@ -388,7 +396,7 @@ async function doProceed(message, customText = ''){
// console.log(">>>>>>>>>>>> doProceed customText: " + customText);
// console.log(">>>>>>>>>>>> doProceed final_prompt: " + final_prompt);
// console.log(">>>>>>>>>>>> doProceed mztaPhDefVal: " + JSON.stringify(mztaPhDefVal));
//check if there is che additional_text placeholder
//check if there is the additional_text placeholder
if(final_prompt.includes('{%additional_text%}')){
// console.log(">>>>>>>>>>>> found ph customText: " + customText);
final_prompt = final_prompt.replace('{%additional_text%}', customText || (mztaPhDefVal == '1'?'':'{%additional_text%}'));
@ -408,14 +416,7 @@ async function doProceed(message, customText = ''){
break;
case -2: // textarea not found
let curr_model_warn = document.getElementById('mzta-model_warn');
let message = browser.i18n.getMessage("chatgpt_textarea_not_found_error");
let parts = message.split(/<a href="([^"]+)">([^<]+)<\\/a>/);
curr_model_warn.textContent = parts[0];
let link = document.createElement('a');
link.href = parts[1];
link.textContent = parts[2];
curr_model_warn.appendChild(link);
curr_model_warn.appendChild(document.createTextNode(parts[3]));
curr_model_warn.textContent = browser.i18n.getMessage("chatgpt_textarea_not_found_error");
curr_model_warn.style.display = 'inline-block';
document.getElementById('mzta-curr_msg').textContent = "";
document.getElementById('mzta-loading').style.display = 'none';
@ -437,6 +438,10 @@ async function doProceed(message, customText = ''){
}
function doRetry(){
document.getElementById('mzta-model_warn').style.display = 'none';
document.getElementById('mzta-btn_retry').remove();
document.getElementById('mzta-loading').style.display = 'inline-block';
document.getElementById('mzta-curr_msg').textContent = browser.i18n.getMessage("chatgpt_win_working");
doProceed(current_message);
}
@ -647,7 +652,7 @@ browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
current_message = message;
current_tabId = message.tabId;
current_mailMessageId = message.mailMessageId;
if(current_mailMessageId == -1) { // we are using the reply from the compose window!
if((current_mailMessageId == -1) && (current_action == '1')) { // we are using the reply from the compose window!
current_action = '2'; // replace text
}
run();

View file

@ -79,11 +79,14 @@ switch (message.command) {
for (const node of children) {
if (node instanceof Element) {
if (node.classList.contains('moz-cite-prefix')) {
if (node.classList.contains('moz-cite-prefix')) { // quoted text in a reply
break;
}
if (node.classList.contains('moz-forward-container')) { // quoted text in a forward
break;
}
}
t += node.textContent;
t += node.textContent + " ";
// Track the first and last nodes for range
if (!firstNode) {
@ -110,6 +113,51 @@ switch (message.command) {
return Promise.resolve(t);
}
case "getOnlyQuotedText": {
let t = '';
const children = window.document.body.childNodes;
const selection = window.getSelection();
let firstNode = null;
let lastNode = null;
let foundCitePrefix = false;
for (const node of children) {
if (!foundCitePrefix) {
if (node instanceof Element && (node.classList.contains('moz-cite-prefix') || node.classList.contains('moz-forward-container'))) {
foundCitePrefix = true;
} else {
continue;
}
}
t += node.textContent + " ";
if (!firstNode) {
firstNode = node;
}
if (node.textContent.trim() !== '') {
lastNode = node;
}
}
if (!lastNode) {
lastNode = firstNode;
}
if (message.do_autoselect && firstNode && lastNode) {
const range = document.createRange();
range.setStartBefore(firstNode);
range.setEndAfter(lastNode);
selection.removeAllRanges();
selection.addRange(range);
}
return Promise.resolve(t);
}
case 'sendAlert':
//console.log(">>>>>> message.curr_tab_type: " + JSON.stringify(message.curr_tab_type));
if(message.curr_tab_type == 'mail'){ // workaround for Thunderbird bug not showing the alert

View file

@ -84,7 +84,8 @@ export class mzta_Menus {
selection: await browser.tabs.sendMessage(tabs[0].id, { command: "getSelectedText" }),
text: await browser.tabs.sendMessage(tabs[0].id, { command: "getTextOnly" }),
html: await browser.tabs.sendMessage(tabs[0].id, { command: "getFullHtml" }),
only_typed_text: await browser.tabs.sendMessage(tabs[0].id, { command: "getOnlyTypedText", do_autoselect: do_autoselect })
only_typed_text: await browser.tabs.sendMessage(tabs[0].id, { command: "getOnlyTypedText", do_autoselect: do_autoselect }),
only_quoted_text: await browser.tabs.sendMessage(tabs[0].id, { command: "getOnlyQuotedText" })
};
};
@ -105,11 +106,18 @@ export class mzta_Menus {
let body_text = '';
let selection_text = '';
let only_typed_text = '';
let only_quoted_text = '';
only_typed_text = msg_text.only_typed_text.replace(/\s+/g, ' ').trim();
selection_text = msg_text.selection.replace(/\s+/g, ' ').trim();
if(selection_text === ''){
if(placeholdersUtils.hasPlaceholder(curr_prompt.text, "mail_typed_text")){
selection_text = only_typed_text;
}
}
only_quoted_text = msg_text.only_quoted_text.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...");
let chatgpt_lang = await taPromptUtils.getDefaultLang(curr_prompt);
@ -133,7 +141,7 @@ export class mzta_Menus {
break;
}
fullPrompt = await taPromptUtils.preparePrompt(curr_prompt, curr_message, chatgpt_lang, selection_text, body_text, await getMailSubject(tabs[0]), msg_text, only_typed_text, tags_full_list);
fullPrompt = await taPromptUtils.preparePrompt(curr_prompt, curr_message, chatgpt_lang, selection_text, body_text, await getMailSubject(tabs[0]), msg_text, only_typed_text, only_quoted_text, tags_full_list);
switch(curr_prompt.id){
case 'prompt_translate_this':
@ -252,12 +260,86 @@ export class mzta_Menus {
}
}catch(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") });
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("no_valid_data_received") });
taWorkingStatus.stopWorking();
return {ok:'0'};
}
break; // Get a calendar event info - END
}
case 'prompt_get_task': { // Get a task info
let task_data = '';
let prefs_at = await browser.storage.sync.get({connection_type: '', calendar_enforce_timezone: false, calendar_timezone: '',});
if((prefs_at.connection_type === '')||(prefs_at.connection_type === null)||(prefs_at.connection_type === undefined)||(prefs_at.connection_type === 'chatgpt_web')){
console.error("[ThunderAI | GetTask] Invalid connection type: " + prefs_at.connection_type);
taWorkingStatus.stopWorking();
return {ok:'0'};
}
/* We expect to receive from the AI a JSON object like this:
* {
* "InitialDate": "YYYYMMDDTHHMMSS",
* "dueDate": "YYYYMMDDTHHMMSS",
* "summary": "Task summary here"
* }
*/
this.logger.log("fullPrompt: " + fullPrompt);
let cmd_GetTask = new mzta_specialCommand(fullPrompt,prefs_at.connection_type,true);
await cmd_GetTask.initWorker();
try{
task_data = await cmd_GetTask.sendPrompt();
// console.log(">>>>>>>>>>> task_data: " + task_data);
}catch(err){
console.error("[ThunderAI] Error getting task data: ", err.message);
browser.tabs.sendMessage(tabs[0].id, { command: "sendAlert", curr_tab_type: tabs[0].type, message: browser.i18n.getMessage("task_getting_data_error") + ": " + err.message });
taWorkingStatus.stopWorking();
return {ok:'0'};
}
let task_data_obj = {};
try{
task_data_obj = extractJsonObject(task_data);
if (!task_data_obj.dueDate || isNaN(Date.parse(task_data_obj.dueDate)) || task_data_obj.dueDate == '' ) {
delete task_data_obj.dueDate;
}
if (!task_data_obj.InitialDate || isNaN(Date.parse(task_data_obj.InitialDate)) || task_data_obj.InitialDate == '' ) {
delete task_data_obj.InitialDate;
}
}catch(err){
console.error("[ThunderAI] Error extracting JSON object from task data: ", err.message);
browser.tabs.sendMessage(tabs[0].id, { command: "sendAlert", curr_tab_type: tabs[0].type, message: browser.i18n.getMessage("task_getting_data_error") + ": " + err.message });
taWorkingStatus.stopWorking();
return {ok:'0'};
}
// Timezone management
task_data_obj.use_timezone = false;
if(prefs_at.calendar_enforce_timezone){
task_data_obj.use_timezone = true;
task_data_obj.timezone = prefs_at.calendar_timezone;
}
let task_data_str = JSON.stringify(task_data_obj);
// Timezone management - END
this.logger.log("task_data: " + task_data);
this.logger.log("task_data_obj: " + task_data_str);
try{
let result_openTaskDialog = await browser.runtime.sendMessage('thunderai-sparks@micz.it',{action: "openTaskDialog", task_data: task_data_str})
if(result_openTaskDialog == 'ok'){
taWorkingStatus.stopWorking();
return {ok:'1'};
} else {
let err = result_openTaskDialog.error;
if (err && typeof err === 'string' && err.startsWith('|>>')) {
result_openTaskDialog.error = browser.i18n.getMessage(result_openTaskDialog.error.substring(3));
}
browser.tabs.sendMessage(tabs[0].id, { command: "sendAlert", curr_tab_type: tabs[0].type, message: browser.i18n.getMessage("task_opening_dialog_error") + ": " + result_openTaskDialog.error });
taWorkingStatus.stopWorking();
return {ok:'0'};
}
}catch(err){
console.error("[ThunderAI] Error opening task dialog: ", err);
browser.tabs.sendMessage(tabs[0].id, { command: "sendAlert", curr_tab_type: tabs[0].type, message: browser.i18n.getMessage("task_opening_dialog_error") + ": " + browser.i18n.getMessage("no_valid_data_received") });
taWorkingStatus.stopWorking();
return {ok:'0'};
}
break;
} // Get a task info - END
default:
console.error("[ThunderAI] Unknown special prompt id: " + curr_prompt.id);
taWorkingStatus.stopWorking();

View file

@ -56,6 +56,13 @@ const defaultPlaceholders = [
type: 2,
is_default: "1",
},
{
id: 'mail_quoted_text',
name: "__MSG_placeholder_mail_quoted_text__",
default_value: "",
type: 2,
is_default: "1",
},
{
id: 'mail_subject',
name: "__MSG_placeholder_mail_subject__",
@ -168,6 +175,13 @@ const defaultPlaceholders = [
type: 0,
is_default: "1",
},
{
id: 'empty',
name: "__MSG_placeholder_empty__",
default_value: "",
type: 0,
is_default: "1",
},
];
@ -183,7 +197,6 @@ export async function getPlaceholders(onlyEnabled = false){
output.sort((a, b) => a.id.localeCompare(b.id));
}
// console.log('>>>>>>>>>>>> getPlaceholders output: ' + JSON.stringify(output));
let prefs = await browser.storage.local.get({ add_tags: false });
return output;
}
@ -288,7 +301,7 @@ export const placeholdersUtils = {
return regex.test(text);
},
async getPlaceholdersValues(prompt_text, curr_message, mail_subject, body_text, msg_text, only_typed_text, selection_text, tags_full_list) {
async getPlaceholdersValues(prompt_text, curr_message, mail_subject, body_text, msg_text, only_typed_text, only_quoted_text, selection_text, tags_full_list) {
let currPHs = await placeholdersUtils.extractPlaceholders(prompt_text);
// console.log(">>>>>>>>>> currPHs: " + JSON.stringify(currPHs));
let finalSubs = {};
@ -303,6 +316,9 @@ export const placeholdersUtils = {
case 'mail_typed_text':
finalSubs['mail_typed_text'] = placeholdersUtils.failSafePlaceholders(only_typed_text);
break;
case 'mail_quoted_text':
finalSubs['mail_quoted_text'] = placeholdersUtils.failSafePlaceholders(only_quoted_text);
break;
case 'mail_subject':
finalSubs['mail_subject'] = placeholdersUtils.failSafePlaceholders(mail_subject);
break;
@ -352,6 +368,9 @@ export const placeholdersUtils = {
let prefs_def_lang = await browser.storage.sync.get({default_chatgpt_lang: ''});
finalSubs['thunderai_def_lang'] = placeholdersUtils.failSafePlaceholders(prefs_def_lang.default_chatgpt_lang);
break;
case 'empty':
finalSubs['empty'] = '';
break;
default: // TODO Manage custom placeholders https://github.com/micz/ThunderAI/issues/156
break;
}

View file

@ -63,6 +63,15 @@
Position Compose Message (position_compose attribute):
<num>: position number
ChatGPT Web Model (chatgpt_web_model attribute):
<model>: model name (e.g. gpt-4, gpt-3.5-turbo, etc.)
ChatGPT Web Project (chatgpt_web_project attribute):
<project>: project id url
ChatGPT Web Custom GPT (chatgpt_web_custom_gpt attribute):
<custom_gpt>: custom gpt id url
*/
const defaultPrompts = [
@ -77,6 +86,9 @@ const defaultPrompts = [
need_custom_text: "0",
define_response_lang: "1",
use_diff_viewer: "0",
chatgpt_web_model: '',
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
is_default: "1",
is_special: "0",
},
@ -91,6 +103,9 @@ const defaultPrompts = [
need_custom_text: "0",
define_response_lang: "1",
use_diff_viewer: "0",
chatgpt_web_model: '',
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
is_default: "1",
is_special: "0",
},
@ -105,6 +120,9 @@ const defaultPrompts = [
need_custom_text: "0",
define_response_lang: "1",
use_diff_viewer: "1",
chatgpt_web_model: '',
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
is_default: "1",
is_special: "0",
},
@ -119,6 +137,9 @@ const defaultPrompts = [
need_custom_text: "0",
define_response_lang: "1",
use_diff_viewer: "1",
chatgpt_web_model: '',
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
is_default: "1",
is_special: "0",
},
@ -133,6 +154,9 @@ const defaultPrompts = [
need_custom_text: "0",
define_response_lang: "1",
use_diff_viewer: "0",
chatgpt_web_model: '',
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
is_default: "1",
is_special: "0",
},
@ -147,6 +171,26 @@ const defaultPrompts = [
need_custom_text: "0",
define_response_lang: "1",
use_diff_viewer: "0",
chatgpt_web_model: '',
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
is_default: "1",
is_special: "0",
},
{
id: 'prompt_proofread_this',
name: "__MSG_prompt_proofread_this__",
text: "prompt_proofread_this_full_text",
type: "2",
action: "2",
need_selected: "0",
need_signature: "0",
need_custom_text: "0",
define_response_lang: "1",
use_diff_viewer: "1",
chatgpt_web_model: '',
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
is_default: "1",
is_special: "0",
},
@ -161,6 +205,9 @@ const defaultPrompts = [
need_custom_text: "0",
define_response_lang: "0",
use_diff_viewer: "0",
chatgpt_web_model: '',
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
is_default: "1",
is_special: "0",
},
@ -175,6 +222,9 @@ const defaultPrompts = [
need_custom_text: "0",
define_response_lang: "0",
use_diff_viewer: "0",
chatgpt_web_model: '',
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
is_default: "1",
is_special: "0",
},
@ -209,6 +259,20 @@ const specialPrompts = [
is_default: "1",
is_special: "1",
},
{
id: 'prompt_get_task',
name: "__MSG_prompt_get_task__",
text: "prompt_get_task_full_text",
type: "1",
action: "0",
need_selected: "1",
need_signature: "0",
need_custom_text: "0",
define_response_lang: "0",
use_diff_viewer: "0",
is_default: "1",
is_special: "1",
},
{
id: 'prompt_spamfilter',
name: "__MSG_prompt_spamfilter__",
@ -343,6 +407,15 @@ async function getCustomPrompts() {
if (prompt.use_diff_viewer === undefined) {
prompt.use_diff_viewer = "0";
}
if(prompt.chatgpt_web_model === undefined){
prompt.chatgpt_web_model = "";
}
if(prompt.chatgpt_web_project === undefined){
prompt.chatgpt_web_project = "";
}
if(prompt.chatgpt_web_custom_gpt === undefined){
prompt.chatgpt_web_custom_gpt = "";
}
});
return prefs._custom_prompt;
}
@ -380,7 +453,7 @@ export async function getSpecialPrompts(){
updatedPrompts.push(newPrompt);
}
});
// console.log(">>>>>>>>>>>>> getSpecialPrompts updatedPrompts: " + JSON.stringify(updatedPrompts));
if (updatedPrompts.length !== prefs._special_prompts.length) {
await browser.storage.local.set({ _special_prompts: updatedPrompts });
}

View file

@ -29,7 +29,7 @@ export const taPromptUtils = {
}
},
async preparePrompt(curr_prompt, curr_message, chatgpt_lang, selection_text, body_text, subject_text, msg_text, only_typed_text, tags_full_list){
async preparePrompt(curr_prompt, curr_message, chatgpt_lang, selection_text, body_text, subject_text, msg_text, only_typed_text, only_quoted_text, tags_full_list){
let fullPrompt = '';
if(!placeholdersUtils.hasPlaceholder(curr_prompt.text)){
@ -37,7 +37,7 @@ export const taPromptUtils = {
fullPrompt = curr_prompt.text + (String(curr_prompt.need_signature) == "1" ? " " + await taPromptUtils.getDefaultSignature():"") + " " + chatgpt_lang + " \"" + (selection_text=='' ? body_text : selection_text) + "\" ";
}else{
// we have at least a placeholder, do the magic!
let finalSubs = await placeholdersUtils.getPlaceholdersValues(curr_prompt.text, curr_message, subject_text, body_text, msg_text, only_typed_text, selection_text, tags_full_list);
let finalSubs = await placeholdersUtils.getPlaceholdersValues(curr_prompt.text, curr_message, subject_text, body_text, msg_text, only_typed_text, only_quoted_text, selection_text, tags_full_list);
// console.log(">>>>>>>>>> finalSubs: " + JSON.stringify(finalSubs));
let prefs_ph = await browser.storage.sync.get({placeholders_use_default_value: false});
fullPrompt = (placeholdersUtils.replacePlaceholders(curr_prompt.text, finalSubs, prefs_ph.placeholders_use_default_value, true) + (String(curr_prompt.need_signature) == "1" ? " " + await taPromptUtils.getDefaultSignature():"") + " " + chatgpt_lang).trim();

View file

@ -16,6 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
const sparks_min = '1.2.0'; // Minimum version of ThunderAI-Sparks required for the add-on to work
export const ChatGPTWeb_models = ['gpt-4o', 'o3', 'o4-mini', 'o4-mini-high', 'gpt-4o-mini']; // List of models available in ChatGPT Web
export const getMenuContextCompose = () => 'compose_action_menu';
export const getMenuContextDisplay = () => 'message_display_action_menu';
@ -41,46 +44,54 @@ function fixMsgHeader(msgHeader) {
return msgHeader;
}
export async function getCurrentIdentity(msgHeader, getFull = false) {
let identities_array = [];
let fallback_identity = '';
msgHeader = fixMsgHeader(msgHeader);
export async function getAccountsList() {
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));
}
}
}
// check if the author is an identity
let author = extractEmail(msgHeader.author);
let author_identity = identities_array.find(identity => identity.email === author);
if (author_identity) {
// 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);
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) {
// console.log(">>>>>>>>>> getCurrentIdentity matching_identity: " + JSON.stringify(matching_identity));
return getFull ? matching_identity : matching_identity.id;
} else { // no identity found. using the fallback one
// console.log(">>>>>>>>>> getCurrentIdentity fallback_identity: " + JSON.stringify(fallback_identity));
return getFull ? fallback_identity : fallback_identity.id;
let accounts_array = [];
for (let account of accounts) {
let account_id = account.id;
let account_name = account.name;
accounts_array.push({id: account_id, name: account_name});
}
return accounts_array;
}
export async function getCurrentIdentity(msgHeader, getFull = false) {
let identities = [];
let fallbackIdentity = null;
msgHeader = fixMsgHeader(msgHeader);
const accounts = await browser.accounts.list();
for (const account of accounts) {
for (const identity of account.identities) {
const entry = { id: identity.id, email: identity.email };
identities.push(entry);
if (!fallbackIdentity) fallbackIdentity = entry;
}
}
// Check if author is a known identity
const authorEmail = extractEmail(msgHeader.author);
const authorIdentity = identities.find(identity => identity.email === authorEmail);
if (authorIdentity) {
return getFull ? authorIdentity : authorIdentity.id;
}
// Check if any of the recipients (to/cc/bcc) are a known identity
const allRecipients = [...msgHeader.recipients, ...msgHeader.ccList, ...msgHeader.bccList];
for (const recipient of allRecipients) {
const email = extractEmail(recipient);
const identity = identities.find(id => id.email === email);
if (identity) {
return getFull ? identity : identity.id;
}
}
// Fallback
return getFull ? fallbackIdentity : fallbackIdentity?.id || null;
}
function extractEmail(text) {
if((text=='')||(text==undefined)) return '';
const emailRegex = /[\w.-]+@[\w.-]+\.\w+/;
@ -203,6 +214,59 @@ export function getGPTWebModelString(model) {
}
}
export function getChatGPTWebModelsList_HTML(values, targetRowId) {
const rowElement = document.getElementById(targetRowId);
if (!rowElement) return;
// Clears any existing td elements
rowElement.innerHTML = '';
// First TD: label
const labelTd = document.createElement('td');
const label = document.createElement('i');
label.className = 'small_info';
const labelNobr = document.createElement('nobr');
labelNobr.textContent = browser.i18n.getMessage("AllowedValues") + ":";
label.appendChild(labelNobr);
labelTd.appendChild(label);
// Second TD: values
const valuesTd = document.createElement('td');
const valuesContainer = document.createElement('i');
valuesContainer.className = 'small_info';
values.forEach(value => {
const nbspBefore = document.createTextNode(' \u00A0 '); // " &nbsp; "
const valueNobr = document.createElement('nobr');
valueNobr.className = 'conntype_chatgpt_web_option';
valueNobr.textContent = value;
const nbspAfter = document.createTextNode(' \u00A0 ');
valuesContainer.appendChild(nbspBefore);
valuesContainer.appendChild(valueNobr);
valuesContainer.appendChild(nbspAfter);
});
valuesTd.appendChild(valuesContainer);
// Adds the td elements to the row
rowElement.appendChild(labelTd);
rowElement.appendChild(valuesTd);
}
export function openTab(url){
// check if the tab is already there
browser.tabs.query({url: browser.runtime.getURL(url)}).then((tabs) => {
if (tabs.length > 0) {
// if the tab is already there, focus it
browser.tabs.update(tabs[0].id, {active: true});
} else {
// if the tab is not there, create it
browser.tabs.create({url: browser.runtime.getURL(url)});
}
})
}
export function i18nConditionalGet(str) {
// if we are getting a string that starts with '__MSG_' and ends with '__' we return the translated string
// using the browser.i18n API
@ -337,18 +401,22 @@ export async function transformTagsLabels(labels, tags_list) {
return output;
}
export function getActiveSpecialPromptsIDs(addtags = false, get_calendar_event = false, is_chatgpt_web = false) {
export function getActiveSpecialPromptsIDs(args = {}) {
const { addtags = false, get_calendar_event = false, get_task = false, is_chatgpt_web = false } = args;
let output = [];
// console.log(">>>>>>>>>> getActiveSpecialPromptsIDs addtags: " + addtags + " get_calendar_event: " + get_calendar_event + " is_chatgpt_web: " + is_chatgpt_web);
if(is_chatgpt_web){
// console.log(">>>>>>>>>> getActiveSpecialPromptsIDs args: " + JSON.stringify(args));
if (is_chatgpt_web) {
return output;
}
if(addtags){
if (addtags) {
output.push('prompt_add_tags');
}
if(get_calendar_event){
if (get_calendar_event) {
output.push('prompt_get_calendar_event');
}
if (get_task) {
output.push('prompt_get_task');
}
// console.log(">>>>>>>>>> getActiveSpecialPromptsIDs output: " + JSON.stringify(output));
return output;
}
@ -374,12 +442,38 @@ export function extractJsonObject(inputString) {
export async function checkSparksPresence() {
try {
return (await browser.runtime.sendMessage('thunderai-sparks@micz.it',{action: "checkPresence"}) === 'ok');
let sparks_current = await browser.runtime.sendMessage('thunderai-sparks@micz.it',{action: "checkPresence"});
if(sparks_current === undefined || sparks_current === null) {
return -1;
}
if (compareThunderbirdVersions(sparks_current, sparks_min) < 0) {
return 0;
}else{
return 1;
}
} catch (error) {
return false;
return -1;
}
}
export function validateChatGPTWebCustomData(data) {
return /^\/g\/[a-zA-Z0-9/-]+$/.test(data) || data == '';
}
export function sanitizeChatGPTModelData(input) {
return encodeURIComponent(input).toLowerCase()
}
export function sanitizeChatGPTWebCustomData(input) {
// Removes all characters that are not letters, numbers, dashes, or slashes
return input.replace(/[^\p{L}\p{N}\/-]+/gu, '');
}
export function validateCustomData_ChatGPTWeb(event) {
let is_valid = validateChatGPTWebCustomData(event.target.value);
event.target.style.borderColor = is_valid ? 'green' : 'red';
document.getElementById(event.target.id + '_info').style.color = is_valid ? '' : 'red';
}
// The following methods are a modified version derived from https://github.com/ali-raheem/Aify/blob/13ff87583bc520fb80f555ab90a90c5c9df797a7/plugin/content_scripts/compose.js
@ -388,8 +482,11 @@ const insertHtml = function (replyHtml, fullBody_string) {
let fullBody = parser.parseFromString(fullBody_string, "text/html");
let reply = parser.parseFromString(replyHtml, "text/html");
// looking for the first quoted mail or the signature, which come first in case of "signature above the quote".
const prefix_quote = fullBody.getElementsByClassName("moz-cite-prefix");
// looking for the first quoted mail (reply or forward) or the signature, which come first in case of "signature above the quote".
let prefix_quote = fullBody.getElementsByClassName("moz-cite-prefix");
if(prefix_quote.length == 0){
prefix_quote = fullBody.getElementsByClassName("moz-forward-container");
}
const prefix_sign = fullBody.getElementsByClassName("moz-signature");
let firstElement = null;

View file

@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "ThunderAI",
"description": "__MSG_extensionDescription__",
"version": "3.3.6",
"version": "3.4.0",
"author": "Mic (m@micz.it)",
"homepage_url": "https://micz.it/thunderbird-addon-thunderai/",
"browser_specific_settings": {
@ -31,13 +31,13 @@
"activeTab",
"accountsRead",
"downloads",
"messagesTagsList",
"https://*.chatgpt.com/*"
"messagesTagsList"
],
"optional_permissions": [
"messagesTags",
"messagesUpdate",
"messagesMove",
"https://*.chatgpt.com/*",
"<all_urls>"
],
"background": {

View file

@ -20,7 +20,7 @@ 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, contextMenuID_AddTags, contextMenuID_Spamfilter, stripHtmlKeepLines } 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, sanitizeChatGPTModelData, sanitizeChatGPTWebCustomData, stripHtmlKeepLines } 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';
@ -45,6 +45,7 @@ var original_html = '';
var modified_html = '';
let _process_incoming = false;
let _sparks_presence = false;
let prefs_init = {};
await reload_pref_init();
@ -52,7 +53,12 @@ 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"));
let special_prompts_ids = getActiveSpecialPromptsIDs({
addtags: prefs_init.add_tags,
get_calendar_event: doGetSparkFeature(prefs_init.get_calendar_event),
get_task: doGetSparkFeature(prefs_init.get_task),
is_chatgpt_web: (prefs_init.connection_type === "chatgpt_web")
});
browser.composeScripts.register({
js: [{file: "/js/mzta-compose-script.js"}]
@ -146,11 +152,16 @@ function preparePopupMenu(tab) {
}
async function _reload_menus() {
let prefs_reload = await browser.storage.sync.get({add_tags: true, get_calendar_event: false, connection_type: 'chatgpt_web'});
doGetCalendarEvent(prefs_reload.get_calendar_event).then(calendarEvent => {
const special_prompts_ids = getActiveSpecialPromptsIDs(prefs_reload.add_tags, calendarEvent, (prefs_reload.connection_type === "chatgpt_web"));
menus.reload(special_prompts_ids);
});
let prefs_reload = await browser.storage.sync.get({add_tags: prefs_default.add_tags, get_calendar_event: prefs_default.get_calendar_event, get_task: prefs_default.get_task, connection_type: prefs_default.connection_type});
let getCalendarEvent = doGetSparkFeature(prefs_reload.get_calendar_event);
let getTask = doGetSparkFeature(prefs_reload.get_task);
const special_prompts_ids = getActiveSpecialPromptsIDs({
addtags: prefs_reload.add_tags,
get_calendar_event: getCalendarEvent,
get_task: getTask,
is_chatgpt_web: (prefs_reload.connection_type === "chatgpt_web")
});
menus.reload(special_prompts_ids);
taLog.log("Reloading menus");
return true;
}
@ -288,6 +299,9 @@ messenger.runtime.onMessage.addListener((message, sender, sendResponse) => {
case 'assign_tags':
return _assign_tags(message);
break;
case 'api_send_custom_text':
browser.tabs.sendMessage(message.tabId, { command: "api_send_custom_text", custom_text: message.custom_text });
break;
default:
break;
}
@ -310,6 +324,7 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_
taLog.changeDebug(prefs.do_debug);
prefs = checkScreenDimensions(prefs);
//console.log(">>>>>>>>>>>>>>>> prefs: " + JSON.stringify(prefs));
// console.log(">>>>>>>>>>>>>>>> prompt_info: " + JSON.stringify(prompt_info));
taLog.log("Prompt length: " + promptText.length);
if(promptText.length > prefs.max_prompt_length){
// Prompt too long for ChatGPT
@ -327,18 +342,40 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_
let rand_call_id = '_chatgptweb_' + generateCallID();
let call_opt = '';
let _wait_time = 1000;
let _base_url = "https://chatgpt.com";
let _webproject_set = false;
let _custom_gpt_set = false;
let _use_prompt_info_custom_gpt = false;
let _custom_model = sanitizeChatGPTModelData(prompt_info.chatgpt_web_model != '' ? prompt_info.chatgpt_web_model : prefs.chatgpt_web_model);
let _web_project = sanitizeChatGPTWebCustomData(prompt_info.chatgpt_web_project != '' ? prompt_info.chatgpt_web_project : prefs.chatgpt_web_project)
let _custom_gpt = sanitizeChatGPTWebCustomData(prompt_info.chatgpt_web_custom_gpt != '' ? prompt_info.chatgpt_web_custom_gpt : prefs.chatgpt_web_custom_gpt)
if(prefs.chatgpt_web_tempchat){
call_opt += '&temporary-chat=true';
}
if(prefs.chatgpt_web_model != ''){
call_opt += '&model=' + encodeURIComponent(prefs.chatgpt_web_model).toLowerCase();
if((prompt_info.chatgpt_web_model != '') || (prefs.chatgpt_web_model != '')){
call_opt += '&model=' + _custom_model;
}
taLog.log("[chatgpt_web] call_opt: " + call_opt);
// If there is a custom gpt on the prompt, but also a web_project on the prefs, we need to use the custom gpt
_use_prompt_info_custom_gpt = (prompt_info.chatgpt_web_custom_gpt != '' && prompt_info.chatgpt_web_project == '');
if(!_use_prompt_info_custom_gpt && ((prompt_info.chatgpt_web_project != '') || (prefs.chatgpt_web_project != ''))){
_base_url += _web_project;
_webproject_set = true;
_wait_time = 2000;
}
if(!_webproject_set && ((prompt_info.chatgpt_web_custom_gpt != '') || (prefs.chatgpt_web_custom_gpt != ''))){
_base_url += _custom_gpt;
_custom_gpt_set = true;
}
let win_options = {
url: "https://chatgpt.com?call_id=" + rand_call_id + call_opt,
url: _base_url + "?call_id=" + rand_call_id + call_opt,
type: "popup",
}
@ -353,9 +390,9 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_
async function handleChatGptWeb(createdTab) {
taLog.log("ChatGPT web interface script started...");
let _gpt_model = getGPTWebModelString(prefs.chatgpt_web_model);
let _gpt_model = getGPTWebModelString(_custom_model);
taLog.log("prefs.chatgpt_web_model: " + prefs.chatgpt_web_model);
taLog.log("_custom_model: " + _custom_model);
taLog.log("_gpt_model: " + _gpt_model);
let originalText = prompt_info.selection_text;
@ -370,15 +407,15 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_
let mztaDoCustomText=`+ do_custom_text +`;
let mztaPromptName="[`+ i18nConditionalGet(prompt_name) +`]";
let mztaPhDefVal="`+(prefs.placeholders_use_default_value?'1':'0')+`";
let mztaGPTModel="`+ _gpt_model +`";
let mztaGPTModel="`+ (_custom_gpt_set ? '' : _gpt_model) +`";
let mztaDoDebug="`+(prefs.do_debug?'1':'0')+`";
let mztaUseDiffViewer="`+(prompt_info.use_diff_viewer=='1'?'1':'0')+`";
let mztaOriginalText="`+ JSON.stringify(originalText).slice(1, -1) +`";
`;
taLog.log("Waiting 1 sec");
await new Promise(resolve => setTimeout(resolve, 1000));
taLog.log("Waiting 1 sec done");
taLog.log("Waiting " + _wait_time + " millisec");
await new Promise(resolve => setTimeout(resolve, _wait_time));
taLog.log("Waiting " + _wait_time + " millisec done");
await browser.tabs.executeScript(createdTab.id, { code: pre_script + mzta_script, matchAboutBlank: false });
// let mailMessage = await browser.messageDisplay.getDisplayedMessage(curr_tabId);
@ -623,17 +660,18 @@ function checkScreenDimensions(prefs){
return prefs;
}
async function doGetCalendarEvent(get_calendar_event) {
if(get_calendar_event) {
return await checkSparksPresence();
function doGetSparkFeature(spark_feature_active) {
if(spark_feature_active) {
return (_sparks_presence == 1);
} else {
return false;
}
}
async function reload_pref_init(){
prefs_init = await browser.storage.sync.get({do_debug: false, add_tags: false, 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});
prefs_init = await browser.storage.sync.get({do_debug: prefs_default.do_debug, add_tags: prefs_default.add_tags, get_calendar_event: prefs_default.get_calendar_event, get_task: prefs_default.get_task, connection_type: prefs_default.connection_type, add_tags_auto: prefs_default.add_tags_auto, add_tags_auto_force_existing: prefs_default.add_tags_auto_force_existing, add_tags_auto_only_inbox: prefs_default.add_tags_auto_only_inbox, spamfilter: prefs_default.spamfilter, spamfilter_threshold: prefs_default.spamfilter_threshold, dynamic_menu_force_enter: prefs_default.dynamic_menu_force_enter, add_tags_context_menu: prefs_default.add_tags_context_menu, spamfilter_context_menu: prefs_default.spamfilter_context_menu});
_process_incoming = prefs_init.add_tags_auto || prefs_init.spamfilter;
_sparks_presence = await checkSparksPresence();
}
@ -645,28 +683,57 @@ function setupStorageChangeListener() {
// Process 'add_tags' changes
if (changes.add_tags) {
const newTags = changes.add_tags.newValue;
doGetCalendarEvent(prefs_init.get_calendar_event).then(calendarEvent => {
const special_prompts_ids = getActiveSpecialPromptsIDs(newTags, calendarEvent, (prefs_init.connection_type === "chatgpt_web"));
menus.reload(special_prompts_ids);
});
let getCalendarEvent = doGetSparkFeature(prefs_init.get_calendar_event);
let getTask = doGetSparkFeature(prefs_init.get_task);
const special_prompts_ids = getActiveSpecialPromptsIDs({
addtags: newTags,
get_calendar_event: getCalendarEvent,
get_task: getTask,
is_chatgpt_web: (prefs_init.connection_type === "chatgpt_web")
});
menus.reload(special_prompts_ids);
}
// Process 'get_calendar_event' changes
if (changes.get_calendar_event) {
const newCalendarEvent = changes.get_calendar_event.newValue;
doGetCalendarEvent(newCalendarEvent).then(calendarEvent => {
const special_prompts_ids = getActiveSpecialPromptsIDs(prefs_init.add_tags, calendarEvent, (prefs_init.connection_type === "chatgpt_web"));
menus.reload(special_prompts_ids);
});
let getCalendarEvent = doGetSparkFeature(newCalendarEvent);
let getTask = doGetSparkFeature(prefs_init.get_task);
const special_prompts_ids = getActiveSpecialPromptsIDs({
addtags: prefs_init.add_tags,
get_calendar_event: getCalendarEvent,
get_task: getTask,
is_chatgpt_web: (prefs_init.connection_type === "chatgpt_web")
});
menus.reload(special_prompts_ids);
}
// Process 'get_task' changes
if (changes.get_task) {
const newTask = changes.get_task.newValue;
let getCalendarEvent = doGetSparkFeature(prefs_init.get_calendar_event);
let getTask = doGetSparkFeature(newTask);
const special_prompts_ids = getActiveSpecialPromptsIDs({
addtags: prefs_init.add_tags,
get_calendar_event: getCalendarEvent,
get_task: getTask,
is_chatgpt_web: (prefs_init.connection_type === "chatgpt_web")
});
menus.reload(special_prompts_ids);
}
// Process 'connection_type' changes
if (changes.connection_type) {
const newConnectionType = changes.connection_type.newValue;
doGetCalendarEvent(prefs_init.get_calendar_event).then(calendarEvent => {
const special_prompts_ids = getActiveSpecialPromptsIDs(prefs_init.add_tags, calendarEvent, (newConnectionType === "chatgpt_web"));
menus.reload(special_prompts_ids);
});
let getCalendarEvent = doGetSparkFeature(prefs_init.get_calendar_event);
let getTask = doGetSparkFeature(prefs_init.get_task);
const special_prompts_ids = getActiveSpecialPromptsIDs({
addtags: prefs_init.add_tags,
get_calendar_event: getCalendarEvent,
get_task: getTask,
is_chatgpt_web: (newConnectionType === "chatgpt_web")
});
menus.reload(special_prompts_ids);
if(newConnectionType === "chatgpt_web"){
removeContextMenu(contextMenuID_AddTags);
@ -808,6 +875,9 @@ const newEmailListener = (folder, messagesList) => {
async function processEmails(messages, addTagsAuto, spamFilter) {
taWorkingStatus.startWorking();
let prefs_aats = await browser.storage.sync.get({ add_tags_maxnum: prefs_default.add_tags_maxnum, connection_type: prefs_default.connection_type, add_tags_force_lang: prefs_default.add_tags_force_lang, default_chatgpt_lang: prefs_default.default_chatgpt_lang, add_tags_auto_force_existing: prefs_default.add_tags_auto_force_existing, add_tags_enabled_accounts: prefs_default.add_tags_enabled_accounts, spamfilter_enabled_accounts: prefs_default.spamfilter_enabled_accounts });
for await (let message of messages) {
let curr_fullMessage = null;
let msg_text = null;
@ -820,12 +890,18 @@ async function processEmails(messages, addTagsAuto, spamFilter) {
}
if (addTagsAuto) {
if(prefs_aats.add_tags_enabled_accounts.length > 0){
let accountId = message.folder.accountId;
if(!prefs_aats.add_tags_enabled_accounts.includes(accountId)){
taLog.log("Account " + accountId + " not enabled for add_tags, skipping...");
continue;
}
}
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);
@ -842,6 +918,13 @@ async function processEmails(messages, addTagsAuto, spamFilter) {
}
if (spamFilter) {
if(prefs_aats.spamfilter_enabled_accounts.length > 0){
let accountId = message.folder.accountId;
if(!prefs_aats.spamfilter_enabled_accounts.includes(accountId)){
taLog.log("Account " + accountId + " not enabled for spamfilter, skipping...");
continue;
}
}
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, '', '');

View file

@ -26,6 +26,8 @@ export const prefs_default = {
connection_type: 'chatgpt_web', //Other values: 'chatgpt_api', 'ollama_api', 'openai_comp_api', 'google_gemini_api'
chatgpt_web_model: '',
chatgpt_web_tempchat: false,
chatgpt_web_project: '',
chatgpt_web_custom_gpt: '',
chatgpt_api_key: '',
chatgpt_model: '',
chatgpt_developer_messages: '',
@ -53,10 +55,13 @@ export const prefs_default = {
add_tags_auto_force_existing: false,
add_tags_auto_only_inbox: true,
add_tags_context_menu: true,
add_tags_enabled_accounts: [],
get_calendar_event: true,
get_task: true,
calendar_enforce_timezone: false,
calendar_timezone: '',
spamfilter: false,
spamfilter_threshold: 70,
spamfilter_context_menu: true,
spamfilter_enabled_accounts: [],
}

View file

@ -74,6 +74,10 @@ span.dims_label{
display: inline-block;
}
span.opt_title{
font-weight: bold;
}
#btn_custom_prompts{
text-align: center;
width: 100%;

View file

@ -18,7 +18,7 @@
<td colspan="2" style="text-align:center;" class="warning"><b>__MSG_hyprland_warning__</b></td>
</tr>
<tr>
<td><span>__MSG_prefs_OptionText_chatgpt_win_text__</span>
<td><span class="opt_title">__MSG_prefs_OptionText_chatgpt_win_text__</span>
<td>
<label>
<span class="dims_label">__MSG_prefs_OptionText_chatgpt_win_height__</span>
@ -35,7 +35,7 @@
</tr>
<tr>
<td><label>
<span>__MSG_prefs_OptionText_default_sign_name__</span>
<span class="opt_title">__MSG_prefs_OptionText_default_sign_name__</span>
</label></td>
<td>
<label>
@ -45,7 +45,7 @@
</tr>
<tr>
<td><label>
<span>__MSG_prefs_OptionText_default_chatgpt_lang__</span>
<span class="opt_title">__MSG_prefs_OptionText_default_chatgpt_lang__</span>
</label></td>
<td>
<label>
@ -56,7 +56,7 @@
<tr>
<td>
<label>
<span>__MSG_prefs_OptionText_reply_type__</span>
<span class="opt_title">__MSG_prefs_OptionText_reply_type__</span>
</label>
</td>
<td>
@ -70,7 +70,7 @@
</tr>
<tr>
<td><label>
<span>__MSG_prefs_OptionText_dynamic_menu_order_alphabet__</span>
<span class="opt_title">__MSG_prefs_OptionText_dynamic_menu_order_alphabet__</span>
</label></td>
<td>
<label>
@ -81,7 +81,7 @@
</tr>
<tr>
<td><label>
<span>__MSG_prefs_OptionText_dynamic_menu_force_enter__</span>
<span class="opt_title">__MSG_prefs_OptionText_dynamic_menu_force_enter__</span>
</label></td>
<td>
<label>
@ -92,7 +92,7 @@
</tr>
<tr>
<td><label>
<span>__MSG_prefs_OptionText_placeholders_use_default_value__</span>
<span class="opt_title">__MSG_prefs_OptionText_placeholders_use_default_value__</span>
</label></td>
<td>
<label>
@ -115,7 +115,7 @@
<tr>
<td>
<label>
<span>__MSG_prefs_Connection_type__</span>
<span class="opt_title">__MSG_prefs_Connection_type__</span>
</label>
</td>
<td>
@ -133,7 +133,7 @@
<tr>
<tr class="conntype_chatgpt_web">
<td><label>
<span>__MSG_prefs_OptionText_chatgpt_web_model__</span>
<span class="opt_title">__MSG_prefs_OptionText_chatgpt_web_model__</span>
<br><table title="__MSG_prefs_OptionText_chatgpt_web_model_tooltip__"><tr id="chatgpt_web_models_list"></tr></table>
</label></td>
<td>
@ -145,26 +145,53 @@
</tr>
<tr class="conntype_chatgpt_web">
<td><label>
<span>__MSG_prefs_OptionText_chatgpt_web_tempchat__</span>
<span class="opt_title">__MSG_prefs_OptionText_chatgpt_web_project__</span>
<br><i class="small_info" id="chatgpt_web_project_info">__MSG_prefs_OptionText_chatgpt_web_custom_data_info__ <b>/g/PROJECT-ID-PROJECT-NAME/project</b>
<br>__MSG_prefs_OptionText_chatgpt_web_custom_data_info2__</i>
</label></td>
<td>
<label>
<input type="checkbox" id="chatgpt_web_tempchat" name="chatgpt_web_tempchat" class="option-input" />
&nbsp;<span>__MSG_prefs_OptionText_chatgpt_web_tempchat_info__</span>
<input type="text" id="chatgpt_web_project" name="chatgpt_web_project" class="option-input" />
<br>__MSG_prefs_OptionText_chatgpt_web_project_info__
</label>
</td>
</tr>
<tr class="conntype_chatgpt_web">
<td><label>
<span>__MSG_OpenChatGPTTab_Info__</span>
<span class="opt_title">__MSG_prefs_OptionText_chatgpt_web_custom_gpt__</span>
<br><i class="small_info" id="chatgpt_web_custom_gpt_info">__MSG_prefs_OptionText_chatgpt_web_custom_data_info__ <b>/g/CUSTOM-GPT-ID</b>
<br>__MSG_prefs_OptionText_chatgpt_web_custom_data_info2__</i>
</label></td>
<td>
<button id="btnChatGPTWeb_Tab">__MSG_OpenChatGPTTab__</button>
<label>
<input type="text" id="chatgpt_web_custom_gpt" name="chatgpt_web_custom_gpt" class="option-input" />
<br>__MSG_prefs_OptionText_chatgpt_web_custom_gpt_info__
<br>__MSG_prefs_OptionText_CustomGPT_Warn__
</label>
</td>
</tr>
<tr class="conntype_chatgpt_web">
<td><label>
<span class="opt_title">__MSG_prefs_OptionText_chatgpt_web_tempchat__</span>
</label></td>
<td>
<label>
<input type="checkbox" id="chatgpt_web_tempchat" name="chatgpt_web_tempchat" class="option-input" />
&nbsp;<span>__MSG_prefs_OptionText_chatgpt_web_tempchat_info__
<br>__MSG_prefs_OptionText_Project_No_temporary_chat_warn__
</span>
</label>
</td>
</tr>
<tr class="conntype_chatgpt_web">
<td colspan="2" style="padding:0px 2em;text-align:center;"><span>__MSG_OpenChatGPTTab_Info__</span>
<br><br><button id="btnChatGPTWeb_Tab">__MSG_OpenChatGPTTab__</button>
<br><br>__MSG_OpenChatGPTTab_Info2__
</td>
</tr>
<tr class="conntype_chatgpt_api">
<td><label>
<span>__MSG_prefs_ChatGPT_API_Key__</span>
<span class="opt_title">__MSG_prefs_ChatGPT_API_Key__</span>
</label></td>
<td>
<div class="api_key-container">
@ -178,7 +205,7 @@
<tr class="conntype_chatgpt_api">
<td>
<label>
<span>__MSG_ChatGPT_Models__</span>
<span class="opt_title">__MSG_ChatGPT_Models__</span>
</label>
</td>
<td>
@ -192,7 +219,7 @@
<tr class="conntype_chatgpt_api">
<td>
<label>
<span>__MSG_ChatGPT_Developer_Messages__</span>
<span class="opt_title">__MSG_ChatGPT_Developer_Messages__</span>
</label>
</td>
<td>
@ -204,7 +231,7 @@
</tr>
<tr class="conntype_google_gemini_api">
<td><label>
<span>__MSG_prefs_GoogleGemini_API_Key__</span>
<span class="opt_title">__MSG_prefs_GoogleGemini_API_Key__</span>
</label></td>
<td>
<div class="api_key-container">
@ -218,7 +245,7 @@
<tr class="conntype_google_gemini_api">
<td>
<label>
<span>__MSG_GoogleGemini_Models__</span>
<span class="opt_title">__MSG_GoogleGemini_Models__</span>
</label>
</td>
<td>
@ -232,7 +259,7 @@
<tr class="conntype_google_gemini_api">
<td>
<label>
<span>__MSG_GoogleGemini_SystemInstruction__</span>
<span class="opt_title">__MSG_GoogleGemini_SystemInstruction__</span>
</label>
</td>
<td>
@ -244,7 +271,7 @@
</tr>
<tr class="conntype_ollama_api">
<td><label>
<span>__MSG_prefs_API_Host__</span>
<span class="opt_title">__MSG_prefs_API_Host__</span>
<br><i class="small_info">__MSG_prefs_API_Host_Info__ http://127.0.0.1:11434</i>
</label></td>
<td>
@ -275,7 +302,7 @@
<tr class="conntype_ollama_api">
<td>
<label>
<span>__MSG_Ollama_Models__</span>
<span class="opt_title">__MSG_Ollama_Models__</span>
</label>
</td>
<td>
@ -288,7 +315,7 @@
</tr>
<tr class="conntype_openai_comp_api">
<td><label>
<span>__MSG_prefs_API_Host__</span>
<span class="opt_title">__MSG_prefs_API_Host__</span>
<br><i class="small_info">__MSG_prefs_API_Host_Info__ http://localhost:1234</i>
</label></td>
<td>
@ -308,7 +335,7 @@
</tr>
<tr class="conntype_openai_comp_api">
<td><label>
<span>__MSG_prefs_OptionText_openai_comp_use_v1__</span>
<span class="opt_title">__MSG_prefs_OptionText_openai_comp_use_v1__</span>
</label></td>
<td>
<label>
@ -319,7 +346,7 @@
</tr>
<tr class="conntype_openai_comp_api">
<td><label>
<span>__MSG_prefs_OpenAIComp_API_Key__</span>
<span class="opt_title">__MSG_prefs_OpenAIComp_API_Key__</span>
<br><i class="small_info">__MSG_Optional__</i>
</label></td>
<td>
@ -334,7 +361,7 @@
<tr class="conntype_openai_comp_api">
<td>
<label>
<span>__MSG_OpenAIComp_Models__</span>
<span class="opt_title">__MSG_OpenAIComp_Models__</span>
<br><button id="btnOpenAICompForceModel" class="btn_small">__MSG_prefs_OpenAIComp_ForceModel__</button></td>
</label>
</td>
@ -348,7 +375,7 @@
</tr>
<tr class="conntype_openai_comp_api">
<td><label>
<span>__MSG_prefs_OpenAIComp_ChatName__</span>
<span class="opt_title">__MSG_prefs_OpenAIComp_ChatName__</span>
</label></td>
<td>
<label>
@ -358,7 +385,7 @@
</td>
</tr>
<tr id="max_prompt_length_tr">
<td><span>__MSG_prefs_OptionText_max_prompt_length__</span></td>
<td><span class="opt_title">__MSG_prefs_OptionText_max_prompt_length__</span></td>
<td>
<label>
<input type="number" id="max_prompt_length" name="max_prompt_length" class="option-input" />
@ -367,7 +394,7 @@
</td>
</tr>
<tr class="add_tags_tr">
<td><span>__MSG_prefs_OptionText_add_tags__</span>
<td><span class="opt_title">__MSG_prefs_OptionText_add_tags__</span>
<br><button id="btnManageTagsInfo" class="btn_small">__MSG_prefs_OptionText_btnManageTagsInfo__</button></td>
<td>
<label>
@ -377,7 +404,7 @@
</td>
</tr>
<tr class="spamfilter_tr">
<td><span>__MSG_prefs_OptionText_spamfilter__</span>
<td><span class="opt_title">__MSG_prefs_OptionText_spamfilter__</span>
<br><button id="btnManageSpamFilterInfo" class="btn_small">__MSG_prefs_OptionText_btnManageSpamFilterInfo__</button></td>
<td>
<label>
@ -387,7 +414,7 @@
</td>
</tr>
<tr class="get_calendar_event_tr">
<td><span>__MSG_prefs_OptionText_get_calendar_event__</span>
<td><span class="opt_title">__MSG_prefs_OptionText_get_calendar_event__</span>
<br><button id="btnManageCalendarEventInfo" class="btn_small">__MSG_prefs_OptionText_btnManageCalendarEventInfo__</button></td>
<td>
<label>
@ -396,15 +423,26 @@
</label>
</td>
</tr>
<tr class="get_task_tr">
<td><span class="opt_title">__MSG_prefs_OptionText_get_task__</span>
<br><button id="btnManageTaskInfo" class="btn_small">__MSG_prefs_OptionText_btnManageTaskInfo__</button></td>
<td>
<label>
<input type="checkbox" id="get_task" name="get_task" class="option-input" />
__MSG_prefs_OptionText_get_task_Info__
</label>
</td>
</tr>
<tr class="get_calendar_event_tr" id="no_sparks">
<td colspan="2">
<span>__MSG_prefs_OptionText_get_calendar_event_Sparks_not_present__</span>
<span id="no_sparks_text">__MSG_prefs_OptionText_get_calendar_event_Sparks_not_present__</span>
<span id="wrong_sparks_text">__MSG_prefs_OptionText_get_calendar_event_Sparks_wrong_version__</span>
<br><a href="https://addons.thunderbird.net/it/thunderbird/addon/thunderai-sparks">__MSG_prefs_OptionText_download_now__</a>
</td>
</tr>
<tr>
<td style="width:20em"><label>
<span>__MSG_Debug__</span>
<span class="opt_title">__MSG_Debug__</span>
</label></td>
<td>
<label>

View file

@ -22,14 +22,12 @@ import { OpenAI } from '../js/api/openai.js';
import { Ollama } from '../js/api/ollama.js';
import { OpenAIComp } from '../js/api/openai_comp.js'
import { GoogleGemini } from '../js/api/google_gemini.js';
import { checkSparksPresence, isThunderbird128OrGreater } from '../js/mzta-utils.js';
import { ChatGPTWeb_models, checkSparksPresence, isThunderbird128OrGreater, openTab, sanitizeChatGPTModelData, sanitizeChatGPTWebCustomData, validateCustomData_ChatGPTWeb, getChatGPTWebModelsList_HTML } from '../js/mzta-utils.js';
let taLog = new taLogger("mzta-options",true);
let _isThunderbird128OrGreater = true;
let permission_all_urls = false;
const ChatGPTWeb_models = ['gpt-4o', 'o3', 'o4-mini', 'o4-mini-high', 'gpt-4o-mini'];
function saveOptions(e) {
e.preventDefault();
let options = {};
@ -300,56 +298,25 @@ function disable_SpamFilter(){
async function disable_GetCalendarEvent(){
let get_calendar_event = document.getElementById('get_calendar_event');
let get_task = document.getElementById('get_task');
let no_sparks_tr = document.getElementById('no_sparks');
let is_spark_present = await checkSparksPresence()
let no_sparks_text = document.getElementById('no_sparks_text');
let wrong_sparks_text = document.getElementById('wrong_sparks_text');
let is_spark_present = await checkSparksPresence();
let conntype_select = document.getElementById("connection_type");
get_calendar_event.disabled = (conntype_select.value === "chatgpt_web") || !is_spark_present;
get_calendar_event.disabled = (conntype_select.value === "chatgpt_web") || !(is_spark_present == 1);
get_task.disabled = (conntype_select.value === "chatgpt_web") || !(is_spark_present == 1);
let get_calendar_event_tr_elements = document.querySelectorAll('.get_calendar_event_tr');
get_calendar_event_tr_elements.forEach(get_calendar_event_tr => {
get_calendar_event_tr.style.display = get_calendar_event.disabled ? 'none' : 'table-row';
});
no_sparks_tr.style.display = (is_spark_present || (conntype_select.value === "chatgpt_web")) ? 'none' : 'table-row';
}
function getChatGPTWebModelsList_HTML(values, targetRowId) {
const rowElement = document.getElementById(targetRowId);
if (!rowElement) return;
// Clears any existing td elements
rowElement.innerHTML = '';
// First TD: label
const labelTd = document.createElement('td');
const label = document.createElement('i');
label.className = 'small_info';
const labelNobr = document.createElement('nobr');
labelNobr.textContent = browser.i18n.getMessage("AllowedValues") + ":";
label.appendChild(labelNobr);
labelTd.appendChild(label);
// Second TD: values
const valuesTd = document.createElement('td');
const valuesContainer = document.createElement('i');
valuesContainer.className = 'small_info';
values.forEach(value => {
const nbspBefore = document.createTextNode(' \u00A0 '); // " &nbsp; "
const valueNobr = document.createElement('nobr');
valueNobr.className = 'conntype_chatgpt_web_option';
valueNobr.textContent = value;
const nbspAfter = document.createTextNode(' \u00A0 ');
valuesContainer.appendChild(nbspBefore);
valuesContainer.appendChild(valueNobr);
valuesContainer.appendChild(nbspAfter);
let get_task_tr_elements = document.querySelectorAll('.get_task_tr');
get_task_tr_elements.forEach(get_task_tr => {
get_task_tr.style.display = get_task.disabled ? 'none' : 'table-row';
});
valuesTd.appendChild(valuesContainer);
// Adds the td elements to the row
rowElement.appendChild(labelTd);
rowElement.appendChild(valuesTd);
no_sparks_tr.style.display = ((is_spark_present == 1) || (conntype_select.value === "chatgpt_web")) ? 'none' : 'table-row';
no_sparks_text.style.display = (is_spark_present == -1) ? 'inline' : 'none';
wrong_sparks_text.style.display = (is_spark_present == 0) ? 'inline' : 'none';
}
@ -419,57 +386,32 @@ document.addEventListener('DOMContentLoaded', async () => {
get_calendar_event_info_btn.disabled = event.target.checked ? '' : 'disabled';
});
get_calendar_event_info_btn.disabled = get_calendar_event_el.checked ? '' : 'disabled';
let get_task_el = document.getElementById('get_task');
let get_task_info_btn = document.getElementById('btnManageTaskInfo');
get_task_el.addEventListener('click', (event) => {
get_task_info_btn.disabled = event.target.checked ? '' : 'disabled';
});
get_task_info_btn.disabled = get_task_el.checked ? '' : 'disabled';
document.getElementById('btnManagePrompts').addEventListener('click', () => {
// check if the tab is already there
browser.tabs.query({url: browser.runtime.getURL('../pages/customprompts/mzta-custom-prompts.html')}).then((tabs) => {
if (tabs.length > 0) {
// if the tab is already there, focus it
browser.tabs.update(tabs[0].id, {active: true});
} else {
// if the tab is not there, create it
browser.tabs.create({url: browser.runtime.getURL('../pages/customprompts/mzta-custom-prompts.html')});
}
})
openTab('../pages/customprompts/mzta-custom-prompts.html');
});
document.getElementById('btnManageTagsInfo').addEventListener('click', () => {
// check if the tab is already there
browser.tabs.query({url: browser.runtime.getURL('../pages/addtags/mzta-add-tags.html')}).then((tabs) => {
if (tabs.length > 0) {
// if the tab is already there, focus it
browser.tabs.update(tabs[0].id, {active: true});
} else {
// if the tab is not there, create it
browser.tabs.create({url: browser.runtime.getURL('../pages/addtags/mzta-add-tags.html')});
}
})
openTab('../pages/addtags/mzta-add-tags.html');
});
document.getElementById('btnManageSpamFilterInfo').addEventListener('click', () => {
// check if the tab is already there
browser.tabs.query({url: browser.runtime.getURL('../pages/spamfilter/mzta-spamfilter.html')}).then((tabs) => {
if (tabs.length > 0) {
// if the tab is already there, focus it
browser.tabs.update(tabs[0].id, {active: true});
} else {
// if the tab is not there, create it
browser.tabs.create({url: browser.runtime.getURL('../pages/spamfilter/mzta-spamfilter.html')});
}
})
openTab('../pages/spamfilter/mzta-spamfilter.html');
});
document.getElementById('btnManageCalendarEventInfo').addEventListener('click', () => {
// check if the tab is already there
browser.tabs.query({url: browser.runtime.getURL('../pages/get-calendar-event/mzta-get-calendar-event.html')}).then((tabs) => {
if (tabs.length > 0) {
// if the tab is already there, focus it
browser.tabs.update(tabs[0].id, {active: true});
} else {
// if the tab is not there, create it
browser.tabs.create({url: browser.runtime.getURL('../pages/get-calendar-event/mzta-get-calendar-event.html')});
}
})
openTab('../pages/get-calendar-event/mzta-get-calendar-event.html');
});
document.getElementById('btnManageTaskInfo').addEventListener('click', () => {
openTab('../pages/get-task/mzta-get-task.html');
});
document.getElementById('btnOpenAICompForceModel').addEventListener('click', () => {
@ -515,6 +457,8 @@ document.addEventListener('DOMContentLoaded', async () => {
document.getElementById("ollama_host").addEventListener("change", warn_Ollama_HostEmpty);
document.getElementById("openai_comp_host").addEventListener("change", warn_OpenAIComp_HostEmpty);
document.getElementById("google_gemini_api_key").addEventListener("change", warn_GoogleGemini_APIKeyEmpty);
document.getElementById("chatgpt_web_project").addEventListener("input", validateCustomData_ChatGPTWeb);
document.getElementById("chatgpt_web_custom_gpt").addEventListener("input", validateCustomData_ChatGPTWeb);
let prefs = await browser.storage.sync.get({chatgpt_web_model: '', chatgpt_model: '', ollama_model: '', openai_comp_model: '', google_gemini_model: '', chatgpt_win_height: 0, chatgpt_win_width: 0 });
@ -741,12 +685,23 @@ document.addEventListener('DOMContentLoaded', async () => {
const btnChatGPTWeb_Tab = document.getElementById('btnChatGPTWeb_Tab');
btnChatGPTWeb_Tab.addEventListener('click', async () => {
let prefs_mod = await browser.storage.sync.get({chatgpt_web_model: ''});
let prefs_mod = await browser.storage.sync.get({chatgpt_web_model: prefs_default.chatgpt_web_model, chatgpt_web_project: prefs_default.chatgpt_web_project, chatgpt_web_custom_gpt: prefs_default.chatgpt_web_custom_gpt});
let base_url = 'https://chatgpt.com';
let model_opt = '';
let webproject_set = false;
if((prefs_mod.chatgpt_web_model != '') && (prefs_mod.chatgpt_web_model != undefined)){
model_opt = '?model=' + encodeURIComponent(prefs_mod.chatgpt_web_model).toLowerCase();
model_opt = '?model=' + sanitizeChatGPTModelData(prefs_mod.chatgpt_web_model);
}
browser.tabs.create({ url: 'https://chatgpt.com/' + model_opt });
if((prefs_mod.chatgpt_web_project != '') && (prefs_mod.chatgpt_web_project != undefined)){
base_url += sanitizeChatGPTWebCustomData(prefs_mod.chatgpt_web_project);
webproject_set = true;
}
if(!webproject_set && (prefs_mod.chatgpt_web_custom_gpt != '') && (prefs_mod.chatgpt_web_custom_gpt != undefined)){
base_url += sanitizeChatGPTWebCustomData(prefs_mod.chatgpt_web_custom_gpt);
}
browser.tabs.create({ url: base_url + model_opt });
});
browser.runtime.getPlatformInfo().then(info => {

View file

@ -7,10 +7,23 @@
<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.6 - ??/??/2025</h2>
<h2>Version 3.4.0 - 07/05/2025</h2>
<ul>
<li><i>[All APIs]</i> Added a special prompt to get tasks data from emails [<a href="https://github.com/micz/ThunderAI/issues/333">#333</a>]. To use this feature, you must install also the <a href="https://addons.thunderbird.net/it/thunderbird/addon/thunderai-sparks/">Sparks</a> add-on.</li>
<li><i>[ChatGPT Web]</i> It is now possible to define a Custom GPT or a Project in the options page to be used by default, or directly in a custom prompt to be used only for that prompt [<a href="https://github.com/micz/ThunderAI/issues/168">#168</a>, <a href="https://github.com/micz/ThunderAI/issues/277">#277</a>].</li>
<li>The chatgpt.com access permission is no more requested when installing the addon. It's mandatory to give this permission to use the ChatGPT Web Interface integration [<a href="https://github.com/micz/ThunderAI/issues/293">#293</a>].</li>
<li>Added the <i>{%mail_quoted_text%}</i> placeholder to get the quoted text when composing a new message [<a href="https://github.com/micz/ThunderAI/issues/324">#324</a>].</li>
<li>Fix: correctly choosing the right account when replying [<a href="https://github.com/micz/ThunderAI/issues/369">#369</a>].</li>
<li>Fix: In the <i>{%mail_typed_text%}</i> placeholder text on different lines is now separated by a space.</li>
<li>Fix: correctly showing text differences when using {%mail_typed_text%} placeholder.</li>
<li>Added a default proofread prompt [<a href="https://github.com/micz/ThunderAI/issues/21">#21</a>].</li>
<li>Added a check for the presence of the correct version of ThunderAI Sparks [<a href="https://github.com/micz/ThunderAI/issues/315">#315</a>].</li>
<li>Added the <i>{%empty%}</i> placeholder to prevent the email body from being automatically appended at the end of the prompt [<a href="https://github.com/micz/ThunderAI/issues/345">#345</a>].</li>
<li><i>[All APIs]</i> Improved the form asking for additional text [<a href="https://github.com/micz/ThunderAI/issues/97">#97</a>].</li>
<li><i>[All APIs]</i> Fix: Ensure HTML body is generated from plain text if no parts are available when processing incoming messages for tags or spam.</li>
<li>...</li>
<li>Fix a condition when using a prompt from the compose window with a "Do reply" action that is changed in "Substitute Text" [<a href="https://github.com/micz/ThunderAI/issues/353">#353</a>].</li>
<li>Custom Prompts form improved.</li>
<li>Various improvements.</li>
</ul>
<h2>Version 3.3.5 - 22/04/2025</h2>
<ul>

View file

@ -12,7 +12,7 @@
font-style: italic;
}
#addtags_excl_list_container{
#addtags_excl_list_container, #account_selector_container{
width: 90%;
margin: 40px auto;
}
@ -21,6 +21,22 @@
width: 30em;
}
#account_selector_container{
display: none;
}
#account_selector_checkboxes{
padding: 10px;
border: 1px solid gray;
width: 24em;
margin-bottom: 10px;
margin-top: 10px;
}
.add_tags_auto{
background-color: #e9ffdf;
}
.btn_div{
width: 100%;
display: flex;
@ -129,4 +145,8 @@ table#miczPrefs tr:last-child td {
.autocomplete-list li.active {
background-color: #4c4e58;
}
.add_tags_auto{
background-color: #415c35;
}
}

View file

@ -49,8 +49,9 @@
</label>
</td>
</tr>
<tr class="add_tags_tr">
<td><span>__MSG_prefs_OptionText_add_tags_auto__</span></td>
<tr class="add_tags_tr add_tags_auto">
<td><span>__MSG_prefs_OptionText_add_tags_auto__</span>
<span class="infoline" id="add_tags_auto_infoline"><br>__MSG_prefs_OptionText_add_tags_auto_Info2__</span></td>
<td>
<label>
<input type="checkbox" id="add_tags_auto" name="add_tags_auto" class="option-input" />
@ -58,7 +59,7 @@
</label>
</td>
</tr>
<tr class="add_tags_tr" id="add_tags_auto_force_existing_tr">
<tr class="add_tags_tr add_tags_auto" id="add_tags_auto_force_existing_tr">
<td><span>__MSG_prefs_OptionText_add_tags_auto_force_existing__</span></td>
<td>
<label>
@ -67,7 +68,7 @@
</label>
</td>
</tr>
<tr class="add_tags_tr" id="add_tags_auto_only_inbox_tr">
<tr class="add_tags_tr add_tags_auto" id="add_tags_auto_only_inbox_tr">
<td><span>__MSG_prefs_OptionText_add_tags_auto_only_inbox__</span></td>
<td>
<label>
@ -106,6 +107,13 @@
<br><textarea id="addtags_excl_list" rows="15"></textarea>
<div class="btn_div"><button id="btn_save_excl_list" disabled>__MSG_save__</button></div>
</div>
<div id="account_selector_container">
<div id="account_selector_info"><span class="section_title">__MSG_AccountSelector_AutoTags__</span>
<br><span class="infoline">__MSG_AccountSelector_AutoTags_infoline__</span></div>
<div id="account_selector_checkboxes"></div>
<button type="button" id="accounts_select_all">Select All</button>
<button type="button" id="accounts_deselect_all">Deselect All</button>
</div>
<script src="mzta-add-tags.js" type="module"></script>
<script src="../../js/mzta-i18n.js"></script>
</body>

View file

@ -22,7 +22,7 @@ import { getSpecialPrompts, setSpecialPrompts } from "../../js/mzta-prompts.js";
import { getPlaceholders } from "../../js/mzta-placeholders.js";
import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js";
import { addTags_getExclusionList, addTags_setExclusionList } from "../../js/mzta-addatags-exclusion-list.js";
import { getAccountsList } from "../../js/mzta-utils.js";
let autocompleteSuggestions = [];
let taLog = new taLogger("mzta-addtags-page",true);
@ -56,12 +56,18 @@ document.addEventListener('DOMContentLoaded', async () => {
let add_tags_auto_el = document.getElementById('add_tags_auto');
let add_tags_auto_force_existing_tr = document.getElementById('add_tags_auto_force_existing_tr');
let add_tags_auto_only_inbox_tr = document.getElementById('add_tags_auto_only_inbox_tr');
let account_selector_container = document.getElementById('account_selector_container');
let add_tags_auto_infoline = document.getElementById('add_tags_auto_infoline');
add_tags_auto_el.addEventListener('click', (event) => {
add_tags_auto_force_existing_tr.style.display = event.target.checked ? 'table-row' : 'none';
add_tags_auto_only_inbox_tr.style.display = event.target.checked ? 'table-row' : 'none';
account_selector_container.style.display = event.target.checked ? 'block' : 'none';
add_tags_auto_infoline.style.display = event.target.checked ? 'inline' : 'none';
});
add_tags_auto_force_existing_tr.style.display = add_tags_auto_el.checked ? 'table-row' : 'none';
add_tags_auto_only_inbox_tr.style.display = add_tags_auto_el.checked ? 'table-row' : 'none';
account_selector_container.style.display = add_tags_auto_el.checked ? 'block' : 'none';
add_tags_auto_infoline.style.display = add_tags_auto_el.checked ? 'inline' : 'none';
addtags_reset_btn.addEventListener('click', () => {
addtags_textarea.value = browser.i18n.getMessage('prompt_add_tags_full_text');
@ -118,6 +124,60 @@ document.addEventListener('DOMContentLoaded', async () => {
document.getElementById('excl_list_unsaved').classList.add('hidden');
});
//Accounts manager
let accounts = await getAccountsList();
const accountsContainer = document.getElementById('account_selector_checkboxes');
accounts.forEach(account => {
const accountLabel = document.createElement('label');
const accountCheckbox = document.createElement('input');
accountCheckbox.type = 'checkbox';
accountCheckbox.classList.add('accountCheckbox');
accountCheckbox.value = account.id;
accountLabel.appendChild(accountCheckbox);
accountLabel.appendChild(document.createTextNode(account.name));
accountsContainer.appendChild(accountLabel);
accountsContainer.appendChild(document.createElement('br'));
});
let prefs_add_tags = await browser.storage.sync.get({ add_tags_enabled_accounts: [] });
let add_tags_enabled_accounts = prefs_add_tags.add_tags_enabled_accounts;
taLog.log("add_tags_enabled_accounts = " + JSON.stringify(add_tags_enabled_accounts) + ".");
document.querySelectorAll('.accountCheckbox').forEach(checkbox => {
if (add_tags_enabled_accounts.length === 0 || add_tags_enabled_accounts.includes(checkbox.value)) {
checkbox.checked = true;
} else {
checkbox.checked = false;
}
});
document.querySelectorAll('.accountCheckbox').forEach(checkbox => {
checkbox.addEventListener('change', () => {
let selectedAccounts = Array.from(document.querySelectorAll('.accountCheckbox:checked')).map(checkbox => checkbox.value);
if (selectedAccounts.length === 0) {
checkbox.checked = true; // Prevent deselecting the last selected checkbox
taLog.log("At least one account must be selected.");
return;
}
if (selectedAccounts.length === document.querySelectorAll('.accountCheckbox').length) {
browser.storage.sync.set({ add_tags_enabled_accounts: [] });
taLog.log("All accounts selected, saving add_tags_enabled_accounts = [].");
} else {
browser.storage.sync.set({ add_tags_enabled_accounts: selectedAccounts });
taLog.log("Saving add_tags_enabled_accounts = " + JSON.stringify(selectedAccounts) + ".");
}
});
});
document.getElementById('accounts_select_all').addEventListener('click', () => {
let checkboxes = document.querySelectorAll('.accountCheckbox');
checkboxes.forEach(checkbox => checkbox.checked = true);
});
document.getElementById('accounts_deselect_all').addEventListener('click', () => {
let checkboxes = document.querySelectorAll('.accountCheckbox');
checkboxes.forEach(checkbox => checkbox.checked = false);
});
});

View file

@ -25,6 +25,7 @@ table {
thead {
position: sticky;
top: 26px;
z-index: 90;
}
#command_palette{
@ -33,6 +34,7 @@ thead {
padding-top: 1px;
height: 26px;
width: 100%;
z-index: 90;
}
#btnNew{
@ -102,6 +104,10 @@ table .sort.desc {
background-image: url(../images/listjs-arrow-sort-active-up.png);
}
tbody.list tr{
vertical-align: top;
}
.hiddendata{
display: none;
}
@ -135,6 +141,24 @@ table .sort.desc {
font-style: italic;
}
.field_title{
font-weight: bold;
}
.field_title_s{
font-weight: bold;
font-size: small;
}
.field_title_us{
font-weight: bold;
font-size: smaller;
}
label, .id_show, .text_show, .name_show, .type_show, .action_show{
font-size: small;
}
#txtIdNew, .id_output{
text-transform: lowercase;
}
@ -204,6 +228,80 @@ table .sort.desc {
padding-right: 2px;
}
#chatgpt_web_additional_info_toggle td{
padding:0px 5px;
font-style: italic;
}
#chatgpt_web_additional_info, #chatgpt_web_additional_info_toggle, .chatgpt_web_additional_info, .chatgpt_web_additional_info_toggle, .chatgpt_web_additional_info_show{
background-color: rgb(255, 209, 183);
display:none;
}
.chatgpt_web_models_list_table{
background-color: rgb(255, 209, 183);
border:0;
}
.chatgpt_web_models_list_table *{
border:0;
}
.chatgpt_web_models_list_table td{
padding:2px;
}
#chatgpt_web_additional_info_toggle, .chatgpt_web_additional_info_toggle{
cursor: pointer;
}
#chatgpt_web_additional_info_toggle:hover, .chatgpt_web_additional_info_toggle:hover{
background-color: rgb(255, 189, 153);
text-decoration: underline;
}
#chatgpt_web_additional_info_toggle td{
text-align: center;
}
#chatgpt_web_additional_info td{
vertical-align: top;
}
.chatgpt_web_additional_info_toggle{
width: -moz-available;
text-align: center;
margin-top: 10px;
}
.chatgpt_web_additional_info_show{
flex-direction: column;
justify-content: space-between;
height: 100%;
padding: 3px;
margin-top: 5px;
}
.chatgpt_web_additional_info_row{
display: flex;
}
.chatgpt_web_additional_info_row span{
margin-right: 0.4em;
}
input.input_additional[type="text"]{
width: -moz-available;
}
.small_info{
font-size:smaller;
}
.conntype_chatgpt_web_option{
cursor: pointer;
}
@media (prefers-color-scheme: dark) {
body {
background-color: #1C1B22;
@ -250,4 +348,13 @@ table .sort.desc {
.autocomplete-list li.active {
background-color: #4c4e58;
}
#chatgpt_web_additional_info, #chatgpt_web_additional_info_toggle, .chatgpt_web_additional_info, .chatgpt_web_additional_info_toggle, .chatgpt_web_additional_info_show, .chatgpt_web_models_list_table{
background-color: rgb(39, 11, 0);
color: rgb(182, 182, 182);
}
#chatgpt_web_additional_info_toggle:hover, .chatgpt_web_additional_info_toggle:hover{
background-color: rgb(88, 25, 0);
}
}

View file

@ -27,29 +27,39 @@
<table class="width_all">
<tr>
<td class="w19">
<label for="txtIdNew">*__MSG_customPrompts_form_label_ID__:</label>
<label for="txtIdNew" class="field_title">*__MSG_customPrompts_form_label_ID__:</label>
<br>
<input type="text" id="txtIdNew" name="id" class="input_new" tabindex="1">
<br><span class="small_label">[__MSG_customPrompts_form_label_ID_rules__]</span>
</td>
<td rowspan="2" class="w25">
<label for="txtTextNew">*__MSG_customPrompts_form_label_Text__:</label>
<label for="txtTextNew" class="field_title">*__MSG_customPrompts_form_label_Text__:</label>
<br>
<div class="autocomplete-container">
<textarea id="txtTextNew" name="text" class="input_new text_output editor" tabindex="3"></textarea>
<ul class="autocomplete-list hidden"></ul>
</div>
</td>
<td class="w19">
<label for="selectTypeNew">__MSG_customPrompts_add_to_menu__:</label>
<td rowspan="2" class="w19">
<label for="selectTypeNew" class="field_title">__MSG_customPrompts_add_to_menu__:</label>
<br>
<select id="selectTypeNew" name="type" tabindex="4" class="type_output">
<option value="0">__MSG_customPrompts_add_to_menu_always__</option>
<option value="1">__MSG_customPrompts_add_to_menu_reading__</option>
<option value="2">__MSG_customPrompts_add_to_menu_composing__</option>
</select>
<br><br>
<label for="selectActionNew" class="field_title">__MSG_customPrompts_form_label_Action__:</label>
<br>
<select id="selectActionNew" name="action" tabindex="5">
<option value="0">__MSG_customPrompts_close_button__</option>
<option value="1">__MSG_customPrompts_do_reply__</option>
<option value="2">__MSG_customPrompts_substitute_text__</option>
</select>
</td>
<td rowspan="2" class="w19">
<label class="field_title">__MSG_customPrompts_Properties__:</label>
<br>
<span class="need_selected_span"><input type="checkbox" id="checkboxNeedSelectedNew" name="need_selected" class="need_selected_new" value="1" tabindex="6"> <label for="checkboxNeedSelectedNew">__MSG_customPrompts_form_label_need_selected__</label></span>
<br>
<input type="checkbox" id="checkboxNeedSignatureNew" name="need_signature" value="1" tabindex="7"> <label for="checkboxNeedSignatureNew">__MSG_customPrompts_form_label_need_signature__</label>
@ -58,23 +68,36 @@
<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>
<input type="checkbox" id="checkboxUseDiffViewerNew" name="use_diff_viewer" value="1" tabindex="9" title="__MSG_customPrompts_form_label_use_diff_viewer_title__"> <label for="checkboxUseDiffViewerNew" title="__MSG_customPrompts_form_label_use_diff_viewer_title__">__MSG_customPrompts_form_label_use_diff_viewer__</label>
</td>
</tr>
<tr>
<td class="w19">
<label for="txtNameNew">*__MSG_customPrompts_form_label_Name__:</label>
<label for="txtNameNew" class="field_title">*__MSG_customPrompts_form_label_Name__:</label>
<br>
<input type="text" id="txtNameNew" name="name" class="input_new" tabindex="2">
</td>
<td class="w19">
<label for="selectActionNew">__MSG_customPrompts_form_label_Action__:</label>
<br>
<select id="selectActionNew" name="action" tabindex="5">
<option value="0">__MSG_customPrompts_close_button__</option>
<option value="1">__MSG_customPrompts_do_reply__</option>
<option value="2">__MSG_customPrompts_substitute_text__</option>
</select>
</tr>
<tr id="chatgpt_web_additional_info_toggle"><td colspan="4"><span class="small_info">__MSG_customPrompts_show_additional_info__</span></td></tr>
<tr id="chatgpt_web_additional_info"><!-- ChatGPT Web additional info -->
<td colspan="2">
<label for="chatGPTWebModelNew" class="field_title">__MSG_prefs_OptionText_chatgpt_web_model__:</label>
<br>
<input type="text" id="chatGPTWebModelNew" name="chatGPTWebModelNew" class="input_new input_additional" tabindex="10">
<table class="chatgpt_web_models_list_table" title="__MSG_prefs_OptionText_chatgpt_web_model_tooltip__"><tr id="chatgpt_web_models_list"></tr></table>
<br><br>
<label for="chatGPTWebProjectNew" class="field_title">__MSG_prefs_OptionText_chatgpt_web_project__:</label>
<br>
<input type="text" id="chatGPTWebProjectNew" name="chatGPTWebProjectNew" class="input_new input_additional" tabindex="11">
<br><i class="small_info" id="chatGPTWebProjectNew_info">__MSG_prefs_OptionText_chatgpt_web_custom_data_info__ <b>/g/PROJECT-ID-PROJECT-NAME/project</b>
<br>__MSG_prefs_OptionText_chatgpt_web_custom_data_info2__</i>
</td>
<td colspan="2">
<label for="chatGPTWebCustomGPTNew" class="field_title">__MSG_prefs_OptionText_chatgpt_web_custom_gpt__:</label>
<br>
<input type="text" id="chatGPTWebCustomGPTNew" name="chatGPTWebCustomGPTNew" class="input_new input_additional" tabindex="11">
<br><i class="small_info" id="chatGPTWebCustomGPTNew_info">__MSG_prefs_OptionText_chatgpt_web_custom_data_info__ <b>/g/CUSTOM-GPT-ID</b>
<br>__MSG_prefs_OptionText_chatgpt_web_custom_data_info2__</i>
</td>
</tr>
</table>
@ -89,9 +112,9 @@
<th class="sort" data-sort="id">__MSG_customPrompts_form_label_ID__</th>
<th class="sort" data-sort="name">__MSG_customPrompts_form_label_Name__</th>
<th class="sort" data-sort="text">__MSG_customPrompts_form_label_Text__</th>
<th class="sort" data-sort="type">__MSG_customPrompts_add_to_menu__</th>
<th>Properties</th>
<th>__MSG_customPrompts_form_label_Action__</th>
<th>&nbsp;</th>
<th>__MSG_customPrompts_Properties__</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody class="list">

View file

@ -16,12 +16,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { prefs_default } from "../../options/mzta-options-default.js";
import { getPrompts, setDefaultPromptsProperties, setCustomPrompts, preparePromptsForExport, preparePromptsForImport } from "../../js/mzta-prompts.js";
import { isThunderbird128OrGreater, getCustomPromptsUsedSpace, sanitizeHtml } from "../../js/mzta-utils.js";
import { ChatGPTWeb_models, isThunderbird128OrGreater, getCustomPromptsUsedSpace, sanitizeHtml, validateCustomData_ChatGPTWeb, getChatGPTWebModelsList_HTML } from "../../js/mzta-utils.js";
import { taLogger } from "../../js/mzta-logger.js";
import { getPlaceholders } from "../../js/mzta-placeholders.js";
import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js";
let prefs = null;
var promptsList = null;
var somethingChanged = false;
var positionMax_compose = 0;
@ -33,8 +35,8 @@ let autocompleteSuggestions = [];
document.addEventListener('DOMContentLoaded', async () => {
let prefs_debug = await browser.storage.sync.get({do_debug: false});
taLog = new taLogger("mzta-custom-prompts", prefs_debug.do_debug);
prefs = await browser.storage.sync.get({ connection_type:prefs_default.connection_type, do_debug: prefs_default.do_debug });
taLog = new taLogger("mzta-custom-prompts", prefs.do_debug);
setStorageSpace();
@ -62,6 +64,9 @@ document.addEventListener('DOMContentLoaded', async () => {
e.preventDefault();
e.target.disabled = true;
document.getElementById('formNew').style.display = 'block';
let _checkboxUseDiffViewerNew = document.getElementById('checkboxUseDiffViewerNew');
_checkboxUseDiffViewerNew.checked = false;
_checkboxUseDiffViewerNew.disabled = true;
window.scrollTo({
top: 0,
behavior: 'smooth'
@ -69,40 +74,6 @@ document.addEventListener('DOMContentLoaded', async () => {
}
btnNew.addEventListener('click', handleNewClick);
// Display selected value next to select input
// function handleSelectChange(e) {
// e.preventDefault();
// const spanElement = e.target.nextElementSibling;
// spanElement.textContent = e.target.value;
// }
// document.querySelectorAll('select.input_mod').forEach(element => {
// element.addEventListener('change', handleSelectChange);
// });
// Log data ID number from item row and prepare for edit action
// Handle "type" select changes and log new state
// function handleTypeSelectChange(e) {
// e.preventDefault();
// const spanElement = e.target.nextElementSibling;
// spanElement.textContent = e.target.value;
// }
// let type_select_elements = document.querySelectorAll("select.type_output");
// type_select_elements.forEach(element => {
// element.addEventListener('change', handleTypeSelectChange);
// });
// Handle "action" select changes and log new state
// function handleActionSelectChange(e) {
// e.preventDefault();
// const spanElement = e.target.nextElementSibling;
// spanElement.textContent = e.target.value;
// }
// let action_select_elements = document.querySelectorAll("select.action_output");
// action_select_elements.forEach(element => {
// element.addEventListener('change', handleActionSelectChange);
// });
// for the new prompt form
let btnNew_elements = document.querySelectorAll(".input_new");
if(btnNew_elements) {
@ -129,22 +100,68 @@ document.addEventListener('DOMContentLoaded', async () => {
});
});
// document.addEventListener('click', (e) => {
// // Check if the click was outside the textarea or suggestion list
// const isClickInsideTextarea = e.target.closest('.editor');
// const isClickInsideAutocompleteList = e.target.closest('.autocomplete-list');
// if (!isClickInsideTextarea && !isClickInsideAutocompleteList) {
// textareas.forEach(textarea => {
// const container = textarea.closest('.autocomplete-container');
// const autocompleteList = container.querySelector('.autocomplete-list');
// hideSuggestions(autocompleteList);
// });
// }
// });
i18n.updateDocument();
switch(prefs.connection_type) {
case 'chatgpt_web': {
// for the new item form
document.getElementById('chatgpt_web_additional_info_toggle').style.display = 'table-row';
// for the edit list items form
document.querySelectorAll('.chatgpt_web_additional_info_toggle').forEach(element => {
element.addEventListener('click', (e) => {
e.preventDefault();
let additionalInfoRow = e.target.closest('td').querySelector('.chatgpt_web_additional_info');
if (additionalInfoRow.style.display === 'none' || additionalInfoRow.style.display === '') {
additionalInfoRow.style.display = 'block';
e.target.innerText = browser.i18n.getMessage('customPrompts_hide_additional_info');
} else {
additionalInfoRow.style.display = 'none';
e.target.innerText = browser.i18n.getMessage('customPrompts_show_additional_info');
}
});
});
document.querySelectorAll('input.chatgpt_web_project_output').forEach(element => {
element.addEventListener("input", validateCustomData_ChatGPTWeb);
});
document.querySelectorAll('input.chatgpt_web_custom_gpt_output').forEach(element => {
element.addEventListener("input", validateCustomData_ChatGPTWeb);
});
break;
}
// case 'chatgpt_api':
// document.getElementById('chatgpt_api').style.display = 'block';
// break;
// case 'ollama_api':
// document.getElementById('ollama_api').style.display = 'block';
// break;
// case 'openai_comp_api':
// document.getElementById('openai_comp_api').style.display = 'block';
// break;
// case 'google_gemini_api':
// document.getElementById('google_gemini_api').style.display = 'block';
// break;
}
const chatgptWebAdditionalPropToggle = document.getElementById('chatgpt_web_additional_info_toggle');
chatgptWebAdditionalPropToggle.addEventListener('click', (e) => {
e.preventDefault();
const additionalInfoRow = document.getElementById('chatgpt_web_additional_info');
if (additionalInfoRow.style.display === 'none' || additionalInfoRow.style.display === '') {
additionalInfoRow.style.display = 'table-row';
let subspan = chatgptWebAdditionalPropToggle.querySelector('td span');
if (subspan) {
subspan.innerText = browser.i18n.getMessage('customPrompts_hide_additional_info');
}
} else {
additionalInfoRow.style.display = 'none';
let subspan = chatgptWebAdditionalPropToggle.querySelector('td span');
if (subspan) {
subspan.innerText = browser.i18n.getMessage('customPrompts_show_additional_info');
}
}
});
//To add a new item
var txtIdNew = document.getElementById('txtIdNew');
var txtNameNew = document.getElementById('txtNameNew');
@ -156,6 +173,21 @@ document.addEventListener('DOMContentLoaded', async () => {
var checkboxNeedCustomTextNew = document.getElementById('checkboxNeedCustomTextNew');
var checkboxDefineResponseLangNew = document.getElementById('checkboxDefineResponseLangNew');
var checkboxUseDiffViewerNew = document.getElementById('checkboxUseDiffViewerNew');
// ChatGTP Web Integration
var chatgptWebModelNew = document.getElementById('chatGPTWebModelNew');
var chatgptWebProjectNew = document.getElementById('chatGPTWebProjectNew');
var chatgptWebCustomGptNew = document.getElementById('chatGPTWebCustomGPTNew');
chatgptWebProjectNew.addEventListener("input", validateCustomData_ChatGPTWeb);
chatgptWebCustomGptNew.addEventListener("input", validateCustomData_ChatGPTWeb);
selectActionNew.addEventListener('change', (e) => {
if (e.target.value === "2") {
checkboxUseDiffViewerNew.disabled = false;
} else {
checkboxUseDiffViewerNew.checked = false;
checkboxUseDiffViewerNew.disabled = true;
}
});
const btnAddNew = document.getElementById('btnAddNew');
btnAddNew.addEventListener('click', (e) => {
@ -163,7 +195,7 @@ document.addEventListener('DOMContentLoaded', async () => {
if(!checkFields()) {
return;
}
let newItem = promptsList.add({
let newItemData = {
id: String(txtIdNew.value.trim()).toLocaleLowerCase(),
name: txtNameNew.value.trim(),
text: txtTextNew.value.trim(),
@ -179,7 +211,29 @@ document.addEventListener('DOMContentLoaded', async () => {
position_display: positionMax_display + 1,
is_default: 0,
idnum: idnumMax + 1,
});
};
switch(prefs.connection_type) {
case 'chatgpt_web':
newItemData.chatgpt_web_model = chatgptWebModelNew.value.trim();
newItemData.chatgpt_web_project = chatgptWebProjectNew.value.trim();
newItemData.chatgpt_web_custom_gpt = chatgptWebCustomGptNew.value.trim();
break;
// case 'chatgpt_api':
// document.getElementById('chatgpt_api').style.display = 'block';
// break;
// case 'ollama_api':
// document.getElementById('ollama_api').style.display = 'block';
// break;
// case 'openai_comp_api':
// document.getElementById('openai_comp_api').style.display = 'block';
// break;
// case 'google_gemini_api':
// document.getElementById('google_gemini_api').style.display = 'block';
// break;
}
let newItem = promptsList.add(newItemData);
idnumMax++;
let curr_idnum = newItem[0].values().idnum;
let checkboxes = document.querySelectorAll(`tr[data-idnum="${curr_idnum}"] input[type="checkbox"]`);
@ -288,6 +342,32 @@ document.addEventListener('DOMContentLoaded', async () => {
};
}
document.querySelectorAll('.chatgpt_web_additional_info_show').forEach(element => {
toggleAdditionalPropertiesShow(element.closest('tr'));
});
getChatGPTWebModelsList_HTML(ChatGPTWeb_models, 'chatgpt_web_models_list');
let formNewWebModelList = document.getElementById('chatgpt_web_models_list');
formNewWebModelList.querySelectorAll('.conntype_chatgpt_web_option').forEach(element => {
element.addEventListener("click", () => {
let el = document.getElementById("chatGPTWebModelNew");
el.value = element.textContent;
el.dispatchEvent(new Event('change'), { bubbles: true });
});
});
document.querySelectorAll('.id_output').forEach(element => {
getChatGPTWebModelsList_HTML(ChatGPTWeb_models, 'chatgpt_web_models_list_' + element.value);
let formWebModelList = document.getElementById('chatgpt_web_models_list_' + element.value);
formWebModelList.querySelectorAll('.conntype_chatgpt_web_option').forEach(element2 => {
element2.addEventListener("click", () => {
let el = document.getElementById("chatgpt_web_model_output_" + element.value);
el.value = element2.textContent;
el.dispatchEvent(new Event('change'), { bubbles: true });
});
});
});
}, { once: true });
//========= handling an item in a row
@ -301,6 +381,7 @@ function handleEditClick(e) {
// tr.querySelector('.btnEditItem').style.display = 'none'; // Edit btn
tr.querySelector('.btnDeleteItem').style.display = 'none'; // Delete btn
showItemRowEditor(tr);
toggleDiffviewer(e);
}
function showItemRowEditor(tr) {
@ -312,9 +393,13 @@ function showItemRowEditor(tr) {
text_output.style.display = 'inline';
textareaAutocomplete(text_output, autocompleteSuggestions)
tr.querySelector('.text_show').style.display = 'none';
toggleAdditionalPropertiesEditor(tr);
tr.querySelector('.chatgpt_web_additional_info_show').style.display = 'none';
tr.querySelector('.type_output').style.display = 'inline';
tr.querySelector('.type_show').style.display = 'none';
tr.querySelector('.action_output').style.display = 'inline';
const action_output = tr.querySelector('.action_output')
action_output.style.display = 'inline';
action_output.addEventListener('change', toggleDiffviewer);
tr.querySelector('.action_show').style.display = 'none';
tr.querySelector('input.need_selected').disabled = false;
tr.querySelector('input.need_signature').disabled = false;
@ -330,9 +415,14 @@ function hideItemRowEditor(tr) {
tr.querySelector('.name_show').style.display = 'inline';
tr.querySelector('.text_output').style.display = 'none';
tr.querySelector('.text_show').style.display = 'inline';
tr.querySelector('.chatgpt_web_additional_info_toggle').style.display = 'none';
tr.querySelector('.chatgpt_web_additional_info').style.display = 'none';
toggleAdditionalPropertiesShow(tr);
tr.querySelector('.type_output').style.display = 'none';
tr.querySelector('.type_show').style.display = 'inline';
tr.querySelector('.action_output').style.display = 'none';
const action_output = tr.querySelector('.action_output')
action_output.style.display = 'none';
action_output.addEventListener('change', toggleDiffviewer);
tr.querySelector('.action_show').style.display = 'inline';
tr.querySelector('input.need_selected').disabled = true;
tr.querySelector('input.need_signature').disabled = true;
@ -341,6 +431,104 @@ function hideItemRowEditor(tr) {
tr.querySelector('input.use_diff_viewer').disabled = true;
}
function toggleAdditionalPropertiesShow(tr) {
switch(prefs.connection_type) {
case 'chatgpt_web': {
let element = tr.querySelector('.chatgpt_web_additional_info_show');
let chatGPTWebModel_show = tr.querySelector('.chatgpt_web_model_show');
let chatGPTWebProject_show = tr.querySelector('.chatgpt_web_project_show');
let chatGPTWebCustomGPT_show = tr.querySelector('.chatgpt_web_custom_gpt_show');
if ((chatGPTWebModel_show.innerText !== '' && chatGPTWebModel_show.innerText !== 'undefined') ||
(chatGPTWebProject_show.innerText !== '' && chatGPTWebProject_show.innerText !== 'undefined') ||
(chatGPTWebCustomGPT_show.innerText !== '' && chatGPTWebCustomGPT_show.innerText !== 'undefined')) {
element.style.display = 'flex';
} else {
element.style.display = 'none';
}
if(chatGPTWebModel_show.innerText === '' || chatGPTWebModel_show.innerText === 'undefined') {
chatGPTWebModel_show.parentNode.style.display = 'none';
} else {
chatGPTWebModel_show.parentNode.style.display = 'inline';
}
if(chatGPTWebProject_show.innerText === '' || chatGPTWebProject_show.innerText === 'undefined') {
chatGPTWebProject_show.parentNode.style.display = 'none';
} else {
chatGPTWebProject_show.parentNode.style.display = 'inline';
}
if(chatGPTWebCustomGPT_show.innerText === '' || chatGPTWebCustomGPT_show.innerText === 'undefined') {
chatGPTWebCustomGPT_show.parentNode.style.display = 'none';
} else {
chatGPTWebCustomGPT_show.parentNode.style.display = 'inline';
}
break;
}
// case 'chatgpt_api':
// document.getElementById('chatgpt_api').style.display = 'block';
// break;
// case 'ollama_api':
// document.getElementById('ollama_api').style.display = 'block';
// break;
// case 'openai_comp_api':
// document.getElementById('openai_comp_api').style.display = 'block';
// break;
// case 'google_gemini_api':
// document.getElementById('google_gemini_api').style.display = 'block';
// break;
}
}
function toggleAdditionalPropertiesEditor(tr) {
switch(prefs.connection_type) {
case 'chatgpt_web': {
let info_toggle = tr.querySelector('.chatgpt_web_additional_info_toggle');
info_toggle.style.display = 'block';
let chatGPTWebModel_show = tr.querySelector('.chatgpt_web_model_show').innerText;
let chatGPTWebProject_show = tr.querySelector('.chatgpt_web_project_show').innerText;
let chatGPTWebCustomGPT_show = tr.querySelector('.chatgpt_web_custom_gpt_show').innerText;
if ((chatGPTWebModel_show !== '' && chatGPTWebModel_show !== 'undefined') ||
(chatGPTWebProject_show !== '' && chatGPTWebProject_show !== 'undefined') ||
(chatGPTWebCustomGPT_show !== '' && chatGPTWebCustomGPT_show !== 'undefined')) {
info_toggle.click();
}
break;
}
// case 'chatgpt_api':
// document.getElementById('chatgpt_api').style.display = 'block';
// break;
// case 'ollama_api':
// document.getElementById('ollama_api').style.display = 'block';
// break;
// case 'openai_comp_api':
// document.getElementById('openai_comp_api').style.display = 'block';
// break;
// case 'google_gemini_api':
// document.getElementById('google_gemini_api').style.display = 'block';
// break;
}
}
function toggleDiffviewer(e) {
e.preventDefault();
const tr = e.target.parentNode.parentNode;
const action = tr.querySelector('.action_output').value;
const checkbox = tr.querySelector('.use_diff_viewer');
if (action === "2") {
checkbox.disabled = false;
} else {
checkbox.checked = false;
checkbox.setAttribute('checked_val', '0');
checkbox.disabled = true;
}
//console.log('>>>>>>>> tr: ' + tr.getAttribute('data-idnum'));
//console.log('>>>>>>>> action: ' + action);
//console.log('>>>>>>>> checkbox: ' + checkbox.checked);
//console.log('>>>>>>>> checkbox: ' + checkbox.style.display);
}
// Confirm and log deletion action
function handleDeleteClick(e) {
e.preventDefault();
@ -369,6 +557,9 @@ function handleCancelClick(e) {
// tr.querySelector('.type_output').selectedOptions[0].text = tr.querySelector('.type_show').innerText;
tr.querySelector('.action_output').value = tr.querySelector('.action').innerText;
// tr.querySelector('.action_output').selectedOptions[0].text = tr.querySelector('.action_show').innerText;
tr.querySelector('.chatgpt_web_model_output').value = tr.querySelector('.chatgpt_web_model_show').innerText;
tr.querySelector('.chatgpt_web_project_output').value = tr.querySelector('.chatgpt_web_project_show').innerText;
tr.querySelector('.chatgpt_web_custom_gpt_output').value = tr.querySelector('.chatgpt_web_custom_gpt_show').innerText;
hideItemRowEditor(tr);
}
@ -384,6 +575,9 @@ function handleConfirmClick(e) {
tr.querySelector('.id_show').innerText = String(tr.querySelector('.id_output').value).toLocaleLowerCase();
tr.querySelector('.name_show').innerText = tr.querySelector('.name_output').value;
tr.querySelector('.text_show').innerText = tr.querySelector('.text_output').value;
tr.querySelector('.chatgpt_web_model_show').innerText = tr.querySelector('.chatgpt_web_model_output').value;
tr.querySelector('.chatgpt_web_project_show').innerText = tr.querySelector('.chatgpt_web_project_output').value;
tr.querySelector('.chatgpt_web_custom_gpt_show').innerText = tr.querySelector('.chatgpt_web_custom_gpt_output').value;
tr.querySelector('.type').innerText = tr.querySelector('.type_output').value;
tr.querySelector('.type_show').innerText = tr.querySelector('.type_output').selectedOptions[0].text;
tr.querySelector('.action').innerText = tr.querySelector('.action_output').value;
@ -449,38 +643,72 @@ function loadPromptsList(values){
let output = `<tr ` + ((values.is_default == 1) ? 'class="is_default"':'') + `>
<td class="w08"><span class="id id_show"></span><input type="text" class="hiddendata id_output" value="` + values.id + `" /></td>
<td class="w08"><span class="name name_show"></span><input type="text" class="hiddendata name_output" value="` + values.name + `" /></td>
<td class="w40"><span class="text text_show"></span><div class="autocomplete-container"><textarea class="hiddendata text_output editor">` + values.text.replace(/<br\s*\/?>/gi, "\n") + `</textarea><ul class="autocomplete-list hidden"></ul></div></td>
<td class="w08"><span class="type_show">` + type_output + `</span>
<td class="w40">
<span class="text text_show"></span>
<div class="autocomplete-container">
<textarea class="hiddendata text_output editor">` + values.text.replace(/<br\s*\/?>/gi, "\n") + `</textarea>
<ul class="autocomplete-list hidden"></ul>
</div>
<div class="chatgpt_web_additional_info_toggle small_info">__MSG_customPrompts_show_additional_info__</div>
<div class="chatgpt_web_additional_info">
<span class="field_title_us">__MSG_prefs_OptionText_chatgpt_web_model__:</span>
<br>
<input type="text" id="chatgpt_web_model_output_` + values.id + `" class="input_additional chatgpt_web_model_output" tabindex="10" value="` + values.chatgpt_web_model + `">
<table class="chatgpt_web_models_list_table" title="__MSG_prefs_OptionText_chatgpt_web_model_tooltip__"><tr id="chatgpt_web_models_list_` + values.id + `"></tr></table>
<br><br>
<span class="field_title_us">__MSG_prefs_OptionText_chatgpt_web_project__:</span>
<br>
<input type="text" id="chatgpt_web_project_` + values.id + `" class="input_additional chatgpt_web_project_output" tabindex="11" value="` + values.chatgpt_web_project + `">
<br><i class="small_info" id="chatgpt_web_project_` + values.id + `_info">__MSG_prefs_OptionText_chatgpt_web_custom_data_info__ <b>/g/PROJECT_ID-PROJECT_NAME/project</b>
<br>__MSG_prefs_OptionText_chatgpt_web_custom_data_info2__</i>
<br><br>
<span class="field_title_us">__MSG_prefs_OptionText_chatgpt_web_custom_gpt__:</span>
<br>
<input type="text" id="chatgpt_web_custom_gpt_` + values.id + `" class="input_additional chatgpt_web_custom_gpt_output" tabindex="11" value="` + values.chatgpt_web_custom_gpt + `">
<br><i class="small_info" id="chatgpt_web_custom_gpt_` + values.id + `_info">__MSG_prefs_OptionText_chatgpt_web_custom_data_info__ <b>/g/CUSTOM_GPT_ID</b>
<br>__MSG_prefs_OptionText_chatgpt_web_custom_data_info2__
<br>__MSG_prefs_OptionText_CustomGPT_Warn__</i>
</div>
</td>
<td class="w08"><span class="field_title_s">__MSG_customPrompts_add_to_menu__:</span>
<br>
<span class="type_show">` + type_output + `</span>
<select class="type_output hiddendata">
<option value="0"` + ((values.type == "0") ? ' selected':'') + `>__MSG_customPrompts_add_to_menu_always__</option>
<option value="1"` + ((values.type == "1") ? ' selected':'') + `>__MSG_customPrompts_add_to_menu_reading__</option>
<option value="2"` + ((values.type == "2") ? ' selected':'') + `>__MSG_customPrompts_add_to_menu_composing__</option>
</select>` +
`<span class="type hiddendata"></span>
<br><br>
<span class="field_title_s">__MSG_customPrompts_form_label_Action__:</span>
<br><span class="action_show">` + action_output + `</span>
<select class="action_output hiddendata">
<option value="0"` + ((values.action == "0") ? ' selected':'') + `>__MSG_customPrompts_close_button__</option>
<option value="1"` + ((values.action == "1") ? ' selected':'') + `>__MSG_customPrompts_do_reply__</option>
<option value="2"` + ((values.action == "2") ? ' selected':'') + `>__MSG_customPrompts_substitute_text__</option>
</select>` +
`<span class="action hiddendata"></span>
</td>
<td class="w17">
Action: <span class="action_show">` + action_output + `</span>
<select class="action_output hiddendata">
<option value="0"` + ((values.action == "0") ? ' selected':'') + `>__MSG_customPrompts_close_button__</option>
<option value="1"` + ((values.action == "1") ? ' selected':'') + `>__MSG_customPrompts_do_reply__</option>
<option value="2"` + ((values.action == "2") ? ' selected':'') + `>__MSG_customPrompts_substitute_text__</option>
</select>` +
`<span class="action hiddendata"></span>
<label><span class="need_selected_span"><input type="checkbox" class="need_selected" disabled> __MSG_customPrompts_form_label_need_selected__</span></label>
<br>
<span class="need_selected_span"><input type="checkbox" class="need_selected" disabled> __MSG_customPrompts_form_label_need_selected__</span>
<label><input type="checkbox" class="need_signature" disabled> __MSG_customPrompts_form_label_need_signature__</label>
<br>
<input type="checkbox" class="need_signature" disabled> __MSG_customPrompts_form_label_need_signature__
<label><span class="need_custom_text_span"><input type="checkbox" class="need_custom_text` + ((values.is_default == 1) ? ' input_mod':'') + `"` + ((values.is_default == 0) ? ' disabled':'') + ` > __MSG_customPrompts_form_label_need_custom_text__</span></label>
<br>
<span class="need_custom_text_span"><input type="checkbox" class="need_custom_text` + ((values.is_default == 1) ? ' input_mod':'') + `"` + ((values.is_default == 0) ? ' disabled':'') + ` > __MSG_customPrompts_form_label_need_custom_text__</span>
<label><input type="checkbox" class="define_response_lang" disabled> __MSG_customPrompts_form_label_define_response_lang__</label>
<br>
<input type="checkbox" class="define_response_lang" disabled> __MSG_customPrompts_form_label_define_response_lang__
<label title="__MSG_customPrompts_form_label_use_diff_viewer_title__"><input type="checkbox" class="use_diff_viewer" disabled> __MSG_customPrompts_form_label_use_diff_viewer__</label>
<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__
<label><input type="checkbox" class="enabled input_mod"> __MSG_customPrompts_form_label_enabled__</label>
<span class="is_default hiddendata"></span>
<span class="position_compose hiddendata"></span>
<span class="position_display hiddendata"></span>
<div class="chatgpt_web_additional_info_show small_info"><span class="chatgpt_web_additional_info_row field_title"><i>__MSG_customPrompts_show_additional_info_show__</i></span>
<div class="chatgpt_web_additional_info_row"><span class="field_title">__MSG_prefs_OptionText_chatgpt_web_model__:</span><span class="chatgpt_web_model chatgpt_web_model_show">` + values.chatgpt_web_model + `</span></div>
<div class="chatgpt_web_additional_info_row"><span class="field_title">__MSG_prefs_OptionText_chatgpt_web_project__:</span><span class="chatgpt_web_project chatgpt_web_project_show">` + values.chatgpt_web_project + `</span></div>
<div class="chatgpt_web_additional_info_row"><span class="field_title">__MSG_prefs_OptionText_chatgpt_web_custom_gpt__:</span><span class="chatgpt_web_custom_gpt chatgpt_web_custom_gpt_show">` + values.chatgpt_web_custom_gpt + `</span></div>
</div>
</td>
<td>
<button class="btnEditItem"` + ((values.is_default == 1) ? ' disabled':'') + `>__MSG_customPrompts_btnEdit__</button>
@ -498,6 +726,28 @@ function loadPromptsList(values){
}
};
switch(prefs.connection_type) {
case 'chatgpt_web': {
options.valueNames.push('chatgpt_web_model', 'chatgpt_web_project', 'chatgpt_web_custom_gpt');
break;
}
// case 'chatgpt_api':
// document.getElementById('chatgpt_api').style.display = 'block';
// break;
// case 'ollama_api':
// document.getElementById('ollama_api').style.display = 'block';
// break;
// case 'openai_comp_api':
// document.getElementById('openai_comp_api').style.display = 'block';
// break;
// case 'google_gemini_api':
// document.getElementById('google_gemini_api').style.display = 'block';
// break;
}
// console.log('>>>>>>>>>>>>> options: ' + JSON.stringify(options));
// console.log('>>>>>>>>>>>>> values: ' + JSON.stringify(values));
promptsList = new List('all_prompts', options, values);
checkSelectedBoxes();
@ -572,6 +822,9 @@ function clearFields() {
document.getElementById('txtIdNew').value = '';
document.getElementById('txtNameNew').value = '';
document.getElementById('txtTextNew').value = '';
document.getElementById('chatGPTWebModelNew').value = '';
document.getElementById('chatGPTWebProjectNew').value = '';
document.getElementById('chatGPTWebCustomGPTNew').value = '';
document.getElementById('selectTypeNew').value = '0';
document.getElementById('selectActionNew').value = '0';
document.getElementById('checkboxNeedSelectedNew').value = '0';
@ -641,6 +894,7 @@ async function saveAll() {
promptsList.reIndex();
let newPrompts = promptsList.items.map(item => {
// For each item in the array, return only the '_values' part
// console.log(">>>>>>>>>>>>>>>> item: " + JSON.stringify(item))
return item.values();
});
taLog.log('newPrompts: ' + JSON.stringify(newPrompts));

View file

@ -0,0 +1,119 @@
#get_task_prompt_container{
width: 90%;
margin: 20px auto;
}
#get_task_prompt_text{
width: 100%;
}
.infoline{
font-size: 0.8em;
font-style: italic;
}
.btn_div{
width: 100%;
display: flex;
justify-content: space-between;
}
table#miczPrefs {
padding: 10px;
border-spacing: 0px;
width: 90%;
margin: 0px auto 40px auto;
border: 1px solid #ccc;
}
.get_task_table_title{
width: 90%;
margin: auto;
}
.section_title{
font-weight: bold;
}
table#miczPrefs td{
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
vertical-align: top;
padding: 2px;
}
table#miczPrefs tr:first-child td {
border-top: none;
}
table#miczPrefs tr:last-child td {
border-bottom: none;
}
.autocomplete-container {
position: relative;
}
.autocomplete-list {
position: absolute;
top: 100%;
left: 0;
right: 0;
background-color: white;
border: 1px solid #ccc;
z-index: 1000;
max-height: 200px;
overflow-y: auto;
padding: 0;
margin: 0;
list-style: none;
font-size: small;
}
.autocomplete-list li {
padding: 8px;
cursor: pointer;
}
.autocomplete-list li:hover {
background-color: #f0f0f0;
}
.autocomplete-list li.active {
background-color: #ddd;
}
.hidden {
display: none;
}
.unsaved{
color: red;
}
@media (prefers-color-scheme: dark) {
body {
background-color: #1C1B22;
color: rgb(251, 251, 254);
}
a:link { color: #409EFF; }
a:visited { color: #409EFF; }
a:hover { color: #66B1FF; }
a:active { color: #66B1FF; }
a:active { color: #66B1FF; }
.autocomplete-list {
background-color: #2E2F36;
border: 1px solid #2E2F36;
}
.autocomplete-list li:hover {
background-color: #4c4e58;
}
.autocomplete-list li.active {
background-color: #4c4e58;
}
}

View file

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ThunderAI - __MSG_GetTask_PageTitle__</title>
<link rel="stylesheet" href="mzta-get-task.css">
<link rel="icon" href="../../images/icon-16px.png">
</head>
<body>
<div>
<h1 class="page_title">__MSG_GetTask_PageTitle__</h1>
<p>__MSG_GetTask_info_default__</p>
</div>
<div class="get_calendar_event_table_title section_title">__MSG_get_calendar_event_prompt_prefs_title__</div>
<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_task_container">
<span class="section_title">__MSG_GetCalendarEvent_prompt_text_title__</span><span id="get_task_prompt_unsaved" class="unsaved hidden"> __MSG_customPrompts_unsaved_changes__</span>
<br><span class="infoline">__MSG_prefs_OptionText_btnManagePrompts_infoline__ <a href="https://micz.it/thunderbird-addon-thunderai/data-placeholders/">__MSG_customPrompts_managePrompts_help__</a>
<br><b>__MSG_prefs_OptionText_GetCalendarEvent_infoline2__</b></span>
<br>
<div class="autocomplete-container">
<textarea id="get_task_prompt_text" rows="15"></textarea>
<ul class="autocomplete-list hidden"></ul>
</div>
<div id="get_task_info_additional_statements"></div>
<div class="btn_div"><button id="btn_reset_prompt" disabled>__MSG_reset_default__</button><button id="btn_save_prompt" disabled>__MSG_save__</button></div>
</div>
<script src="mzta-get-task.js" type="module"></script>
<script src="../../js/mzta-i18n.js"></script>
</body>
</html>

View file

@ -0,0 +1,149 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
* Copyright (C) 2024 - 2025 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { prefs_default } from '../../options/mzta-options-default.js';
import { taLogger } from '../../js/mzta-logger.js';
import { getSpecialPrompts, setSpecialPrompts } from "../../js/mzta-prompts.js";
import { getPlaceholders } from "../../js/mzta-placeholders.js";
import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js";
let autocompleteSuggestions = [];
let taLog = new taLogger("mzta-get-calendar-event-page",true);
document.addEventListener('DOMContentLoaded', async () => {
i18n.updateDocument();
await restoreOptions();
document.querySelectorAll(".option-input").forEach(element => {
element.addEventListener("change", saveOptions);
});
let get_calendar_event_textarea = document.getElementById('get_task_prompt_text');
let get_calendar_event_save_btn = document.getElementById('btn_save_prompt');
let get_calendar_event_reset_btn = document.getElementById('btn_reset_prompt');
let specialPrompts = await getSpecialPrompts();
let get_calendar_event_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_get_task');
get_calendar_event_textarea.addEventListener('input', (event) => {
get_calendar_event_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_get_task_full_text'));
get_calendar_event_save_btn.disabled = (event.target.value === get_calendar_event_prompt.text);
if(get_calendar_event_save_btn.disabled){
document.getElementById('get_task_prompt_unsaved').classList.add('hidden');
} else {
document.getElementById('get_task_prompt_unsaved').classList.remove('hidden');
}
});
get_calendar_event_reset_btn.addEventListener('click', () => {
get_calendar_event_textarea.value = browser.i18n.getMessage('prompt_get_task_full_text');
get_calendar_event_reset_btn.disabled = true;
let event = new Event('input', { bubbles: true, cancelable: true });
get_calendar_event_textarea.dispatchEvent(event);
});
get_calendar_event_save_btn.addEventListener('click', () => {
specialPrompts.find(prompt => prompt.id === 'prompt_get_task').text = get_calendar_event_textarea.value;
setSpecialPrompts(specialPrompts);
get_calendar_event_save_btn.disabled = true;
document.getElementById('get_task_prompt_unsaved').classList.add('hidden');
browser.runtime.sendMessage({command: "reload_menus"});
});
if(get_calendar_event_prompt.text === 'prompt_get_task_full_text'){
get_calendar_event_prompt.text = browser.i18n.getMessage(get_calendar_event_prompt.text);
}
get_calendar_event_textarea.value = get_calendar_event_prompt.text;
get_calendar_event_reset_btn.disabled = (get_calendar_event_textarea.value === browser.i18n.getMessage('prompt_get_task_full_text'));
autocompleteSuggestions = (await getPlaceholders(true)).filter(p => !(p.id === 'additional_text')).map(p => ({command: '{%'+p.id+'%}', type: p.type}));
textareaAutocomplete(get_calendar_event_textarea, autocompleteSuggestions, 1); // type_value = 1, only when reading an email
});
// Methods to manage options, derived from: /options/mzta-options.js
function saveOptions(e) {
e.preventDefault();
let options = {};
let element = e.target;
switch (element.type) {
case 'checkbox':
options[element.id] = element.checked;
break;
case 'number':
options[element.id] = element.valueAsNumber;
break;
case 'text':
case 'password':
options[element.id] = element.value.trim();
break;
default:
if (element.tagName === 'SELECT') {
options[element.id] = element.value;
}else{
console.error("[ThunderAI] Unhandled input type:", element.type);
}
}
browser.storage.sync.set(options);
}
async function restoreOptions() {
function setCurrentChoice(result) {
document.querySelectorAll(".option-input").forEach(element => {
taLog.log("Options restoring " + element.id + " = " + (element.id=="chatgpt_api_key" || element.id=="openai_comp_api_key" ? "****************" : result[element.id]));
switch (element.type) {
case 'checkbox':
element.checked = result[element.id] || false;
break;
case 'number':
let default_number_value = 0;
if(element.id == 'chatgpt_win_height') default_number_value = prefs_default.chatgpt_win_height;
if(element.id == 'chatgpt_win_width') default_number_value = prefs_default.chatgpt_win_width;
element.value = result[element.id] ?? default_number_value;
break;
case 'text':
case 'password':
let default_text_value = '';
if(element.id == 'default_chatgpt_lang') default_text_value = prefs_default.default_chatgpt_lang;
element.value = result[element.id] || default_text_value;
break;
default:
if (element.tagName === 'SELECT') {
let default_select_value = '';
if(element.id == 'reply_type') default_select_value = 'reply_all';
if(element.id == 'connection_type') default_select_value = 'chatgpt_web';
element.value = result[element.id] || default_select_value;
if (element.value === '') {
element.selectedIndex = -1;
}
}else{
console.error("[ThunderAI] Unhandled input type:", element.type);
}
}
});
}
let getting = await browser.storage.sync.get(prefs_default);
setCurrentChoice(getting);
}

View file

@ -181,3 +181,39 @@ h2 {
.section .button:active {
box-shadow: inset 5px 2px 5px rgba(0, 0, 0, 0.3);
}
#chatgpt_web_permission {
display: none;
background-color: red;
color: white;
padding: 10px;
border-radius: 5px;
margin: 10px 0;
font-size: 18px;
font-weight: bold;
text-align: center;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.3s ease;
}
#chatgpt_web_permission:hover {
background-color: darkred;
transform: scale(1.05);
}
#chatgpt_web_permission_ok {
display: none;
background-color: green;
color: white;
padding: 10px;
border-radius: 5px;
margin: 10px 0;
font-size: 18px;
font-weight: bold;
text-align: center;
cursor: pointer;
}
#chatgpt_web_permission_ok:hover {
background-color: darkgreen;
transform: scale(1.05);
}

View file

@ -14,6 +14,10 @@
</head>
<body>
<div class="content">
<div id="chatgpt_web_permission">__MSG_ask_chatgptweb_permission_1__
<br>__MSG_ask_chatgptweb_permission_2__
</div>
<div id="chatgpt_web_permission_ok">__MSG_ask_chatgptweb_permission_ok__</div>
<div class="section header">
<h1><img src="../../images/icon.png" class="title-icon"/>ThunderAI</h1>
<p>
@ -82,5 +86,7 @@
</p>
</div>
</div>
<script src="onboarding.js" type="module"></script>
<script src="../../js/mzta-i18n.js"></script>
</body>
</html>

View file

@ -0,0 +1,46 @@
/*
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
* Copyright (C) 2024 - 2025 Mic (m@micz.it)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { taLogger } from '../../js/mzta-logger.js';
let taLog = null;
document.addEventListener('DOMContentLoaded', async () => {
let prefs = await browser.storage.sync.get({do_debug: false, connection_type: 'chatgpt_web'});
taLog = new taLogger("mzta-popup",prefs.do_debug);
i18n.updateDocument();
if(prefs.connection_type === 'chatgpt_web'){
let permission_chatgpt = await messenger.permissions.contains({ origins: ["https://*.chatgpt.com/*"] });
if(permission_chatgpt === false){
document.getElementById("chatgpt_web_permission").style.display = "block";
document.getElementById("chatgpt_web_permission").addEventListener("click", async () => {
let granted = await messenger.permissions.request({ origins: ["https://*.chatgpt.com/*"] });
if(granted){
document.getElementById("chatgpt_web_permission").style.display = "none";
document.getElementById("chatgpt_web_permission_ok").style.display = "block";
taLog.log("ChatGPT web permission granted");
}else{
taLog.log("ChatGPT web permission denied");
}
});
document.getElementById("chatgpt_web_permission_ok").addEventListener("click", async () => {
await messenger.tabs.remove((await messenger.tabs.getCurrent()).id);
});
}
}
}, { once: true });

View file

@ -1,4 +1,4 @@
#spamfilter_prompt_container{
#spamfilter_container, #account_selector_container, #spamfitler_reports_container{
width: 90%;
margin: 20px auto;
}
@ -7,6 +7,19 @@
width: 100%;
}
#account_selector_container{
margin-top: 40px;
margin-bottom: 40px;
}
#account_selector_checkboxes{
padding: 10px;
border: 1px solid gray;
width: 24em;
margin-bottom: 10px;
margin-top: 10px;
}
.infoline{
font-size: 0.8em;
font-style: italic;

View file

@ -44,24 +44,33 @@
<div id="spamfilter_info_additional_statements"></div>
<div class="btn_div"><button id="btn_reset_prompt" disabled>__MSG_reset_default__</button><button id="btn_save_prompt" disabled>__MSG_save__</button></div>
</div>
<h2>__MSG_SpamReport_Title__</h2>
<table id="report_data">
<thead>
<tr>
<th>Message_ID</th>
<th>__MSG_Date__</th>
<th>__MSG_From__</th>
<th>__MSG_Subject__</th>
<th>__MSG_Spam_Value__</th>
<th>__MSG_Moved_to_Spam__</th>
<th>__MSG_Explanation__</th>
<th>__MSG_Report_Date__</th>
</tr>
</thead>
<tbody id="report_data_body">
<!-- Rows will be inserted dynamically -->
</tbody>
</table>
<div id="account_selector_container">
<div id="account_selector_info"><span class="section_title">__MSG_AccountSelector_Spamfilter__</span>
<br><span class="infoline">__MSG_AccountSelector_AutoTags_infoline__</span></div>
<div id="account_selector_checkboxes"></div>
<button type="button" id="accounts_select_all">Select All</button>
<button type="button" id="accounts_deselect_all">Deselect All</button>
</div>
<div id="spamfitler_reports_container">
<h2>__MSG_SpamReport_Title__</h2>
<table id="report_data">
<thead>
<tr>
<th>Message_ID</th>
<th>__MSG_Date__</th>
<th>__MSG_From__</th>
<th>__MSG_Subject__</th>
<th>__MSG_Spam_Value__</th>
<th>__MSG_Moved_to_Spam__</th>
<th>__MSG_Explanation__</th>
<th>__MSG_Report_Date__</th>
</tr>
</thead>
<tbody id="report_data_body">
<!-- Rows will be inserted dynamically -->
</tbody>
</table>
</div>
<script src="mzta-spamfilter.js" type="module"></script>
<script src="../../js/mzta-i18n.js"></script>
</body>

View file

@ -22,6 +22,7 @@ import { getSpecialPrompts, setSpecialPrompts } from "../../js/mzta-prompts.js";
import { getPlaceholders } from "../../js/mzta-placeholders.js";
import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js";
import { taSpamReport } from '../../js/mzta-spamreport.js';
import { getAccountsList } from "../../js/mzta-utils.js";
let autocompleteSuggestions = [];
let taLog = new taLogger("mzta-spamfilter-page",true);
@ -80,7 +81,61 @@ document.addEventListener('DOMContentLoaded', async () => {
autocompleteSuggestions = (await getPlaceholders(true)).filter(p => !(p.id === 'additional_text')).map(p => ({command: '{%'+p.id+'%}', type: p.type}));
textareaAutocomplete(spamfilter_textarea, autocompleteSuggestions, 1); // type_value = 1, only when reading an email
loadSpamReport()
//Accounts manager
let accounts = await getAccountsList();
const accountsContainer = document.getElementById('account_selector_checkboxes');
accounts.forEach(account => {
const accountLabel = document.createElement('label');
const accountCheckbox = document.createElement('input');
accountCheckbox.type = 'checkbox';
accountCheckbox.classList.add('accountCheckbox');
accountCheckbox.value = account.id;
accountLabel.appendChild(accountCheckbox);
accountLabel.appendChild(document.createTextNode(account.name));
accountsContainer.appendChild(accountLabel);
accountsContainer.appendChild(document.createElement('br'));
});
let prefs_spamfilter = await browser.storage.sync.get({ spamfilter_enabled_accounts: [] });
let spamfilter_enabled_accounts = prefs_spamfilter.spamfilter_enabled_accounts;
taLog.log("spamfilter_enabled_accounts: " + JSON.stringify(spamfilter_enabled_accounts));
document.querySelectorAll('.accountCheckbox').forEach(checkbox => {
if (spamfilter_enabled_accounts.length === 0 || spamfilter_enabled_accounts.includes(checkbox.value)) {
checkbox.checked = true;
} else {
checkbox.checked = false;
}
});
document.querySelectorAll('.accountCheckbox').forEach(checkbox => {
checkbox.addEventListener('change', () => {
let selectedAccounts = Array.from(document.querySelectorAll('.accountCheckbox:checked')).map(checkbox => checkbox.value);
if (selectedAccounts.length === 0) {
checkbox.checked = true; // Prevent deselecting the last selected checkbox
taLog.log("At least one account must be selected.");
return;
}
if (selectedAccounts.length === document.querySelectorAll('.accountCheckbox').length) {
browser.storage.sync.set({ spamfilter_enabled_accounts: [] });
taSpamReport.logger.log("All accounts selected, saving spamfilter_enabled_accounts = [].");
} else {
browser.storage.sync.set({ spamfilter_enabled_accounts: selectedAccounts });
taSpamReport.logger.log("Saving spamfilter_enabled_accounts = " + JSON.stringify(selectedAccounts) + ".");
}
});
});
document.getElementById('accounts_select_all').addEventListener('click', () => {
let checkboxes = document.querySelectorAll('.accountCheckbox');
checkboxes.forEach(checkbox => checkbox.checked = true);
});
document.getElementById('accounts_deselect_all').addEventListener('click', () => {
let checkboxes = document.querySelectorAll('.accountCheckbox');
checkboxes.forEach(checkbox => checkbox.checked = false);
});
loadSpamReport();
});
function check_spamfilter_threshold(event) {

View file

@ -68,7 +68,19 @@ body {
background-color: #cfe9ff;
}
#ask_chatgpt_web_perm{
display: none;
max-width: 20em;
background-color: red;
color: white;
padding: 10px;
border-radius: 5px;
font-size: 18px;
font-weight: bold;
text-align: center;
cursor: pointer;
}
@media (prefers-color-scheme: dark) {
body{

View file

@ -8,6 +8,9 @@
</head>
<body>
<div id="ask_chatgpt_web_perm">__MSG_ask_chatgptweb_permission_1__
<br>__MSG_ask_chatgptweb_permission_2_popup__
</div>
<div id="mzta_search_banner">
<div id="_spacer_div">&nbsp;</div>
<div id="mzta_sending_prompt"><img src="mzta-loading.svg" title="__MSG_SendingPrompt__"></div>

View file

@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { prefs_default } from "../options/mzta-options-default.js";
import { taLogger } from "../js/mzta-logger.js";
import { checkSparksPresence } from "../js/mzta-utils.js";
@ -24,11 +25,13 @@ let taLog = console;
let connection_type = 'chatgpt_web';
let add_tags = false;
let get_calendar_event = false;
let get_task = false;
let _ok_sparks = false;
let tabType;
let num_special_menu_items = 0;
document.addEventListener('DOMContentLoaded', async () => {
let prefs = await browser.storage.sync.get({do_debug: false, dynamic_menu_force_enter: false, add_tags: true, get_calendar_event: true, connection_type: 'chatgpt_web'});
let prefs = await browser.storage.sync.get({do_debug: prefs_default.do_debug, dynamic_menu_force_enter: prefs_default.dynamic_menu_force_enter, add_tags: prefs_default.add_tags, get_calendar_event: prefs_default.get_calendar_event, get_task: prefs_default.get_task, connection_type: prefs_default.connection_type});
taLog = new taLogger("mzta-popup",prefs.do_debug);
i18n.updateDocument();
let reponse = await browser.runtime.sendMessage({command: "popup_menu_ready"});
@ -44,8 +47,25 @@ document.addEventListener('DOMContentLoaded', async () => {
connection_type = prefs.connection_type;
add_tags = prefs.add_tags;
get_calendar_event = prefs.get_calendar_event;
get_task = prefs.get_task;
_ok_sparks = await checkSparksPresence() == 1;
// console.log(">>>>>>>>>>>>>>>>> add_tags: " + add_tags);
// console.log(">>>>>>>>>>>>>>>>> get_calendar_event: " + get_calendar_event);
// console.log(">>>>>>>>>>>>>>>>> get_task: " + get_task);
// console.log(">>>>>>>>>>>>>>>>> _ok_sparks: " + _ok_sparks);
searchPrompt(active_prompts, tabId, tabType);
i18n.updateDocument();
if(prefs.connection_type === 'chatgpt_web'){
let permission_chatgpt = await browser.permissions.contains({ origins: ["https://*.chatgpt.com/*"] });
if(permission_chatgpt === false){
document.getElementById("mzta_search_banner").style.display = "none";
document.getElementById("ask_chatgpt_web_perm").style.display = "block";
document.getElementById('ask_chatgpt_web_perm').addEventListener('click', async () => {
await browser.tabs.create({ url: "../pages/onboarding/onboarding.html" });
});
}
}
}, { once: true });
async function searchPrompt(allPrompts, tabId, tabType){
@ -105,18 +125,15 @@ async function searchPrompt(allPrompts, tabId, tabType){
let do_add_tags = checkDoAddTags();
let do_get_calendar_event = checkDoCalendarEvent();
let do_get_task = checkDoTask();
// console.log(">>>>>>>>>>> do_add_tags: " + do_add_tags);
// console.log(">>>>>>>>>>> do_get_calendar_event: " + do_get_calendar_event);
// console.log(">>>>>>>>>>> do_get_task: " + do_get_task);
// console.log(">>>>>>>>>>> filteredData: " + JSON.stringify(filteredData));
if(do_add_tags){
num_special_menu_items++;
}
if(do_get_calendar_event){
num_special_menu_items++;
}
// console.log(">>>>>>>>>>>> num_special_menu_items: " + num_special_menu_items);
num_special_menu_items = (do_add_tags ? 1 : 0) + (do_get_calendar_event ? 1 : 0) + (do_get_task ? 1 : 0);
// console.log(">>>>>>>>>>>> num_special_menu_items: " + num_special_menu_items);
if(num_special_menu_items > 0){
max_num_el -= num_special_menu_items;
first_num_el = num_special_menu_items;
@ -137,16 +154,18 @@ async function searchPrompt(allPrompts, tabId, tabType){
filteredData[gce_curr_pos].label = gce_curr_pos + '. ' + filteredData[gce_curr_pos].label;
}
}
if(do_get_task){
filteredData = ensurePromptGetTaskFirst(filteredData, do_add_tags, do_get_calendar_event);
let gtask_curr_pos = (do_add_tags ? 1 : 0) + (do_get_calendar_event ? 1 : 0);
if (!filteredData[gtask_curr_pos].numberPrepended) {
filteredData[gtask_curr_pos].numberPrepended = 'true';
filteredData[gtask_curr_pos].label = gtask_curr_pos + '. ' + filteredData[gtask_curr_pos].label;
}
}
}
// if(checkDoAddTags()){
// max_num_el = 9;
// first_num_el = 1;
// filteredData = ensurePromptAddTagsFirst(filteredData);
// if (!filteredData[0].numberPrepended) {
// filteredData[0].numberPrepended = 'true';
// filteredData[0].label = '0. ' + filteredData[0].label;
// }
// }
// console.log(">>>>>>>>>>> filteredData after special items check: " + JSON.stringify(filteredData));
Array.from(filteredData).slice(first_num_el, max_num_el).forEach((item, index) => {
let number = (index + first_num_el).toString();
// Check if the number is already prepended to avoid duplication
@ -164,7 +183,7 @@ async function searchPrompt(allPrompts, tabId, tabType){
itemDiv.classList.add('mzta_autocomplete-item');
itemDiv.textContent = item.label;
itemDiv.setAttribute('data-id', item.id);
if((item.id === 'prompt_add_tags')||(item.id === 'prompt_get_calendar_event')){
if((item.id === 'prompt_add_tags')||(item.id === 'prompt_get_calendar_event')||(item.id === 'prompt_get_task')){
itemDiv.className += ' special_prompt';
}
@ -327,7 +346,11 @@ function checkDoAddTags(){
}
function checkDoCalendarEvent(){
return get_calendar_event && (connection_type !== "chatgpt_web" && tabType !== 'messageCompose') && checkSparksPresence();
return get_calendar_event && (connection_type !== "chatgpt_web" && tabType !== 'messageCompose') && _ok_sparks;
}
function checkDoTask(){
return get_task && (connection_type !== "chatgpt_web" && tabType !== 'messageCompose') && _ok_sparks;
}
function ensurePromptAddTagsFirst(arr) {
@ -359,5 +382,24 @@ function ensurePromptGetCalendarEventFirst(arr, do_add_tags) {
arr.splice(targetPosition, 0, promptAddTags);
}
return arr;
}
function ensurePromptGetTaskFirst(arr, do_add_tags, do_get_calendar_event) {
// Find the index of the object with id "prompt_get_task"
const index = arr.findIndex(item => item.id === "prompt_get_task");
// If found and needs repositioning
if (index !== -1 && ((do_get_calendar_event && do_add_tags) ? index !== 2 : (do_get_calendar_event ? index !== 1 : index !== 0))) {
// Remove it from its current position
const [promptGetTask] = arr.splice(index, 1);
// Determine the target position to insert "prompt_get_task" after calendar
const targetPosition = do_add_tags && do_get_calendar_event ? 2 : (do_get_calendar_event ? 1 : 0);
// Add it to the specified position
arr.splice(targetPosition, 0, promptGetTask);
}
return arr;
}