From d4048979113af6284dcaa473f7e2f5bd3418f7de Mon Sep 17 00:00:00 2001 From: Mic Date: Tue, 2 Sep 2025 22:45:00 +0200 Subject: [PATCH 01/53] connection_type dynamic loading --- js/mzta-utils.js | 31 ++++++++++++++++++++++++++++++- options/mzta-options.html | 9 +-------- options/mzta-options.js | 3 ++- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/js/mzta-utils.js b/js/mzta-utils.js index bf41319a..4f55343c 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -364,6 +364,35 @@ export function generateCallID(length = 10) { return result; } +export function populateConnectionTypeOptions(selectId) { + const selectEl = document.getElementById(selectId); + if (!selectEl) return; + + const prevValue = selectEl.value; + + const options = [ + { value: 'chatgpt_web', msgKey: 'prefs_Connection_type_ChatGPT_Web' }, + { value: 'chatgpt_api', msgKey: 'prefs_Connection_type_ChatGPT_API' }, + { value: 'google_gemini_api', msgKey: 'prefs_Connection_type_Google_Gemini_API' }, + { value: 'anthropic_api', msgKey: 'prefs_Connection_type_Anthropic_API' }, + { value: 'ollama_api', msgKey: 'prefs_Connection_type_Ollama_API' }, + { value: 'openai_comp_api', msgKey: 'prefs_Connection_type_OpenAI_Comp_API' } + ]; + + selectEl.innerHTML = ''; + + for (const opt of options) { + const optionEl = document.createElement('option'); + optionEl.value = opt.value; + optionEl.textContent = browser.i18n.getMessage(opt.msgKey) || opt.msgKey; + selectEl.appendChild(optionEl); + } + + if (options.some(o => o.value === prevValue)) { + selectEl.value = prevValue; + } +} + export async function getTagsList(){ let messageTags = []; if(await isThunderbird128OrGreater()) { @@ -753,4 +782,4 @@ export async function* getMessages(list) { yield message; } } -} \ No newline at end of file +} diff --git a/options/mzta-options.html b/options/mzta-options.html index f8c12e4b..a9c90554 100644 --- a/options/mzta-options.html +++ b/options/mzta-options.html @@ -121,14 +121,7 @@ diff --git a/options/mzta-options.js b/options/mzta-options.js index 13604510..794a3d7a 100644 --- a/options/mzta-options.js +++ b/options/mzta-options.js @@ -23,7 +23,7 @@ import { Ollama } from '../js/api/ollama.js'; import { OpenAIComp } from '../js/api/openai_comp.js' import { GoogleGemini } from '../js/api/google_gemini.js'; import { Anthropic } from '../js/api/anthropic.js'; -import { ChatGPTWeb_models, checkSparksPresence, isThunderbird128OrGreater, openTab, sanitizeChatGPTModelData, sanitizeChatGPTWebCustomData, validateCustomData_ChatGPTWeb, getChatGPTWebModelsList_HTML } from '../js/mzta-utils.js'; +import { ChatGPTWeb_models, checkSparksPresence, isThunderbird128OrGreater, openTab, sanitizeChatGPTModelData, sanitizeChatGPTWebCustomData, validateCustomData_ChatGPTWeb, getChatGPTWebModelsList_HTML, populateConnectionTypeOptions } from '../js/mzta-utils.js'; import { openAICompConfigs } from '../js/api/openai_comp_configs.js'; let taLog = new taLogger("mzta-options",true); @@ -405,6 +405,7 @@ function resetMaxPromptLength(){ } document.addEventListener('DOMContentLoaded', async () => { + populateConnectionTypeOptions('connection_type'); await restoreOptions(); permission_all_urls = await messenger.permissions.contains({ origins: [""] }) From e551974a5642bd60c63d57381b2657e624431d7d Mon Sep 17 00:00:00 2001 From: Mic Date: Tue, 2 Sep 2025 22:45:00 +0200 Subject: [PATCH 02/53] work in progress, saving a point before working on generalizing the connetiontype html code. see #438 --- _locales/en/messages.json | 8 ++++++++ js/mzta-utils.js | 4 ++-- options/mzta-options-default.js | 2 ++ pages/addtags/mzta-add-tags.css | 11 ++++++++++- pages/addtags/mzta-add-tags.html | 19 +++++++++++++++++++ pages/addtags/mzta-add-tags.js | 3 ++- 6 files changed, 43 insertions(+), 4 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 48cd1b80..480e90cf 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1151,6 +1151,14 @@ "message": "If checked, the AI will only add tags to emails received in the inbox folder.", "description": "" }, + "prefs_OptionText_add_tags_use_specific_integration": { + "message": "Use specific Model and API", + "description": "" + }, + "prefs_OptionText_add_tags_use_specific_integration_Info": { + "message": "If checked, the Model and API specified below will be used for adding tags to emails, regardless the one choosen in the ThunderAI options page.", + "description": "" + }, "placeholder_thunderai_def_sign": { "message": "Default signature as defined in ThunderAI options.", "description": "" diff --git a/js/mzta-utils.js b/js/mzta-utils.js index 4f55343c..f0d428f1 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -364,7 +364,7 @@ export function generateCallID(length = 10) { return result; } -export function populateConnectionTypeOptions(selectId) { +export function populateConnectionTypeOptions(selectId, no_chatgpt_web = false) { const selectEl = document.getElementById(selectId); if (!selectEl) return; @@ -381,7 +381,7 @@ export function populateConnectionTypeOptions(selectId) { selectEl.innerHTML = ''; - for (const opt of options) { + for (const opt of options.filter(o => !(no_chatgpt_web && o.value === 'chatgpt_web'))) { const optionEl = document.createElement('option'); optionEl.value = opt.value; optionEl.textContent = browser.i18n.getMessage(opt.msgKey) || opt.msgKey; diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js index e1aeb908..96ef973b 100644 --- a/options/mzta-options-default.js +++ b/options/mzta-options-default.js @@ -66,6 +66,8 @@ export const prefs_default = { add_tags_auto_uselist_list: '', add_tags_context_menu: true, add_tags_enabled_accounts: [], + add_tags_use_specific_integration: false, + add_tags_connection_type: '', get_calendar_event: true, get_task: true, calendar_enforce_timezone: false, diff --git a/pages/addtags/mzta-add-tags.css b/pages/addtags/mzta-add-tags.css index 070f3bdf..ee43e00c 100644 --- a/pages/addtags/mzta-add-tags.css +++ b/pages/addtags/mzta-add-tags.css @@ -43,7 +43,12 @@ background-color: #e9ffdf; } -tr.add_tags_auto_sub td{ +.specific_integration{ + background-color: #dfeaff; +} + +tr.add_tags_auto_sub td, +tr.specific_integration_sub td{ padding-left: 0.8em !important; } @@ -159,4 +164,8 @@ table#miczPrefs tr:last-child td { .add_tags_auto{ background-color: #415c35; } + + .specific_integration{ + background-color: #2E3A4F; + } } \ No newline at end of file diff --git a/pages/addtags/mzta-add-tags.html b/pages/addtags/mzta-add-tags.html index bf9d8c53..0f525f84 100644 --- a/pages/addtags/mzta-add-tags.html +++ b/pages/addtags/mzta-add-tags.html @@ -13,6 +13,25 @@
__MSG_AddTags_prompt_prefs_title__
+ + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + `; + + const template = document.createElement('template'); + template.innerHTML = tpl.trim(); + const frag = template.content; + + const parent = anchorTr.parentElement; + const nodes = Array.from(frag.childNodes); + let last = anchorTr; + nodes.forEach(node => { + if (node.nodeType === Node.ELEMENT_NODE) { + parent.insertBefore(node, last.nextSibling); + last = node; + } + }); + + // Bindings + const bindClick = (id, cb) => { const el = document.getElementById(id); if (el && typeof cb === 'function') el.addEventListener('click', cb); }; + const bindChange = (id, cb) => { const el = document.getElementById(id); if (el && typeof cb === 'function') el.addEventListener('change', cb); }; + const bindInput = (id, cb) => { const el = document.getElementById(id); if (el && typeof cb === 'function') el.addEventListener('input', cb); }; + + populateConnectionTypeOptions(selectId, no_chatgpt_web); + + let selectEl = document.getElementById(selectId); + + if (!selectEl) { + console.error('[ThuderAI | injectConnectionUI] Select not found after insertion.'); + } + + const bindPasswordToggle = (idBase) => { + const input = document.getElementById(idBase); + const toggler = document.getElementById(`toggle_\${idBase}`); + const icon = document.getElementById(`pwd-icon_\${idBase}`); + if (!input || !toggler) return; + toggler.addEventListener('click', () => { + input.type = input.type === 'password' ? 'text' : 'password'; + if (icon) icon.src = input.type === 'password' ? '/images/pwd-show.png' : '/images/pwd-hide.png'; + }); + }; + + bindPasswordToggle('chatgpt_api_key'); + bindPasswordToggle('google_gemini_api_key'); + bindPasswordToggle('openai_comp_api_key'); + bindPasswordToggle('anthropic_api_key'); + + // Live warnings and enable/disable logic + const applyLiveWarnings = () => { + // ChatGPT API + const chatgptKey = document.getElementById('chatgpt_api_key'); + const btnChatGPT = document.getElementById('btnUpdateChatGPTModels'); + const selChatGPT = document.getElementById('chatgpt_model'); + if (chatgptKey && btnChatGPT && selChatGPT) { + const empty = !chatgptKey.value; + chatgptKey.style.border = empty ? '2px solid red' : ''; + btnChatGPT.disabled = !!empty; + selChatGPT.disabled = !!empty; + if (!empty) { + selChatGPT.style.border = (!selChatGPT.value || selChatGPT.selectedIndex === -1) ? '2px solid red' : ''; + } else { + selChatGPT.style.border = ''; + } + } + + // Google Gemini API + const geminiKey = document.getElementById('google_gemini_api_key'); + const btnGemini = document.getElementById('btnUpdateGoogleGeminiModels'); + const selGemini = document.getElementById('google_gemini_model'); + if (geminiKey && btnGemini && selGemini) { + const empty = !geminiKey.value; + geminiKey.style.border = empty ? '2px solid red' : ''; + btnGemini.disabled = !!empty; + selGemini.disabled = !!empty; + if (!empty) { + selGemini.style.border = (!selGemini.value || selGemini.selectedIndex === -1) ? '2px solid red' : ''; + } else { + selGemini.style.border = ''; + } + } + + // Ollama API + const ollamaHost = document.getElementById('ollama_host'); + const btnOllama = document.getElementById('btnUpdateOllamaModels'); + const selOllama = document.getElementById('ollama_model'); + if (ollamaHost && btnOllama && selOllama) { + const empty = !ollamaHost.value; + ollamaHost.style.border = empty ? '2px solid red' : ''; + btnOllama.disabled = !!empty; + selOllama.disabled = !!empty; + if (!empty) { + selOllama.style.border = (!selOllama.value || selOllama.selectedIndex === -1) ? '2px solid red' : ''; + } else { + selOllama.style.border = ''; + } + } + + // OpenAI-Compatible API + const openaiCompHost = document.getElementById('openai_comp_host'); + const btnOpenAIComp = document.getElementById('btnUpdateOpenAICompModels'); + const selOpenAIComp = document.getElementById('openai_comp_model'); + if (openaiCompHost && btnOpenAIComp && selOpenAIComp) { + const empty = !openaiCompHost.value; + openaiCompHost.style.border = empty ? '2px solid red' : ''; + btnOpenAIComp.disabled = !!empty; + selOpenAIComp.disabled = !!empty; + if (!empty) { + selOpenAIComp.style.border = (!selOpenAIComp.value || selOpenAIComp.selectedIndex === -1) ? '2px solid red' : ''; + } else { + selOpenAIComp.style.border = ''; + } + } + + // Anthropic API + const anthropicKey = document.getElementById('anthropic_api_key'); + const btnAnthropic = document.getElementById('btnUpdateAnthropicModels'); + const selAnthropic = document.getElementById('anthropic_model'); + const anthropicVersion = document.getElementById('anthropic_version'); + if (anthropicKey && selAnthropic) { + const emptyKey = !anthropicKey.value; + anthropicKey.style.border = emptyKey ? '2px solid red' : ''; + if (btnAnthropic) btnAnthropic.disabled = !!emptyKey; + if (selAnthropic) selAnthropic.disabled = !!emptyKey; + if (!emptyKey && selAnthropic) { + selAnthropic.style.border = (!selAnthropic.value || selAnthropic.selectedIndex === -1) ? '2px solid red' : ''; + } else if (selAnthropic) { + selAnthropic.style.border = ''; + } + } + if (anthropicVersion) { + const emptyVer = !anthropicVersion.value; + anthropicVersion.style.border = emptyVer ? '2px solid red' : ''; + } + }; + + // Bind inputs to live warnings + bindInput('chatgpt_api_key', applyLiveWarnings); + bindInput('google_gemini_api_key', applyLiveWarnings); + bindInput('ollama_host', applyLiveWarnings); + bindInput('openai_comp_host', applyLiveWarnings); + bindInput('anthropic_api_key', applyLiveWarnings); + bindInput('anthropic_version', applyLiveWarnings); + + bindChange('chatgpt_model', applyLiveWarnings); + bindChange('google_gemini_model', applyLiveWarnings); + bindChange('ollama_model', applyLiveWarnings); + bindChange('openai_comp_model', applyLiveWarnings); + bindChange('anthropic_model', applyLiveWarnings); + + // Run once on init + applyLiveWarnings(); + + + // Bind button clicks to provided callbacks (page-specific logic stays outside) + // bindClick('btnChatGPTWeb_Tab', onOpenChatGPTWebTab); + // bindClick('btnUpdateChatGPTModels', onFetchChatGPTModels); + // bindClick('btnUpdateGoogleGeminiModels', onFetchGoogleGeminiModels); + // bindClick('btnUpdateOllamaModels', onFetchOllamaModels); + // bindClick('btnUpdateOpenAICompModels', onFetchOpenAICompModels); + // bindClick('btnOpenAICompForceModel', onOpenAICompForceModel); + // bindClick('btnOpenAICompClearModelsList', onOpenAICompClearModelsList); + // bindClick('btnUpdateAnthropicModels', onFetchAnthropicModels); + // bindClick('btnGiveAllUrlsPermission_ollama_api', onGiveAllUrlsPermissionOllama); + // bindClick('btnGiveAllUrlsPermission_openai_comp_api', onGiveAllUrlsPermissionOpenAIComp); + + selectEl.addEventListener("change", () => showConnectionOptions(selectEl)); + + showConnectionOptions(selectEl); + + return { + select: selectEl, + onTypeChange: (fn) => { onTypeChange = fn; fn(selectEl.value, { select: selectEl }); } + }; +} + + +function populateConnectionTypeOptions(selectId, no_chatgpt_web = false) { + const selectEl = document.getElementById(selectId); + if (!selectEl) return; + + const prevValue = selectEl.value; + + const options = [ + { value: 'chatgpt_web', msgKey: 'prefs_Connection_type_ChatGPT_Web' }, + { value: 'chatgpt_api', msgKey: 'prefs_Connection_type_ChatGPT_API' }, + { value: 'google_gemini_api', msgKey: 'prefs_Connection_type_Google_Gemini_API' }, + { value: 'anthropic_api', msgKey: 'prefs_Connection_type_Anthropic_API' }, + { value: 'ollama_api', msgKey: 'prefs_Connection_type_Ollama_API' }, + { value: 'openai_comp_api', msgKey: 'prefs_Connection_type_OpenAI_Comp_API' } + ]; + + selectEl.innerHTML = ''; + + for (const opt of options.filter(o => !(no_chatgpt_web && o.value === 'chatgpt_web'))) { + const optionEl = document.createElement('option'); + optionEl.value = opt.value; + optionEl.textContent = browser.i18n.getMessage(opt.msgKey) || opt.msgKey; + selectEl.appendChild(optionEl); + } + + if (options.some(o => o.value === prevValue)) { + selectEl.value = prevValue; + } +} + + +export function showConnectionOptions(conntype_select) { + let chatgpt_web_display = 'table-row'; + let chatgpt_api_display = 'none'; + let ollama_api_display = 'none'; + let openai_comp_api_display = 'none'; + let google_gemini_api_display = 'none'; + let anthropic_api_display = 'none'; + let parent = conntype_select.parentElement.parentElement.parentElement; + parent.classList.toggle("conntype_chatgpt_web", (conntype_select.value === "chatgpt_web")); + parent.classList.toggle("conntype_chatgpt_api", (conntype_select.value === "chatgpt_api")); + parent.classList.toggle("conntype_ollama_api", (conntype_select.value === "ollama_api")); + parent.classList.toggle("conntype_openai_comp_api", (conntype_select.value === "openai_comp_api")); + parent.classList.toggle("conntype_google_gemini_api", (conntype_select.value === "google_gemini_api")); + parent.classList.toggle("conntype_anthropic_api", (conntype_select.value === "anthropic_api")); + if (conntype_select.value === "chatgpt_web") { + chatgpt_web_display = 'table-row'; + }else{ + chatgpt_web_display = 'none'; + } + if (conntype_select.value === "chatgpt_api") { + chatgpt_api_display = 'table-row'; + }else{ + chatgpt_api_display = 'none'; + } + if (conntype_select.value === "ollama_api") { + ollama_api_display = 'table-row'; + }else{ + ollama_api_display = 'none'; + } + if (conntype_select.value === "openai_comp_api") { + openai_comp_api_display = 'table-row'; + }else{ + openai_comp_api_display = 'none'; + } + if (conntype_select.value === "google_gemini_api") { + google_gemini_api_display = 'table-row'; + }else{ + google_gemini_api_display = 'none'; + } + if (conntype_select.value === "anthropic_api") { + anthropic_api_display = 'table-row'; + }else{ + anthropic_api_display = 'none'; + } + document.querySelectorAll(".conntype_chatgpt_web").forEach(element => { + element.style.display = chatgpt_web_display; + }); + document.querySelectorAll(".conntype_chatgpt_api").forEach(element => { + element.style.display = chatgpt_api_display; + }); + document.querySelectorAll(".conntype_ollama_api").forEach(element => { + element.style.display = ollama_api_display; + }); + document.querySelectorAll(".conntype_openai_comp_api").forEach(element => { + element.style.display = openai_comp_api_display; + }); + document.querySelectorAll(".conntype_google_gemini_api").forEach(element => { + element.style.display = google_gemini_api_display; + }); + document.querySelectorAll(".conntype_anthropic_api").forEach(element => { + element.style.display = anthropic_api_display; + }); + if (varConnectionUI.permission_all_urls) { + document.getElementById('openai_comp_api_cors_warning').style.display = 'none'; + document.getElementById('ollama_api_cors_warning').style.display = 'none'; + } +} \ No newline at end of file diff --git a/pages/addtags/mzta-add-tags.html b/pages/addtags/mzta-add-tags.html index 0f525f84..298cf42a 100644 --- a/pages/addtags/mzta-add-tags.html +++ b/pages/addtags/mzta-add-tags.html @@ -4,6 +4,7 @@ ThunderAI - __MSG_AddTags_PageTitle__ + @@ -23,15 +24,7 @@ - - - - + + - + @@ -67,7 +67,7 @@ export async function injectConnectionUI({ - + - + - + - + @@ -119,13 +119,13 @@ export async function injectConnectionUI({ - + - + @@ -138,7 +138,7 @@ export async function injectConnectionUI({ - + - + - + - + @@ -190,7 +190,7 @@ export async function injectConnectionUI({ - + - + - + - + - + - + @@ -259,7 +259,7 @@ export async function injectConnectionUI({ - + @@ -270,7 +270,7 @@ export async function injectConnectionUI({ - + @@ -281,7 +281,7 @@ export async function injectConnectionUI({ - + - + - + @@ -312,7 +312,7 @@ export async function injectConnectionUI({ - + - + - + @@ -352,7 +352,7 @@ export async function injectConnectionUI({ - + @@ -365,7 +365,7 @@ export async function injectConnectionUI({ - + - + - + @@ -199,7 +200,7 @@ export async function injectConnectionUI({ @@ -244,7 +245,7 @@ export async function injectConnectionUI({ @@ -337,7 +338,7 @@ export async function injectConnectionUI({ @@ -374,7 +375,7 @@ export async function injectConnectionUI({ @@ -430,32 +431,32 @@ export async function injectConnectionUI({ } conntype_select.addEventListener("change", () => showConnectionOptions(conntype_select)); - conntype_select.addEventListener("change", warn_ChatGPT_APIKeyEmpty); - conntype_select.addEventListener("change", warn_Ollama_HostEmpty); - conntype_select.addEventListener("change", warn_OpenAIComp_HostEmpty); - conntype_select.addEventListener("change", warn_GoogleGemini_APIKeyEmpty); - conntype_select.addEventListener("change", warn_Anthropic_APIKeyEmpty); - conntype_select.addEventListener("change", warn_Anthropic_VersionEmpty); + conntype_select.addEventListener("change", (ev) => warn_ChatGPT_APIKeyEmpty(modelId_prefix)); + conntype_select.addEventListener("change", (ev) => warn_Ollama_HostEmpty(modelId_prefix)); + conntype_select.addEventListener("change", (ev) => warn_OpenAIComp_HostEmpty(modelId_prefix)); + conntype_select.addEventListener("change", (ev) => warn_GoogleGemini_APIKeyEmpty(modelId_prefix)); + conntype_select.addEventListener("change", (ev) => warn_Anthropic_APIKeyEmpty(modelId_prefix)); + conntype_select.addEventListener("change", (ev) => warn_Anthropic_VersionEmpty(modelId_prefix)); document.getElementById("chatgpt_web_project").addEventListener("input", validateCustomData_ChatGPTWeb); document.getElementById("chatgpt_web_custom_gpt").addEventListener("input", validateCustomData_ChatGPTWeb); - document.getElementById("chatgpt_api_key").addEventListener("change", warn_ChatGPT_APIKeyEmpty); - 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("anthropic_api_key").addEventListener("change", warn_Anthropic_APIKeyEmpty); - document.getElementById("anthropic_version").addEventListener("change", warn_Anthropic_VersionEmpty); + document.getElementById("chatgpt_api_key").addEventListener("change", (ev) => warn_ChatGPT_APIKeyEmpty(modelId_prefix)); + document.getElementById("ollama_host").addEventListener("change", (ev) => warn_Ollama_HostEmpty(modelId_prefix)); + document.getElementById("openai_comp_host").addEventListener("change", (ev) => warn_OpenAIComp_HostEmpty(modelId_prefix)); + document.getElementById("google_gemini_api_key").addEventListener("change", (ev) => warn_GoogleGemini_APIKeyEmpty(modelId_prefix)); + document.getElementById("anthropic_api_key").addEventListener("change", (ev) => warn_Anthropic_APIKeyEmpty(modelId_prefix)); + document.getElementById("anthropic_version").addEventListener("change", (ev) => warn_Anthropic_VersionEmpty(modelId_prefix)); document.getElementById("openai_comp_host").addEventListener("input", resetOpenAICompConfigs); document.getElementById("openai_comp_chat_name").addEventListener("input", resetOpenAICompConfigs); document.getElementById("openai_comp_use_v1").addEventListener("input", resetOpenAICompConfigs); showConnectionOptions(conntype_select); loadOpenAICompConfigs(); - warn_ChatGPT_APIKeyEmpty(); - warn_Ollama_HostEmpty(); - warn_OpenAIComp_HostEmpty(); - warn_GoogleGemini_APIKeyEmpty(); - warn_Anthropic_APIKeyEmpty(); - warn_Anthropic_VersionEmpty(); + warn_ChatGPT_APIKeyEmpty(modelId_prefix); + warn_Ollama_HostEmpty(modelId_prefix); + warn_OpenAIComp_HostEmpty(modelId_prefix); + warn_GoogleGemini_APIKeyEmpty(modelId_prefix); + warn_Anthropic_APIKeyEmpty(modelId_prefix); + warn_Anthropic_VersionEmpty(modelId_prefix); const passwordField_chatgpt_api_key = document.getElementById('chatgpt_api_key'); const toggleIcon_chatgpt_api_key = document.getElementById('toggle_chatgpt_api_key'); @@ -532,7 +533,7 @@ export async function injectConnectionUI({ } document.getElementById('openai_comp_host').value = config.host || ''; // Clear all options from the select except the first (placeholder) one - const openaiCompModelSelect = document.getElementById('openai_comp_model'); + const openaiCompModelSelect = getModelEl('openai_comp_model', modelId_prefix); openaiCompModelSelect.value = ''; while (openaiCompModelSelect.options.length > 0) { openaiCompModelSelect.remove(0); @@ -541,7 +542,7 @@ export async function injectConnectionUI({ document.getElementById('openai_comp_chat_name').value = config.chat_name || ''; // Trigger change events if needed document.getElementById('openai_comp_host').dispatchEvent(new Event('change', { bubbles: true })); - document.getElementById('openai_comp_model').dispatchEvent(new Event('change', { bubbles: true })); + getModelEl('openai_comp_model', modelId_prefix).dispatchEvent(new Event('change', { bubbles: true })); document.getElementById('openai_comp_use_v1').dispatchEvent(new Event('change', { bubbles: true })); document.getElementById('openai_comp_chat_name').dispatchEvent(new Event('change', { bubbles: true })); } @@ -550,12 +551,12 @@ export async function injectConnectionUI({ let prefs = await browser.storage.sync.get({chatgpt_web_model: '', chatgpt_model: '', ollama_model: '', openai_comp_model: '', google_gemini_model: '', anthropic_model: '', anthropic_version: '', chatgpt_win_height: 0, chatgpt_win_width: 0 }); // OpenAI API ChatGPT model fetching - let select_chatgpt_model = document.getElementById('chatgpt_model'); + let select_chatgpt_model = getModelEl('chatgpt_model', modelId_prefix); const chatgpt_option = document.createElement('option'); chatgpt_option.value = prefs.chatgpt_model; chatgpt_option.text = prefs.chatgpt_model; select_chatgpt_model.appendChild(chatgpt_option); - select_chatgpt_model.addEventListener("change", warn_ChatGPT_APIKeyEmpty); + select_chatgpt_model.addEventListener("change", () => warn_ChatGPT_APIKeyEmpty(modelId_prefix)); document.getElementById('btnUpdateChatGPTModels').addEventListener('click', async () => { document.getElementById('chatgpt_model_fetch_loading').style.display = 'inline'; @@ -586,16 +587,16 @@ export async function injectConnectionUI({ document.getElementById('chatgpt_model_fetch_loading').style.display = 'none'; }); - warn_ChatGPT_APIKeyEmpty(); + warn_ChatGPT_APIKeyEmpty(modelId_prefix); }); // Google Gemini API model fetching - let select_google_gemini_model = document.getElementById('google_gemini_model'); + let select_google_gemini_model = getModelEl('google_gemini_model', modelId_prefix); const google_gemini_option = document.createElement('option'); google_gemini_option.value = prefs.google_gemini_model; google_gemini_option.text = prefs.google_gemini_model; select_google_gemini_model.appendChild(google_gemini_option); - select_google_gemini_model.addEventListener("change", warn_GoogleGemini_APIKeyEmpty); + select_google_gemini_model.addEventListener("change", () => warn_GoogleGemini_APIKeyEmpty(modelId_prefix)); document.getElementById('btnUpdateGoogleGeminiModels').addEventListener('click', async () => { document.getElementById('google_gemini_model_fetch_loading').style.display = 'inline'; @@ -626,16 +627,16 @@ export async function injectConnectionUI({ document.getElementById('google_gemini_model_fetch_loading').style.display = 'none'; }); - warn_GoogleGemini_APIKeyEmpty(); + warn_GoogleGemini_APIKeyEmpty(modelId_prefix); }); // Ollama API Model fetching - let select_ollama_model = document.getElementById('ollama_model'); + let select_ollama_model = getModelEl('ollama_model', modelId_prefix); const ollama_option = document.createElement('option'); ollama_option.value = prefs.ollama_model; ollama_option.text = prefs.ollama_model; select_ollama_model.appendChild(ollama_option); - select_ollama_model.addEventListener("change", warn_Ollama_HostEmpty); + select_ollama_model.addEventListener("change", () => warn_Ollama_HostEmpty(modelId_prefix)); document.getElementById('btnUpdateOllamaModels').addEventListener('click', async () => { document.getElementById('ollama_model_fetch_loading').style.display = 'inline'; @@ -683,16 +684,16 @@ export async function injectConnectionUI({ alert(browser.i18n.getMessage("Ollama_Models_Error_fetching")+": " + error.message); } - warn_Ollama_HostEmpty(); + warn_Ollama_HostEmpty(modelId_prefix); }); // OpenAI Comp API Model fetching - let select_openai_comp_model = document.getElementById('openai_comp_model'); + let select_openai_comp_model = getModelEl('openai_comp_model', modelId_prefix); const openai_comp_option = document.createElement('option'); openai_comp_option.value = prefs.openai_comp_model; openai_comp_option.text = prefs.openai_comp_model; select_openai_comp_model.appendChild(openai_comp_option); - select_openai_comp_model.addEventListener("change", warn_OpenAIComp_HostEmpty); + select_openai_comp_model.addEventListener("change", () => warn_OpenAIComp_HostEmpty(modelId_prefix)); document.getElementById('btnUpdateOpenAICompModels').addEventListener('click', async () => { document.getElementById('openai_comp_model_fetch_loading').style.display = 'inline'; @@ -723,17 +724,17 @@ export async function injectConnectionUI({ document.getElementById('openai_comp_model_fetch_loading').style.display = 'none'; }); - warn_OpenAIComp_HostEmpty(); + warn_OpenAIComp_HostEmpty(modelId_prefix); }); // Anthropic API model fetching - let select_anthropic_model = document.getElementById('anthropic_model'); + let select_anthropic_model = getModelEl('anthropic_model', modelId_prefix); const anthropic_option = document.createElement('option'); anthropic_option.value = prefs.anthropic_model; anthropic_option.text = prefs.anthropic_model; select_anthropic_model.appendChild(anthropic_option); - select_anthropic_model.addEventListener("change", warn_Anthropic_APIKeyEmpty); - select_anthropic_model.addEventListener("change", warn_Anthropic_VersionEmpty); + select_anthropic_model.addEventListener("change", () => warn_Anthropic_APIKeyEmpty(modelId_prefix)); + select_anthropic_model.addEventListener("change", () => warn_Anthropic_VersionEmpty(modelId_prefix)); document.getElementById('btnUpdateAnthropicModels').addEventListener('click', async () => { document.getElementById('anthropic_model_fetch_loading').style.display = 'inline'; @@ -767,13 +768,13 @@ export async function injectConnectionUI({ document.getElementById('anthropic_model_fetch_loading').style.display = 'none'; }); - warn_Anthropic_APIKeyEmpty(); + warn_Anthropic_APIKeyEmpty(modelId_prefix); }); document.getElementById('btnOpenAICompForceModel').addEventListener('click', () => { let modelName = prompt(browser.i18n.getMessage('OpenAIComp_force_model_ask')).trim(); if ((modelName !== null) && (modelName !== undefined) && (modelName !== '')) { - let select_openai_comp_model = document.getElementById('openai_comp_model'); + let select_openai_comp_model = getModelEl('openai_comp_model', modelId_prefix); let option = document.createElement('option'); option.value = modelName; option.text = modelName; @@ -787,7 +788,7 @@ export async function injectConnectionUI({ if (!confirm(browser.i18n.getMessage('OpenAIComp_ClearModelsList_Confirm'))) { return; } - let select_openai_comp_model = document.getElementById('openai_comp_model'); + let select_openai_comp_model = getModelEl('openai_comp_model', modelId_prefix); while (select_openai_comp_model.options.length > 0) { select_openai_comp_model.remove(0); } @@ -803,12 +804,12 @@ export async function injectConnectionUI({ permission_all_urls = await messenger.permissions.request({ origins: [""] }); }); - warn_ChatGPT_APIKeyEmpty(); - warn_Ollama_HostEmpty(); - warn_OpenAIComp_HostEmpty(); - warn_GoogleGemini_APIKeyEmpty(); - warn_Anthropic_APIKeyEmpty(); - warn_Anthropic_VersionEmpty(); + warn_ChatGPT_APIKeyEmpty(modelId_prefix); + warn_Ollama_HostEmpty(modelId_prefix); + warn_OpenAIComp_HostEmpty(modelId_prefix); + warn_GoogleGemini_APIKeyEmpty(modelId_prefix); + warn_Anthropic_APIKeyEmpty(modelId_prefix); + warn_Anthropic_VersionEmpty(modelId_prefix); return { select: conntype_select, @@ -819,13 +820,13 @@ export async function injectConnectionUI({ // From here there are exported functions -export function updateWarnings() { - warn_ChatGPT_APIKeyEmpty(); - warn_Ollama_HostEmpty(); - warn_OpenAIComp_HostEmpty(); - warn_GoogleGemini_APIKeyEmpty(); - warn_Anthropic_APIKeyEmpty(); - warn_Anthropic_VersionEmpty(); +export function updateWarnings(modelId_prefix = '') { + warn_ChatGPT_APIKeyEmpty(modelId_prefix); + warn_Ollama_HostEmpty(modelId_prefix); + warn_OpenAIComp_HostEmpty(modelId_prefix); + warn_GoogleGemini_APIKeyEmpty(modelId_prefix); + warn_Anthropic_APIKeyEmpty(modelId_prefix); + warn_Anthropic_VersionEmpty(modelId_prefix); } export function changeConnTypeRowColor(conntype_row, conntype_select) { @@ -903,6 +904,10 @@ export function showConnectionOptions(conntype_select) { // From here there are internal functions +function getModelEl(model, modelId_prefix) { + return document.getElementById((modelId_prefix ? modelId_prefix : '') + model); +} + function populateConnectionTypeOptions(selectId, no_chatgpt_web = false) { const conntype_select = document.getElementById(selectId); if (!conntype_select) return; @@ -932,10 +937,10 @@ function populateConnectionTypeOptions(selectId, no_chatgpt_web = false) { } } -function warn_ChatGPT_APIKeyEmpty() { +function warn_ChatGPT_APIKeyEmpty(modelId_prefix) { let apiKeyInput = document.getElementById('chatgpt_api_key'); let btnFetchChatGPTModels = document.getElementById('btnUpdateChatGPTModels'); - let modelChatGPT = document.getElementById('chatgpt_model'); + let modelChatGPT = getModelEl('chatgpt_model', modelId_prefix); if(apiKeyInput.value === ''){ apiKeyInput.style.border = '2px solid red'; btnFetchChatGPTModels.disabled = true; @@ -954,10 +959,10 @@ function warn_ChatGPT_APIKeyEmpty() { } } -function warn_GoogleGemini_APIKeyEmpty() { +function warn_GoogleGemini_APIKeyEmpty(modelId_prefix) { let apiKeyInput = document.getElementById('google_gemini_api_key'); let btnFetchGoogleGeminiModels = document.getElementById('btnUpdateGoogleGeminiModels'); - let modelGoogleGemini = document.getElementById('google_gemini_model'); + let modelGoogleGemini = getModelEl('google_gemini_model', modelId_prefix); if(apiKeyInput.value === ''){ apiKeyInput.style.border = '2px solid red'; btnFetchGoogleGeminiModels.disabled = true; @@ -976,10 +981,10 @@ function warn_GoogleGemini_APIKeyEmpty() { } } -function warn_Ollama_HostEmpty() { +function warn_Ollama_HostEmpty(modelId_prefix) { let hostInput = document.getElementById('ollama_host'); let btnFetchOllamaModels = document.getElementById('btnUpdateOllamaModels'); - let modelOllama = document.getElementById('ollama_model'); + let modelOllama = getModelEl('ollama_model', modelId_prefix); if(hostInput.value === ''){ hostInput.style.border = '2px solid red'; btnFetchOllamaModels.disabled = true; @@ -998,10 +1003,10 @@ function warn_Ollama_HostEmpty() { } } -function warn_OpenAIComp_HostEmpty() { +function warn_OpenAIComp_HostEmpty(modelId_prefix) { let hostInput = document.getElementById('openai_comp_host'); let btnUpdateOpenAICompModels = document.getElementById('btnUpdateOpenAICompModels'); - let modelOpenAIComp = document.getElementById('openai_comp_model'); + let modelOpenAIComp = getModelEl('openai_comp_model', modelId_prefix); if(hostInput.value === ''){ hostInput.style.border = '2px solid red'; btnUpdateOpenAICompModels.disabled = true; @@ -1020,10 +1025,10 @@ function warn_OpenAIComp_HostEmpty() { } } -function warn_Anthropic_APIKeyEmpty() { +function warn_Anthropic_APIKeyEmpty(modelId_prefix) { let apiKeyInput = document.getElementById('anthropic_api_key'); let btnFetchAnthropicModels = document.getElementById('btnUpdateAnthropicModels'); - let modelAnthropic = document.getElementById('anthropic_model'); + let modelAnthropic = getModelEl('anthropic_model', modelId_prefix); if(apiKeyInput.value === ''){ apiKeyInput.style.border = '2px solid red'; btnFetchAnthropicModels.disabled = true; @@ -1042,10 +1047,10 @@ function warn_Anthropic_APIKeyEmpty() { } } -function warn_Anthropic_VersionEmpty() { +function warn_Anthropic_VersionEmpty(modelId_prefix) { let versionInput = document.getElementById('anthropic_version'); let btnFetchAnthropicModels = document.getElementById('btnUpdateAnthropicModels'); - let modelAnthropic = document.getElementById('anthropic_model'); + let modelAnthropic = getModelEl('anthropic_model', modelId_prefix); if(versionInput.value === ''){ versionInput.style.border = '2px solid red'; btnFetchAnthropicModels.disabled = true; diff --git a/pages/addtags/mzta-add-tags.js b/pages/addtags/mzta-add-tags.js index e83316a2..7986e773 100644 --- a/pages/addtags/mzta-add-tags.js +++ b/pages/addtags/mzta-add-tags.js @@ -28,6 +28,7 @@ import { injectConnectionUI, updateWarnings, changeConnTypeRowColor } from "../_ let autocompleteSuggestions = []; let taLog = new taLogger("mzta-addtags-page",true); let conntype_select_id = 'add_tags_connection_type'; +let model_prefix = 'add_tags_'; document.addEventListener('DOMContentLoaded', async () => { try { @@ -35,6 +36,7 @@ document.addEventListener('DOMContentLoaded', async () => { afterTrId: 'connection_ui_anchor', tr_class: 'specific_integration_sub', selectId: conntype_select_id, + modelId_prefix: model_prefix, no_chatgpt_web: true, taLog: taLog }); @@ -218,7 +220,7 @@ document.addEventListener('DOMContentLoaded', async () => { checkboxes.forEach(checkbox => checkbox.checked = false); }); - updateWarnings(); + updateWarnings(model_prefix); }); From e39f48c06c1fee26998bbff622441f5b2d370f43 Mon Sep 17 00:00:00 2001 From: Mic Date: Wed, 3 Sep 2025 23:03:00 +0200 Subject: [PATCH 14/53] savePrompt method added to save a single prompt --- js/mzta-prompts.js | 58 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/js/mzta-prompts.js b/js/mzta-prompts.js index 9b9d567a..549d2ec2 100644 --- a/js/mzta-prompts.js +++ b/js/mzta-prompts.js @@ -436,6 +436,11 @@ async function getDefaultPrompts_withProps() { prompt.position_display = prefs._default_prompts_properties[prompt.id].position_display; prompt.enabled = prefs._default_prompts_properties[prompt.id].enabled; prompt.need_custom_text = prefs._default_prompts_properties[prompt.id].need_custom_text; + prompt.chatgpt_web_model = prefs._default_prompts_properties[prompt.id].chatgpt_web_model; + prompt.chatgpt_web_project = prefs._default_prompts_properties[prompt.id].chatgpt_web_project; + prompt.chatgpt_web_custom_gpt = prefs._default_prompts_properties[prompt.id].chatgpt_web_custom_gpt; + prompt.api_type = prefs._default_prompts_properties[prompt.id].api_type; + prompt.api_model = prefs._default_prompts_properties[prompt.id].api_model; }else{ prompt.position_display = pos; prompt.position_compose = pos; @@ -481,7 +486,17 @@ async function getCustomPrompts() { export async function setDefaultPromptsProperties(prompts) { let default_prompts_properties = {}; prompts.forEach((prompt) => { - default_prompts_properties[prompt.id] = {position_compose: prompt.position_compose, position_display: prompt.position_display, enabled: prompt.enabled, need_custom_text: prompt.need_custom_text}; + default_prompts_properties[prompt.id] = { + position_compose: prompt.position_compose, + position_display: prompt.position_display, + enabled: prompt.enabled, + need_custom_text: prompt.need_custom_text, + chatgpt_web_model: prompt.chatgpt_web_model, + chatgpt_web_project: prompt.chatgpt_web_project, + chatgpt_web_custom_gpt: prompt.chatgpt_web_custom_gpt, + api_type: prompt.api_type, + api_model: prompt.api_model + }; }); //console.log('>>>>>>>>>>>>>> default_prompts_properties: ' + JSON.stringify(default_prompts_properties)); await browser.storage.local.set({_default_prompts_properties: default_prompts_properties}); @@ -526,4 +541,43 @@ export async function setSpecialPrompts(prompts) { export async function getSpamFilterPrompt(){ return (await getSpecialPrompts()).find(prompt => prompt.id == 'prompt_spamfilter'); -} \ No newline at end of file +} + +export async function savePrompt(prompt) { + // console.log(">>>>>>>>>>>>> savePrompt prompt: " + JSON.stringify(prompt)); + if (prompt.id === undefined) { + throw new Error("Invalid prompt: " + JSON.stringify(prompt)); + } + // Special Prompt + if (prompt.is_special === "1") { + let specialPrompts = await getSpecialPrompts(); + let index = specialPrompts.findIndex(p => p.id === prompt.id); + if (index === -1) { + specialPrompts.push(prompt); + } else { + specialPrompts[index] = prompt; + } + await setSpecialPrompts(specialPrompts); + return; + } + // Custom Prompt + if (prompt.is_default === "0") { + let customPrompts = await getCustomPrompts(); + let index = customPrompts.findIndex(p => p.id === prompt.id); + if (index === -1) { + customPrompts.push(prompt); + } else { + customPrompts[index] = prompt; + } + await setCustomPrompts(customPrompts); + } else { // Default Prompt + let defaultPrompts = getDefaultPrompts_withProps(); + let index = defaultPrompts.findIndex(p => p.id === prompt.id); + if (index === -1) { + defaultPrompts.push(prompt); + } else { + defaultPrompts[index] = prompt; + } + await setDefaultPromptsProperties(defaultPrompts); + } +} From 0aa342084cedd1364201435beee3fff5edf63609 Mon Sep 17 00:00:00 2001 From: Mic Date: Wed, 3 Sep 2025 23:08:00 +0200 Subject: [PATCH 15/53] loadPrompt method added to load a single prompt --- js/mzta-prompts.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/js/mzta-prompts.js b/js/mzta-prompts.js index 549d2ec2..0b7f038f 100644 --- a/js/mzta-prompts.js +++ b/js/mzta-prompts.js @@ -341,7 +341,7 @@ const specialPrompts = [ ]; -export async function getPrompts(onlyEnabled = false, includeSpecial = []){ // includeSpecial is an array of active special prompts ids +export async function getPrompts(onlyEnabled = false, includeSpecial = [], allSpecial = false){ // includeSpecial is an array of active special prompts ids const _defaultPrompts = await getDefaultPrompts_withProps(); // console.log('>>>>>>>>>>>> getPrompts _defaultPrompts: ' + JSON.stringify(_defaultPrompts)); const customPrompts = await getCustomPrompts(); @@ -352,7 +352,7 @@ export async function getPrompts(onlyEnabled = false, includeSpecial = []){ // i output = output.filter(obj => obj.is_special != 1); // we do not want special prompts }else{ // console.log(">>>>>>>>>> getPrompts includeSpecial: " + JSON.stringify(includeSpecial)); - output = output.filter(obj => includeSpecial.includes(obj.id) || obj.is_special != 1); + output = output.filter(obj => includeSpecial.includes(obj.id) || obj.is_special != 1 || allSpecial); // output = output.filter(obj => { // const isIncluded = includeSpecial.includes(obj.id); // const isNotSpecial = obj.is_special != 1; @@ -543,6 +543,11 @@ export async function getSpamFilterPrompt(){ return (await getSpecialPrompts()).find(prompt => prompt.id == 'prompt_spamfilter'); } +export function loadPrompt(id) { + let allPrompts = getPrompts(false,[],true); + return allPrompts.find(prompt => prompt.id === id); +} + export async function savePrompt(prompt) { // console.log(">>>>>>>>>>>>> savePrompt prompt: " + JSON.stringify(prompt)); if (prompt.id === undefined) { From 0bd576eb8ff8f56b430ed5dd1963c9a7013f14fc Mon Sep 17 00:00:00 2001 From: Mic Date: Wed, 3 Sep 2025 23:13:00 +0200 Subject: [PATCH 16/53] allSpecial fixed --- js/mzta-prompts.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/js/mzta-prompts.js b/js/mzta-prompts.js index 0b7f038f..2cc334c4 100644 --- a/js/mzta-prompts.js +++ b/js/mzta-prompts.js @@ -348,7 +348,7 @@ export async function getPrompts(onlyEnabled = false, includeSpecial = [], allSp // console.log('>>>>>>>>>>>> getPrompts customPrompts: ' + JSON.stringify(customPrompts)); const specialPrompts = await getSpecialPrompts(); let output = specialPrompts.concat(_defaultPrompts).concat(customPrompts); - if(includeSpecial.length == 0){ + if((includeSpecial.length == 0) && !allSpecial){ output = output.filter(obj => obj.is_special != 1); // we do not want special prompts }else{ // console.log(">>>>>>>>>> getPrompts includeSpecial: " + JSON.stringify(includeSpecial)); @@ -543,8 +543,9 @@ export async function getSpamFilterPrompt(){ return (await getSpecialPrompts()).find(prompt => prompt.id == 'prompt_spamfilter'); } -export function loadPrompt(id) { - let allPrompts = getPrompts(false,[],true); +export async function loadPrompt(id) { + let allPrompts = await getPrompts(false,[],true); + // console.log(">>>>>>>>>>>> loadPrompt id: " + id + " - allPrompts: " + JSON.stringify(allPrompts)); return allPrompts.find(prompt => prompt.id === id); } From 72fb7647c34ca17cf7e334a2507b8578757a5d41 Mon Sep 17 00:00:00 2001 From: Mic Date: Wed, 3 Sep 2025 23:13:00 +0200 Subject: [PATCH 17/53] saving connection type and model per prompt. see #438 --- pages/_lib/connection-ui.js | 10 +++---- pages/addtags/mzta-add-tags.css | 23 ++++++++++++++ pages/addtags/mzta-add-tags.html | 1 + pages/addtags/mzta-add-tags.js | 51 ++++++++++++++++++++++++-------- 4 files changed, 68 insertions(+), 17 deletions(-) diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js index bce3bc02..36c0bd28 100644 --- a/pages/_lib/connection-ui.js +++ b/pages/_lib/connection-ui.js @@ -148,7 +148,7 @@ export async function injectConnectionUI({ @@ -200,7 +200,7 @@ export async function injectConnectionUI({ @@ -245,7 +245,7 @@ export async function injectConnectionUI({ @@ -338,7 +338,7 @@ export async function injectConnectionUI({ @@ -375,7 +375,7 @@ export async function injectConnectionUI({ diff --git a/pages/addtags/mzta-add-tags.css b/pages/addtags/mzta-add-tags.css index d012c5c1..a19ab48f 100644 --- a/pages/addtags/mzta-add-tags.css +++ b/pages/addtags/mzta-add-tags.css @@ -56,6 +56,29 @@ tr.specific_integration_sub td{ display: none; } +table { + border-collapse: separate; + border-spacing: 0; +} + +.group td { + border-top: none; + border-bottom: none; +} + +.specific_integration_sub td:first-child { + border-left: 10px solid #dfeaff; +} + +.specific_integration_sub td:last-child { + border-right: 10px solid #dfeaff; +} + +#connection_ui_end td{ + height: 6px; + background-color: #dfeaff; +} + .btn_div{ width: 100%; display: flex; diff --git a/pages/addtags/mzta-add-tags.html b/pages/addtags/mzta-add-tags.html index 298cf42a..5af0fbd9 100644 --- a/pages/addtags/mzta-add-tags.html +++ b/pages/addtags/mzta-add-tags.html @@ -25,6 +25,7 @@ + @@ -142,6 +143,7 @@ diff --git a/options/mzta-options.js b/options/mzta-options.js index 1924e3c4..aeb16f64 100644 --- a/options/mzta-options.js +++ b/options/mzta-options.js @@ -18,8 +18,21 @@ import { prefs_default } from './mzta-options-default.js'; import { taLogger } from '../js/mzta-logger.js'; -import { ChatGPTWeb_models, checkSparksPresence, isThunderbird128OrGreater, openTab, getChatGPTWebModelsList_HTML, isAPIKeyValue } from '../js/mzta-utils.js'; -import { injectConnectionUI, varConnectionUI, showConnectionOptions, updateWarnings } from '../pages/_lib/connection-ui.js'; +import { + ChatGPTWeb_models, + checkSparksPresence, + isThunderbird128OrGreater, + openTab, + getChatGPTWebModelsList_HTML, + isAPIKeyValue, + getConnectionType, +} from '../js/mzta-utils.js'; +import { + injectConnectionUI, + varConnectionUI, + showConnectionOptions, + updateWarnings +} from '../pages/_lib/connection-ui.js'; let taLog = new taLogger("mzta-options",true); let _isThunderbird128OrGreater = true; @@ -111,39 +124,36 @@ function disable_MaxPromptLength(){ maxPromptLength_tr.style.display = (maxPromptLength.disabled) ? 'none' : 'table-row'; } -function disable_AddTags(){ +function disable_AddTags(prefs_opt){ let add_tags = document.getElementById('add_tags'); let conntype_select = document.getElementById("connection_type"); - add_tags.disabled = (conntype_select.value === "chatgpt_web"); - add_tags.checked = add_tags.disabled ? false : add_tags.checked; + let add_tags_disabled = (getConnectionType(conntype_select.value, {api: prefs_opt.add_tags_use_specific_integration ? prefs_opt.add_tags_connection_type : ''}) === "chatgpt_web"); + console.log('>>>>>>>>>>>>> add_tags_disabled: ' + add_tags_disabled); + add_tags.checked = add_tags_disabled ? false : add_tags.checked; let add_tags_checked_original = add_tags.checked; if(!add_tags.checked){ let add_tags_info_btn = document.getElementById('btnManageTagsInfo'); add_tags_info_btn.disabled = 'disabled'; } - let add_tags_tr_elements = document.querySelectorAll('.add_tags_tr'); - add_tags_tr_elements.forEach(add_tags_tr => { - add_tags_tr.style.display = (add_tags.disabled) ? 'none' : 'table-row'; - }); + let add_tags_warn_API_needed = document.getElementById('add_tags_warn_API_needed'); + add_tags_warn_API_needed.style.display = (add_tags_disabled) ? 'inline-block' : 'none'; if(add_tags_checked_original != add_tags.checked){ browser.storage.sync.set({add_tags: add_tags.checked}); } } -function disable_SpamFilter(){ +function disable_SpamFilter(prefs_opt){ let spamfilter = document.getElementById('spamfilter'); let conntype_select = document.getElementById("connection_type"); - spamfilter.disabled = (conntype_select.value === "chatgpt_web"); + let spamfilter_disabled = (getConnectionType(conntype_select.value, {api: prefs_opt.spamfilter_use_specific_integration ? prefs_opt.spamfilter_connection_type : ''}) === "chatgpt_web");; let spamfilter_checked_original = spamfilter.checked; - spamfilter.checked = spamfilter.disabled ? false : spamfilter.checked; + spamfilter.checked = spamfilter_disabled ? false : spamfilter.checked; if(!spamfilter.checked){ let spamfilter_info_btn = document.getElementById('btnManageSpamFilterInfo'); spamfilter_info_btn.disabled = 'disabled'; } - let spamfilter_tr_elements = document.querySelectorAll('.spamfilter_tr'); - spamfilter_tr_elements.forEach(spamfilter_tr => { - spamfilter_tr.style.display = (spamfilter.disabled) ? 'none' : 'table-row'; - }); + let spamfilter_warn_API_needed = document.getElementById('spamfilter_warn_API_needed'); + spamfilter_warn_API_needed.style.display = (spamfilter_disabled) ? 'inline-block' : 'none'; if(spamfilter_checked_original != spamfilter.checked){ browser.storage.sync.set({spamfilter: spamfilter.checked}); } @@ -291,16 +301,23 @@ document.addEventListener('DOMContentLoaded', async () => { }); }); + let prefs_opt = await browser.storage.sync.get({ + add_tags_use_specific_integration: prefs_default.add_tags_use_specific_integration, + add_tags_connection_type: prefs_default.add_tags_connection_type, + spamfilter_use_specific_integration: prefs_default.spamfilter_use_specific_integration, + spamfilter_connection_type: prefs_default.spamfilter_connection_type, + }); + let conntype_select = document.getElementById("connection_type"); conntype_select.addEventListener("change", disable_MaxPromptLength); - conntype_select.addEventListener("change", disable_AddTags); - conntype_select.addEventListener("change", disable_SpamFilter); + conntype_select.addEventListener("change", () => disable_AddTags(prefs_opt)); + conntype_select.addEventListener("change", () => disable_SpamFilter(prefs_opt)); conntype_select.addEventListener("change", disable_GetCalendarEvent); showConnectionOptions(conntype_select); disable_MaxPromptLength(); - disable_AddTags(); - disable_SpamFilter(); + disable_AddTags(prefs_opt); + disable_SpamFilter(prefs_opt); disable_GetCalendarEvent(); document.getElementById('reset_max_prompt_length').addEventListener('click', resetMaxPromptLength); From 3a1e7dde3e8ce36753a11a993e7fb7823f8bbafe Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 4 Sep 2025 23:01:00 +0200 Subject: [PATCH 36/53] correctly hiding connection_ui_end --- pages/addtags/mzta-add-tags.css | 4 ++++ pages/addtags/mzta-add-tags.js | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/pages/addtags/mzta-add-tags.css b/pages/addtags/mzta-add-tags.css index a19ab48f..fa820b4e 100644 --- a/pages/addtags/mzta-add-tags.css +++ b/pages/addtags/mzta-add-tags.css @@ -79,6 +79,10 @@ table { background-color: #dfeaff; } +#connection_ui_end{ + display: none; +} + .btn_div{ width: 100%; display: flex; diff --git a/pages/addtags/mzta-add-tags.js b/pages/addtags/mzta-add-tags.js index 5874d5fd..e8476134 100644 --- a/pages/addtags/mzta-add-tags.js +++ b/pages/addtags/mzta-add-tags.js @@ -55,10 +55,16 @@ document.addEventListener('DOMContentLoaded', async () => { }); let conntype_el = document.getElementById(conntype_select_id); + let conntype_end_el = document.getElementById('connection_ui_end'); conntype_el.addEventListener('change', updatePromptAPIInfo); let add_tags_use_specific_integration_el = document.getElementById('add_tags_use_specific_integration'); + let prefs_add_tags = await browser.storage.sync.get({ add_tags_enabled_accounts: [], connection_type: 'chatgpt_web' }); + if(prefs_add_tags.connection_type == 'chatgpt_web'){ + add_tags_use_specific_integration_el.checked = true; + } + let conntype_row = document.getElementById(conntype_select_id + '_tr'); add_tags_use_specific_integration_el.addEventListener('change', (event) => { // console.log(">>>>>>>>>>>>> conntype_el.value: " + conntype_el.value); @@ -66,6 +72,7 @@ document.addEventListener('DOMContentLoaded', async () => { tr.style.display = event.target.checked && tr.classList.contains('conntype_' + conntype_el.value) ? 'table-row' : 'none'; }); conntype_el.style.display = event.target.checked ? 'table-row' : 'none'; + conntype_end_el.style.display = event.target.checked ? 'table-row' : 'none'; changeConnTypeRowColor(conntype_row, conntype_el); }); @@ -74,6 +81,7 @@ document.addEventListener('DOMContentLoaded', async () => { tr.style.display = add_tags_use_specific_integration_el.checked && tr.classList.contains('conntype_' + conntype_el.value) ? 'table-row' : 'none'; }); document.getElementById(conntype_select_id + '_tr').style.display = add_tags_use_specific_integration_el.checked ? 'table-row' : 'none'; + conntype_end_el.style.display = add_tags_use_specific_integration_el.checked ? 'table-row' : 'none'; changeConnTypeRowColor(conntype_row, conntype_el); let addtags_textarea = document.getElementById('addtags_prompt_text'); @@ -188,7 +196,6 @@ document.addEventListener('DOMContentLoaded', async () => { 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 => { From fb6815b664c18fcc6b9fd783cd78a7d535db018f Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 4 Sep 2025 23:01:00 +0200 Subject: [PATCH 37/53] disabling add_tags_use_specific_integration checkbox if chatgptweb is selected. see #438 --- pages/addtags/mzta-add-tags.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pages/addtags/mzta-add-tags.js b/pages/addtags/mzta-add-tags.js index e8476134..7b1e6b23 100644 --- a/pages/addtags/mzta-add-tags.js +++ b/pages/addtags/mzta-add-tags.js @@ -63,6 +63,8 @@ document.addEventListener('DOMContentLoaded', async () => { let prefs_add_tags = await browser.storage.sync.get({ add_tags_enabled_accounts: [], connection_type: 'chatgpt_web' }); if(prefs_add_tags.connection_type == 'chatgpt_web'){ add_tags_use_specific_integration_el.checked = true; + add_tags_use_specific_integration_el.dispatchEvent(new Event('change')); + add_tags_use_specific_integration_el.disabled = true; } let conntype_row = document.getElementById(conntype_select_id + '_tr'); From f8effcc8ce4765a16dad41f4a51d58efecaffb02 Mon Sep 17 00:00:00 2001 From: mic Date: Sat, 6 Sep 2025 00:43:25 +0200 Subject: [PATCH 38/53] color for dark theme fixed --- pages/addtags/mzta-add-tags.css | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pages/addtags/mzta-add-tags.css b/pages/addtags/mzta-add-tags.css index fa820b4e..58d50677 100644 --- a/pages/addtags/mzta-add-tags.css +++ b/pages/addtags/mzta-add-tags.css @@ -199,4 +199,16 @@ table#miczPrefs tr:last-child td { .specific_integration{ background-color: #2E3A4F; } + + .specific_integration_sub td:first-child { + border-left: 10px solid #2E3A4F; + } + + .specific_integration_sub td:last-child { + border-right: 10px solid #2E3A4F; + } + + #connection_ui_end td{ + background-color: #2E3A4F; + } } \ No newline at end of file From 30c9b3b1efd5733a3e9ca2c91cac3794c6d8c4a3 Mon Sep 17 00:00:00 2001 From: mic Date: Sat, 6 Sep 2025 00:43:54 +0200 Subject: [PATCH 39/53] add_tags_connection_type default value is no more empty. see #438 --- options/mzta-options-default.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js index 3250ed64..cc28ecd6 100644 --- a/options/mzta-options-default.js +++ b/options/mzta-options-default.js @@ -67,7 +67,7 @@ export const prefs_default = { add_tags_context_menu: true, add_tags_enabled_accounts: [], add_tags_use_specific_integration: false, - add_tags_connection_type: '', + add_tags_connection_type: 'chatgpt_api', add_tags_chatgpt_model: '', add_tags_ollama_model: '', add_tags_openai_comp_model: '', From 119e99df6a806b24bec3e4e72b5d862417879d9b Mon Sep 17 00:00:00 2001 From: mic Date: Sat, 6 Sep 2025 00:47:22 +0200 Subject: [PATCH 40/53] thunderai menu addtags is now using the prompt api config. see #438 --- js/mzta-menus.js | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/js/mzta-menus.js b/js/mzta-menus.js index 3d4d181e..3756a544 100644 --- a/js/mzta-menus.js +++ b/js/mzta-menus.js @@ -19,7 +19,19 @@ // Some original methods are derived from https://github.com/ali-raheem/Aify/blob/cfadf52f576b7be3720b5b73af7c8d3129c054da/plugin/html/actions.js import { getPrompts } from './mzta-prompts.js'; -import { getLanguageDisplayName, getMenuContextCompose, getMenuContextDisplay, i18nConditionalGet, getMailSubject, getTagsList, extractJsonObject, convertNewlinesToBr, cleanupNewlines, checkIfTagLabelExists } from './mzta-utils.js' +import { + getLanguageDisplayName, + getMenuContextCompose, + getMenuContextDisplay, + i18nConditionalGet, + getMailSubject, + getTagsList, + extractJsonObject, + convertNewlinesToBr, + cleanupNewlines, + checkIfTagLabelExists, + getConnectionType, + } from './mzta-utils.js' import { taPromptUtils } from './mzta-utils-prompt.js'; import { taLogger } from './mzta-logger.js'; import { placeholdersUtils } from './mzta-placeholders.js'; @@ -195,9 +207,12 @@ export class mzta_Menus { // TODO: use the current API, abort if using chatgpt web // COMMENTED TO DO TESTS // tags_current_email = "recipients, TEST, home, work, CAR, light"; + console.log(">>>>>>>>>>>>> curr_prompt: " + JSON.stringify(curr_prompt)); + console.log(">>>>>>>>>>>>>> prefs_at.connection_type: " + JSON.stringify(prefs_at.connection_type)); let cmd_addTags = new mzta_specialCommand({ prompt: fullPrompt, - llm: prefs_at.connection_type, + llm: getConnectionType(prefs_at.connection_type, curr_prompt), + custom_model: curr_prompt.model ? curr_prompt.model : '', do_debug: prefs_at.do_debug }); await cmd_addTags.initWorker(); From f973f8b8d0f508d03a0a55ef63734db806392183 Mon Sep 17 00:00:00 2001 From: Mic Date: Sun, 7 Sep 2025 19:50:00 +0200 Subject: [PATCH 41/53] prompt api now used also from the thunderai menu. see #438 --- js/mzta-menus.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/js/mzta-menus.js b/js/mzta-menus.js index 3756a544..711bbf22 100644 --- a/js/mzta-menus.js +++ b/js/mzta-menus.js @@ -195,8 +195,9 @@ export class mzta_Menus { let tags_current_email = []; let tags_current_email_final = []; let prefs_at = await browser.storage.sync.get({add_tags_maxnum: 3, connection_type: '', add_tags_force_lang: true, add_tags_auto_force_existing: false, default_chatgpt_lang: '', do_debug: false}); - if((prefs_at.connection_type === '')||(prefs_at.connection_type === null)||(prefs_at.connection_type === undefined)||(prefs_at.connection_type === 'chatgpt_web')){ - console.error("[ThunderAI | AddTags] Invalid connection type: " + prefs_at.connection_type); + let def_conntype = getConnectionType(prefs_at.connection_type, curr_prompt); + if((def_conntype === '')||(def_conntype === null)||(def_conntype === undefined)||(def_conntype === 'chatgpt_web')){ + console.error("[ThunderAI | AddTags] Invalid connection type: " + def_conntype); taWorkingStatus.stopWorking(); return {ok:'0'}; } @@ -204,14 +205,14 @@ export class mzta_Menus { this.logger.log("fullPrompt: " + fullPrompt); let create_new_tags = !prefs_at.add_tags_auto_force_existing; let all_tags_list = tags_full_list[1]; - // TODO: use the current API, abort if using chatgpt web // COMMENTED TO DO TESTS // tags_current_email = "recipients, TEST, home, work, CAR, light"; console.log(">>>>>>>>>>>>> curr_prompt: " + JSON.stringify(curr_prompt)); console.log(">>>>>>>>>>>>>> prefs_at.connection_type: " + JSON.stringify(prefs_at.connection_type)); + console.log(">>>>>>>>>>>>>> def_conntype: " + JSON.stringify(def_conntype)); let cmd_addTags = new mzta_specialCommand({ prompt: fullPrompt, - llm: getConnectionType(prefs_at.connection_type, curr_prompt), + llm: def_conntype, custom_model: curr_prompt.model ? curr_prompt.model : '', do_debug: prefs_at.do_debug }); From d4f7cf5e659004aedb583c90a2620128c223df2c Mon Sep 17 00:00:00 2001 From: Mic Date: Sun, 7 Sep 2025 19:55:00 +0200 Subject: [PATCH 42/53] clearPromptAPI method added --- js/mzta-prompts.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/js/mzta-prompts.js b/js/mzta-prompts.js index 2cc334c4..2d63fc09 100644 --- a/js/mzta-prompts.js +++ b/js/mzta-prompts.js @@ -587,3 +587,10 @@ export async function savePrompt(prompt) { await setDefaultPromptsProperties(defaultPrompts); } } + +export async function clearPromptAPI(id){ + let _prompt = await loadPrompt(id); + _prompt.api_type = ""; + _prompt.api_model = ""; + await savePrompt(_prompt); +} \ No newline at end of file From b8501f5974070fa5a6e77f9e1fe2f8ab26da1dca Mon Sep 17 00:00:00 2001 From: Mic Date: Sun, 7 Sep 2025 19:55:00 +0200 Subject: [PATCH 43/53] clearPromptAPI method prop names fixed --- js/mzta-prompts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/mzta-prompts.js b/js/mzta-prompts.js index 2d63fc09..3fa64d79 100644 --- a/js/mzta-prompts.js +++ b/js/mzta-prompts.js @@ -590,7 +590,7 @@ export async function savePrompt(prompt) { export async function clearPromptAPI(id){ let _prompt = await loadPrompt(id); - _prompt.api_type = ""; - _prompt.api_model = ""; + _prompt.api = ""; + _prompt.model = ""; await savePrompt(_prompt); } \ No newline at end of file From 8bac021c28395ad10cdb3e4500bbbbb9630bb787 Mon Sep 17 00:00:00 2001 From: Mic Date: Sun, 7 Sep 2025 19:55:00 +0200 Subject: [PATCH 44/53] saving and clearing prompt when checking and unchecking the cehckbox for specific api fon addtags. see #438 --- pages/addtags/mzta-add-tags.js | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/pages/addtags/mzta-add-tags.js b/pages/addtags/mzta-add-tags.js index 7b1e6b23..ccb7b0bc 100644 --- a/pages/addtags/mzta-add-tags.js +++ b/pages/addtags/mzta-add-tags.js @@ -18,12 +18,29 @@ import { prefs_default } from '../../options/mzta-options-default.js'; import { taLogger } from '../../js/mzta-logger.js'; -import { getSpecialPrompts, setSpecialPrompts, loadPrompt, savePrompt } from "../../js/mzta-prompts.js"; +import { + getSpecialPrompts, + setSpecialPrompts, + loadPrompt, + savePrompt, + clearPromptAPI +} 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, normalizeStringList, isAPIKeyValue } from "../../js/mzta-utils.js"; -import { injectConnectionUI, updateWarnings, changeConnTypeRowColor } from "../_lib/connection-ui.js"; +import { + addTags_getExclusionList, + addTags_setExclusionList +} from "../../js/mzta-addatags-exclusion-list.js"; +import { + getAccountsList, + normalizeStringList, + isAPIKeyValue +} from "../../js/mzta-utils.js"; +import { + injectConnectionUI, + updateWarnings, + changeConnTypeRowColor +} from "../_lib/connection-ui.js"; let autocompleteSuggestions = []; let taLog = new taLogger("mzta-addtags-page",true); @@ -76,6 +93,11 @@ document.addEventListener('DOMContentLoaded', async () => { conntype_el.style.display = event.target.checked ? 'table-row' : 'none'; conntype_end_el.style.display = event.target.checked ? 'table-row' : 'none'; changeConnTypeRowColor(conntype_row, conntype_el); + if(!event.target.checked){ + clearPromptAPI('prompt_add_tags'); + }else{ + updatePromptAPIInfo(); + } }); // console.log(">>>>>>>>>>>>> conntype_el.value: " + conntype_el.value); From 6cb2cffd27c611ae536d39338239480d81640bb8 Mon Sep 17 00:00:00 2001 From: Mic Date: Sun, 7 Sep 2025 20:00:00 +0200 Subject: [PATCH 45/53] console.log debug lines commented out --- pages/addtags/mzta-add-tags.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pages/addtags/mzta-add-tags.js b/pages/addtags/mzta-add-tags.js index ccb7b0bc..570dd5ec 100644 --- a/pages/addtags/mzta-add-tags.js +++ b/pages/addtags/mzta-add-tags.js @@ -294,12 +294,12 @@ async function updatePromptAPIInfo(){ let conntype = document.getElementById(conntype_select_id).value; let model_value = conntype.substring(0, conntype.length - 4) + '_model'; let model = document.getElementById(model_prefix + model_value).value; - console.log(">>>>>>>>>>> updatePromptAPIInfo: conntype: " + conntype + " - model: " + model + " - model_value: " + model_value); + // console.log(">>>>>>>>>>> updatePromptAPIInfo: conntype: " + conntype + " - model: " + model + " - model_value: " + model_value); let add_tags_prompt = await loadPrompt('prompt_add_tags'); - console.log(">>>>>>>>>>> updatePromptAPIInfo: BEFORE add_tags_prompt: " + JSON.stringify(add_tags_prompt)); + // console.log(">>>>>>>>>>> updatePromptAPIInfo: BEFORE add_tags_prompt: " + JSON.stringify(add_tags_prompt)); add_tags_prompt.api = conntype; add_tags_prompt.model = model; - console.log(">>>>>>>>>>> updatePromptAPIInfo: AFTER add_tags_prompt: " + JSON.stringify(add_tags_prompt)); + // console.log(">>>>>>>>>>> updatePromptAPIInfo: AFTER add_tags_prompt: " + JSON.stringify(add_tags_prompt)); await savePrompt(add_tags_prompt); } From 124b31c83093b6680026fc2e89fa013b485ca28f Mon Sep 17 00:00:00 2001 From: Mic Date: Sun, 7 Sep 2025 20:00:00 +0200 Subject: [PATCH 46/53] spamfilter settings page updated. see #438 --- _locales/en/messages.json | 14 +++- options/mzta-options-default.js | 4 +- pages/spamfilter/mzta-spamfilter.html | 15 +++- pages/spamfilter/mzta-spamfilter.js | 103 ++++++++++++++++++++++++-- 4 files changed, 125 insertions(+), 11 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index d4080c9c..3515a3b5 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1151,11 +1151,11 @@ "message": "If checked, the AI will only add tags to emails received in the inbox folder.", "description": "" }, - "prefs_OptionText_add_tags_use_specific_integration": { + "prefs_OptionText_use_specific_integration": { "message": "Use specific Model and API", "description": "" }, - "prefs_OptionText_add_tags_use_specific_integration_Info": { + "prefs_OptionText_use_specific_integration_Info": { "message": "If checked, the Model and API specified below will be used for adding tags to emails, regardless the one choosen in the ThunderAI options page.", "description": "" }, @@ -1211,6 +1211,14 @@ "message": "Spam Filter Options", "description": "" }, + "prefs_OptionText_spamfilter_use_specific_integration": { + "message": "Use specific Model and API", + "description": "" + }, + "prefs_OptionText_spamfilter_use_specific_integration_Info": { + "message": "If checked, the Model and API specified below will be used for the spam filter, regardless the one chosen in the ThunderAI options page.", + "description": "" + }, "prefs_OptionText_spamfilter_threshold": { "message": "Spam threshold", "description": "" @@ -1665,4 +1673,4 @@ "message": "To use this feature, you need an API integration rather than the ChatGPT Web Integration. You can define a specific API in the feature settings page by first checking the checkbox above and then clicking the button on the left.", "description": "" } -} \ No newline at end of file +} diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js index cc28ecd6..de164daa 100644 --- a/options/mzta-options-default.js +++ b/options/mzta-options-default.js @@ -82,10 +82,10 @@ export const prefs_default = { spamfilter_context_menu: true, spamfilter_enabled_accounts: [], spamfilter_use_specific_integration: false, - spamfilter_connection_type: '', + spamfilter_connection_type: 'chatgpt_api', spamfilter_chatgpt_model: '', spamfilter_ollama_model: '', spamfilter_openai_comp_model: '', spamfilter_google_gemini_model: '', spamfilter_anthropic_model: '', -} \ No newline at end of file +} diff --git a/pages/spamfilter/mzta-spamfilter.html b/pages/spamfilter/mzta-spamfilter.html index 9c7b4fd3..0a3d8a21 100644 --- a/pages/spamfilter/mzta-spamfilter.html +++ b/pages/spamfilter/mzta-spamfilter.html @@ -4,6 +4,7 @@ ThunderAI - __MSG_SpamFilter_PageTitle__ + @@ -13,6 +14,18 @@
__MSG_SpamFilter_prompt_prefs_title__
__MSG_prefs_OptionText_add_tags_use_specific_integration__ + + +
__MSG_prefs_Connection_type__ + + +
__MSG_prefs_OptionText_add_tags_maxnum__ diff --git a/pages/addtags/mzta-add-tags.js b/pages/addtags/mzta-add-tags.js index 7205bc28..9fc4113b 100644 --- a/pages/addtags/mzta-add-tags.js +++ b/pages/addtags/mzta-add-tags.js @@ -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, normalizeStringList } from "../../js/mzta-utils.js"; +import { getAccountsList, normalizeStringList, populateConnectionTypeOptions } from "../../js/mzta-utils.js"; let autocompleteSuggestions = []; let taLog = new taLogger("mzta-addtags-page",true); @@ -30,6 +30,7 @@ let taLog = new taLogger("mzta-addtags-page",true); document.addEventListener('DOMContentLoaded', async () => { i18n.updateDocument(); + populateConnectionTypeOptions('add_tags_connection_type', true); await restoreOptions(); document.querySelectorAll(".option-input").forEach(element => { From 0ec19550c0ec8224cc9ceabdb83e82560de97391 Mon Sep 17 00:00:00 2001 From: Mic Date: Tue, 2 Sep 2025 22:50:00 +0200 Subject: [PATCH 03/53] moved populateConnectionTypeOptions --- js/mzta-utils.js | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/js/mzta-utils.js b/js/mzta-utils.js index f0d428f1..44273acd 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -364,35 +364,6 @@ export function generateCallID(length = 10) { return result; } -export function populateConnectionTypeOptions(selectId, no_chatgpt_web = false) { - const selectEl = document.getElementById(selectId); - if (!selectEl) return; - - const prevValue = selectEl.value; - - const options = [ - { value: 'chatgpt_web', msgKey: 'prefs_Connection_type_ChatGPT_Web' }, - { value: 'chatgpt_api', msgKey: 'prefs_Connection_type_ChatGPT_API' }, - { value: 'google_gemini_api', msgKey: 'prefs_Connection_type_Google_Gemini_API' }, - { value: 'anthropic_api', msgKey: 'prefs_Connection_type_Anthropic_API' }, - { value: 'ollama_api', msgKey: 'prefs_Connection_type_Ollama_API' }, - { value: 'openai_comp_api', msgKey: 'prefs_Connection_type_OpenAI_Comp_API' } - ]; - - selectEl.innerHTML = ''; - - for (const opt of options.filter(o => !(no_chatgpt_web && o.value === 'chatgpt_web'))) { - const optionEl = document.createElement('option'); - optionEl.value = opt.value; - optionEl.textContent = browser.i18n.getMessage(opt.msgKey) || opt.msgKey; - selectEl.appendChild(optionEl); - } - - if (options.some(o => o.value === prevValue)) { - selectEl.value = prevValue; - } -} - export async function getTagsList(){ let messageTags = []; if(await isThunderbird128OrGreater()) { From c15fe8e85f1014b06c435795ddc9fc525b6df5fa Mon Sep 17 00:00:00 2001 From: Mic Date: Tue, 2 Sep 2025 22:50:00 +0200 Subject: [PATCH 04/53] isAPIKeyValue method added --- js/mzta-utils.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/mzta-utils.js b/js/mzta-utils.js index 44273acd..c8a989dc 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -586,6 +586,10 @@ export function extractJsonObject(inputString) { } } +export function isAPIKeyValue(id){ + return id=="chatgpt_api_key" || id=="openai_comp_api_key" || id=="google_gemini_api_key" || id=="anthropic_api_key"; +} + export async function checkSparksPresence() { try { let sparks_current = await browser.runtime.sendMessage('thunderai-sparks@micz.it',{action: "checkPresence"}); From ef78043bb944a19bfad12ca8b1937a98fc819700 Mon Sep 17 00:00:00 2001 From: Mic Date: Tue, 2 Sep 2025 22:50:00 +0200 Subject: [PATCH 05/53] using isAPIKeyValue method --- pages/get-calendar-event/mzta-get-calendar-event.js | 3 ++- pages/get-task/mzta-get-task.js | 3 ++- pages/spamfilter/mzta-spamfilter.js | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pages/get-calendar-event/mzta-get-calendar-event.js b/pages/get-calendar-event/mzta-get-calendar-event.js index 1ca4ddab..455e12d4 100644 --- a/pages/get-calendar-event/mzta-get-calendar-event.js +++ b/pages/get-calendar-event/mzta-get-calendar-event.js @@ -21,6 +21,7 @@ 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-get-calendar-event-page",true); @@ -110,7 +111,7 @@ function saveOptions(e) { 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])); + taLog.log("Options restoring " + element.id + " = " + (isAPIKeyValue(element.id) ? "****************" : result[element.id])); switch (element.type) { case 'checkbox': element.checked = result[element.id] || false; diff --git a/pages/get-task/mzta-get-task.js b/pages/get-task/mzta-get-task.js index 2dce1dcb..da7c0fee 100644 --- a/pages/get-task/mzta-get-task.js +++ b/pages/get-task/mzta-get-task.js @@ -21,6 +21,7 @@ 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-get-calendar-event-page",true); @@ -110,7 +111,7 @@ function saveOptions(e) { 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])); + taLog.log("Options restoring " + element.id + " = " + (isAPIKeyValue(element.id) ? "****************" : result[element.id])); switch (element.type) { case 'checkbox': element.checked = result[element.id] || false; diff --git a/pages/spamfilter/mzta-spamfilter.js b/pages/spamfilter/mzta-spamfilter.js index 7aa7f8e1..164465ab 100644 --- a/pages/spamfilter/mzta-spamfilter.js +++ b/pages/spamfilter/mzta-spamfilter.js @@ -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 { taSpamReport } from '../../js/mzta-spamreport.js'; -import { getAccountsList } from "../../js/mzta-utils.js"; +import { getAccountsList, isAPIKeyValue } from "../../js/mzta-utils.js"; let autocompleteSuggestions = []; let taLog = new taLogger("mzta-spamfilter-page",true); @@ -245,7 +245,7 @@ function saveOptions(e) { 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])); + taLog.log("Options restoring " + element.id + " = " + (isAPIKeyValue(element.id) ? "****************" : result[element.id])); switch (element.type) { case 'checkbox': element.checked = result[element.id] || false; From c8d0d430d3c8fa5f98b68b0495838968cfa7ed3b Mon Sep 17 00:00:00 2001 From: Mic Date: Tue, 2 Sep 2025 22:55:00 +0200 Subject: [PATCH 06/53] work in progress, moved html to connection-ui.js, starting to move the relative methods. see #438 --- options/mzta-options.css | 80 ---- options/mzta-options.html | 364 +---------------- options/mzta-options.js | 152 ++----- pages/_lib/connection-ui.css | 109 ++++++ pages/_lib/connection-ui.js | 652 +++++++++++++++++++++++++++++++ pages/addtags/mzta-add-tags.html | 11 +- pages/addtags/mzta-add-tags.js | 18 +- 7 files changed, 819 insertions(+), 567 deletions(-) create mode 100644 pages/_lib/connection-ui.css create mode 100644 pages/_lib/connection-ui.js diff --git a/options/mzta-options.css b/options/mzta-options.css index 280c5bcf..4cd0810b 100644 --- a/options/mzta-options.css +++ b/options/mzta-options.css @@ -104,40 +104,6 @@ div#miczTranslate{ font-size:smaller; } -tr.conntype_chatgpt_api, tr.conntype_chatgpt_api2{ - background-color: rgb(185, 220, 252); -} - -tr.conntype_chatgpt_web, tr.conntype_chatgpt_web2{ - background-color: rgb(255, 209, 183); -} - -tr.conntype_ollama_api, tr.conntype_ollama_api2{ - background-color: rgb(177, 238, 169); -} - -tr.conntype_openai_comp_api, tr.conntype_openai_comp_api2{ - background-color: rgb(213, 169, 238); -} - -tr.conntype_google_gemini_api, tr.conntype_google_gemini_api2{ - background-color: rgb(233, 238, 169); -} - -tr.conntype_anthropic_api, tr.conntype_anthropic_api2{ - background-color: rgb(255, 168, 204); -} - -#chatgpt_model_fetch_loading{ - display: none; - font-style: italic; -} - -#google_gemini_model_fetch_loading{ - display: none; - font-style: italic; -} - #no_sparks td{ text-align: center; padding: 1em !important; @@ -149,48 +115,6 @@ textarea.option-textarea{ height: 10em; } -.api_key-container { - position: relative; - width: 100%; -} - -.api_key-container input { - width: -moz-available; - margin-right: 25px; -} - -input[type="text"], input[type="password"]{ - border-radius: 4px; - padding: 2px; -} - -input.option-input[type="text"]{ - width: -moz-available; -} - -.api_key-container .toggle-icon { - position: absolute; - right: 0px; - top: 50%; - transform: translateY(-50%); - cursor: pointer; -} - -#ollama_model_fetch_loading{ - display: none; - font-style: italic; -} - -#openai_comp_model_fetch_loading{ - display: none; - font-style: italic; -} - -#anthropic_model_fetch_loading{ - display: none; - font-style: italic; -} - #owl_warning{ display: none; } @@ -235,10 +159,6 @@ input.option-input[type="text"]{ color: #FF6600; } -.conntype_chatgpt_web_option{ - cursor: pointer; -} - .btn_small{ font-size: 0.8em; } diff --git a/options/mzta-options.html b/options/mzta-options.html index a9c90554..9b1b9d58 100644 --- a/options/mzta-options.html +++ b/options/mzta-options.html @@ -3,6 +3,7 @@ + @@ -113,368 +114,7 @@
- - - -
- -
- -
- -
- -
- -
__MSG_OpenChatGPTTab_Info__ -

-

__MSG_OpenChatGPTTab_Info2__ -
-
- - -
-
- - - __MSG_Loading__
- -
- - - -
- - - -
-
- - -
-
- - - __MSG_Loading__
- -
- - - -
- -
- __MSG_remember_CORS__ [__MSG_more_info_string__] -

__MSG_CORS_alternative_1__ -
__MSG_CORS_alternative_2__ -

-
- - - __MSG_Loading__
- -
- -
- -
- -
- -
- __MSG_maybe_CORS_openai_comp__ [__MSG_more_info_string__] -

__MSG_CORS_alternative_1__ -
__MSG_CORS_alternative_2__ -

-
- -
-
- - -
-
- - __MSG_Loading__
- -
- -
-
- - -
-
- - - __MSG_Loading__
- -
- - - -
__MSG_prefs_OptionText_anthropic_max_tokens__ - -
__MSG_prefs_OptionText_max_prompt_length__ diff --git a/options/mzta-options.js b/options/mzta-options.js index 794a3d7a..ddc27be1 100644 --- a/options/mzta-options.js +++ b/options/mzta-options.js @@ -23,12 +23,12 @@ import { Ollama } from '../js/api/ollama.js'; import { OpenAIComp } from '../js/api/openai_comp.js' import { GoogleGemini } from '../js/api/google_gemini.js'; import { Anthropic } from '../js/api/anthropic.js'; -import { ChatGPTWeb_models, checkSparksPresence, isThunderbird128OrGreater, openTab, sanitizeChatGPTModelData, sanitizeChatGPTWebCustomData, validateCustomData_ChatGPTWeb, getChatGPTWebModelsList_HTML, populateConnectionTypeOptions } from '../js/mzta-utils.js'; +import { ChatGPTWeb_models, checkSparksPresence, isThunderbird128OrGreater, openTab, sanitizeChatGPTModelData, sanitizeChatGPTWebCustomData, validateCustomData_ChatGPTWeb, getChatGPTWebModelsList_HTML, isAPIKeyValue } from '../js/mzta-utils.js'; import { openAICompConfigs } from '../js/api/openai_comp_configs.js'; +import { injectConnectionUI, varConnectionUI, showConnectionOptions } from '../pages/_lib/connection-ui.js'; let taLog = new taLogger("mzta-options",true); let _isThunderbird128OrGreater = true; -let permission_all_urls = false; function saveOptions(e) { e.preventDefault(); @@ -70,7 +70,7 @@ function saveOptions(e) { 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" || element.id=="google_gemini_api_key" || element.id=="anthropic_api_key" ? "****************" : result[element.id])); + taLog.log("Options restoring " + element.id + " = " + (isAPIKeyValue(element.id) ? "****************" : result[element.id])); switch (element.type) { case 'checkbox': element.checked = result[element.id] || false; @@ -109,79 +109,6 @@ async function restoreOptions() { setCurrentChoice(getting); } -function showConnectionOptions() { - disable_MaxPromptLength(); - disable_AddTags(); - disable_SpamFilter(); - disable_GetCalendarEvent(); - let chatgpt_web_display = 'table-row'; - let chatgpt_api_display = 'none'; - let ollama_api_display = 'none'; - let openai_comp_api_display = 'none'; - let google_gemini_api_display = 'none'; - let anthropic_api_display = 'none'; - let conntype_select = document.getElementById("connection_type"); - let parent = conntype_select.parentElement.parentElement.parentElement; - parent.classList.toggle("conntype_chatgpt_web", (conntype_select.value === "chatgpt_web")); - parent.classList.toggle("conntype_chatgpt_api", (conntype_select.value === "chatgpt_api")); - parent.classList.toggle("conntype_ollama_api", (conntype_select.value === "ollama_api")); - parent.classList.toggle("conntype_openai_comp_api", (conntype_select.value === "openai_comp_api")); - parent.classList.toggle("conntype_google_gemini_api", (conntype_select.value === "google_gemini_api")); - parent.classList.toggle("conntype_anthropic_api", (conntype_select.value === "anthropic_api")); - if (conntype_select.value === "chatgpt_web") { - chatgpt_web_display = 'table-row'; - }else{ - chatgpt_web_display = 'none'; - } - if (conntype_select.value === "chatgpt_api") { - chatgpt_api_display = 'table-row'; - }else{ - chatgpt_api_display = 'none'; - } - if (conntype_select.value === "ollama_api") { - ollama_api_display = 'table-row'; - }else{ - ollama_api_display = 'none'; - } - if (conntype_select.value === "openai_comp_api") { - openai_comp_api_display = 'table-row'; - }else{ - openai_comp_api_display = 'none'; - } - if (conntype_select.value === "google_gemini_api") { - google_gemini_api_display = 'table-row'; - }else{ - google_gemini_api_display = 'none'; - } - if (conntype_select.value === "anthropic_api") { - anthropic_api_display = 'table-row'; - }else{ - anthropic_api_display = 'none'; - } - document.querySelectorAll(".conntype_chatgpt_web").forEach(element => { - element.style.display = chatgpt_web_display; - }); - document.querySelectorAll(".conntype_chatgpt_api").forEach(element => { - element.style.display = chatgpt_api_display; - }); - document.querySelectorAll(".conntype_ollama_api").forEach(element => { - element.style.display = ollama_api_display; - }); - document.querySelectorAll(".conntype_openai_comp_api").forEach(element => { - element.style.display = openai_comp_api_display; - }); - document.querySelectorAll(".conntype_google_gemini_api").forEach(element => { - element.style.display = google_gemini_api_display; - }); - document.querySelectorAll(".conntype_anthropic_api").forEach(element => { - element.style.display = anthropic_api_display; - }); - if (permission_all_urls) { - document.getElementById('openai_comp_api_cors_warning').style.display = 'none'; - document.getElementById('ollama_api_cors_warning').style.display = 'none'; - } -} - function warn_ChatGPT_APIKeyEmpty() { let apiKeyInput = document.getElementById('chatgpt_api_key'); let btnFetchChatGPTModels = document.getElementById('btnUpdateChatGPTModels'); @@ -405,10 +332,10 @@ function resetMaxPromptLength(){ } document.addEventListener('DOMContentLoaded', async () => { - populateConnectionTypeOptions('connection_type'); + injectConnectionUI({ afterTrId: 'connection_ui_anchor', selectId: 'connection_type' }); await restoreOptions(); - permission_all_urls = await messenger.permissions.contains({ origins: [""] }) + varConnectionUI.permission_all_urls = await messenger.permissions.contains({ origins: [""] }) _isThunderbird128OrGreater = await isThunderbird128OrGreater(); @@ -503,38 +430,38 @@ document.addEventListener('DOMContentLoaded', async () => { openTab('/pages/get-task/mzta-get-task.html'); }); - document.getElementById('btnOpenAICompForceModel').addEventListener('click', () => { - let modelName = prompt(browser.i18n.getMessage('OpenAIComp_force_model_ask')).trim(); - if ((modelName !== null) && (modelName !== undefined) && (modelName !== '')) { - let select_openai_comp_model = document.getElementById('openai_comp_model'); - let option = document.createElement('option'); - option.value = modelName; - option.text = modelName; - select_openai_comp_model.appendChild(option); - select_openai_comp_model.value = modelName; - select_openai_comp_model.dispatchEvent(new Event('change', { bubbles: true })); - } - }); + // document.getElementById('btnOpenAICompForceModel').addEventListener('click', () => { + // let modelName = prompt(browser.i18n.getMessage('OpenAIComp_force_model_ask')).trim(); + // if ((modelName !== null) && (modelName !== undefined) && (modelName !== '')) { + // let select_openai_comp_model = document.getElementById('openai_comp_model'); + // let option = document.createElement('option'); + // option.value = modelName; + // option.text = modelName; + // select_openai_comp_model.appendChild(option); + // select_openai_comp_model.value = modelName; + // select_openai_comp_model.dispatchEvent(new Event('change', { bubbles: true })); + // } + // }); - document.getElementById('btnOpenAICompClearModelsList').addEventListener('click', () => { - if (!confirm(browser.i18n.getMessage('OpenAIComp_ClearModelsList_Confirm'))) { - return; - } - let select_openai_comp_model = document.getElementById('openai_comp_model'); - while (select_openai_comp_model.options.length > 0) { - select_openai_comp_model.remove(0); - } - select_openai_comp_model.value = ''; - select_openai_comp_model.dispatchEvent(new Event('change', { bubbles: true })); - }); + // document.getElementById('btnOpenAICompClearModelsList').addEventListener('click', () => { + // if (!confirm(browser.i18n.getMessage('OpenAIComp_ClearModelsList_Confirm'))) { + // return; + // } + // let select_openai_comp_model = document.getElementById('openai_comp_model'); + // while (select_openai_comp_model.options.length > 0) { + // select_openai_comp_model.remove(0); + // } + // select_openai_comp_model.value = ''; + // select_openai_comp_model.dispatchEvent(new Event('change', { bubbles: true })); + // }); - document.getElementById('btnGiveAllUrlsPermission_ollama_api').addEventListener('click', async () => { - permission_all_urls = await messenger.permissions.request({ origins: [""] }); - }); + // document.getElementById('btnGiveAllUrlsPermission_ollama_api').addEventListener('click', async () => { + // permission_all_urls = await messenger.permissions.request({ origins: [""] }); + // }); - document.getElementById('btnGiveAllUrlsPermission_openai_comp_api').addEventListener('click', async () => { - permission_all_urls = await messenger.permissions.request({ origins: [""] }); - }); + // document.getElementById('btnGiveAllUrlsPermission_openai_comp_api').addEventListener('click', async () => { + // permission_all_urls = await messenger.permissions.request({ origins: [""] }); + // }); getChatGPTWebModelsList_HTML(ChatGPTWeb_models, 'chatgpt_web_models_list'); document.querySelectorAll(".conntype_chatgpt_web_option").forEach(element => { @@ -546,13 +473,13 @@ document.addEventListener('DOMContentLoaded', async () => { }); let conntype_select = document.getElementById("connection_type"); - conntype_select.addEventListener("change", showConnectionOptions); conntype_select.addEventListener("change", warn_ChatGPT_APIKeyEmpty); conntype_select.addEventListener("change", warn_Ollama_HostEmpty); conntype_select.addEventListener("change", warn_OpenAIComp_HostEmpty); conntype_select.addEventListener("change", warn_GoogleGemini_APIKeyEmpty); conntype_select.addEventListener("change", warn_Anthropic_APIKeyEmpty); conntype_select.addEventListener("change", warn_Anthropic_VersionEmpty); + conntype_select.addEventListener("change", disable_MaxPromptLength); conntype_select.addEventListener("change", disable_AddTags); conntype_select.addEventListener("change", disable_SpamFilter); conntype_select.addEventListener("change", disable_GetCalendarEvent); @@ -568,7 +495,12 @@ document.addEventListener('DOMContentLoaded', async () => { document.getElementById("openai_comp_chat_name").addEventListener("input", resetOpenAICompConfigs); document.getElementById("openai_comp_use_v1").addEventListener("input", resetOpenAICompConfigs); - + showConnectionOptions(conntype_select); + disable_MaxPromptLength(); + disable_AddTags(); + disable_SpamFilter(); + disable_GetCalendarEvent(); + let prefs = await browser.storage.sync.get({chatgpt_web_model: '', chatgpt_model: '', ollama_model: '', openai_comp_model: '', google_gemini_model: '', anthropic_model: '', anthropic_version: '', chatgpt_win_height: 0, chatgpt_win_width: 0 }); // OpenAI API ChatGPT model fetching @@ -793,14 +725,12 @@ document.addEventListener('DOMContentLoaded', async () => { warn_Anthropic_APIKeyEmpty(); }); - showConnectionOptions(); warn_ChatGPT_APIKeyEmpty(); warn_Ollama_HostEmpty(); warn_OpenAIComp_HostEmpty(); warn_GoogleGemini_APIKeyEmpty(); warn_Anthropic_APIKeyEmpty(); warn_Anthropic_VersionEmpty(); - disable_MaxPromptLength(); disable_AddTags(); disable_SpamFilter(); disable_GetCalendarEvent(); diff --git a/pages/_lib/connection-ui.css b/pages/_lib/connection-ui.css new file mode 100644 index 00000000..1a203629 --- /dev/null +++ b/pages/_lib/connection-ui.css @@ -0,0 +1,109 @@ +tr.conntype_chatgpt_api, tr.conntype_chatgpt_api2{ + background-color: rgb(185, 220, 252); +} + +tr.conntype_chatgpt_web, tr.conntype_chatgpt_web2{ + background-color: rgb(255, 209, 183); +} + +tr.conntype_ollama_api, tr.conntype_ollama_api2{ + background-color: rgb(177, 238, 169); +} + +tr.conntype_openai_comp_api, tr.conntype_openai_comp_api2{ + background-color: rgb(213, 169, 238); +} + +tr.conntype_google_gemini_api, tr.conntype_google_gemini_api2{ + background-color: rgb(233, 238, 169); +} + +tr.conntype_anthropic_api, tr.conntype_anthropic_api2{ + background-color: rgb(255, 168, 204); +} + +#chatgpt_model_fetch_loading{ + display: none; + font-style: italic; +} + +#google_gemini_model_fetch_loading{ + display: none; + font-style: italic; +} + +.api_key-container { + position: relative; + width: 100%; +} + +.api_key-container input { + width: -moz-available; + margin-right: 25px; +} + +input[type="text"], input[type="password"]{ + border-radius: 4px; + padding: 2px; +} + +input.option-input[type="text"]{ + width: -moz-available; +} + +.api_key-container .toggle-icon { + position: absolute; + right: 0px; + top: 50%; + transform: translateY(-50%); + cursor: pointer; +} + +#ollama_model_fetch_loading{ + display: none; + font-style: italic; +} + +#openai_comp_model_fetch_loading{ + display: none; + font-style: italic; +} + +#anthropic_model_fetch_loading{ + display: none; + font-style: italic; +} + +.conntype_chatgpt_web_option{ + cursor: pointer; +} + +@media (prefers-color-scheme: dark) { + tr.conntype_chatgpt_api, tr.conntype_chatgpt_api2{ + background-color: rgb(0, 0, 58); + } + + tr.conntype_chatgpt_web,tr.conntype_chatgpt_web2{ + background-color: rgb(39, 11, 0); + } + + tr.conntype_ollama_api, tr.conntype_ollama_api2{ + background-color: rgb(7, 58, 0); + } + + tr.conntype_openai_comp_api, tr.conntype_openai_comp_api2{ + background-color: rgb(89, 20, 129); + } + + tr.conntype_google_gemini_api, tr.conntype_google_gemini_api2{ + background-color: rgb(72, 77, 3); + } + + tr.conntype_anthropic_api, tr.conntype_anthropic_api2{ + background-color: rgb(83, 0, 35); + } + + .api_key-container .toggle-icon img { + filter: invert(1); + } +} \ No newline at end of file diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js new file mode 100644 index 00000000..517f7b8b --- /dev/null +++ b/pages/_lib/connection-ui.js @@ -0,0 +1,652 @@ +// connection-ui.js +// Public API: +// injectConnectionUI({ afterTrId, groupId?, selectId?, defaultType?, idSuffix?, onTypeChange? }) +// +// All variable names and comments are in English. +// It generates the connection type UI rows and handles basic show/hide behavior. + +export const varConnectionUI = { + permission_all_urls: false +} + +export function injectConnectionUI({ + afterTrId = '', + selectId = '', + no_chatgpt_web = false, + defaultType = '', + tr_class = '', + } = {}) { + + const anchorTr = document.getElementById(afterTrId); + if (!anchorTr) { + console.error(`[ThuderAI | injectConnectionUI] Can't find tr#${afterTrId}`); + return null; + } + + let tpl = ` +
+ + + +
+ +
+ +
+ +
+ +
+ +
__MSG_OpenChatGPTTab_Info__ +

+

__MSG_OpenChatGPTTab_Info2__ +
+
+ + +
+
+ + + __MSG_Loading__
+ +
+ + + +
+ + + +
+
+ + +
+
+ + + __MSG_Loading__
+ +
+ + + +
+ +
+ __MSG_remember_CORS__ [__MSG_more_info_string__] +

__MSG_CORS_alternative_1__ +
__MSG_CORS_alternative_2__ +

+
+ + + __MSG_Loading__
+ +
+ +
+ +
+ +
+ +
+ __MSG_maybe_CORS_openai_comp__ [__MSG_more_info_string__] +

__MSG_CORS_alternative_1__ +
__MSG_CORS_alternative_2__ +

+
+ +
+
+ + +
+
+ + __MSG_Loading__
+ +
+ +
+
+ + +
+
+ + + __MSG_Loading__
+ +
+ + + +
__MSG_prefs_OptionText_anthropic_max_tokens__ + +
__MSG_prefs_Connection_type__ - - -
__MSG_prefs_OptionText_add_tags_maxnum__ diff --git a/pages/addtags/mzta-add-tags.js b/pages/addtags/mzta-add-tags.js index 9fc4113b..e068b0df 100644 --- a/pages/addtags/mzta-add-tags.js +++ b/pages/addtags/mzta-add-tags.js @@ -22,15 +22,23 @@ 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, normalizeStringList, populateConnectionTypeOptions } from "../../js/mzta-utils.js"; +import { getAccountsList, normalizeStringList, isAPIKeyValue } from "../../js/mzta-utils.js"; +import { injectConnectionUI } from "../_lib/connection-ui.js"; let autocompleteSuggestions = []; let taLog = new taLogger("mzta-addtags-page",true); document.addEventListener('DOMContentLoaded', async () => { - + try { + injectConnectionUI({ + afterTrId: 'connection_ui_anchor', + selectId: 'add_tags_connection_type', + no_chatgpt_web: true + }); + } catch (e) { + console.error('Failed to inject connection UI (add-tags)', e); + } i18n.updateDocument(); - populateConnectionTypeOptions('add_tags_connection_type', true); await restoreOptions(); document.querySelectorAll(".option-input").forEach(element => { @@ -257,7 +265,7 @@ function saveOptions(e) { 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])); + taLog.log("Options restoring " + element.id + " = " + (isAPIKeyValue(element.id) ? "****************" : result[element.id])); switch (element.type) { case 'checkbox': element.checked = result[element.id] || false; @@ -296,4 +304,4 @@ async function restoreOptions() { let getting = await browser.storage.sync.get(prefs_default); setCurrentChoice(getting); -} \ No newline at end of file +} From d8082e22eae584bd13749b92c8bbba29ccbdf544 Mon Sep 17 00:00:00 2001 From: Mic Date: Wed, 3 Sep 2025 00:54:00 +0200 Subject: [PATCH 07/53] options and addtags pages are working. more tests needed and some details on the addtags page need some attention. see #438 --- options/mzta-options.css | 5 - options/mzta-options.js | 541 +---------------------- pages/_lib/connection-ui.css | 5 + pages/_lib/connection-ui.js | 768 +++++++++++++++++++++++++-------- pages/addtags/mzta-add-tags.js | 9 +- 5 files changed, 617 insertions(+), 711 deletions(-) diff --git a/options/mzta-options.css b/options/mzta-options.css index 4cd0810b..f2f53464 100644 --- a/options/mzta-options.css +++ b/options/mzta-options.css @@ -110,11 +110,6 @@ div#miczTranslate{ background: #bbf7f1; } -textarea.option-textarea{ - width: -moz-available; - height: 10em; -} - #owl_warning{ display: none; } diff --git a/options/mzta-options.js b/options/mzta-options.js index ddc27be1..1924e3c4 100644 --- a/options/mzta-options.js +++ b/options/mzta-options.js @@ -18,14 +18,8 @@ import { prefs_default } from './mzta-options-default.js'; import { taLogger } from '../js/mzta-logger.js'; -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 { Anthropic } from '../js/api/anthropic.js'; -import { ChatGPTWeb_models, checkSparksPresence, isThunderbird128OrGreater, openTab, sanitizeChatGPTModelData, sanitizeChatGPTWebCustomData, validateCustomData_ChatGPTWeb, getChatGPTWebModelsList_HTML, isAPIKeyValue } from '../js/mzta-utils.js'; -import { openAICompConfigs } from '../js/api/openai_comp_configs.js'; -import { injectConnectionUI, varConnectionUI, showConnectionOptions } from '../pages/_lib/connection-ui.js'; +import { ChatGPTWeb_models, checkSparksPresence, isThunderbird128OrGreater, openTab, getChatGPTWebModelsList_HTML, isAPIKeyValue } from '../js/mzta-utils.js'; +import { injectConnectionUI, varConnectionUI, showConnectionOptions, updateWarnings } from '../pages/_lib/connection-ui.js'; let taLog = new taLogger("mzta-options",true); let _isThunderbird128OrGreater = true; @@ -109,138 +103,6 @@ async function restoreOptions() { setCurrentChoice(getting); } -function warn_ChatGPT_APIKeyEmpty() { - let apiKeyInput = document.getElementById('chatgpt_api_key'); - let btnFetchChatGPTModels = document.getElementById('btnUpdateChatGPTModels'); - let modelChatGPT = document.getElementById('chatgpt_model'); - if(apiKeyInput.value === ''){ - apiKeyInput.style.border = '2px solid red'; - btnFetchChatGPTModels.disabled = true; - modelChatGPT.disabled = true; - modelChatGPT.selectedIndex = -1; - modelChatGPT.style.border = ''; - }else{ - apiKeyInput.style.border = ''; - btnFetchChatGPTModels.disabled = false; - modelChatGPT.disabled = false; - if((modelChatGPT.selectedIndex === -1)||(modelChatGPT.value === '')){ - modelChatGPT.style.border = '2px solid red'; - }else{ - modelChatGPT.style.border = ''; - } - } -} - -function warn_GoogleGemini_APIKeyEmpty() { - let apiKeyInput = document.getElementById('google_gemini_api_key'); - let btnFetchGoogleGeminiModels = document.getElementById('btnUpdateGoogleGeminiModels'); - let modelGoogleGemini = document.getElementById('google_gemini_model'); - if(apiKeyInput.value === ''){ - apiKeyInput.style.border = '2px solid red'; - btnFetchGoogleGeminiModels.disabled = true; - modelGoogleGemini.disabled = true; - modelGoogleGemini.selectedIndex = -1; - modelGoogleGemini.style.border = ''; - }else{ - apiKeyInput.style.border = ''; - btnFetchGoogleGeminiModels.disabled = false; - modelGoogleGemini.disabled = false; - if((modelGoogleGemini.selectedIndex === -1)||(modelGoogleGemini.value === '')){ - modelGoogleGemini.style.border = '2px solid red'; - }else{ - modelGoogleGemini.style.border = ''; - } - } -} - -function warn_Ollama_HostEmpty() { - let hostInput = document.getElementById('ollama_host'); - let btnFetchOllamaModels = document.getElementById('btnUpdateOllamaModels'); - let modelOllama = document.getElementById('ollama_model'); - if(hostInput.value === ''){ - hostInput.style.border = '2px solid red'; - btnFetchOllamaModels.disabled = true; - modelOllama.disabled = true; - modelOllama.selectedIndex = -1; - modelOllama.style.border = ''; - }else{ - hostInput.style.border = ''; - btnFetchOllamaModels.disabled = false; - modelOllama.disabled = false; - if((modelOllama.selectedIndex === -1)||(modelOllama.value === '')){ - modelOllama.style.border = '2px solid red'; - }else{ - modelOllama.style.border = ''; - } - } -} - -function warn_OpenAIComp_HostEmpty() { - let hostInput = document.getElementById('openai_comp_host'); - let btnUpdateOpenAICompModels = document.getElementById('btnUpdateOpenAICompModels'); - let modelOpenAIComp = document.getElementById('openai_comp_model'); - if(hostInput.value === ''){ - hostInput.style.border = '2px solid red'; - btnUpdateOpenAICompModels.disabled = true; - modelOpenAIComp.disabled = true; - modelOpenAIComp.selectedIndex = -1; - modelOpenAIComp.style.border = ''; - }else{ - hostInput.style.border = ''; - btnUpdateOpenAICompModels.disabled = false; - modelOpenAIComp.disabled = false; - if((modelOpenAIComp.selectedIndex === -1)||(modelOpenAIComp.value === '')){ - modelOpenAIComp.style.border = '2px solid red'; - }else{ - modelOpenAIComp.style.border = ''; - } - } -} - -function warn_Anthropic_APIKeyEmpty() { - let apiKeyInput = document.getElementById('anthropic_api_key'); - let btnFetchAnthropicModels = document.getElementById('btnUpdateAnthropicModels'); - let modelAnthropic = document.getElementById('anthropic_model'); - if(apiKeyInput.value === ''){ - apiKeyInput.style.border = '2px solid red'; - btnFetchAnthropicModels.disabled = true; - modelAnthropic.disabled = true; - modelAnthropic.selectedIndex = -1; - modelAnthropic.style.border = ''; - }else{ - apiKeyInput.style.border = ''; - btnFetchAnthropicModels.disabled = false; - modelAnthropic.disabled = false; - if((modelAnthropic.selectedIndex === -1)||(modelAnthropic.value === '')){ - modelAnthropic.style.border = '2px solid red'; - }else{ - modelAnthropic.style.border = ''; - } - } -} - -function warn_Anthropic_VersionEmpty() { - let versionInput = document.getElementById('anthropic_version'); - let btnFetchAnthropicModels = document.getElementById('btnUpdateAnthropicModels'); - let modelAnthropic = document.getElementById('anthropic_model'); - if(versionInput.value === ''){ - versionInput.style.border = '2px solid red'; - btnFetchAnthropicModels.disabled = true; - modelAnthropic.disabled = true; - modelAnthropic.selectedIndex = -1; - modelAnthropic.style.border = ''; - }else{ - versionInput.style.border = ''; - btnFetchAnthropicModels.disabled = false; - modelAnthropic.disabled = false; - if((modelAnthropic.selectedIndex === -1)||(modelAnthropic.value === '')){ - modelAnthropic.style.border = '2px solid red'; - }else{ - modelAnthropic.style.border = ''; - } - } -} - function disable_MaxPromptLength(){ let maxPromptLength = document.getElementById('max_prompt_length'); let conntype_select = document.getElementById("connection_type"); @@ -310,21 +172,6 @@ async function disable_GetCalendarEvent(){ wrong_sparks_text.style.display = (is_spark_present == 0) ? 'inline' : 'none'; } -function loadOpenAICompConfigs(){ - let select_openai_comp_model = document.getElementById('openai_comp_services_shortcut'); - openAICompConfigs.forEach(config => { - const option = document.createElement('option'); - option.value = config.id; - option.text = config.name; - select_openai_comp_model.appendChild(option); - }); -} - -function resetOpenAICompConfigs(){ - let select_openai_comp_model = document.getElementById('openai_comp_services_shortcut'); - select_openai_comp_model.value = 'custom'; -} - function resetMaxPromptLength(){ let maxPromptLength = document.getElementById('max_prompt_length'); maxPromptLength.value = prefs_default.max_prompt_length; @@ -332,7 +179,12 @@ function resetMaxPromptLength(){ } document.addEventListener('DOMContentLoaded', async () => { - injectConnectionUI({ afterTrId: 'connection_ui_anchor', selectId: 'connection_type' }); + await injectConnectionUI({ + afterTrId: 'connection_ui_anchor', + selectId: 'connection_type', + taLog: taLog + }); + await restoreOptions(); varConnectionUI.permission_all_urls = await messenger.permissions.contains({ origins: [""] }) @@ -430,39 +282,6 @@ document.addEventListener('DOMContentLoaded', async () => { openTab('/pages/get-task/mzta-get-task.html'); }); - // document.getElementById('btnOpenAICompForceModel').addEventListener('click', () => { - // let modelName = prompt(browser.i18n.getMessage('OpenAIComp_force_model_ask')).trim(); - // if ((modelName !== null) && (modelName !== undefined) && (modelName !== '')) { - // let select_openai_comp_model = document.getElementById('openai_comp_model'); - // let option = document.createElement('option'); - // option.value = modelName; - // option.text = modelName; - // select_openai_comp_model.appendChild(option); - // select_openai_comp_model.value = modelName; - // select_openai_comp_model.dispatchEvent(new Event('change', { bubbles: true })); - // } - // }); - - // document.getElementById('btnOpenAICompClearModelsList').addEventListener('click', () => { - // if (!confirm(browser.i18n.getMessage('OpenAIComp_ClearModelsList_Confirm'))) { - // return; - // } - // let select_openai_comp_model = document.getElementById('openai_comp_model'); - // while (select_openai_comp_model.options.length > 0) { - // select_openai_comp_model.remove(0); - // } - // select_openai_comp_model.value = ''; - // select_openai_comp_model.dispatchEvent(new Event('change', { bubbles: true })); - // }); - - // document.getElementById('btnGiveAllUrlsPermission_ollama_api').addEventListener('click', async () => { - // permission_all_urls = await messenger.permissions.request({ origins: [""] }); - // }); - - // document.getElementById('btnGiveAllUrlsPermission_openai_comp_api').addEventListener('click', async () => { - // permission_all_urls = await messenger.permissions.request({ origins: [""] }); - // }); - getChatGPTWebModelsList_HTML(ChatGPTWeb_models, 'chatgpt_web_models_list'); document.querySelectorAll(".conntype_chatgpt_web_option").forEach(element => { element.addEventListener("click", () => { @@ -473,332 +292,18 @@ document.addEventListener('DOMContentLoaded', async () => { }); let conntype_select = document.getElementById("connection_type"); - conntype_select.addEventListener("change", warn_ChatGPT_APIKeyEmpty); - conntype_select.addEventListener("change", warn_Ollama_HostEmpty); - conntype_select.addEventListener("change", warn_OpenAIComp_HostEmpty); - conntype_select.addEventListener("change", warn_GoogleGemini_APIKeyEmpty); - conntype_select.addEventListener("change", warn_Anthropic_APIKeyEmpty); - conntype_select.addEventListener("change", warn_Anthropic_VersionEmpty); conntype_select.addEventListener("change", disable_MaxPromptLength); conntype_select.addEventListener("change", disable_AddTags); conntype_select.addEventListener("change", disable_SpamFilter); conntype_select.addEventListener("change", disable_GetCalendarEvent); - document.getElementById("chatgpt_api_key").addEventListener("change", warn_ChatGPT_APIKeyEmpty); - 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); - document.getElementById("anthropic_api_key").addEventListener("change", warn_Anthropic_APIKeyEmpty); - document.getElementById("anthropic_version").addEventListener("change", warn_Anthropic_VersionEmpty); - document.getElementById("openai_comp_host").addEventListener("input", resetOpenAICompConfigs); - document.getElementById("openai_comp_chat_name").addEventListener("input", resetOpenAICompConfigs); - document.getElementById("openai_comp_use_v1").addEventListener("input", resetOpenAICompConfigs); showConnectionOptions(conntype_select); disable_MaxPromptLength(); disable_AddTags(); disable_SpamFilter(); disable_GetCalendarEvent(); - - let prefs = await browser.storage.sync.get({chatgpt_web_model: '', chatgpt_model: '', ollama_model: '', openai_comp_model: '', google_gemini_model: '', anthropic_model: '', anthropic_version: '', chatgpt_win_height: 0, chatgpt_win_width: 0 }); - - // OpenAI API ChatGPT model fetching - let select_chatgpt_model = document.getElementById('chatgpt_model'); - const chatgpt_option = document.createElement('option'); - chatgpt_option.value = prefs.chatgpt_model; - chatgpt_option.text = prefs.chatgpt_model; - select_chatgpt_model.appendChild(chatgpt_option); - select_chatgpt_model.addEventListener("change", warn_ChatGPT_APIKeyEmpty); - document.getElementById('btnUpdateChatGPTModels').addEventListener('click', async () => { - document.getElementById('chatgpt_model_fetch_loading').style.display = 'inline'; - let openai = new OpenAI(document.getElementById("chatgpt_api_key").value, '', true); - openai.fetchModels().then((data) => { - if(!data.ok){ - let errorDetail; - try { - errorDetail = JSON.parse(data.error); - errorDetail = errorDetail.error.message; - } catch (e) { - errorDetail = data.error; - } - document.getElementById('chatgpt_model_fetch_loading').style.display = 'none'; - console.error("[ThunderAI] " + browser.i18n.getMessage("ChatGPT_Models_Error_fetching")); - alert(browser.i18n.getMessage("ChatGPT_Models_Error_fetching")+": " + errorDetail); - return; - } - taLog.log("ChatGPT models: " + JSON.stringify(data)); - data.response.forEach(model => { - if (!Array.from(select_chatgpt_model.options).some(option => option.value === model.id)) { - const option = document.createElement('option'); - option.value = model.id; - option.text = model.id; - select_chatgpt_model.appendChild(option); - } - }); - document.getElementById('chatgpt_model_fetch_loading').style.display = 'none'; - }); - - warn_ChatGPT_APIKeyEmpty(); - }); - - // Google Gemini API model fetching - let select_google_gemini_model = document.getElementById('google_gemini_model'); - const google_gemini_option = document.createElement('option'); - google_gemini_option.value = prefs.google_gemini_model; - google_gemini_option.text = prefs.google_gemini_model; - select_google_gemini_model.appendChild(google_gemini_option); - select_google_gemini_model.addEventListener("change", warn_GoogleGemini_APIKeyEmpty); - - document.getElementById('btnUpdateGoogleGeminiModels').addEventListener('click', async () => { - document.getElementById('google_gemini_model_fetch_loading').style.display = 'inline'; - let google_gemini = new GoogleGemini(document.getElementById("google_gemini_api_key").value, '', true); - google_gemini.fetchModels().then((data) => { - if(!data.ok){ - let errorDetail; - try { - errorDetail = JSON.parse(data.error); - errorDetail = errorDetail.error.message; - } catch (e) { - errorDetail = data.error; - } - document.getElementById('google_gemini_model_fetch_loading').style.display = 'none'; - console.error("[ThunderAI] " + browser.i18n.getMessage("GoogleGemini_Models_Error_fetching")); - alert(browser.i18n.getMessage("GoogleGemini_Models_Error_fetching")+": " + errorDetail); - return; - } - taLog.log("GoogleGemini models: " + JSON.stringify(data)); - data.response.forEach(model => { - if (!Array.from(select_google_gemini_model.options).some(option => option.value === model.name.substring(model.name.lastIndexOf("/") + 1))) { - const option = document.createElement('option'); - option.value = model.name.substring(model.name.lastIndexOf("/") + 1); - option.text = model.displayName; - select_google_gemini_model.appendChild(option); - } - }); - document.getElementById('google_gemini_model_fetch_loading').style.display = 'none'; - }); - - warn_GoogleGemini_APIKeyEmpty(); - }); - - // Ollama API Model fetching - let select_ollama_model = document.getElementById('ollama_model'); - const ollama_option = document.createElement('option'); - ollama_option.value = prefs.ollama_model; - ollama_option.text = prefs.ollama_model; - select_ollama_model.appendChild(ollama_option); - select_ollama_model.addEventListener("change", warn_Ollama_HostEmpty); - - document.getElementById('btnUpdateOllamaModels').addEventListener('click', async () => { - document.getElementById('ollama_model_fetch_loading').style.display = 'inline'; - let ollama = new Ollama(document.getElementById("ollama_host").value, true); - try { - let data = await ollama.fetchModels(); - if(!data){ - document.getElementById('ollama_model_fetch_loading').style.display = 'none'; - console.error("[ThunderAI] " + browser.i18n.getMessage("Ollama_Models_Error_fetching")); - alert(browser.i18n.getMessage("Ollama_Models_Error_fetching")); - return; - } - if(!data.ok){ - let errorDetail; - try { - errorDetail = JSON.parse(data.error); - errorDetail = errorDetail.error.message; - } catch (e) { - errorDetail = data.error; - } - document.getElementById('ollama_model_fetch_loading').style.display = 'none'; - console.error("[ThunderAI] " + browser.i18n.getMessage("Ollama_Models_Error_fetching")); - alert(browser.i18n.getMessage("Ollama_Models_Error_fetching")+": " + errorDetail); - return; - } - if(data.response.models.length == 0){ - document.getElementById('ollama_model_fetch_loading').style.display = 'none'; - console.error("[ThunderAI] " + browser.i18n.getMessage("Ollama_Models_Error_fetching")); - alert(browser.i18n.getMessage("Ollama_Models_Error_fetching")+": " + browser.i18n.getMessage("API_Models_Error_NoModels")); - return; - } - taLog.log("Ollama models: " + JSON.stringify(data)); - data.response.models.forEach(model => { - if (!Array.from(select_ollama_model.options).some(option => option.value === model.model)) { - const option = document.createElement('option'); - option.value = model.model; - option.text = model.name + " (" + model.model + ")"; - select_ollama_model.appendChild(option); - } - }); - document.getElementById('ollama_model_fetch_loading').style.display = 'none'; - } catch (error) { - document.getElementById('ollama_model_fetch_loading').style.display = 'none'; - taLog.error(browser.i18n.getMessage("Ollama_Models_Error_fetching")); - alert(browser.i18n.getMessage("Ollama_Models_Error_fetching")+": " + error.message); - } - - warn_Ollama_HostEmpty(); - }); - - - // OpenAI Comp API Model fetching - let select_openai_comp_model = document.getElementById('openai_comp_model'); - const openai_comp_option = document.createElement('option'); - openai_comp_option.value = prefs.openai_comp_model; - openai_comp_option.text = prefs.openai_comp_model; - select_openai_comp_model.appendChild(openai_comp_option); - select_openai_comp_model.addEventListener("change", warn_OpenAIComp_HostEmpty); - - document.getElementById('btnUpdateOpenAICompModels').addEventListener('click', async () => { - document.getElementById('openai_comp_model_fetch_loading').style.display = 'inline'; - let openai_comp = new OpenAIComp(document.getElementById("openai_comp_host").value , null, document.getElementById("openai_comp_api_key").value, true, document.getElementById("openai_comp_use_v1").checked); - openai_comp.fetchModels().then((data) => { - if(!data.ok){ - let errorDetail; - try { - errorDetail = JSON.parse(data.error); - errorDetail = errorDetail.error.message; - } catch (e) { - errorDetail = data.error; - } - document.getElementById('openai_comp_model_fetch_loading').style.display = 'none'; - console.error("[ThunderAI] " + browser.i18n.getMessage("OpenAIComp_Models_Error_fetching")); - alert(browser.i18n.getMessage("OpenAIComp_Models_Error_fetching")+": " + errorDetail); - return; - } - taLog.log("OpenAIComp models: " + JSON.stringify(data)); - data.response.forEach(model => { - if (!Array.from(select_openai_comp_model.options).some(option => option.value === model.id)) { - const option = document.createElement('option'); - option.value = model.id; - option.text = model.id; - select_openai_comp_model.appendChild(option); - } - }); - document.getElementById('openai_comp_model_fetch_loading').style.display = 'none'; - }); - - warn_OpenAIComp_HostEmpty(); - }); - - // Anthropic API model fetching - let select_anthropic_model = document.getElementById('anthropic_model'); - const anthropic_option = document.createElement('option'); - anthropic_option.value = prefs.anthropic_model; - anthropic_option.text = prefs.anthropic_model; - select_anthropic_model.appendChild(anthropic_option); - select_anthropic_model.addEventListener("change", warn_Anthropic_APIKeyEmpty); - select_anthropic_model.addEventListener("change", warn_Anthropic_VersionEmpty); - - document.getElementById('btnUpdateAnthropicModels').addEventListener('click', async () => { - document.getElementById('anthropic_model_fetch_loading').style.display = 'inline'; - let anthropic = new Anthropic(document.getElementById("anthropic_api_key").value, document.getElementById("anthropic_version").value, ''); - anthropic.fetchModels().then((data) => { - if(!data.ok){ - let errorDetail; - try { - errorDetail = JSON.parse(data.error); - errorDetail = errorDetail.error.message; - } catch (e) { - errorDetail = data.error; - } - document.getElementById('anthropic_model_fetch_loading').style.display = 'none'; - console.error("[ThunderAI] " + browser.i18n.getMessage("Anthropic_Models_Error_fetching")); - alert(browser.i18n.getMessage("Anthropic_Models_Error_fetching")+": " + errorDetail); - return; - } - taLog.log("Anthropic models: " + JSON.stringify(data)); - data.response.forEach(model => { - const existingOption = Array.from(select_anthropic_model.options).find(option => option.value === model.id); - if (existingOption) { - existingOption.text = model.display_name + " (" + model.id + ")"; - } else { - const option = document.createElement('option'); - option.value = model.id; - option.text = model.display_name + " (" + model.id + ")"; - select_anthropic_model.appendChild(option); - } - }); - document.getElementById('anthropic_model_fetch_loading').style.display = 'none'; - }); - - warn_Anthropic_APIKeyEmpty(); - }); - - warn_ChatGPT_APIKeyEmpty(); - warn_Ollama_HostEmpty(); - warn_OpenAIComp_HostEmpty(); - warn_GoogleGemini_APIKeyEmpty(); - warn_Anthropic_APIKeyEmpty(); - warn_Anthropic_VersionEmpty(); - disable_AddTags(); - disable_SpamFilter(); - disable_GetCalendarEvent(); - - const passwordField_chatgpt_api_key = document.getElementById('chatgpt_api_key'); - const toggleIcon_chatgpt_api_key = document.getElementById('toggle_chatgpt_api_key'); - const icon_img_chatgpt_api_key = document.getElementById('pwd-icon_chatgpt_api_key'); - - toggleIcon_chatgpt_api_key.addEventListener('click', () => { - const type = passwordField_chatgpt_api_key.getAttribute('type') === 'password' ? 'text' : 'password'; - passwordField_chatgpt_api_key.setAttribute('type', type); - - icon_img_chatgpt_api_key.src = type === 'password' ? "../images/pwd-show.png" : "../images/pwd-hide.png"; - }); - - const passwordField_google_gemini_api_key = document.getElementById('google_gemini_api_key'); - const toggleIcon_google_gemini_api_key = document.getElementById('toggle_google_gemini_api_key'); - const icon_img_google_gemini_api_key = document.getElementById('pwd-icon_google_gemini_api_key'); - - toggleIcon_google_gemini_api_key.addEventListener('click', () => { - const type = passwordField_google_gemini_api_key.getAttribute('type') === 'password' ? 'text' : 'password'; - passwordField_google_gemini_api_key.setAttribute('type', type); - - icon_img_google_gemini_api_key.src = type === 'password' ? "../images/pwd-show.png" : "../images/pwd-hide.png"; - }); - - const passwordField_openai_comp_api_key = document.getElementById('openai_comp_api_key'); - const toggleIcon_openai_comp_api_key = document.getElementById('toggle_openai_comp_api_key'); - const icon_img_openai_comp_api_key = document.getElementById('pwd-icon_openai_comp_api_key'); - - toggleIcon_openai_comp_api_key.addEventListener('click', () => { - const type = passwordField_openai_comp_api_key.getAttribute('type') === 'password' ? 'text' : 'password'; - passwordField_openai_comp_api_key.setAttribute('type', type); - - icon_img_openai_comp_api_key.src = type === 'password' ? "../images/pwd-show.png" : "../images/pwd-hide.png"; - }); - - const passwordField_anthropic_api_key = document.getElementById('anthropic_api_key'); - const toggleIcon_anthropic_api_key = document.getElementById('toggle_anthropic_api_key'); - const icon_img_anthropic_api_key = document.getElementById('pwd-icon_anthropic_api_key'); - - toggleIcon_anthropic_api_key.addEventListener('click', () => { - const type = passwordField_anthropic_api_key.getAttribute('type') === 'password' ? 'text' : 'password'; - passwordField_anthropic_api_key.setAttribute('type', type); - - icon_img_anthropic_api_key.src = type === 'password' ? "../images/pwd-show.png" : "../images/pwd-hide.png"; - }); - - const btnChatGPTWeb_Tab = document.getElementById('btnChatGPTWeb_Tab'); - btnChatGPTWeb_Tab.addEventListener('click', async () => { - 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=' + sanitizeChatGPTModelData(prefs_mod.chatgpt_web_model); - } - 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 }); - }); + document.getElementById('reset_max_prompt_length').addEventListener('click', resetMaxPromptLength); browser.runtime.getPlatformInfo().then(info => { taLog.log("OS: " + info.os); @@ -807,32 +312,6 @@ document.addEventListener('DOMContentLoaded', async () => { } }); - loadOpenAICompConfigs(); - let select_openai_comp_services_shortcut = document.getElementById('openai_comp_services_shortcut'); - select_openai_comp_services_shortcut.addEventListener("change", () => { - let selectedOption = select_openai_comp_services_shortcut.options[select_openai_comp_services_shortcut.selectedIndex]; - const config = openAICompConfigs.find(cfg => cfg.id === selectedOption.value); - if (config) { - if (!confirm(browser.i18n.getMessage('OpenAIComp_Configs_ConfirmApply', config.name))) { - return; - } - document.getElementById('openai_comp_host').value = config.host || ''; - // Clear all options from the select except the first (placeholder) one - const openaiCompModelSelect = document.getElementById('openai_comp_model'); - openaiCompModelSelect.value = ''; - while (openaiCompModelSelect.options.length > 0) { - openaiCompModelSelect.remove(0); - } - document.getElementById('openai_comp_use_v1').checked = !!config.use_v1; - document.getElementById('openai_comp_chat_name').value = config.chat_name || ''; - // Trigger change events if needed - document.getElementById('openai_comp_host').dispatchEvent(new Event('change', { bubbles: true })); - document.getElementById('openai_comp_model').dispatchEvent(new Event('change', { bubbles: true })); - document.getElementById('openai_comp_use_v1').dispatchEvent(new Event('change', { bubbles: true })); - document.getElementById('openai_comp_chat_name').dispatchEvent(new Event('change', { bubbles: true })); - } - }); - - document.getElementById('reset_max_prompt_length').addEventListener('click', resetMaxPromptLength); + updateWarnings(); }, { once: true }); diff --git a/pages/_lib/connection-ui.css b/pages/_lib/connection-ui.css index 1a203629..15ffd18b 100644 --- a/pages/_lib/connection-ui.css +++ b/pages/_lib/connection-ui.css @@ -32,6 +32,11 @@ tr.conntype_anthropic_api, tr.conntype_anthropic_api2{ font-style: italic; } +textarea.option-textarea{ + width: -moz-available; + height: 10em; +} + .api_key-container { position: relative; width: 100%; diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js index 517f7b8b..fdfce511 100644 --- a/pages/_lib/connection-ui.js +++ b/pages/_lib/connection-ui.js @@ -1,20 +1,41 @@ -// connection-ui.js -// Public API: -// injectConnectionUI({ afterTrId, groupId?, selectId?, defaultType?, idSuffix?, onTypeChange? }) -// -// All variable names and comments are in English. -// It generates the connection type UI rows and handles basic show/hide behavior. +/* + * 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 { 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 { Anthropic } from '../../js/api/anthropic.js'; +import { validateCustomData_ChatGPTWeb, sanitizeChatGPTModelData, sanitizeChatGPTWebCustomData } from '../../js/mzta-utils.js'; +import { openAICompConfigs } from '../../js/api/openai_comp_configs.js'; export const varConnectionUI = { permission_all_urls: false } -export function injectConnectionUI({ +export async function injectConnectionUI({ afterTrId = '', selectId = '', no_chatgpt_web = false, defaultType = '', tr_class = '', + taLog = console } = {}) { const anchorTr = document.getElementById(afterTrId); @@ -396,193 +417,417 @@ export function injectConnectionUI({ }); // Bindings - const bindClick = (id, cb) => { const el = document.getElementById(id); if (el && typeof cb === 'function') el.addEventListener('click', cb); }; - const bindChange = (id, cb) => { const el = document.getElementById(id); if (el && typeof cb === 'function') el.addEventListener('change', cb); }; - const bindInput = (id, cb) => { const el = document.getElementById(id); if (el && typeof cb === 'function') el.addEventListener('input', cb); }; + // const bindClick = (id, cb) => { const el = document.getElementById(id); if (el && typeof cb === 'function') el.addEventListener('click', cb); }; + // const bindChange = (id, cb) => { const el = document.getElementById(id); if (el && typeof cb === 'function') el.addEventListener('change', cb); }; + // const bindInput = (id, cb) => { const el = document.getElementById(id); if (el && typeof cb === 'function') el.addEventListener('input', cb); }; populateConnectionTypeOptions(selectId, no_chatgpt_web); - let selectEl = document.getElementById(selectId); + let conntype_select = document.getElementById(selectId); - if (!selectEl) { + if (!conntype_select) { console.error('[ThuderAI | injectConnectionUI] Select not found after insertion.'); } - const bindPasswordToggle = (idBase) => { - const input = document.getElementById(idBase); - const toggler = document.getElementById(`toggle_\${idBase}`); - const icon = document.getElementById(`pwd-icon_\${idBase}`); - if (!input || !toggler) return; - toggler.addEventListener('click', () => { - input.type = input.type === 'password' ? 'text' : 'password'; - if (icon) icon.src = input.type === 'password' ? '/images/pwd-show.png' : '/images/pwd-hide.png'; - }); - }; + conntype_select.addEventListener("change", () => showConnectionOptions(conntype_select)); + conntype_select.addEventListener("change", warn_ChatGPT_APIKeyEmpty); + conntype_select.addEventListener("change", warn_Ollama_HostEmpty); + conntype_select.addEventListener("change", warn_OpenAIComp_HostEmpty); + conntype_select.addEventListener("change", warn_GoogleGemini_APIKeyEmpty); + conntype_select.addEventListener("change", warn_Anthropic_APIKeyEmpty); + conntype_select.addEventListener("change", warn_Anthropic_VersionEmpty); + document.getElementById("chatgpt_web_project").addEventListener("input", validateCustomData_ChatGPTWeb); + document.getElementById("chatgpt_web_custom_gpt").addEventListener("input", validateCustomData_ChatGPTWeb); + document.getElementById("chatgpt_api_key").addEventListener("change", warn_ChatGPT_APIKeyEmpty); + 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("anthropic_api_key").addEventListener("change", warn_Anthropic_APIKeyEmpty); + document.getElementById("anthropic_version").addEventListener("change", warn_Anthropic_VersionEmpty); + document.getElementById("openai_comp_host").addEventListener("input", resetOpenAICompConfigs); + document.getElementById("openai_comp_chat_name").addEventListener("input", resetOpenAICompConfigs); + document.getElementById("openai_comp_use_v1").addEventListener("input", resetOpenAICompConfigs); - bindPasswordToggle('chatgpt_api_key'); - bindPasswordToggle('google_gemini_api_key'); - bindPasswordToggle('openai_comp_api_key'); - bindPasswordToggle('anthropic_api_key'); + showConnectionOptions(conntype_select); + loadOpenAICompConfigs(); + warn_ChatGPT_APIKeyEmpty(); + warn_Ollama_HostEmpty(); + warn_OpenAIComp_HostEmpty(); + warn_GoogleGemini_APIKeyEmpty(); + warn_Anthropic_APIKeyEmpty(); + warn_Anthropic_VersionEmpty(); - // Live warnings and enable/disable logic - const applyLiveWarnings = () => { - // ChatGPT API - const chatgptKey = document.getElementById('chatgpt_api_key'); - const btnChatGPT = document.getElementById('btnUpdateChatGPTModels'); - const selChatGPT = document.getElementById('chatgpt_model'); - if (chatgptKey && btnChatGPT && selChatGPT) { - const empty = !chatgptKey.value; - chatgptKey.style.border = empty ? '2px solid red' : ''; - btnChatGPT.disabled = !!empty; - selChatGPT.disabled = !!empty; - if (!empty) { - selChatGPT.style.border = (!selChatGPT.value || selChatGPT.selectedIndex === -1) ? '2px solid red' : ''; - } else { - selChatGPT.style.border = ''; + const passwordField_chatgpt_api_key = document.getElementById('chatgpt_api_key'); + const toggleIcon_chatgpt_api_key = document.getElementById('toggle_chatgpt_api_key'); + const icon_img_chatgpt_api_key = document.getElementById('pwd-icon_chatgpt_api_key'); + + toggleIcon_chatgpt_api_key.addEventListener('click', () => { + const type = passwordField_chatgpt_api_key.getAttribute('type') === 'password' ? 'text' : 'password'; + passwordField_chatgpt_api_key.setAttribute('type', type); + + icon_img_chatgpt_api_key.src = type === 'password' ? "/images/pwd-show.png" : "/images/pwd-hide.png"; + }); + + const passwordField_google_gemini_api_key = document.getElementById('google_gemini_api_key'); + const toggleIcon_google_gemini_api_key = document.getElementById('toggle_google_gemini_api_key'); + const icon_img_google_gemini_api_key = document.getElementById('pwd-icon_google_gemini_api_key'); + + toggleIcon_google_gemini_api_key.addEventListener('click', () => { + const type = passwordField_google_gemini_api_key.getAttribute('type') === 'password' ? 'text' : 'password'; + passwordField_google_gemini_api_key.setAttribute('type', type); + + icon_img_google_gemini_api_key.src = type === 'password' ? "/images/pwd-show.png" : "/images/pwd-hide.png"; + }); + + const passwordField_openai_comp_api_key = document.getElementById('openai_comp_api_key'); + const toggleIcon_openai_comp_api_key = document.getElementById('toggle_openai_comp_api_key'); + const icon_img_openai_comp_api_key = document.getElementById('pwd-icon_openai_comp_api_key'); + + toggleIcon_openai_comp_api_key.addEventListener('click', () => { + const type = passwordField_openai_comp_api_key.getAttribute('type') === 'password' ? 'text' : 'password'; + passwordField_openai_comp_api_key.setAttribute('type', type); + + icon_img_openai_comp_api_key.src = type === 'password' ? "/images/pwd-show.png" : "/images/pwd-hide.png"; + }); + + const passwordField_anthropic_api_key = document.getElementById('anthropic_api_key'); + const toggleIcon_anthropic_api_key = document.getElementById('toggle_anthropic_api_key'); + const icon_img_anthropic_api_key = document.getElementById('pwd-icon_anthropic_api_key'); + + toggleIcon_anthropic_api_key.addEventListener('click', () => { + const type = passwordField_anthropic_api_key.getAttribute('type') === 'password' ? 'text' : 'password'; + passwordField_anthropic_api_key.setAttribute('type', type); + + icon_img_anthropic_api_key.src = type === 'password' ? "/images/pwd-show.png" : "/images/pwd-hide.png"; + }); + + const btnChatGPTWeb_Tab = document.getElementById('btnChatGPTWeb_Tab'); + btnChatGPTWeb_Tab.addEventListener('click', async () => { + 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=' + sanitizeChatGPTModelData(prefs_mod.chatgpt_web_model); + } + 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 }); + }); + + let select_openai_comp_services_shortcut = document.getElementById('openai_comp_services_shortcut'); + select_openai_comp_services_shortcut.addEventListener("change", () => { + let selectedOption = select_openai_comp_services_shortcut.options[select_openai_comp_services_shortcut.selectedIndex]; + const config = openAICompConfigs.find(cfg => cfg.id === selectedOption.value); + if (config) { + if (!confirm(browser.i18n.getMessage('OpenAIComp_Configs_ConfirmApply', config.name))) { + return; } - } - - // Google Gemini API - const geminiKey = document.getElementById('google_gemini_api_key'); - const btnGemini = document.getElementById('btnUpdateGoogleGeminiModels'); - const selGemini = document.getElementById('google_gemini_model'); - if (geminiKey && btnGemini && selGemini) { - const empty = !geminiKey.value; - geminiKey.style.border = empty ? '2px solid red' : ''; - btnGemini.disabled = !!empty; - selGemini.disabled = !!empty; - if (!empty) { - selGemini.style.border = (!selGemini.value || selGemini.selectedIndex === -1) ? '2px solid red' : ''; - } else { - selGemini.style.border = ''; + document.getElementById('openai_comp_host').value = config.host || ''; + // Clear all options from the select except the first (placeholder) one + const openaiCompModelSelect = document.getElementById('openai_comp_model'); + openaiCompModelSelect.value = ''; + while (openaiCompModelSelect.options.length > 0) { + openaiCompModelSelect.remove(0); } + document.getElementById('openai_comp_use_v1').checked = !!config.use_v1; + document.getElementById('openai_comp_chat_name').value = config.chat_name || ''; + // Trigger change events if needed + document.getElementById('openai_comp_host').dispatchEvent(new Event('change', { bubbles: true })); + document.getElementById('openai_comp_model').dispatchEvent(new Event('change', { bubbles: true })); + document.getElementById('openai_comp_use_v1').dispatchEvent(new Event('change', { bubbles: true })); + document.getElementById('openai_comp_chat_name').dispatchEvent(new Event('change', { bubbles: true })); } + }); - // Ollama API - const ollamaHost = document.getElementById('ollama_host'); - const btnOllama = document.getElementById('btnUpdateOllamaModels'); - const selOllama = document.getElementById('ollama_model'); - if (ollamaHost && btnOllama && selOllama) { - const empty = !ollamaHost.value; - ollamaHost.style.border = empty ? '2px solid red' : ''; - btnOllama.disabled = !!empty; - selOllama.disabled = !!empty; - if (!empty) { - selOllama.style.border = (!selOllama.value || selOllama.selectedIndex === -1) ? '2px solid red' : ''; - } else { - selOllama.style.border = ''; - } - } - - // OpenAI-Compatible API - const openaiCompHost = document.getElementById('openai_comp_host'); - const btnOpenAIComp = document.getElementById('btnUpdateOpenAICompModels'); - const selOpenAIComp = document.getElementById('openai_comp_model'); - if (openaiCompHost && btnOpenAIComp && selOpenAIComp) { - const empty = !openaiCompHost.value; - openaiCompHost.style.border = empty ? '2px solid red' : ''; - btnOpenAIComp.disabled = !!empty; - selOpenAIComp.disabled = !!empty; - if (!empty) { - selOpenAIComp.style.border = (!selOpenAIComp.value || selOpenAIComp.selectedIndex === -1) ? '2px solid red' : ''; - } else { - selOpenAIComp.style.border = ''; - } - } - - // Anthropic API - const anthropicKey = document.getElementById('anthropic_api_key'); - const btnAnthropic = document.getElementById('btnUpdateAnthropicModels'); - const selAnthropic = document.getElementById('anthropic_model'); - const anthropicVersion = document.getElementById('anthropic_version'); - if (anthropicKey && selAnthropic) { - const emptyKey = !anthropicKey.value; - anthropicKey.style.border = emptyKey ? '2px solid red' : ''; - if (btnAnthropic) btnAnthropic.disabled = !!emptyKey; - if (selAnthropic) selAnthropic.disabled = !!emptyKey; - if (!emptyKey && selAnthropic) { - selAnthropic.style.border = (!selAnthropic.value || selAnthropic.selectedIndex === -1) ? '2px solid red' : ''; - } else if (selAnthropic) { - selAnthropic.style.border = ''; - } - } - if (anthropicVersion) { - const emptyVer = !anthropicVersion.value; - anthropicVersion.style.border = emptyVer ? '2px solid red' : ''; - } - }; - - // Bind inputs to live warnings - bindInput('chatgpt_api_key', applyLiveWarnings); - bindInput('google_gemini_api_key', applyLiveWarnings); - bindInput('ollama_host', applyLiveWarnings); - bindInput('openai_comp_host', applyLiveWarnings); - bindInput('anthropic_api_key', applyLiveWarnings); - bindInput('anthropic_version', applyLiveWarnings); - - bindChange('chatgpt_model', applyLiveWarnings); - bindChange('google_gemini_model', applyLiveWarnings); - bindChange('ollama_model', applyLiveWarnings); - bindChange('openai_comp_model', applyLiveWarnings); - bindChange('anthropic_model', applyLiveWarnings); - - // Run once on init - applyLiveWarnings(); - - - // Bind button clicks to provided callbacks (page-specific logic stays outside) - // bindClick('btnChatGPTWeb_Tab', onOpenChatGPTWebTab); - // bindClick('btnUpdateChatGPTModels', onFetchChatGPTModels); - // bindClick('btnUpdateGoogleGeminiModels', onFetchGoogleGeminiModels); - // bindClick('btnUpdateOllamaModels', onFetchOllamaModels); - // bindClick('btnUpdateOpenAICompModels', onFetchOpenAICompModels); - // bindClick('btnOpenAICompForceModel', onOpenAICompForceModel); - // bindClick('btnOpenAICompClearModelsList', onOpenAICompClearModelsList); - // bindClick('btnUpdateAnthropicModels', onFetchAnthropicModels); - // bindClick('btnGiveAllUrlsPermission_ollama_api', onGiveAllUrlsPermissionOllama); - // bindClick('btnGiveAllUrlsPermission_openai_comp_api', onGiveAllUrlsPermissionOpenAIComp); - - selectEl.addEventListener("change", () => showConnectionOptions(selectEl)); - - showConnectionOptions(selectEl); + let prefs = await browser.storage.sync.get({chatgpt_web_model: '', chatgpt_model: '', ollama_model: '', openai_comp_model: '', google_gemini_model: '', anthropic_model: '', anthropic_version: '', chatgpt_win_height: 0, chatgpt_win_width: 0 }); + // OpenAI API ChatGPT model fetching + let select_chatgpt_model = document.getElementById('chatgpt_model'); + const chatgpt_option = document.createElement('option'); + chatgpt_option.value = prefs.chatgpt_model; + chatgpt_option.text = prefs.chatgpt_model; + select_chatgpt_model.appendChild(chatgpt_option); + select_chatgpt_model.addEventListener("change", warn_ChatGPT_APIKeyEmpty); + + document.getElementById('btnUpdateChatGPTModels').addEventListener('click', async () => { + document.getElementById('chatgpt_model_fetch_loading').style.display = 'inline'; + let openai = new OpenAI(document.getElementById("chatgpt_api_key").value, '', true); + openai.fetchModels().then((data) => { + if(!data.ok){ + let errorDetail; + try { + errorDetail = JSON.parse(data.error); + errorDetail = errorDetail.error.message; + } catch (e) { + errorDetail = data.error; + } + document.getElementById('chatgpt_model_fetch_loading').style.display = 'none'; + console.error("[ThunderAI] " + browser.i18n.getMessage("ChatGPT_Models_Error_fetching")); + alert(browser.i18n.getMessage("ChatGPT_Models_Error_fetching")+": " + errorDetail); + return; + } + taLog.log("ChatGPT models: " + JSON.stringify(data)); + data.response.forEach(model => { + if (!Array.from(select_chatgpt_model.options).some(option => option.value === model.id)) { + const option = document.createElement('option'); + option.value = model.id; + option.text = model.id; + select_chatgpt_model.appendChild(option); + } + }); + document.getElementById('chatgpt_model_fetch_loading').style.display = 'none'; + }); + + warn_ChatGPT_APIKeyEmpty(); + }); + + // Google Gemini API model fetching + let select_google_gemini_model = document.getElementById('google_gemini_model'); + const google_gemini_option = document.createElement('option'); + google_gemini_option.value = prefs.google_gemini_model; + google_gemini_option.text = prefs.google_gemini_model; + select_google_gemini_model.appendChild(google_gemini_option); + select_google_gemini_model.addEventListener("change", warn_GoogleGemini_APIKeyEmpty); + + document.getElementById('btnUpdateGoogleGeminiModels').addEventListener('click', async () => { + document.getElementById('google_gemini_model_fetch_loading').style.display = 'inline'; + let google_gemini = new GoogleGemini(document.getElementById("google_gemini_api_key").value, '', true); + google_gemini.fetchModels().then((data) => { + if(!data.ok){ + let errorDetail; + try { + errorDetail = JSON.parse(data.error); + errorDetail = errorDetail.error.message; + } catch (e) { + errorDetail = data.error; + } + document.getElementById('google_gemini_model_fetch_loading').style.display = 'none'; + console.error("[ThunderAI] " + browser.i18n.getMessage("GoogleGemini_Models_Error_fetching")); + alert(browser.i18n.getMessage("GoogleGemini_Models_Error_fetching")+": " + errorDetail); + return; + } + taLog.log("GoogleGemini models: " + JSON.stringify(data)); + data.response.forEach(model => { + if (!Array.from(select_google_gemini_model.options).some(option => option.value === model.name.substring(model.name.lastIndexOf("/") + 1))) { + const option = document.createElement('option'); + option.value = model.name.substring(model.name.lastIndexOf("/") + 1); + option.text = model.displayName; + select_google_gemini_model.appendChild(option); + } + }); + document.getElementById('google_gemini_model_fetch_loading').style.display = 'none'; + }); + + warn_GoogleGemini_APIKeyEmpty(); + }); + + // Ollama API Model fetching + let select_ollama_model = document.getElementById('ollama_model'); + const ollama_option = document.createElement('option'); + ollama_option.value = prefs.ollama_model; + ollama_option.text = prefs.ollama_model; + select_ollama_model.appendChild(ollama_option); + select_ollama_model.addEventListener("change", warn_Ollama_HostEmpty); + + document.getElementById('btnUpdateOllamaModels').addEventListener('click', async () => { + document.getElementById('ollama_model_fetch_loading').style.display = 'inline'; + let ollama = new Ollama(document.getElementById("ollama_host").value, true); + try { + let data = await ollama.fetchModels(); + if(!data){ + document.getElementById('ollama_model_fetch_loading').style.display = 'none'; + console.error("[ThunderAI] " + browser.i18n.getMessage("Ollama_Models_Error_fetching")); + alert(browser.i18n.getMessage("Ollama_Models_Error_fetching")); + return; + } + if(!data.ok){ + let errorDetail; + try { + errorDetail = JSON.parse(data.error); + errorDetail = errorDetail.error.message; + } catch (e) { + errorDetail = data.error; + } + document.getElementById('ollama_model_fetch_loading').style.display = 'none'; + console.error("[ThunderAI] " + browser.i18n.getMessage("Ollama_Models_Error_fetching")); + alert(browser.i18n.getMessage("Ollama_Models_Error_fetching")+": " + errorDetail); + return; + } + if(data.response.models.length == 0){ + document.getElementById('ollama_model_fetch_loading').style.display = 'none'; + console.error("[ThunderAI] " + browser.i18n.getMessage("Ollama_Models_Error_fetching")); + alert(browser.i18n.getMessage("Ollama_Models_Error_fetching")+": " + browser.i18n.getMessage("API_Models_Error_NoModels")); + return; + } + taLog.log("Ollama models: " + JSON.stringify(data)); + data.response.models.forEach(model => { + if (!Array.from(select_ollama_model.options).some(option => option.value === model.model)) { + const option = document.createElement('option'); + option.value = model.model; + option.text = model.name + " (" + model.model + ")"; + select_ollama_model.appendChild(option); + } + }); + document.getElementById('ollama_model_fetch_loading').style.display = 'none'; + } catch (error) { + document.getElementById('ollama_model_fetch_loading').style.display = 'none'; + taLog.error(browser.i18n.getMessage("Ollama_Models_Error_fetching")); + alert(browser.i18n.getMessage("Ollama_Models_Error_fetching")+": " + error.message); + } + + warn_Ollama_HostEmpty(); + }); + + // OpenAI Comp API Model fetching + let select_openai_comp_model = document.getElementById('openai_comp_model'); + const openai_comp_option = document.createElement('option'); + openai_comp_option.value = prefs.openai_comp_model; + openai_comp_option.text = prefs.openai_comp_model; + select_openai_comp_model.appendChild(openai_comp_option); + select_openai_comp_model.addEventListener("change", warn_OpenAIComp_HostEmpty); + + document.getElementById('btnUpdateOpenAICompModels').addEventListener('click', async () => { + document.getElementById('openai_comp_model_fetch_loading').style.display = 'inline'; + let openai_comp = new OpenAIComp(document.getElementById("openai_comp_host").value , null, document.getElementById("openai_comp_api_key").value, true, document.getElementById("openai_comp_use_v1").checked); + openai_comp.fetchModels().then((data) => { + if(!data.ok){ + let errorDetail; + try { + errorDetail = JSON.parse(data.error); + errorDetail = errorDetail.error.message; + } catch (e) { + errorDetail = data.error; + } + document.getElementById('openai_comp_model_fetch_loading').style.display = 'none'; + console.error("[ThunderAI] " + browser.i18n.getMessage("OpenAIComp_Models_Error_fetching")); + alert(browser.i18n.getMessage("OpenAIComp_Models_Error_fetching")+": " + errorDetail); + return; + } + taLog.log("OpenAIComp models: " + JSON.stringify(data)); + data.response.forEach(model => { + if (!Array.from(select_openai_comp_model.options).some(option => option.value === model.id)) { + const option = document.createElement('option'); + option.value = model.id; + option.text = model.id; + select_openai_comp_model.appendChild(option); + } + }); + document.getElementById('openai_comp_model_fetch_loading').style.display = 'none'; + }); + + warn_OpenAIComp_HostEmpty(); + }); + + // Anthropic API model fetching + let select_anthropic_model = document.getElementById('anthropic_model'); + const anthropic_option = document.createElement('option'); + anthropic_option.value = prefs.anthropic_model; + anthropic_option.text = prefs.anthropic_model; + select_anthropic_model.appendChild(anthropic_option); + select_anthropic_model.addEventListener("change", warn_Anthropic_APIKeyEmpty); + select_anthropic_model.addEventListener("change", warn_Anthropic_VersionEmpty); + + document.getElementById('btnUpdateAnthropicModels').addEventListener('click', async () => { + document.getElementById('anthropic_model_fetch_loading').style.display = 'inline'; + let anthropic = new Anthropic(document.getElementById("anthropic_api_key").value, document.getElementById("anthropic_version").value, ''); + anthropic.fetchModels().then((data) => { + if(!data.ok){ + let errorDetail; + try { + errorDetail = JSON.parse(data.error); + errorDetail = errorDetail.error.message; + } catch (e) { + errorDetail = data.error; + } + document.getElementById('anthropic_model_fetch_loading').style.display = 'none'; + console.error("[ThunderAI] " + browser.i18n.getMessage("Anthropic_Models_Error_fetching")); + alert(browser.i18n.getMessage("Anthropic_Models_Error_fetching")+": " + errorDetail); + return; + } + taLog.log("Anthropic models: " + JSON.stringify(data)); + data.response.forEach(model => { + const existingOption = Array.from(select_anthropic_model.options).find(option => option.value === model.id); + if (existingOption) { + existingOption.text = model.display_name + " (" + model.id + ")"; + } else { + const option = document.createElement('option'); + option.value = model.id; + option.text = model.display_name + " (" + model.id + ")"; + select_anthropic_model.appendChild(option); + } + }); + document.getElementById('anthropic_model_fetch_loading').style.display = 'none'; + }); + + warn_Anthropic_APIKeyEmpty(); + }); + + document.getElementById('btnOpenAICompForceModel').addEventListener('click', () => { + let modelName = prompt(browser.i18n.getMessage('OpenAIComp_force_model_ask')).trim(); + if ((modelName !== null) && (modelName !== undefined) && (modelName !== '')) { + let select_openai_comp_model = document.getElementById('openai_comp_model'); + let option = document.createElement('option'); + option.value = modelName; + option.text = modelName; + select_openai_comp_model.appendChild(option); + select_openai_comp_model.value = modelName; + select_openai_comp_model.dispatchEvent(new Event('change', { bubbles: true })); + } + }); + + document.getElementById('btnOpenAICompClearModelsList').addEventListener('click', () => { + if (!confirm(browser.i18n.getMessage('OpenAIComp_ClearModelsList_Confirm'))) { + return; + } + let select_openai_comp_model = document.getElementById('openai_comp_model'); + while (select_openai_comp_model.options.length > 0) { + select_openai_comp_model.remove(0); + } + select_openai_comp_model.value = ''; + select_openai_comp_model.dispatchEvent(new Event('change', { bubbles: true })); + }); + + document.getElementById('btnGiveAllUrlsPermission_ollama_api').addEventListener('click', async () => { + permission_all_urls = await messenger.permissions.request({ origins: [""] }); + }); + + document.getElementById('btnGiveAllUrlsPermission_openai_comp_api').addEventListener('click', async () => { + permission_all_urls = await messenger.permissions.request({ origins: [""] }); + }); + + warn_ChatGPT_APIKeyEmpty(); + warn_Ollama_HostEmpty(); + warn_OpenAIComp_HostEmpty(); + warn_GoogleGemini_APIKeyEmpty(); + warn_Anthropic_APIKeyEmpty(); + warn_Anthropic_VersionEmpty(); + return { - select: selectEl, - onTypeChange: (fn) => { onTypeChange = fn; fn(selectEl.value, { select: selectEl }); } + select: conntype_select, + onTypeChange: (fn) => { onTypeChange = fn; fn(conntype_select.value, { select: conntype_select }); } }; } -function populateConnectionTypeOptions(selectId, no_chatgpt_web = false) { - const selectEl = document.getElementById(selectId); - if (!selectEl) return; +// From here there are exported functions - const prevValue = selectEl.value; - - const options = [ - { value: 'chatgpt_web', msgKey: 'prefs_Connection_type_ChatGPT_Web' }, - { value: 'chatgpt_api', msgKey: 'prefs_Connection_type_ChatGPT_API' }, - { value: 'google_gemini_api', msgKey: 'prefs_Connection_type_Google_Gemini_API' }, - { value: 'anthropic_api', msgKey: 'prefs_Connection_type_Anthropic_API' }, - { value: 'ollama_api', msgKey: 'prefs_Connection_type_Ollama_API' }, - { value: 'openai_comp_api', msgKey: 'prefs_Connection_type_OpenAI_Comp_API' } - ]; - - selectEl.innerHTML = ''; - - for (const opt of options.filter(o => !(no_chatgpt_web && o.value === 'chatgpt_web'))) { - const optionEl = document.createElement('option'); - optionEl.value = opt.value; - optionEl.textContent = browser.i18n.getMessage(opt.msgKey) || opt.msgKey; - selectEl.appendChild(optionEl); - } - - if (options.some(o => o.value === prevValue)) { - selectEl.value = prevValue; - } +export function updateWarnings() { + warn_ChatGPT_APIKeyEmpty(); + warn_Ollama_HostEmpty(); + warn_OpenAIComp_HostEmpty(); + warn_GoogleGemini_APIKeyEmpty(); + warn_Anthropic_APIKeyEmpty(); + warn_Anthropic_VersionEmpty(); } - export function showConnectionOptions(conntype_select) { let chatgpt_web_display = 'table-row'; let chatgpt_api_display = 'none'; @@ -649,4 +894,183 @@ export function showConnectionOptions(conntype_select) { document.getElementById('openai_comp_api_cors_warning').style.display = 'none'; document.getElementById('ollama_api_cors_warning').style.display = 'none'; } +} + + +// From here there are internal functions + +function populateConnectionTypeOptions(selectId, no_chatgpt_web = false) { + const conntype_select = document.getElementById(selectId); + if (!conntype_select) return; + + const prevValue = conntype_select.value; + + const options = [ + { value: 'chatgpt_web', msgKey: 'prefs_Connection_type_ChatGPT_Web' }, + { value: 'chatgpt_api', msgKey: 'prefs_Connection_type_ChatGPT_API' }, + { value: 'google_gemini_api', msgKey: 'prefs_Connection_type_Google_Gemini_API' }, + { value: 'anthropic_api', msgKey: 'prefs_Connection_type_Anthropic_API' }, + { value: 'ollama_api', msgKey: 'prefs_Connection_type_Ollama_API' }, + { value: 'openai_comp_api', msgKey: 'prefs_Connection_type_OpenAI_Comp_API' } + ]; + + conntype_select.innerHTML = ''; + + for (const opt of options.filter(o => !(no_chatgpt_web && o.value === 'chatgpt_web'))) { + const optionEl = document.createElement('option'); + optionEl.value = opt.value; + optionEl.textContent = browser.i18n.getMessage(opt.msgKey) || opt.msgKey; + conntype_select.appendChild(optionEl); + } + + if (options.some(o => o.value === prevValue)) { + conntype_select.value = prevValue; + } +} + +function warn_ChatGPT_APIKeyEmpty() { + let apiKeyInput = document.getElementById('chatgpt_api_key'); + let btnFetchChatGPTModels = document.getElementById('btnUpdateChatGPTModels'); + let modelChatGPT = document.getElementById('chatgpt_model'); + if(apiKeyInput.value === ''){ + apiKeyInput.style.border = '2px solid red'; + btnFetchChatGPTModels.disabled = true; + modelChatGPT.disabled = true; + modelChatGPT.selectedIndex = -1; + modelChatGPT.style.border = ''; + }else{ + apiKeyInput.style.border = ''; + btnFetchChatGPTModels.disabled = false; + modelChatGPT.disabled = false; + if((modelChatGPT.selectedIndex === -1)||(modelChatGPT.value === '')){ + modelChatGPT.style.border = '2px solid red'; + }else{ + modelChatGPT.style.border = ''; + } + } +} + +function warn_GoogleGemini_APIKeyEmpty() { + let apiKeyInput = document.getElementById('google_gemini_api_key'); + let btnFetchGoogleGeminiModels = document.getElementById('btnUpdateGoogleGeminiModels'); + let modelGoogleGemini = document.getElementById('google_gemini_model'); + if(apiKeyInput.value === ''){ + apiKeyInput.style.border = '2px solid red'; + btnFetchGoogleGeminiModels.disabled = true; + modelGoogleGemini.disabled = true; + modelGoogleGemini.selectedIndex = -1; + modelGoogleGemini.style.border = ''; + }else{ + apiKeyInput.style.border = ''; + btnFetchGoogleGeminiModels.disabled = false; + modelGoogleGemini.disabled = false; + if((modelGoogleGemini.selectedIndex === -1)||(modelGoogleGemini.value === '')){ + modelGoogleGemini.style.border = '2px solid red'; + }else{ + modelGoogleGemini.style.border = ''; + } + } +} + +function warn_Ollama_HostEmpty() { + let hostInput = document.getElementById('ollama_host'); + let btnFetchOllamaModels = document.getElementById('btnUpdateOllamaModels'); + let modelOllama = document.getElementById('ollama_model'); + if(hostInput.value === ''){ + hostInput.style.border = '2px solid red'; + btnFetchOllamaModels.disabled = true; + modelOllama.disabled = true; + modelOllama.selectedIndex = -1; + modelOllama.style.border = ''; + }else{ + hostInput.style.border = ''; + btnFetchOllamaModels.disabled = false; + modelOllama.disabled = false; + if((modelOllama.selectedIndex === -1)||(modelOllama.value === '')){ + modelOllama.style.border = '2px solid red'; + }else{ + modelOllama.style.border = ''; + } + } +} + +function warn_OpenAIComp_HostEmpty() { + let hostInput = document.getElementById('openai_comp_host'); + let btnUpdateOpenAICompModels = document.getElementById('btnUpdateOpenAICompModels'); + let modelOpenAIComp = document.getElementById('openai_comp_model'); + if(hostInput.value === ''){ + hostInput.style.border = '2px solid red'; + btnUpdateOpenAICompModels.disabled = true; + modelOpenAIComp.disabled = true; + modelOpenAIComp.selectedIndex = -1; + modelOpenAIComp.style.border = ''; + }else{ + hostInput.style.border = ''; + btnUpdateOpenAICompModels.disabled = false; + modelOpenAIComp.disabled = false; + if((modelOpenAIComp.selectedIndex === -1)||(modelOpenAIComp.value === '')){ + modelOpenAIComp.style.border = '2px solid red'; + }else{ + modelOpenAIComp.style.border = ''; + } + } +} + +function warn_Anthropic_APIKeyEmpty() { + let apiKeyInput = document.getElementById('anthropic_api_key'); + let btnFetchAnthropicModels = document.getElementById('btnUpdateAnthropicModels'); + let modelAnthropic = document.getElementById('anthropic_model'); + if(apiKeyInput.value === ''){ + apiKeyInput.style.border = '2px solid red'; + btnFetchAnthropicModels.disabled = true; + modelAnthropic.disabled = true; + modelAnthropic.selectedIndex = -1; + modelAnthropic.style.border = ''; + }else{ + apiKeyInput.style.border = ''; + btnFetchAnthropicModels.disabled = false; + modelAnthropic.disabled = false; + if((modelAnthropic.selectedIndex === -1)||(modelAnthropic.value === '')){ + modelAnthropic.style.border = '2px solid red'; + }else{ + modelAnthropic.style.border = ''; + } + } +} + +function warn_Anthropic_VersionEmpty() { + let versionInput = document.getElementById('anthropic_version'); + let btnFetchAnthropicModels = document.getElementById('btnUpdateAnthropicModels'); + let modelAnthropic = document.getElementById('anthropic_model'); + if(versionInput.value === ''){ + versionInput.style.border = '2px solid red'; + btnFetchAnthropicModels.disabled = true; + modelAnthropic.disabled = true; + modelAnthropic.selectedIndex = -1; + modelAnthropic.style.border = ''; + }else{ + versionInput.style.border = ''; + btnFetchAnthropicModels.disabled = false; + modelAnthropic.disabled = false; + if((modelAnthropic.selectedIndex === -1)||(modelAnthropic.value === '')){ + modelAnthropic.style.border = '2px solid red'; + }else{ + modelAnthropic.style.border = ''; + } + } +} + +function resetOpenAICompConfigs(){ + let select_openai_comp_model = document.getElementById('openai_comp_services_shortcut'); + select_openai_comp_model.value = 'custom'; +} + +function loadOpenAICompConfigs(){ + let select_openai_comp_model = document.getElementById('openai_comp_services_shortcut'); + openAICompConfigs.forEach(config => { + const option = document.createElement('option'); + option.value = config.id; + option.text = config.name; + select_openai_comp_model.appendChild(option); + }); } \ No newline at end of file diff --git a/pages/addtags/mzta-add-tags.js b/pages/addtags/mzta-add-tags.js index e068b0df..dc122b8d 100644 --- a/pages/addtags/mzta-add-tags.js +++ b/pages/addtags/mzta-add-tags.js @@ -23,17 +23,18 @@ 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, normalizeStringList, isAPIKeyValue } from "../../js/mzta-utils.js"; -import { injectConnectionUI } from "../_lib/connection-ui.js"; +import { injectConnectionUI, updateWarnings } from "../_lib/connection-ui.js"; let autocompleteSuggestions = []; let taLog = new taLogger("mzta-addtags-page",true); document.addEventListener('DOMContentLoaded', async () => { try { - injectConnectionUI({ + await injectConnectionUI({ afterTrId: 'connection_ui_anchor', selectId: 'add_tags_connection_type', - no_chatgpt_web: true + no_chatgpt_web: true, + taLog: taLog }); } catch (e) { console.error('Failed to inject connection UI (add-tags)', e); @@ -196,6 +197,8 @@ document.addEventListener('DOMContentLoaded', async () => { checkboxes.forEach(checkbox => checkbox.checked = false); }); + updateWarnings(); + }); From 9b267938955a49b1f406a84abff50426dfca8da9 Mon Sep 17 00:00:00 2001 From: Mic Date: Wed, 3 Sep 2025 22:43:00 +0200 Subject: [PATCH 08/53] always trying to remove the add tags menu item before creating it --- mzta-background.js | 1 + 1 file changed, 1 insertion(+) diff --git a/mzta-background.js b/mzta-background.js index 4046b52a..9246e91e 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -895,6 +895,7 @@ menus.loadMenus(special_prompts_ids); // Context Menus function addContextMenu(menu_id) { + browser.menus.remove(menu_id); browser.menus.create({ id: menu_id, title: browser.i18n.getMessage("context_menu_" + menu_id), From 558c96f67c1cfeb2beac677d6ef52e5cebaff3f7 Mon Sep 17 00:00:00 2001 From: Mic Date: Wed, 3 Sep 2025 22:43:00 +0200 Subject: [PATCH 09/53] release notes updated --- CHANGELOG.md | 1 + options/mzta-release-notes.html | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7f677e5..a60d1416 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@
  • Added the {%mail_attachments_info%} placeholder to retrieve the name, type and file size of the mail attachments [#446].
  • [ChatGPT Web] Added a message to explain to click on "Force completion" if the ChatGPT job is not done after 7 seconds [#419].
  • [All APIs] The prompt id and name are now shown in the information header in the AI API chat [#436].
  • +
  • Minor code improvements and bugs fixed.
  • ...
  • Version 3.6.1 - 23/08/2025

    diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index dd3b1bcd..b9595662 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -12,6 +12,7 @@
  • Added the {%mail_attachments_info%} placeholder to retrieve the name, type and file size of the mail attachments [#446].
  • [ChatGPT Web] Added a message to explain to click on "Force completion" if the ChatGPT job is not done after 7 seconds [#419].
  • [All APIs] The prompt id and name are now shown in the information header in the AI API chat [#436].
  • +
  • Minor code improvements and bugs fixed.
  • ...
  • Version 3.6.1 - 23/08/2025

    From bf7fdd3739972496223f45649660ede721218e59 Mon Sep 17 00:00:00 2001 From: Mic Date: Wed, 3 Sep 2025 22:43:00 +0200 Subject: [PATCH 10/53] tr class added. see #438 --- pages/_lib/connection-ui.js | 60 ++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js index fdfce511..061c4735 100644 --- a/pages/_lib/connection-ui.js +++ b/pages/_lib/connection-ui.js @@ -45,7 +45,7 @@ export async function injectConnectionUI({ } let tpl = ` -
    __MSG_OpenChatGPTTab_Info__



    __MSG_OpenChatGPTTab_Info2__
    __MSG_remember_CORS__ [__MSG_more_info_string__]

    __MSG_CORS_alternative_1__ @@ -235,7 +235,7 @@ export async function injectConnectionUI({

    __MSG_maybe_CORS_openai_comp__ [__MSG_more_info_string__]

    __MSG_CORS_alternative_1__ @@ -301,7 +301,7 @@ export async function injectConnectionUI({

    __MSG_prefs_OptionText_anthropic_max_tokens__
    __MSG_Loading__
    __MSG_Loading__
    __MSG_Loading__
    __MSG_Loading__
    __MSG_Loading__
    __MSG_Loading__
    __MSG_Loading__
    __MSG_Loading__
    __MSG_Loading__
    __MSG_Loading__
    __MSG_prefs_OptionText_add_tags_maxnum__ diff --git a/pages/addtags/mzta-add-tags.js b/pages/addtags/mzta-add-tags.js index 7986e773..5874d5fd 100644 --- a/pages/addtags/mzta-add-tags.js +++ b/pages/addtags/mzta-add-tags.js @@ -18,7 +18,7 @@ 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 { getSpecialPrompts, setSpecialPrompts, loadPrompt, savePrompt } 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"; @@ -50,11 +50,18 @@ document.addEventListener('DOMContentLoaded', async () => { element.addEventListener("change", saveOptions); }); + document.querySelectorAll(".option-input-model").forEach(element => { + element.addEventListener("change", updatePromptAPIInfo); + }); + let conntype_el = document.getElementById(conntype_select_id); + + conntype_el.addEventListener('change', updatePromptAPIInfo); + let add_tags_use_specific_integration_el = document.getElementById('add_tags_use_specific_integration'); let conntype_row = document.getElementById(conntype_select_id + '_tr'); add_tags_use_specific_integration_el.addEventListener('change', (event) => { - console.log(">>>>>>>>>>>>> conntype_el.value: " + conntype_el.value); + // console.log(">>>>>>>>>>>>> conntype_el.value: " + conntype_el.value); document.querySelectorAll(".specific_integration_sub").forEach(tr => { tr.style.display = event.target.checked && tr.classList.contains('conntype_' + conntype_el.value) ? 'table-row' : 'none'; }); @@ -62,7 +69,7 @@ document.addEventListener('DOMContentLoaded', async () => { changeConnTypeRowColor(conntype_row, conntype_el); }); - console.log(">>>>>>>>>>>>> conntype_el.value: " + conntype_el.value); + // console.log(">>>>>>>>>>>>> conntype_el.value: " + conntype_el.value); document.querySelectorAll(".specific_integration_sub").forEach(tr => { tr.style.display = add_tags_use_specific_integration_el.checked && tr.classList.contains('conntype_' + conntype_el.value) ? 'table-row' : 'none'; }); @@ -221,7 +228,6 @@ document.addEventListener('DOMContentLoaded', async () => { }); updateWarnings(model_prefix); - }); @@ -253,6 +259,19 @@ async function updateAdditionalPromptStatements(){ } } +async function updatePromptAPIInfo(){ + let conntype = document.getElementById(conntype_select_id).value; + let model_value = conntype.substring(0, conntype.length - 4) + '_model'; + let model = document.getElementById(model_prefix + model_value).value; + console.log(">>>>>>>>>>> updatePromptAPIInfo: conntype: " + conntype + " - model: " + model + " - model_value: " + model_value); + let add_tags_prompt = await loadPrompt('prompt_add_tags'); + console.log(">>>>>>>>>>> updatePromptAPIInfo: BEFORE add_tags_prompt: " + JSON.stringify(add_tags_prompt)); + add_tags_prompt.api = conntype; + add_tags_prompt.model = model; + console.log(">>>>>>>>>>> updatePromptAPIInfo: AFTER add_tags_prompt: " + JSON.stringify(add_tags_prompt)); + await savePrompt(add_tags_prompt); +} + // Methods to manage options, derived from: /options/mzta-options.js @@ -260,7 +279,7 @@ function saveOptions(e) { e.preventDefault(); let options = {}; let element = e.target; - + // console.log(">>>>>>>>>> Saving option: " + element.id + " = " + element.value); switch (element.type) { case 'checkbox': options[element.id] = element.checked; @@ -273,6 +292,7 @@ function saveOptions(e) { options[element.id] = element.value.trim(); break; case 'select-one': + // console.log(">>>>>>>>>> Saving option [select-one]: " + element.id + " = " + element.value); options[element.id] = element.value; break; case 'textarea': @@ -314,13 +334,20 @@ async function restoreOptions() { break; default: if (element.tagName === 'SELECT') { - let default_select_value = ''; - if(element.id == 'reply_type') default_select_value = 'reply_all'; - if(element.id == 'connection_type') default_select_value = 'chatgpt_web'; - element.value = result[element.id] || default_select_value; - if (element.value === '') { - element.selectedIndex = -1; - } + let default_select_value = ''; + const restoreValue = result[element.id] || default_select_value; + // Check if option exists + let optionExists = Array.from(element.options).some(opt => opt.value === restoreValue); + // If it doesn't exist and restoreValue is not empty, create it + if (!optionExists && restoreValue !== '') { + let newOption = new Option(restoreValue, restoreValue); + element.add(newOption); + } + // Set value + element.value = restoreValue; + if (element.value === '') { + element.selectedIndex = -1; + } }else{ console.error("[ThunderAI] Unhandled input type:", element.type); } From c34e5f5fed864ce77c5981921a5c19a86580b905 Mon Sep 17 00:00:00 2001 From: Mic Date: Wed, 3 Sep 2025 23:18:00 +0200 Subject: [PATCH 18/53] getConnectionType method added --- js/mzta-utils.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/js/mzta-utils.js b/js/mzta-utils.js index c8a989dc..281e5296 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -590,6 +590,14 @@ export function isAPIKeyValue(id){ return id=="chatgpt_api_key" || id=="openai_comp_api_key" || id=="google_gemini_api_key" || id=="anthropic_api_key"; } +export function getConnectionType(conntype, prompt) { + if (prompt?.api != null && prompt.api !== '') { + return prompt.api; + } else { + return conntype; + } +} + export async function checkSparksPresence() { try { let sparks_current = await browser.runtime.sendMessage('thunderai-sparks@micz.it',{action: "checkPresence"}); From 40b6571e0470b2fc23b2c6622b961e3528b7227e Mon Sep 17 00:00:00 2001 From: Mic Date: Wed, 3 Sep 2025 23:18:00 +0200 Subject: [PATCH 19/53] spamfilter specific model and api default options added. see #438 --- options/mzta-options-default.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js index ca61bb18..3250ed64 100644 --- a/options/mzta-options-default.js +++ b/options/mzta-options-default.js @@ -81,4 +81,11 @@ export const prefs_default = { spamfilter_threshold: 70, spamfilter_context_menu: true, spamfilter_enabled_accounts: [], + spamfilter_use_specific_integration: false, + spamfilter_connection_type: '', + spamfilter_chatgpt_model: '', + spamfilter_ollama_model: '', + spamfilter_openai_comp_model: '', + spamfilter_google_gemini_model: '', + spamfilter_anthropic_model: '', } \ No newline at end of file From f1377f7de8ed3aadafaac31570927de05f7e6dc3 Mon Sep 17 00:00:00 2001 From: Mic Date: Wed, 3 Sep 2025 23:18:00 +0200 Subject: [PATCH 20/53] using the prompt conntype in addtags. see #438 --- mzta-background.js | 55 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/mzta-background.js b/mzta-background.js index 9246e91e..07469fb2 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -20,7 +20,34 @@ 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, checkIfTagLabelExists, getActiveSpecialPromptsIDs, checkSparksPresence, getMessages, getMailBody, extractJsonObject, contextMenuID_AddTags, contextMenuID_Spamfilter, sanitizeChatGPTModelData, sanitizeChatGPTWebCustomData, stripHtmlKeepLines, htmlBodyToPlainText, convertNewlinesToParagraphs } from './js/mzta-utils.js'; +import { + getCurrentIdentity, + getOriginalBody, + replaceBody, + setBody, + i18nConditionalGet, + generateCallID, + migrateCustomPromptsStorage, + migrateDefaultPromptsPropStorage, + getGPTWebModelString, + getTagsList, + createTag, + assignTagsToMessage, + checkIfTagLabelExists, + getActiveSpecialPromptsIDs, + checkSparksPresence, + getMessages, + getMailBody, + extractJsonObject, + contextMenuID_AddTags, + contextMenuID_Spamfilter, + sanitizeChatGPTModelData, + sanitizeChatGPTWebCustomData, + stripHtmlKeepLines, + htmlBodyToPlainText, + convertNewlinesToParagraphs, + getConnectionType + } 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'; @@ -749,7 +776,23 @@ function doGetSparkFeature(spark_feature_active) { } async function reload_pref_init(){ - 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}); + 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, + add_tags_connection_type: prefs_default.add_tags_connection_type, + spamfilter_connection_type: prefs_default.spamfilter_connection_type + }); _process_incoming = prefs_init.add_tags_auto || prefs_init.spamfilter; _sparks_presence = await checkSparksPresence(); } @@ -910,12 +953,12 @@ function removeContextMenu(menu_id) { } // Add Context menu: Add tags -if(prefs_init.add_tags && prefs_init.add_tags_context_menu && (prefs_init.connection_type !== "chatgpt_web")){ +if(prefs_init.add_tags && prefs_init.add_tags_context_menu && ((prefs_init.connection_type !== "chatgpt_web")||(prefs_init.add_tags_connection_type !== ""))){ addContextMenu(contextMenuID_AddTags); } // Add Context menu: Spamfilter -if(prefs_init.spamfilter && prefs_init.spamfilter_context_menu && (prefs_init.connection_type !== "chatgpt_web")){ +if(prefs_init.spamfilter && prefs_init.spamfilter_context_menu && ((prefs_init.connection_type !== "chatgpt_web")||(prefs_init.spamfilter_connection_type !== ""))){ addContextMenu(contextMenuID_Spamfilter); } @@ -1019,7 +1062,7 @@ async function processEmails(messages, addTagsAuto, spamFilter) { }); specialFullPrompt_add_tags = taPromptUtils.finalizePrompt_add_tags(specialFullPrompt_add_tags, prefs_aats.add_tags_maxnum, prefs_aats.add_tags_force_lang, prefs_aats.default_chatgpt_lang, prefs_aats.add_tags_auto_uselist, prefs_aats.add_tags_auto_uselist_list); taLog.log("Special prompt: " + specialFullPrompt_add_tags); - let cmd_addTags = new mzta_specialCommand(specialFullPrompt_add_tags, prefs_aats.connection_type, prefs_init.do_debug); + let cmd_addTags = new mzta_specialCommand(specialFullPrompt_add_tags, getConnectionType(prefs_aats.connection_type, curr_prompt_add_tags), prefs_init.do_debug); await cmd_addTags.initWorker(); let tags_current_email = []; try { @@ -1053,7 +1096,7 @@ async function processEmails(messages, addTagsAuto, spamFilter) { }); taLog.log("Special prompt: " + specialFullPrompt_spamfilter); // console.log(">>>>>>>> Special prompt for spamfilter: " + specialFullPrompt_spamfilter); - let cmd_spamfilter = new mzta_specialCommand(specialFullPrompt_spamfilter, prefs_init.connection_type, prefs_init.do_debug); + let cmd_spamfilter = new mzta_specialCommand(specialFullPrompt_spamfilter, getConnectionType(prefs_init.connection_type, curr_prompt_spamfilter), prefs_init.do_debug); await cmd_spamfilter.initWorker(); let spamfilter_result = ''; taLog.log("Sending the prompt..."); From acba02ed446e41342abe125d119a7eee019a30ab Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 4 Sep 2025 22:26:00 +0200 Subject: [PATCH 21/53] added info comment --- js/mzta-utils.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/js/mzta-utils.js b/js/mzta-utils.js index 281e5296..227c64a6 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -548,7 +548,14 @@ export function getAPIsInitMessageString(args = {}) { } export function getActiveSpecialPromptsIDs(args = {}) { - const { addtags = false, get_calendar_event = false, get_task = false, is_chatgpt_web = false } = args; + const { + addtags = false, + get_calendar_event = false, + get_task = false, + is_chatgpt_web = false + } = args; + // The Antispam filter is not here, because this method is used only + // to reload the ThunderAI button menu, not the context menu let output = []; // console.log(">>>>>>>>>> getActiveSpecialPromptsIDs args: " + JSON.stringify(args)); if (is_chatgpt_web) { From 005e697e9c292636b488c4c1713057942903bb7a Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 4 Sep 2025 22:26:00 +0200 Subject: [PATCH 22/53] getActiveSpecialPromptsIDs is considering addtags specific integration configuration. see #438 --- js/mzta-utils.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/mzta-utils.js b/js/mzta-utils.js index 227c64a6..ad483f7d 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -550,6 +550,7 @@ export function getAPIsInitMessageString(args = {}) { export function getActiveSpecialPromptsIDs(args = {}) { const { addtags = false, + addtags_api = false, get_calendar_event = false, get_task = false, is_chatgpt_web = false @@ -559,6 +560,9 @@ export function getActiveSpecialPromptsIDs(args = {}) { let output = []; // console.log(">>>>>>>>>> getActiveSpecialPromptsIDs args: " + JSON.stringify(args)); if (is_chatgpt_web) { + if (addtags_api && addtags) { + output.push('prompt_add_tags'); + } return output; } if (addtags) { From e2c67a1c5ecb90a93387fcebdfec29840b96daa9 Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 4 Sep 2025 22:31:00 +0200 Subject: [PATCH 23/53] reloading menus for addtags is now considering addtags_api: prefs_init.add_tags_use_specific_integration. see #438 --- mzta-background.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/mzta-background.js b/mzta-background.js index 07469fb2..493efa66 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -83,6 +83,7 @@ taWorkingStatus.taLog = taLog; let special_prompts_ids = getActiveSpecialPromptsIDs({ addtags: prefs_init.add_tags, + addtags_api: prefs_init.add_tags_use_specific_integration, 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") @@ -173,6 +174,7 @@ async function _reload_menus() { let getTask = doGetSparkFeature(prefs_reload.get_task); const special_prompts_ids = getActiveSpecialPromptsIDs({ addtags: prefs_reload.add_tags, + addtags_api: prefs_init.add_tags_use_specific_integration, get_calendar_event: getCalendarEvent, get_task: getTask, is_chatgpt_web: (prefs_reload.connection_type === "chatgpt_web") @@ -790,7 +792,9 @@ async function reload_pref_init(){ 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, + add_tags_use_specific_integration: prefs_default.add_tags_use_specific_integration, add_tags_connection_type: prefs_default.add_tags_connection_type, + spamfilter_use_specific_integration: prefs_default.spamfilter_use_specific_integration, spamfilter_connection_type: prefs_default.spamfilter_connection_type }); _process_incoming = prefs_init.add_tags_auto || prefs_init.spamfilter; @@ -810,6 +814,7 @@ function setupStorageChangeListener() { let getTask = doGetSparkFeature(prefs_init.get_task); const special_prompts_ids = getActiveSpecialPromptsIDs({ addtags: newTags, + addtags_api: prefs_init.add_tags_use_specific_integration, get_calendar_event: getCalendarEvent, get_task: getTask, is_chatgpt_web: (prefs_init.connection_type === "chatgpt_web") @@ -824,6 +829,7 @@ function setupStorageChangeListener() { let getTask = doGetSparkFeature(prefs_init.get_task); const special_prompts_ids = getActiveSpecialPromptsIDs({ addtags: prefs_init.add_tags, + addtags_api: prefs_init.add_tags_use_specific_integration, get_calendar_event: getCalendarEvent, get_task: getTask, is_chatgpt_web: (prefs_init.connection_type === "chatgpt_web") @@ -838,6 +844,7 @@ function setupStorageChangeListener() { let getTask = doGetSparkFeature(newTask); const special_prompts_ids = getActiveSpecialPromptsIDs({ addtags: prefs_init.add_tags, + addtags_api: prefs_init.add_tags_use_specific_integration, get_calendar_event: getCalendarEvent, get_task: getTask, is_chatgpt_web: (prefs_init.connection_type === "chatgpt_web") @@ -852,6 +859,7 @@ function setupStorageChangeListener() { let getTask = doGetSparkFeature(prefs_init.get_task); const special_prompts_ids = getActiveSpecialPromptsIDs({ addtags: prefs_init.add_tags, + addtags_api: prefs_init.add_tags_use_specific_integration, get_calendar_event: getCalendarEvent, get_task: getTask, is_chatgpt_web: (newConnectionType === "chatgpt_web") @@ -953,12 +961,12 @@ function removeContextMenu(menu_id) { } // Add Context menu: Add tags -if(prefs_init.add_tags && prefs_init.add_tags_context_menu && ((prefs_init.connection_type !== "chatgpt_web")||(prefs_init.add_tags_connection_type !== ""))){ +if(prefs_init.add_tags && prefs_init.add_tags_context_menu && ((prefs_init.connection_type !== "chatgpt_web")||(prefs_init.add_tags_use_specific_integration && (prefs_init.add_tags_connection_type !== "")))){ addContextMenu(contextMenuID_AddTags); } // Add Context menu: Spamfilter -if(prefs_init.spamfilter && prefs_init.spamfilter_context_menu && ((prefs_init.connection_type !== "chatgpt_web")||(prefs_init.spamfilter_connection_type !== ""))){ +if(prefs_init.spamfilter && prefs_init.spamfilter_context_menu && ((prefs_init.connection_type !== "chatgpt_web")||(prefs_init.spamfilter_use_specific_integration && (prefs_init.spamfilter_connection_type !== "")))){ addContextMenu(contextMenuID_Spamfilter); } From e7f0eb30d7931c3b197ad358d921744ae9629b07 Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 4 Sep 2025 22:31:00 +0200 Subject: [PATCH 24/53] checkSpecificIntegration method added --- js/mzta-utils.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/mzta-utils.js b/js/mzta-utils.js index ad483f7d..c28c1814 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -578,6 +578,10 @@ export function getActiveSpecialPromptsIDs(args = {}) { return output; } +export function checkSpecificIntegration(use, conntype){ + return use && (conntype != null) && (conntype !== ''); +} + export function extractJsonObject(inputString) { try { const jsonMatch = inputString.match(/\{[\s\S]*\}/); From e28f9fed6054472d172ce7cc37b301c659df786c Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 4 Sep 2025 22:36:00 +0200 Subject: [PATCH 25/53] using checkSpecificIntegration. see #438 --- mzta-background.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/mzta-background.js b/mzta-background.js index 493efa66..c9bf85de 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -46,7 +46,8 @@ import { stripHtmlKeepLines, htmlBodyToPlainText, convertNewlinesToParagraphs, - getConnectionType + getConnectionType, + checkSpecificIntegration, } from './js/mzta-utils.js'; import { taPromptUtils } from './js/mzta-utils-prompt.js'; import { mzta_specialCommand } from './js/mzta-special-commands.js'; @@ -83,7 +84,7 @@ taWorkingStatus.taLog = taLog; let special_prompts_ids = getActiveSpecialPromptsIDs({ addtags: prefs_init.add_tags, - addtags_api: prefs_init.add_tags_use_specific_integration, + addtags_api: checkSpecificIntegration(prefs_init.add_tags_use_specific_integration, prefs_init.add_tags_connection_type), 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") @@ -174,7 +175,7 @@ async function _reload_menus() { let getTask = doGetSparkFeature(prefs_reload.get_task); const special_prompts_ids = getActiveSpecialPromptsIDs({ addtags: prefs_reload.add_tags, - addtags_api: prefs_init.add_tags_use_specific_integration, + addtags_api: checkSpecificIntegration(prefs_init.add_tags_use_specific_integration, prefs_init.add_tags_connection_type), get_calendar_event: getCalendarEvent, get_task: getTask, is_chatgpt_web: (prefs_reload.connection_type === "chatgpt_web") @@ -814,7 +815,7 @@ function setupStorageChangeListener() { let getTask = doGetSparkFeature(prefs_init.get_task); const special_prompts_ids = getActiveSpecialPromptsIDs({ addtags: newTags, - addtags_api: prefs_init.add_tags_use_specific_integration, + addtags_api: checkSpecificIntegration(prefs_init.add_tags_use_specific_integration, prefs_init.add_tags_connection_type), get_calendar_event: getCalendarEvent, get_task: getTask, is_chatgpt_web: (prefs_init.connection_type === "chatgpt_web") @@ -829,7 +830,7 @@ function setupStorageChangeListener() { let getTask = doGetSparkFeature(prefs_init.get_task); const special_prompts_ids = getActiveSpecialPromptsIDs({ addtags: prefs_init.add_tags, - addtags_api: prefs_init.add_tags_use_specific_integration, + addtags_api: checkSpecificIntegration(prefs_init.add_tags_use_specific_integration, prefs_init.add_tags_connection_type), get_calendar_event: getCalendarEvent, get_task: getTask, is_chatgpt_web: (prefs_init.connection_type === "chatgpt_web") @@ -844,7 +845,7 @@ function setupStorageChangeListener() { let getTask = doGetSparkFeature(newTask); const special_prompts_ids = getActiveSpecialPromptsIDs({ addtags: prefs_init.add_tags, - addtags_api: prefs_init.add_tags_use_specific_integration, + addtags_api: checkSpecificIntegration(prefs_init.add_tags_use_specific_integration, prefs_init.add_tags_connection_type), get_calendar_event: getCalendarEvent, get_task: getTask, is_chatgpt_web: (prefs_init.connection_type === "chatgpt_web") @@ -859,7 +860,7 @@ function setupStorageChangeListener() { let getTask = doGetSparkFeature(prefs_init.get_task); const special_prompts_ids = getActiveSpecialPromptsIDs({ addtags: prefs_init.add_tags, - addtags_api: prefs_init.add_tags_use_specific_integration, + addtags_api: checkSpecificIntegration(prefs_init.add_tags_use_specific_integration, prefs_init.add_tags_connection_type), get_calendar_event: getCalendarEvent, get_task: getTask, is_chatgpt_web: (newConnectionType === "chatgpt_web") @@ -961,12 +962,12 @@ function removeContextMenu(menu_id) { } // Add Context menu: Add tags -if(prefs_init.add_tags && prefs_init.add_tags_context_menu && ((prefs_init.connection_type !== "chatgpt_web")||(prefs_init.add_tags_use_specific_integration && (prefs_init.add_tags_connection_type !== "")))){ +if(prefs_init.add_tags && prefs_init.add_tags_context_menu && ((prefs_init.connection_type !== "chatgpt_web")||checkSpecificIntegration(prefs_init.add_tags_use_specific_integration,prefs_init.add_tags_connection_type))){ addContextMenu(contextMenuID_AddTags); } // Add Context menu: Spamfilter -if(prefs_init.spamfilter && prefs_init.spamfilter_context_menu && ((prefs_init.connection_type !== "chatgpt_web")||(prefs_init.spamfilter_use_specific_integration && (prefs_init.spamfilter_connection_type !== "")))){ +if(prefs_init.spamfilter && prefs_init.spamfilter_context_menu && ((prefs_init.connection_type !== "chatgpt_web")||checkSpecificIntegration(prefs_init.spamfilter_use_specific_integration,prefs_init.spamfilter_connection_type))){ addContextMenu(contextMenuID_Spamfilter); } From 944138a0c22f0dbf0af751c1db9bfd6e03be48fb Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 4 Sep 2025 22:36:00 +0200 Subject: [PATCH 26/53] code reformatting and using prefs_default --- api_webchat/controller.js | 90 ++++++++++++++++++++++++++++++++++----- 1 file changed, 80 insertions(+), 10 deletions(-) diff --git a/api_webchat/controller.js b/api_webchat/controller.js index ef2b4f77..687855e7 100644 --- a/api_webchat/controller.js +++ b/api_webchat/controller.js @@ -20,6 +20,7 @@ * The original code has been released under the Apache License, Version 2.0. */ +import { prefs_default } from '../options/mzta-options-default.js'; import { placeholdersUtils } from '../js/mzta-placeholders.js'; import { getAPIsInitMessageString, convertNewlinesToBr } from '../js/mzta-utils.js'; @@ -75,13 +76,27 @@ messageInput.setMessagesArea(messagesArea); switch (llm) { case "chatgpt_api": { - let prefs_api = await browser.storage.sync.get({chatgpt_api_key: '', chatgpt_model: '', chatgpt_developer_messages:'', chatgpt_api_store: false, do_debug: false}); + let prefs_api = await browser.storage.sync.get({ + chatgpt_api_key: prefs_default.chatgpt_api_key, + chatgpt_model: prefs_default.chatgpt_model, + chatgpt_developer_messages: prefs_default.chatgpt_developer_messages, + chatgpt_api_store: prefs_default.chatgpt_api_store, + do_debug: prefs_default.do_debug, + }); let i18nStrings = {}; i18nStrings["chatgpt_api_request_failed"] = browser.i18n.getMessage('chatgpt_api_request_failed'); i18nStrings["error_connection_interrupted"] = browser.i18n.getMessage('error_connection_interrupted'); messageInput.setModel(prefs_api.chatgpt_model); messagesArea.setLLMName("ChatGPT"); - worker.postMessage({ type: 'init', chatgpt_api_key: prefs_api.chatgpt_api_key, chatgpt_model: prefs_api.chatgpt_model, chatgpt_developer_messages: prefs_api.chatgpt_developer_messages, chatgpt_api_store: prefs_api.chatgpt_api_store, do_debug: prefs_api.do_debug, i18nStrings: i18nStrings}); + worker.postMessage({ + type: 'init', + chatgpt_api_key: prefs_api.chatgpt_api_key, + chatgpt_model: prefs_api.chatgpt_model, + chatgpt_developer_messages: prefs_api.chatgpt_developer_messages, + chatgpt_api_store: prefs_api.chatgpt_api_store, + do_debug: prefs_api.do_debug, + i18nStrings: i18nStrings, + }); let additional_text_elements = []; additional_text_elements.push({label: 'OpenAI Store', value: (prefs_api.chatgpt_api_store ? 'Yes' : 'No')}); if(prefs_api.chatgpt_developer_messages && prefs_api.chatgpt_developer_messages.length > 0) { @@ -97,7 +112,12 @@ switch (llm) { break; } case "google_gemini_api": { - let prefs_api = await browser.storage.sync.get({google_gemini_api_key: '', google_gemini_model: '', google_gemini_system_instruction: '', do_debug: false}); + let prefs_api = await browser.storage.sync.get({ + google_gemini_api_key: prefs_default.google_gemini_api_key, + google_gemini_model: prefs_default.google_gemini_model, + google_gemini_system_instruction: prefs_default.google_gemini_system_instruction, + do_debug: prefs_default.do_debug, + }); let i18nStrings = {}; i18nStrings["google_gemini_api_request_failed"] = browser.i18n.getMessage('google_gemini_api_request_failed'); i18nStrings["error_connection_interrupted"] = browser.i18n.getMessage('error_connection_interrupted'); @@ -108,7 +128,14 @@ switch (llm) { additional_text_elements.push({label: browser.i18n.getMessage("GoogleGemini_SystemInstruction"), value: prefs_api.google_gemini_system_instruction}); } additional_text_elements.push({label: "Prompt", value: '[' + prompt_id + '] ' + decodeURIComponent(prompt_name)}); - worker.postMessage({ type: 'init', google_gemini_api_key: prefs_api.google_gemini_api_key, google_gemini_model: prefs_api.google_gemini_model, google_gemini_system_instruction: prefs_api.google_gemini_system_instruction, do_debug: prefs_api.do_debug, i18nStrings: i18nStrings}); + worker.postMessage({ + type: 'init', + google_gemini_api_key: prefs_api.google_gemini_api_key, + google_gemini_model: prefs_api.google_gemini_model, + google_gemini_system_instruction: prefs_api.google_gemini_system_instruction, + do_debug: prefs_api.do_debug, + i18nStrings: i18nStrings, + }); messagesArea.appendUserMessage(getAPIsInitMessageString({ api_string: "Google Gemini API", model_string: prefs_api.google_gemini_model, @@ -118,13 +145,27 @@ switch (llm) { break; } case "ollama_api": { - let prefs_api = await browser.storage.sync.get({ollama_host: '', ollama_model: '', ollama_num_ctx: 0, ollama_think: false, do_debug: false}); + let prefs_api = await browser.storage.sync.get({ + ollama_host: prefs_default.ollama_host, + ollama_model: prefs_default.ollama_model, + ollama_num_ctx: prefs_default.ollama_num_ctx, + ollama_think: prefs_default.ollama_think, + do_debug: prefs_default.do_debug, + }); let i18nStrings = {}; i18nStrings["ollama_api_request_failed"] = browser.i18n.getMessage('ollama_api_request_failed'); i18nStrings["error_connection_interrupted"] = browser.i18n.getMessage('error_connection_interrupted'); messageInput.setModel(prefs_api.ollama_model); messagesArea.setLLMName("Ollama Local"); - worker.postMessage({ type: 'init', ollama_host: prefs_api.ollama_host, ollama_model: prefs_api.ollama_model, ollama_num_ctx: prefs_api.ollama_num_ctx, ollama_think: prefs_api.ollama_think, do_debug: prefs_api.do_debug, i18nStrings: i18nStrings}); + worker.postMessage({ + type: 'init', + ollama_host: prefs_api.ollama_host, + ollama_model: prefs_api.ollama_model, + ollama_num_ctx: prefs_api.ollama_num_ctx, + ollama_think: prefs_api.ollama_think, + do_debug: prefs_api.do_debug, + i18nStrings: i18nStrings, + }); browser.runtime.sendMessage({command: "ollama_api_ready_" + call_id, window_id: (await browser.windows.getCurrent()).id}); let additional_text_elements = []; additional_text_elements.push({label: "Prompt", value: '[' + prompt_id + '] ' + decodeURIComponent(prompt_name)}); @@ -137,13 +178,28 @@ switch (llm) { break; } case "openai_comp_api": { - let prefs_api = await browser.storage.sync.get({openai_comp_host: '', openai_comp_model: '', openai_comp_api_key: '', openai_comp_use_v1: true, openai_comp_chat_name: '', do_debug: false}); + let prefs_api = await browser.storage.sync.get({ + openai_comp_host: prefs_default.openai_comp_host, + openai_comp_model: prefs_default.openai_comp_model, + openai_comp_api_key: prefs_default.openai_comp_api_key, + openai_comp_use_v1: prefs_default.openai_comp_use_v1, + openai_comp_chat_name: prefs_default.openai_comp_chat_name, + do_debug: prefs_default.do_debug, + }); let i18nStrings = {}; i18nStrings["OpenAIComp_api_request_failed"] = browser.i18n.getMessage('OpenAIComp_api_request_failed'); i18nStrings["error_connection_interrupted"] = browser.i18n.getMessage('error_connection_interrupted'); messageInput.setModel(prefs_api.openai_comp_model); messagesArea.setLLMName(prefs_api.openai_comp_chat_name); - worker.postMessage({ type: 'init', openai_comp_host: prefs_api.openai_comp_host, openai_comp_model: prefs_api.openai_comp_model, openai_comp_api_key: prefs_api.openai_comp_api_key, openai_comp_use_v1: prefs_api.openai_comp_use_v1, do_debug: prefs_api.do_debug, i18nStrings: i18nStrings}); + worker.postMessage({ + type: 'init', + openai_comp_host: prefs_api.openai_comp_host, + openai_comp_model: prefs_api.openai_comp_model, + openai_comp_api_key: prefs_api.openai_comp_api_key, + openai_comp_use_v1: prefs_api.openai_comp_use_v1, + do_debug: prefs_api.do_debug, + i18nStrings: i18nStrings, + }); let additional_text_elements = []; additional_text_elements.push({label: "Prompt", value: '[' + prompt_id + '] ' + decodeURIComponent(prompt_name)}); messagesArea.appendUserMessage(getAPIsInitMessageString({ @@ -156,13 +212,27 @@ switch (llm) { break; } case "anthropic_api": { - let prefs_api = await browser.storage.sync.get({anthropic_api_key: '', anthropic_model: '', anthropic_version: '2023-06-01', anthropic_max_tokens: 4096, do_debug: false}); + let prefs_api = await browser.storage.sync.get({ + anthropic_api_key: prefs_default.anthropic_api_key, + anthropic_model: prefs_default.anthropic_model, + anthropic_version: prefs_default.anthropic_version, + anthropic_max_tokens: prefs_default.anthropic_max_tokens, + do_debug: prefs_default.do_debug, + }); let i18nStrings = {}; i18nStrings["anthropic_api_request_failed"] = browser.i18n.getMessage('anthropic_api_request_failed'); i18nStrings["error_connection_interrupted"] = browser.i18n.getMessage('error_connection_interrupted'); messageInput.setModel(prefs_api.anthropic_model); messagesArea.setLLMName("Anthropic"); - worker.postMessage({ type: 'init', anthropic_api_key: prefs_api.anthropic_api_key, anthropic_model: prefs_api.anthropic_model, anthropic_version: prefs_api.anthropic_version, anthropic_max_tokens: prefs_api.anthropic_max_tokens, do_debug: prefs_api.do_debug, i18nStrings: i18nStrings}); + worker.postMessage({ + type: 'init', + anthropic_api_key: prefs_api.anthropic_api_key, + anthropic_model: prefs_api.anthropic_model, + anthropic_version: prefs_api.anthropic_version, + anthropic_max_tokens: prefs_api.anthropic_max_tokens, + do_debug: prefs_api.do_debug, + i18nStrings: i18nStrings, + }); let additional_text_elements = []; additional_text_elements.push({label: "Prompt", value: '[' + prompt_id + '] ' + decodeURIComponent(prompt_name)}); messagesArea.appendUserMessage(getAPIsInitMessageString({ From 7f9ee613ab2dfcd92d59e34e19a20cb3b78fd556 Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 4 Sep 2025 22:41:00 +0200 Subject: [PATCH 27/53] code formatted for clarity --- js/mzta-special-commands.js | 79 ++++++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 10 deletions(-) diff --git a/js/mzta-special-commands.js b/js/mzta-special-commands.js index 2ac7ac38..fdd4ac59 100644 --- a/js/mzta-special-commands.js +++ b/js/mzta-special-commands.js @@ -60,28 +60,87 @@ async initWorker() { switch (this.llm) { case "chatgpt_api": { - let prefs_api = await browser.storage.sync.get({chatgpt_api_key: '', chatgpt_model: '', chatgpt_developer_messages: ''}); - this.worker.postMessage({ type: 'init', chatgpt_api_key: prefs_api.chatgpt_api_key, chatgpt_model: prefs_api.chatgpt_model, chatgpt_developer_messages: prefs_api.chatgpt_developer_messages, do_debug: this.do_debug, i18nStrings: ''}); + let prefs_api = await browser.storage.sync.get({ + chatgpt_api_key: '', + chatgpt_model: '', + chatgpt_developer_messages: '' + }); + this.worker.postMessage({ + type: 'init', + chatgpt_api_key: prefs_api.chatgpt_api_key, + chatgpt_model: prefs_api.chatgpt_model, + chatgpt_developer_messages: prefs_api.chatgpt_developer_messages, + do_debug: this.do_debug, + i18nStrings: '' + }); break; } case "google_gemini_api": { - let prefs_api = await browser.storage.sync.get({google_gemini_api_key: '', google_gemini_model: '', google_gemini_system_instruction: ''}); - this.worker.postMessage({ type: 'init', google_gemini_api_key: prefs_api.google_gemini_api_key, google_gemini_model: prefs_api.google_gemini_model, google_gemini_system_instruction: prefs_api.google_gemini_system_instruction, do_debug: this.do_debug, i18nStrings: ''}); + let prefs_api = await browser.storage.sync.get({ + google_gemini_api_key: '', + google_gemini_model: '', + google_gemini_system_instruction: '' + }); + this.worker.postMessage({ + type: 'init', + google_gemini_api_key: prefs_api.google_gemini_api_key, + google_gemini_model: prefs_api.google_gemini_model, + google_gemini_system_instruction: prefs_api.google_gemini_system_instruction, + do_debug: this.do_debug, + i18nStrings: '' + }); break; } case "ollama_api": { - let prefs_api = await browser.storage.sync.get({ollama_host: '', ollama_model: ''}); - this.worker.postMessage({ type: 'init', ollama_host: prefs_api.ollama_host, ollama_model: prefs_api.ollama_model, do_debug: this.do_debug, i18nStrings: ''}); + let prefs_api = await browser.storage.sync.get({ + ollama_host: '', + ollama_model: '', + }); + this.worker.postMessage({ + type: 'init', + ollama_host: prefs_api.ollama_host, + ollama_model: prefs_api.ollama_model, + do_debug: this.do_debug, + i18nStrings: '' + }); break; } case "openai_comp_api": { - let prefs_api = await browser.storage.sync.get({openai_comp_host: '', openai_comp_model: '', openai_comp_api_key: '', openai_comp_use_v1: true, openai_comp_chat_name: '', do_debug: false}); - this.worker.postMessage({ type: 'init', openai_comp_host: prefs_api.openai_comp_host, openai_comp_model: prefs_api.openai_comp_model, openai_comp_api_key: prefs_api.openai_comp_api_key, openai_comp_use_v1: prefs_api.openai_comp_use_v1, do_debug: this.do_debug, i18nStrings: ''}); + let prefs_api = await browser.storage.sync.get({ + openai_comp_host: '', + openai_comp_model: '', + openai_comp_api_key: '', + openai_comp_use_v1: true, + openai_comp_chat_name: '', + do_debug: false, + }); + this.worker.postMessage({ + type: 'init', + openai_comp_host: prefs_api.openai_comp_host, + openai_comp_model: prefs_api.openai_comp_model, + openai_comp_api_key: prefs_api.openai_comp_api_key, + openai_comp_use_v1: prefs_api.openai_comp_use_v1, + do_debug: this.do_debug, + i18nStrings: '' + }); break; } case "anthropic_api": { - let prefs_api = await browser.storage.sync.get({anthropic_api_key: '', anthropic_model: '', anthropic_version: '2023-06-01', anthropic_max_tokens: 4096}); - this.worker.postMessage({ type: 'init', anthropic_api_key: prefs_api.anthropic_api_key, anthropic_model: prefs_api.anthropic_model, anthropic_version: prefs_api.anthropic_version, anthropic_max_tokens: prefs_api.anthropic_max_tokens, do_debug: this.do_debug, i18nStrings: ''}); + let prefs_api = await browser.storage.sync.get({ + anthropic_api_key: '', + anthropic_model: '', + anthropic_version: '2023-06-01', + anthropic_max_tokens: 4096, + }); + this.worker.postMessage({ + type: 'init', + anthropic_api_key: prefs_api.anthropic_api_key, + anthropic_model: prefs_api.anthropic_model, + anthropic_version: prefs_api.anthropic_version, + anthropic_max_tokens: prefs_api.anthropic_max_tokens, + do_debug: this.do_debug, + i18nStrings: '' + }); break; } } From 72f3c49d77c83a70b7926f2d15984ed11bfcd55e Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 4 Sep 2025 22:41:00 +0200 Subject: [PATCH 28/53] using prefs_default --- js/mzta-special-commands.js | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/js/mzta-special-commands.js b/js/mzta-special-commands.js index fdd4ac59..3982642a 100644 --- a/js/mzta-special-commands.js +++ b/js/mzta-special-commands.js @@ -17,7 +17,7 @@ */ // Call the API to use a special prompt - + import { prefs_default } from "../options/mzta-options-default"; import { taLogger } from './mzta-logger.js'; @@ -61,9 +61,9 @@ switch (this.llm) { case "chatgpt_api": { let prefs_api = await browser.storage.sync.get({ - chatgpt_api_key: '', - chatgpt_model: '', - chatgpt_developer_messages: '' + chatgpt_api_key: prefs_default.chatgpt_api_key, + chatgpt_model: prefs_default.chatgpt_model, + chatgpt_developer_messages: prefs_default.chatgpt_developer_messages }); this.worker.postMessage({ type: 'init', @@ -77,9 +77,9 @@ } case "google_gemini_api": { let prefs_api = await browser.storage.sync.get({ - google_gemini_api_key: '', - google_gemini_model: '', - google_gemini_system_instruction: '' + google_gemini_api_key: prefs_default.google_gemini_api_key, + google_gemini_model: prefs_default.google_gemini_model, + google_gemini_system_instruction: prefs_default.google_gemini_system_instruction }); this.worker.postMessage({ type: 'init', @@ -93,8 +93,8 @@ } case "ollama_api": { let prefs_api = await browser.storage.sync.get({ - ollama_host: '', - ollama_model: '', + ollama_host: prefs_default.ollama_host, + ollama_model: prefs_default.ollama_model, }); this.worker.postMessage({ type: 'init', @@ -107,12 +107,11 @@ } case "openai_comp_api": { let prefs_api = await browser.storage.sync.get({ - openai_comp_host: '', - openai_comp_model: '', - openai_comp_api_key: '', - openai_comp_use_v1: true, - openai_comp_chat_name: '', - do_debug: false, + openai_comp_host: prefs_default.openai_comp_host, + openai_comp_model: prefs_default.openai_comp_model, + openai_comp_api_key: prefs_default.openai_comp_api_key, + openai_comp_use_v1: prefs_default.openai_comp_use_v1, + openai_comp_chat_name: prefs_default.openai_comp_chat_name, }); this.worker.postMessage({ type: 'init', @@ -127,10 +126,10 @@ } case "anthropic_api": { let prefs_api = await browser.storage.sync.get({ - anthropic_api_key: '', - anthropic_model: '', - anthropic_version: '2023-06-01', - anthropic_max_tokens: 4096, + anthropic_api_key: prefs_default.anthropic_api_key, + anthropic_model: prefs_default.anthropic_model, + anthropic_version: prefs_default.anthropic_version, + anthropic_max_tokens: prefs_default.anthropic_max_tokens, }); this.worker.postMessage({ type: 'init', From 9967e288618d74ec6312e882847409c7310a758a Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 4 Sep 2025 22:41:00 +0200 Subject: [PATCH 29/53] mzta_specialCommand is now using an object in input --- js/mzta-menus.js | 18 +++++++++++++++--- js/mzta-special-commands.js | 7 ++++++- mzta-background.js | 12 ++++++++++-- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/js/mzta-menus.js b/js/mzta-menus.js index c836acde..3d4d181e 100644 --- a/js/mzta-menus.js +++ b/js/mzta-menus.js @@ -195,7 +195,11 @@ export class mzta_Menus { // TODO: use the current API, abort if using chatgpt web // COMMENTED TO DO TESTS // tags_current_email = "recipients, TEST, home, work, CAR, light"; - let cmd_addTags = new mzta_specialCommand(fullPrompt,prefs_at.connection_type,prefs_at.do_debug); + let cmd_addTags = new mzta_specialCommand({ + prompt: fullPrompt, + llm: prefs_at.connection_type, + do_debug: prefs_at.do_debug + }); await cmd_addTags.initWorker(); try{ tags_current_email = taPromptUtils.getTagsFromResponse(await cmd_addTags.sendPrompt()); @@ -243,7 +247,11 @@ export class mzta_Menus { */ fullPrompt = taPromptUtils.finalizePrompt_get_calendar_event(fullPrompt); this.logger.log("fullPrompt: " + fullPrompt); - let cmd_GetCalendarEvent = new mzta_specialCommand(fullPrompt,prefs_at.connection_type,true); + let cmd_GetCalendarEvent = new mzta_specialCommand({ + prompt: fullPrompt, + llm: prefs_at.connection_type, + do_debug: true + }); await cmd_GetCalendarEvent.initWorker(); try{ calendar_event_data = await cmd_GetCalendarEvent.sendPrompt(); @@ -311,7 +319,11 @@ export class mzta_Menus { * } */ this.logger.log("fullPrompt: " + fullPrompt); - let cmd_GetTask = new mzta_specialCommand(fullPrompt,prefs_at.connection_type,true); + let cmd_GetTask = new mzta_specialCommand({ + prompt: fullPrompt, + llm: prefs_at.connection_type, + do_debug: true + }); await cmd_GetTask.initWorker(); try{ task_data = await cmd_GetTask.sendPrompt(); diff --git a/js/mzta-special-commands.js b/js/mzta-special-commands.js index 3982642a..9688a9f7 100644 --- a/js/mzta-special-commands.js +++ b/js/mzta-special-commands.js @@ -30,7 +30,12 @@ logger = null; do_debug = false; - constructor(prompt, llm, do_debug = false) { + constructor(args = {}) { + let { + prompt = '', + llm = '', + do_debug = false + } = args; this.prompt = prompt; this.llm = llm; this.logger = new taLogger('mzta_specialCommand', do_debug); diff --git a/mzta-background.js b/mzta-background.js index c9bf85de..68dda652 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -1071,7 +1071,11 @@ async function processEmails(messages, addTagsAuto, spamFilter) { }); specialFullPrompt_add_tags = taPromptUtils.finalizePrompt_add_tags(specialFullPrompt_add_tags, prefs_aats.add_tags_maxnum, prefs_aats.add_tags_force_lang, prefs_aats.default_chatgpt_lang, prefs_aats.add_tags_auto_uselist, prefs_aats.add_tags_auto_uselist_list); taLog.log("Special prompt: " + specialFullPrompt_add_tags); - let cmd_addTags = new mzta_specialCommand(specialFullPrompt_add_tags, getConnectionType(prefs_aats.connection_type, curr_prompt_add_tags), prefs_init.do_debug); + let cmd_addTags = new mzta_specialCommand({ + prompt: specialFullPrompt_add_tags, + llm: getConnectionType(prefs_aats.connection_type, curr_prompt_add_tags), + do_debug: prefs_init.do_debug + }); await cmd_addTags.initWorker(); let tags_current_email = []; try { @@ -1105,7 +1109,11 @@ async function processEmails(messages, addTagsAuto, spamFilter) { }); taLog.log("Special prompt: " + specialFullPrompt_spamfilter); // console.log(">>>>>>>> Special prompt for spamfilter: " + specialFullPrompt_spamfilter); - let cmd_spamfilter = new mzta_specialCommand(specialFullPrompt_spamfilter, getConnectionType(prefs_init.connection_type, curr_prompt_spamfilter), prefs_init.do_debug); + let cmd_spamfilter = new mzta_specialCommand({ + prompt: specialFullPrompt_spamfilter, + llm: getConnectionType(prefs_init.connection_type, curr_prompt_spamfilter), + do_debug: prefs_init.do_debug + }); await cmd_spamfilter.initWorker(); let spamfilter_result = ''; taLog.log("Sending the prompt..."); From 9681a938e3f1d0a9515026d45f9b26affc25c678 Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 4 Sep 2025 22:46:00 +0200 Subject: [PATCH 30/53] mzta_specialCommand has now a custom_model parameter. see #438 --- js/mzta-special-commands.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/js/mzta-special-commands.js b/js/mzta-special-commands.js index 9688a9f7..25e9d508 100644 --- a/js/mzta-special-commands.js +++ b/js/mzta-special-commands.js @@ -26,6 +26,7 @@ prompt = ""; worker = null; llm = ""; + custom_model = ""; full_message = ""; logger = null; do_debug = false; @@ -34,10 +35,12 @@ let { prompt = '', llm = '', + custom_model = '', do_debug = false } = args; this.prompt = prompt; this.llm = llm; + this.custom_model = custom_model; this.logger = new taLogger('mzta_specialCommand', do_debug); this.do_debug = do_debug; switch (this.llm) { @@ -73,7 +76,7 @@ this.worker.postMessage({ type: 'init', chatgpt_api_key: prefs_api.chatgpt_api_key, - chatgpt_model: prefs_api.chatgpt_model, + chatgpt_model: this.custom_model != '' ? this.custom_model : prefs_api.chatgpt_model, chatgpt_developer_messages: prefs_api.chatgpt_developer_messages, do_debug: this.do_debug, i18nStrings: '' @@ -89,7 +92,7 @@ this.worker.postMessage({ type: 'init', google_gemini_api_key: prefs_api.google_gemini_api_key, - google_gemini_model: prefs_api.google_gemini_model, + google_gemini_model: this.custom_model != '' ? this.custom_model : prefs_api.google_gemini_model, google_gemini_system_instruction: prefs_api.google_gemini_system_instruction, do_debug: this.do_debug, i18nStrings: '' @@ -104,7 +107,7 @@ this.worker.postMessage({ type: 'init', ollama_host: prefs_api.ollama_host, - ollama_model: prefs_api.ollama_model, + ollama_model: this.custom_model != '' ? this.custom_model : prefs_api.ollama_model, do_debug: this.do_debug, i18nStrings: '' }); @@ -121,7 +124,7 @@ this.worker.postMessage({ type: 'init', openai_comp_host: prefs_api.openai_comp_host, - openai_comp_model: prefs_api.openai_comp_model, + openai_comp_model: this.custom_model != '' ? this.custom_model : prefs_api.openai_comp_model, openai_comp_api_key: prefs_api.openai_comp_api_key, openai_comp_use_v1: prefs_api.openai_comp_use_v1, do_debug: this.do_debug, @@ -139,7 +142,7 @@ this.worker.postMessage({ type: 'init', anthropic_api_key: prefs_api.anthropic_api_key, - anthropic_model: prefs_api.anthropic_model, + anthropic_model: this.custom_model != '' ? this.custom_model : prefs_api.anthropic_model, anthropic_version: prefs_api.anthropic_version, anthropic_max_tokens: prefs_api.anthropic_max_tokens, do_debug: this.do_debug, From 01a1934ddf4f0a95aeb096a72f9987c3d8b1549c Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 4 Sep 2025 22:46:00 +0200 Subject: [PATCH 31/53] missing .js in import fixed --- js/mzta-special-commands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/mzta-special-commands.js b/js/mzta-special-commands.js index 25e9d508..66befc7c 100644 --- a/js/mzta-special-commands.js +++ b/js/mzta-special-commands.js @@ -17,7 +17,7 @@ */ // Call the API to use a special prompt - import { prefs_default } from "../options/mzta-options-default"; + import { prefs_default } from "../options/mzta-options-default.js"; import { taLogger } from './mzta-logger.js'; From 66776d2e20605d2dbae945d83b4b9c2c7b1f619f Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 4 Sep 2025 22:46:00 +0200 Subject: [PATCH 32/53] fixed missing : --- js/mzta-utils-prompt.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/mzta-utils-prompt.js b/js/mzta-utils-prompt.js index 57098416..444e1203 100644 --- a/js/mzta-utils-prompt.js +++ b/js/mzta-utils-prompt.js @@ -88,7 +88,7 @@ export const taPromptUtils = { fullPrompt += " \n" + browser.i18n.getMessage("prompt_add_tags_force_lang") + " " + default_chatgpt_lang + "."; } if(add_tags_auto_uselist && add_tags_auto_uselist_list && add_tags_auto_uselist_list.length > 0){ - fullPrompt += " \n" + browser.i18n.getMessage("prompt_add_tags_use_list") + " " + add_tags_auto_uselist_list + "."; + fullPrompt += " \n" + browser.i18n.getMessage("prompt_add_tags_use_list") + ": " + add_tags_auto_uselist_list + "."; } return fullPrompt; From 14b6c97c9d954bfe449e0bf92a5cf7f8e1ab109d Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 4 Sep 2025 22:46:00 +0200 Subject: [PATCH 33/53] prompt_add_tags_use_list text updated. see #289 --- _locales/en/messages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 480e90cf..7c0eb305 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1140,7 +1140,7 @@ "description": "" }, "prompt_add_tags_use_list": { - "message": "Use only these tags, that are comma separated in the list", + "message": "Use only the tags in this comma separated list", "description": "" }, "prefs_OptionText_add_tags_auto_only_inbox": { From ee7a033e74647c60ba8408248bd8b6b8322522ce Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 4 Sep 2025 22:51:00 +0200 Subject: [PATCH 34/53] use prompt api and model when assigning tags. see #438 --- js/mzta-special-commands.js | 1 + js/workers/model-worker-anthropic.js | 1 + mzta-background.js | 4 +++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/js/mzta-special-commands.js b/js/mzta-special-commands.js index 66befc7c..bb9f58c5 100644 --- a/js/mzta-special-commands.js +++ b/js/mzta-special-commands.js @@ -66,6 +66,7 @@ } async initWorker() { + // console.log((">>>>>>>>>>>> this.custom_model: " + this.custom_model)); switch (this.llm) { case "chatgpt_api": { let prefs_api = await browser.storage.sync.get({ diff --git a/js/workers/model-worker-anthropic.js b/js/workers/model-worker-anthropic.js index a16578c9..3636b5d4 100644 --- a/js/workers/model-worker-anthropic.js +++ b/js/workers/model-worker-anthropic.js @@ -36,6 +36,7 @@ let assistantResponseAccumulator = ''; self.onmessage = async function(event) { if (event.data.type === 'init') { + // console.log(">>>>>>>>>>>>>> event.data: " + JSON.stringify(event.data)); anthropic_api_key = event.data.anthropic_api_key; anthropic_model = event.data.anthropic_model; anthropic = new Anthropic(anthropic_api_key, event.data.anthropic_version, anthropic_model, event.data.anthropic_max_tokens, true); diff --git a/mzta-background.js b/mzta-background.js index 68dda652..faf2dc61 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -1058,7 +1058,7 @@ async function processEmails(messages, addTagsAuto, spamFilter) { let specialFullPrompt_add_tags = ''; let curr_prompt_add_tags = menus.allPrompts.find(p => p.id === 'prompt_add_tags'); let tags_full_list = await getTagsList(); - // console.log(">>>>>>>>>>>>> curr_prompt_add_tags: " + curr_prompt_add_tags); + // console.log(">>>>>>>>>>>>> curr_prompt_add_tags: " + JSON.stringify(curr_prompt_add_tags)); let chatgpt_lang = await taPromptUtils.getDefaultLang(curr_prompt_add_tags); specialFullPrompt_add_tags = await taPromptUtils.preparePrompt({ curr_prompt: curr_prompt_add_tags, @@ -1071,9 +1071,11 @@ async function processEmails(messages, addTagsAuto, spamFilter) { }); specialFullPrompt_add_tags = taPromptUtils.finalizePrompt_add_tags(specialFullPrompt_add_tags, prefs_aats.add_tags_maxnum, prefs_aats.add_tags_force_lang, prefs_aats.default_chatgpt_lang, prefs_aats.add_tags_auto_uselist, prefs_aats.add_tags_auto_uselist_list); taLog.log("Special prompt: " + specialFullPrompt_add_tags); + // console.log(">>>>>>>>>> curr_prompt_add_tags.model: " + curr_prompt_add_tags.model); let cmd_addTags = new mzta_specialCommand({ prompt: specialFullPrompt_add_tags, llm: getConnectionType(prefs_aats.connection_type, curr_prompt_add_tags), + custom_model: curr_prompt_add_tags.model ? curr_prompt_add_tags.model : '', do_debug: prefs_init.do_debug }); await cmd_addTags.initWorker(); From 1c39801a2af74c51e80d6d1cc89bd29eb8006270 Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 4 Sep 2025 22:56:00 +0200 Subject: [PATCH 35/53] always showing with proper message the addtags and spamfilter rows. see #438 --- _locales/en/messages.json | 4 +++ js/mzta-utils.js | 1 + options/mzta-options.css | 5 ++++ options/mzta-options.html | 2 ++ options/mzta-options.js | 57 +++++++++++++++++++++++++-------------- 5 files changed, 49 insertions(+), 20 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 7c0eb305..d4080c9c 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1660,5 +1660,9 @@ "chatgpt_click_force_completion": { "message": "It seems that it's not possible to get if ChatGPT has finished. Click here to force the completion of the job.", "description": "" + }, + "warn_API_needed": { + "message": "To use this feature, you need an API integration rather than the ChatGPT Web Integration. You can define a specific API in the feature settings page by first checking the checkbox above and then clicking the button on the left.", + "description": "" } } \ No newline at end of file diff --git a/js/mzta-utils.js b/js/mzta-utils.js index c28c1814..66fa50be 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -606,6 +606,7 @@ export function isAPIKeyValue(id){ } export function getConnectionType(conntype, prompt) { + console.log(">>>>>>>>>>> getConnectionType conntype: " + conntype + " prompt: " + JSON.stringify(prompt)); if (prompt?.api != null && prompt.api !== '') { return prompt.api; } else { diff --git a/options/mzta-options.css b/options/mzta-options.css index f2f53464..e2721e13 100644 --- a/options/mzta-options.css +++ b/options/mzta-options.css @@ -104,6 +104,11 @@ div#miczTranslate{ font-size:smaller; } +.warn_API_needed{ + display: none; + font-weight: bold; +} + #no_sparks td{ text-align: center; padding: 1em !important; diff --git a/options/mzta-options.html b/options/mzta-options.html index 9b1b9d58..0e24f172 100644 --- a/options/mzta-options.html +++ b/options/mzta-options.html @@ -132,6 +132,7 @@
    + + + + + + + + + +
    __MSG_prefs_OptionText_use_specific_integration__ + + +
    __MSG_prefs_OptionText_spamfilter_threshold__ @@ -74,4 +87,4 @@ - \ No newline at end of file + diff --git a/pages/spamfilter/mzta-spamfilter.js b/pages/spamfilter/mzta-spamfilter.js index 164465ab..a783d3ca 100644 --- a/pages/spamfilter/mzta-spamfilter.js +++ b/pages/spamfilter/mzta-spamfilter.js @@ -18,18 +18,39 @@ 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 { getSpecialPrompts, setSpecialPrompts, loadPrompt, savePrompt, clearPromptAPI } 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, isAPIKeyValue } from "../../js/mzta-utils.js"; +import { + injectConnectionUI, + updateWarnings, + changeConnTypeRowColor +} from "../_lib/connection-ui.js"; let autocompleteSuggestions = []; let taLog = new taLogger("mzta-spamfilter-page",true); taSpamReport.logger = taLog; +let conntype_select_id = 'spamfilter_connection_type'; +let model_prefix = 'spamfilter_'; + document.addEventListener('DOMContentLoaded', async () => { + try { + await injectConnectionUI({ + afterTrId: 'connection_ui_anchor', + tr_class: 'specific_integration_sub', + selectId: conntype_select_id, + modelId_prefix: model_prefix, + no_chatgpt_web: true, + taLog: taLog + }); + } catch (e) { + console.error('Failed to inject connection UI (spamfilter)', e); + } + i18n.updateDocument(); await restoreOptions(); @@ -40,6 +61,48 @@ document.addEventListener('DOMContentLoaded', async () => { document.getElementById("spamfilter_threshold").addEventListener("input", check_spamfilter_threshold); check_spamfilter_threshold({target: document.getElementById("spamfilter_threshold")}); + // Bind prompt API updates to connection type and model selects + document.querySelectorAll(".option-input-model").forEach(element => { + element.addEventListener("change", updatePromptAPIInfo); + }); + const conntype_el = document.getElementById(conntype_select_id); + if (conntype_el) { + conntype_el.addEventListener('change', updatePromptAPIInfo); + const conntype_row = document.getElementById(conntype_select_id + '_tr'); + if (conntype_row) changeConnTypeRowColor(conntype_row, conntype_el); + } + + // Specific integration toggle behavior + const spamfilter_use_specific_integration_el = document.getElementById('spamfilter_use_specific_integration'); + let prefs_spamfilter_init = await browser.storage.sync.get({ spamfilter_enabled_accounts: [], connection_type: 'chatgpt_web' }); + if(prefs_spamfilter_init.connection_type == 'chatgpt_web'){ + spamfilter_use_specific_integration_el.checked = true; + spamfilter_use_specific_integration_el.dispatchEvent(new Event('change')); + spamfilter_use_specific_integration_el.disabled = true; + } + const conntype_end_el = document.getElementById('connection_ui_end'); + const conntype_row = document.getElementById(conntype_select_id + '_tr'); + spamfilter_use_specific_integration_el.addEventListener('change', async (event) => { + document.querySelectorAll('.specific_integration_sub').forEach(tr => { + tr.style.display = event.target.checked && tr.classList.contains('conntype_' + conntype_el.value) ? 'table-row' : 'none'; + }); + if (conntype_row) conntype_row.style.display = event.target.checked ? 'table-row' : 'none'; + if (conntype_end_el) conntype_end_el.style.display = event.target.checked ? 'table-row' : 'none'; + if(!event.target.checked){ + await clearPromptAPI('prompt_spamfilter'); + }else{ + updatePromptAPIInfo(); + } + if (conntype_row) changeConnTypeRowColor(conntype_row, conntype_el); + }); + + // Initialize visibility per current toggle value + document.querySelectorAll('.specific_integration_sub').forEach(tr => { + tr.style.display = spamfilter_use_specific_integration_el.checked && tr.classList.contains('conntype_' + conntype_el.value) ? 'table-row' : 'none'; + }); + if (conntype_row) conntype_row.style.display = spamfilter_use_specific_integration_el.checked ? 'table-row' : 'none'; + if (conntype_end_el) conntype_end_el.style.display = spamfilter_use_specific_integration_el.checked ? 'table-row' : 'none'; + let spamfilter_textarea = document.getElementById('spamfilter_prompt_text'); let spamfilter_save_btn = document.getElementById('btn_save_prompt'); let spamfilter_reset_btn = document.getElementById('btn_reset_prompt'); @@ -136,6 +199,9 @@ document.addEventListener('DOMContentLoaded', async () => { }); loadSpamReport(); + updateWarnings(model_prefix); + // Sync prompt API/model once on load + updatePromptAPIInfo(); }); function check_spamfilter_threshold(event) { @@ -165,6 +231,21 @@ async function loadSpamReport(){ } } +async function updatePromptAPIInfo(){ + const conntypeEl = document.getElementById(conntype_select_id); + if (!conntypeEl || !conntypeEl.value) return; + const conntype = conntypeEl.value; + const model_value = conntype.substring(0, conntype.length - 4) + '_model'; + const modelEl = document.getElementById(model_prefix + model_value); + if (!modelEl) return; + const model = modelEl.value; + let spamfilter_prompt = await loadPrompt('prompt_spamfilter'); + if (!spamfilter_prompt) return; + spamfilter_prompt.api = conntype; + spamfilter_prompt.model = model; + await savePrompt(spamfilter_prompt); +} + // Function to populate the table function populateTable(data) { const tableBody = document.getElementById("report_data_body"); @@ -228,13 +309,16 @@ function saveOptions(e) { case 'number': options[element.id] = element.valueAsNumber; break; - case 'text': - case 'password': + case 'text': + case 'password': options[element.id] = element.value.trim(); break; case 'select-one': options[element.id] = element.value; break; + case 'textarea': + options[element.id] = element.value; + break; default: console.error("[ThunderAI] Unhandled input type:", element.type); } @@ -257,6 +341,7 @@ async function restoreOptions() { element.value = result[element.id] ?? default_number_value; break; case 'text': + case 'textarea': case 'password': let default_text_value = ''; if(element.id == 'default_chatgpt_lang') default_text_value = prefs_default.default_chatgpt_lang; @@ -267,7 +352,15 @@ async function restoreOptions() { 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.id == 'spamfilter_connection_type') default_select_value = 'chatgpt_api'; + const restoreValue = result[element.id] || default_select_value; + // Ensure option exists before restoring + let optionExists = Array.from(element.options).some(opt => opt.value === restoreValue); + if (!optionExists && restoreValue !== '') { + let newOption = new Option(restoreValue, restoreValue); + element.add(newOption); + } + element.value = restoreValue; if (element.value === '') { element.selectedIndex = -1; } @@ -280,4 +373,4 @@ async function restoreOptions() { let getting = await browser.storage.sync.get(prefs_default); setCurrentChoice(getting); -} \ No newline at end of file +} From ef57eb6499e66e158f680a1ade1d785c6ad829e3 Mon Sep 17 00:00:00 2001 From: Mic Date: Sun, 7 Sep 2025 20:00:00 +0200 Subject: [PATCH 47/53] translation fixed. see #438 --- _locales/en/messages.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 3515a3b5..54453c07 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1151,11 +1151,7 @@ "message": "If checked, the AI will only add tags to emails received in the inbox folder.", "description": "" }, - "prefs_OptionText_use_specific_integration": { - "message": "Use specific Model and API", - "description": "" - }, - "prefs_OptionText_use_specific_integration_Info": { + "prefs_OptionText_add_tags_use_specific_integration_Info": { "message": "If checked, the Model and API specified below will be used for adding tags to emails, regardless the one choosen in the ThunderAI options page.", "description": "" }, From c55985d076127a29352d18f1dff5781bc4e69ab3 Mon Sep 17 00:00:00 2001 From: Mic Date: Sun, 7 Sep 2025 20:05:00 +0200 Subject: [PATCH 48/53] getConnectionType now has a use_promptspecific_api = true third parameter --- js/mzta-utils.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/js/mzta-utils.js b/js/mzta-utils.js index 66fa50be..00dab231 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -605,7 +605,10 @@ export function isAPIKeyValue(id){ return id=="chatgpt_api_key" || id=="openai_comp_api_key" || id=="google_gemini_api_key" || id=="anthropic_api_key"; } -export function getConnectionType(conntype, prompt) { +export function getConnectionType(conntype, prompt, use_promptspecific_api = true) { + if(!use_promptspecific_api) { + return conntype; + } console.log(">>>>>>>>>>> getConnectionType conntype: " + conntype + " prompt: " + JSON.stringify(prompt)); if (prompt?.api != null && prompt.api !== '') { return prompt.api; From cd07092ac8bc3aa0de5c54bd5f111e09868125c9 Mon Sep 17 00:00:00 2001 From: Mic Date: Sun, 7 Sep 2025 20:05:00 +0200 Subject: [PATCH 49/53] spamfilter is now using the prompt api, if present. see #438. --- mzta-background.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mzta-background.js b/mzta-background.js index faf2dc61..c0f87e20 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -1029,6 +1029,8 @@ async function processEmails(messages, addTagsAuto, spamFilter) { add_tags_auto_uselist: prefs_default.add_tags_auto_uselist, add_tags_auto_uselist_list: prefs_default.add_tags_auto_uselist_list, spamfilter_enabled_accounts: prefs_default.spamfilter_enabled_accounts, + add_tags_use_specific_integration: prefs_default.add_tags_use_specific_integration, + spamfilter_use_specific_integration: prefs_default.spamfilter_use_specific_integration, }); for await (let message of messages) { @@ -1074,7 +1076,7 @@ async function processEmails(messages, addTagsAuto, spamFilter) { // console.log(">>>>>>>>>> curr_prompt_add_tags.model: " + curr_prompt_add_tags.model); let cmd_addTags = new mzta_specialCommand({ prompt: specialFullPrompt_add_tags, - llm: getConnectionType(prefs_aats.connection_type, curr_prompt_add_tags), + llm: getConnectionType(prefs_aats.connection_type, curr_prompt_add_tags, prefs_aats.add_tags_use_specific_integration), custom_model: curr_prompt_add_tags.model ? curr_prompt_add_tags.model : '', do_debug: prefs_init.do_debug }); @@ -1113,7 +1115,8 @@ async function processEmails(messages, addTagsAuto, spamFilter) { // console.log(">>>>>>>> Special prompt for spamfilter: " + specialFullPrompt_spamfilter); let cmd_spamfilter = new mzta_specialCommand({ prompt: specialFullPrompt_spamfilter, - llm: getConnectionType(prefs_init.connection_type, curr_prompt_spamfilter), + llm: getConnectionType(prefs_aats.connection_type, curr_prompt_spamfilter, prefs_aats.spamfilter_use_specific_integration), + custom_model: curr_prompt_spamfilter.model ? curr_prompt_spamfilter.model : '', do_debug: prefs_init.do_debug }); await cmd_spamfilter.initWorker(); From 1bc111f96fc1f14dfcb27578c281b80a22b2d813 Mon Sep 17 00:00:00 2001 From: Mic Date: Sun, 7 Sep 2025 20:10:00 +0200 Subject: [PATCH 50/53] loading do_debug pref at runtime for auto add tags and spamfilter --- mzta-background.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mzta-background.js b/mzta-background.js index c0f87e20..b658b446 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -1031,6 +1031,7 @@ async function processEmails(messages, addTagsAuto, spamFilter) { spamfilter_enabled_accounts: prefs_default.spamfilter_enabled_accounts, add_tags_use_specific_integration: prefs_default.add_tags_use_specific_integration, spamfilter_use_specific_integration: prefs_default.spamfilter_use_specific_integration, + do_debug: prefs_default.do_debug, }); for await (let message of messages) { @@ -1078,7 +1079,7 @@ async function processEmails(messages, addTagsAuto, spamFilter) { prompt: specialFullPrompt_add_tags, llm: getConnectionType(prefs_aats.connection_type, curr_prompt_add_tags, prefs_aats.add_tags_use_specific_integration), custom_model: curr_prompt_add_tags.model ? curr_prompt_add_tags.model : '', - do_debug: prefs_init.do_debug + do_debug: prefs_aats.do_debug }); await cmd_addTags.initWorker(); let tags_current_email = []; @@ -1117,7 +1118,7 @@ async function processEmails(messages, addTagsAuto, spamFilter) { prompt: specialFullPrompt_spamfilter, llm: getConnectionType(prefs_aats.connection_type, curr_prompt_spamfilter, prefs_aats.spamfilter_use_specific_integration), custom_model: curr_prompt_spamfilter.model ? curr_prompt_spamfilter.model : '', - do_debug: prefs_init.do_debug + do_debug: prefs_aats.do_debug }); await cmd_spamfilter.initWorker(); let spamfilter_result = ''; From 7c68561901a65baff8186c83cce075fdad5823de Mon Sep 17 00:00:00 2001 From: Mic Date: Mon, 8 Sep 2025 22:09:00 +0200 Subject: [PATCH 51/53] gemini thinking budget pref added to the options page. see #494 --- _locales/en/messages.json | 8 ++++++++ options/mzta-options-default.js | 1 + pages/_lib/connection-ui.js | 20 +++++++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 54453c07..536614c7 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1668,5 +1668,13 @@ "warn_API_needed": { "message": "To use this feature, you need an API integration rather than the ChatGPT Web Integration. You can define a specific API in the feature settings page by first checking the checkbox above and then clicking the button on the left.", "description": "" + }, + "prefs_google_gemini_thinking_budget": { + "message": "Thinking Budget", + "description": "" + }, + "prefs_google_gemini_thinking_budget_Info": { + "message": "Define the number of tokens to be used for thinking. Leave this field blank if the selected model does not support thinking or if you want to use the default method. Enter 0 to disable thinking, or -1 to enable dynamic thinking.", + "description": "" } } diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js index de164daa..6efc2cfa 100644 --- a/options/mzta-options-default.js +++ b/options/mzta-options-default.js @@ -45,6 +45,7 @@ export const prefs_default = { google_gemini_api_key: '', google_gemini_model: '', google_gemini_system_instruction: '', + google_gemini_thinking_budget: '', anthropic_api_key: '', anthropic_model: '', anthropic_version: '2023-06-01', diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js index 36c0bd28..eaee61bf 100644 --- a/pages/_lib/connection-ui.js +++ b/pages/_lib/connection-ui.js @@ -22,7 +22,11 @@ import { Ollama } from '../../js/api/ollama.js'; import { OpenAIComp } from '../../js/api/openai_comp.js' import { GoogleGemini } from '../../js/api/google_gemini.js'; import { Anthropic } from '../../js/api/anthropic.js'; -import { validateCustomData_ChatGPTWeb, sanitizeChatGPTModelData, sanitizeChatGPTWebCustomData } from '../../js/mzta-utils.js'; +import { + validateCustomData_ChatGPTWeb, + sanitizeChatGPTModelData, + sanitizeChatGPTWebCustomData +} from '../../js/mzta-utils.js'; import { openAICompConfigs } from '../../js/api/openai_comp_configs.js'; export const varConnectionUI = { @@ -204,6 +208,20 @@ export async function injectConnectionUI({
    + + + +