diff --git a/js/mzta-chatgpt-loader.js b/js/mzta-chatgpt-loader.js new file mode 100644 index 00000000..ce674db9 --- /dev/null +++ b/js/mzta-chatgpt-loader.js @@ -0,0 +1,27 @@ +/* + * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] + * Copyright (C) 2024 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 . + */ + +const urlParams = new URLSearchParams(window.location.search); +const call_id = urlParams.get('call_id'); + +async function page_ready(call_id){ + await browser.runtime.sendMessage({command: "chatgpt_web_ready_" + call_id}); +} + +page_ready(call_id); +//console.log(">>>>>>>>>>> [ThunderAI] call_id: " + call_id) \ No newline at end of file diff --git a/js/mzta-chatgpt.js b/js/mzta-chatgpt.js index 89f46e7a..30e30c4f 100644 --- a/js/mzta-chatgpt.js +++ b/js/mzta-chatgpt.js @@ -22,8 +22,11 @@ export const mzta_script = ` let force_go = false; +let do_force_completion = false; let current_message = null; let current_action = null; +let current_tabId = null; +let current_mailMessageId = null; let selectionChangeTimeout = null; let isDragging = false; @@ -59,19 +62,22 @@ async function chatgpt_sendMsg(msg, method ='') { // return -1 send button async function chatgpt_isIdle() { return new Promise(resolve => { const intervalId = setInterval(() => { - if (chatgpt_getRegenerateButton()) { + if (chatgpt_getRegenerateButton() || do_force_completion) { clearInterval(intervalId); resolve(true); }}, 100);});} function chatgpt_getRegenerateButton() { for (const mainSVG of document.querySelectorAll('main svg')) { - if (mainSVG.querySelector('path[d*="M3.07 10.876C3.623"]')) // regen icon found + if (mainSVG.querySelector('path[d^="M3.06957"]')) // regen icon found return mainSVG.parentNode.parentNode; } } function chatpgt_scrollToBottom () { - try { document.querySelector('button[class*="cursor"][class*="bottom"]').click(); } + try { + //document.querySelector('button[class*="cursor"][class*="bottom"]').click(); + document.querySelector('path[d^="M12 21C11.7348"]').parentNode.parentNode.click(); + } catch (err) { console.error('[ThunderAI] ', err); } } @@ -139,7 +145,7 @@ function addCustomDiv(prompt_action,tabId,mailMessageId) { force_completion_div.textContent = mztaForceCompletionDesc; force_completion_div.title = mztaForceCompletionTitle; force_completion_div.addEventListener('click', function() { - operation_done(); + do_force_completion = true; }); fixedDiv.appendChild(force_completion_div); @@ -492,30 +498,50 @@ function selectContentOnClick(event) { } } +function run(){ + if(!checkLoggedIn()){ + // User not logged in + alert(browser.i18n.getMessage("chatgpt_user_not_logged_in")); + }else{ + addCustomDiv(current_action,current_tabId,current_mailMessageId); + (async () => { + if(mztaDoCustomText === 1){ + showCustomTextField(); + } else { + await doProceed(current_message); + } + // Add an event listener to the document to detect clicks + document.addEventListener('mousedown', selectContentOnMouseDown); + document.addEventListener('mousemove', selectContentOnMouseMove); + document.addEventListener('mouseup', selectContentOnMouseUp); + })(); + } +} // In the content script browser.runtime.onMessage.addListener((message, sender, sendResponse) => { - if (message.command === "chatgpt_send") { - if(!checkLoggedIn()){ - // User not logged in - alert(browser.i18n.getMessage("chatgpt_user_not_logged_in")); - }else{ + //console.log(">>>>>>>>>>>>> content.js onMessage: " + JSON.stringify(message)); + switch(message.command) { + case "chatgpt_send": current_action = message.action; current_message = message; - addCustomDiv(message.action,message.tabId,message.mailMessageId); - (async () => { - if(mztaDoCustomText === 1){ - showCustomTextField(); - } else { - await doProceed(message); - } - // Add an event listener to the document to detect clicks - document.addEventListener('mousedown', selectContentOnMouseDown); - document.addEventListener('mousemove', selectContentOnMouseMove); - document.addEventListener('mouseup', selectContentOnMouseUp); - })(); - } + current_tabId = message.tabId; + current_mailMessageId = message.mailMessageId; + run(); + break; + case "chatgpt_alive": + sendResponse({isAlive: true}); + break; } }); +let checkTab = setInterval(() => { + let customDiv = document.getElementById('mzta-custom_text'); + if(customDiv){ + clearInterval(checkTab); + }else{ + run(); + } +}, 1000); + ` diff --git a/mzta-background.js b/mzta-background.js index 2546efe2..42eb0ed6 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -56,6 +56,12 @@ for (let messageTab of messageTabs) { } } +browser.contentScripts.register({ + matches: ["https://*.chatgpt.com/*"], + js: [{file: "js/mzta-chatgpt-loader.js"}], + runAt: "document_idle" + }); + messenger.runtime.onMessage.addListener(async (message, sender, sendResponse) => { // Check what type of message we have received and invoke the appropriate // handler function. @@ -161,35 +167,38 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_ switch(prefs.connection_type){ case 'chatgpt_web': + + let rand_call_id = '_chatgptweb_' + generateCallID(); + // We are using the ChatGPT web interface let newWindow = await browser.windows.create({ - url: "https://chatgpt.com", + url: "https://chatgpt.com?call_id=" + rand_call_id, type: "popup", width: prefs.chatgpt_win_width, height: prefs.chatgpt_win_height }); - taLog.log("[ThunderAI] ChatGPT web interface script started..."); - let createdTab = newWindow.tabs[0]; let newWindowId = newWindow.id; + let createdTab = newWindow.tabs[0]; - let pre_script = `let mztaWinId = `+ newWindowId +`; - let mztaStatusPageDesc="`+ browser.i18n.getMessage("prefs_status_page") +`"; - let mztaForceCompletionDesc="`+ browser.i18n.getMessage("chatgpt_force_completion") +`"; - let mztaForceCompletionTitle="`+ browser.i18n.getMessage("chatgpt_force_completion_title") +`"; - let mztaDoCustomText=`+ do_custom_text +`; - let mztaPromptName="[`+ i18nConditionalGet(prompt_name) +`]"; - `; + const listener = async (message, sender, sendResponse) => { - let done1 = false; - let try_num = 0; + if (message.command === "chatgpt_web_ready_" + rand_call_id) { - while(!done1){ - if(try_num > 30){ - taLog.error('[ChatGPT Web] Impossible to connect to the window chat!'); - break; - } - try { + taLog.log("[ThunderAI] ChatGPT web interface script started..."); + + let pre_script = `let mztaWinId = `+ newWindowId +`; + let mztaStatusPageDesc="`+ browser.i18n.getMessage("prefs_status_page") +`"; + let mztaForceCompletionDesc="`+ browser.i18n.getMessage("chatgpt_force_completion") +`"; + let mztaForceCompletionTitle="`+ browser.i18n.getMessage("chatgpt_force_completion_title") +`"; + let mztaDoCustomText=`+ do_custom_text +`; + let mztaPromptName="[`+ i18nConditionalGet(prompt_name) +`]"; + `; + + taLog.log("Waiting 1 sec"); + await new Promise(resolve => setTimeout(resolve, 1000)); + taLog.log("Waiting 1 sec done"); + await browser.tabs.executeScript(createdTab.id, { code: pre_script + mzta_script, matchAboutBlank: false }); let mailMessage = await browser.messageDisplay.getDisplayedMessage(curr_tabId); let mailMessageId = -1; @@ -197,24 +206,20 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_ browser.tabs.sendMessage(createdTab.id, { command: "chatgpt_send", prompt: promptText, action: action, tabId: curr_tabId, mailMessageId: mailMessageId}); taLog.log('[ChatGPT Web] Connection succeded!'); taLog.log("[ThunderAI] ChatGPT Web script injected successfully"); - done1 = true; - } catch (error) { - taLog.warn('[ChatGPT Web] Error connecting to the window chat: ' + error); - taLog.warn('[ChatGPT Web] Trying again...'); - done1 = false; - try_num++; + browser.runtime.onMessage.removeListener(listener); } - await new Promise(resolve => setTimeout(resolve, 500)); } - break; // chatgpt_web + + browser.runtime.onMessage.addListener(listener); + break; // chatgpt_web case 'chatgpt_api': // We are using the ChatGPT API - let rand_call_id = '_openai_' + generateCallID(); + let rand_call_id2 = '_openai_' + generateCallID(); await browser.windows.create({ - url: browser.runtime.getURL('api_webchat/index.html?llm='+prefs.connection_type+'&call_id='+rand_call_id), + url: browser.runtime.getURL('api_webchat/index.html?llm='+prefs.connection_type+'&call_id='+rand_call_id2), type: "popup", width: prefs.chatgpt_win_width, height: prefs.chatgpt_win_height @@ -222,7 +227,7 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_ const listener2 = async (message, sender, sendResponse) => { - if (message.command === "openai_api_ready_"+rand_call_id) { + if (message.command === "openai_api_ready_"+rand_call_id2) { let newWindow2 = await browser.windows.get(message.window_id, {populate: true}); let createdTab2 = newWindow2.tabs[0]; @@ -256,10 +261,10 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_ taLog.log("Ollama API window opening..."); - let rand_call_id2 = '_ollama_' + generateCallID(); + let rand_call_id3 = '_ollama_' + generateCallID(); await browser.windows.create({ - url: browser.runtime.getURL('api_webchat/index.html?llm='+prefs.connection_type+'&call_id='+rand_call_id2), + url: browser.runtime.getURL('api_webchat/index.html?llm='+prefs.connection_type+'&call_id='+rand_call_id3), type: "popup", width: prefs.chatgpt_win_width, height: prefs.chatgpt_win_height @@ -267,7 +272,7 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_ const listener3 = async (message, sender, sendResponse) => { - if (message.command === "ollama_api_ready_"+rand_call_id2) { + if (message.command === "ollama_api_ready_"+rand_call_id3) { taLog.log("Ollama API window ready."); taLog.log("message.window_id: " + message.window_id) let newWindow3 = await browser.windows.get(message.window_id, {populate: true});