diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 432b6f34..c98079bd 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1003,6 +1003,14 @@ "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_summarize": { + "message": "Summarize this email or these emails", + "description": "" + }, + "prompt_summarize_full_text": { + "message": "Summarize the following email or emails into a bullet point list. If there are multiple emails, consider the entire thread for the summary.", + "description": "" + }, "prompt_get_task": { "message": "Add a new task", "description": "" @@ -1231,6 +1239,18 @@ "message": "Spam Filter Options", "description": "" }, + "Summarize_PageTitle": { + "message": "Manage Summarize Settings", + "description": "" + }, + "Summarize_info_default": { + "message": "In this page you can modify the default prompt used to summarize emails.", + "description": "" + }, + "Summarize_prompt_text_title": { + "message": "Current prompt text", + "description": "" + }, "prefs_OptionText_use_specific_integration": { "message": "Use specific Model and API", "description": "" @@ -1307,7 +1327,7 @@ "message": "Analyze for spam", "description": "" }, - "context_menu_mzta-summary": { + "context_menu_mzta-summarize": { "message": "Summarize", "description": "" }, diff --git a/js/mzta-utils.js b/js/mzta-utils.js index 79216f9d..eb4f8d49 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -25,11 +25,11 @@ export const getMenuContextDisplay = () => 'message_display_action_menu'; export const contextMenuID_AddTags = 'mzta-add-tags'; export const contextMenuID_Spamfilter = 'mzta-spamfilter'; -export const contextMenuID_Summary = 'mzta-summary'; +export const contextMenuID_Summarize = 'mzta-summarize'; export const contextMenuIconsPath = { [contextMenuID_AddTags]: 'moz-extension:images/autotags.png', [contextMenuID_Spamfilter]: 'moz-extension:images/spamfilter.png', - // [contextMenuID_Summary]: 'moz-extension:images/summary.png', + // [contextMenuID_Summarize]: 'moz-extension:images/summarize.png', }; export function getLanguageDisplayName(languageCode) { diff --git a/mzta-background.js b/mzta-background.js index ce3d1d7b..5ceb483e 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -45,7 +45,7 @@ import { extractJsonObject, contextMenuID_AddTags, contextMenuID_Spamfilter, - contextMenuID_Summary, + contextMenuID_Summarize, contextMenuIconsPath, sanitizeChatGPTModelData, sanitizeChatGPTWebCustomData, @@ -990,10 +990,10 @@ function addContextMenuItems() { addContextMenu(contextMenuID_Spamfilter); } - // Add Context menu: Summary + // Add Context menu: Summarize if(prefs_init.summarize && prefs_init.summarize_context_menu && checkAPIIntegration(prefs_init.connection_type && prefs_init.summarize_use_specific_integration, prefs_init.summarize_connection_type)) { - console.log("adding summary to context menu") - addContextMenu(contextMenuID_Summary); + console.log("adding summarize to context menu") + addContextMenu(contextMenuID_Summariz); } } diff --git a/options/mzta-options.js b/options/mzta-options.js index 16b130fd..3b2ac351 100644 --- a/options/mzta-options.js +++ b/options/mzta-options.js @@ -291,6 +291,10 @@ document.addEventListener('DOMContentLoaded', async () => { document.getElementById('btnManageSpamFilterInfo').addEventListener('click', () => { openTab('/pages/spamfilter/mzta-spamfilter.html'); }); + + document.getElementById('btnManageSummarizeInfo').addEventListener('click', () => { + openTab('/pages/summarize/mzta-summarize.html'); + }); document.getElementById('btnManageCalendarEventInfo').addEventListener('click', () => { openTab('/pages/get-calendar-event/mzta-get-calendar-event.html'); diff --git a/pages/summarize/mzta-summarize.css b/pages/summarize/mzta-summarize.css new file mode 100644 index 00000000..173353e7 --- /dev/null +++ b/pages/summarize/mzta-summarize.css @@ -0,0 +1,123 @@ +#summarize_prompt_container { + width: 90%; + margin: 20px auto; +} + +#summarize_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; +} + +.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; + } +} diff --git a/pages/summarize/mzta-summarize.html b/pages/summarize/mzta-summarize.html new file mode 100644 index 00000000..7433ec82 --- /dev/null +++ b/pages/summarize/mzta-summarize.html @@ -0,0 +1,30 @@ + + + + + ThunderAI - __MSG_Summarize_PageTitle__ + + + + +
+

__MSG_Summarize_PageTitle__

+

__MSG_Summarize_info_default__

+
+
+ __MSG_Summarize_prompt_text_title__ + +
__MSG_prefs_OptionText_btnManagePrompts_infoline__ __MSG_more_info_string__ +
__MSG_prefs_OptionText_AdvancedPromptResponse_infoline2__
+
+
+ + +
+
+
+
+ + + + diff --git a/pages/summarize/mzta-summarize.js b/pages/summarize/mzta-summarize.js new file mode 100644 index 00000000..646cb096 --- /dev/null +++ b/pages/summarize/mzta-summarize.js @@ -0,0 +1,77 @@ +/* + * 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 . + */ + +import { prefs_default } from "../../options/mzta-options-default.js"; +import { taLogger } from "../../js/mzta-logger.js"; +import { getSpecialPrompts, setSpecialPrompts } from "../../js/mzta-prompts.js"; +import { getPlaceholders } from "../../js/mzta-placeholders.js"; +import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js"; +import { isAPIKeyValue } from "../../js/mzta-utils.js"; + +let autocompleteSuggestions = []; +let taLog = new taLogger("mzta-summarize-page", true); + +document.addEventListener("DOMContentLoaded", async () => { + + i18n.updateDocument(); + + + const summarize_textarea = document.getElementById("summarize_prompt_text"); + const summarize_save_btn = document.getElementById("btn_save_prompt"); + const summarize_reset_btn = document.getElementById("btn_reset_prompt"); + + let specialPrompts = await getSpecialPrompts(); + let summarize_prompt = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize'); + + summarize_textarea.addEventListener("input", (event) => { + summarize_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_summarize_full_text')); + summarize_save_btn.disabled = (event.target.value === summarize_prompt.text); + if (summarize_save_btn.disabled) { + document.getElementById("summarize_prompt_unsaved").classList.add("hidden"); + } else { + document.getElementById("summarize_prompt_unsaved").classList.remove("hidden"); + } + }); + + summarize_reset_btn.addEventListener("click", () => { + summarize_textarea.value = browser.i18n.getMessage("prompt_summarize_full_text"); + summarize_reset_btn.disabled = true; + let event = new Event("input", { bubbles: true, cancelable: true }); + summarize_textarea.dispatchEvent(event); + }); + + summarize_save_btn.addEventListener("click", () => { + specialPrompts.find(prompt => prompt.id === 'prompt_summarize') + setSpecialPrompts(specialPrompts); + summarize_save_btn.disabled = true; + document.getElementById("summarize_prompt_unsaved").classList.add("hidden"); + browser.runtime.sendMessage({ command: "reload_menus" }); + }); + + if(summarize_prompt.text === 'prompt_summarize_full_text'){ + summarize_prompt.text = browser.i18n.getMessage(summarize_prompt.text); + } + summarize_textarea.value = summarize_prompt.text; + summarize_reset_btn.disabled = (summarize_textarea.value === browser.i18n.getMessage("prompt_summarize_full_text")); + + autocompleteSuggestions = (await getPlaceholders(true)) + .filter((p) => p.id !== "additional_text") + .map((p) => ({ command: `{%${p.id}%}`, type: p.type })); + textareaAutocomplete(summarize_textarea, autocompleteSuggestions, 1); +}); + diff --git a/pages/summary/mzta-summary.css b/pages/summary/mzta-summary.css deleted file mode 100644 index e69de29b..00000000 diff --git a/pages/summary/mzta-summary.html b/pages/summary/mzta-summary.html deleted file mode 100644 index e69de29b..00000000 diff --git a/pages/summary/mzta-summary.js b/pages/summary/mzta-summary.js deleted file mode 100644 index e69de29b..00000000