Merge pull request #105 from micz/chatgpt_web_new_import_response

ChatGPT Web new response import method
This commit is contained in:
Mic 2024-08-15 00:30:22 +02:00 committed by GitHub
commit 8f9d3e4ec3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 150 additions and 122 deletions

View file

@ -6,6 +6,7 @@
<h2>Version 2.0.2 - ??/??/2024</h2>
<ul>
<li><i>[ChatGPT Web]</i> Now, the ChatGPT response must be selected by the user to be retrieved by ThunderAI. A single click on the text should work, but it's also possible to select the text manually [<a href="https://github.com/micz/ThunderAI/issues/104">#104</a>].</li>
<li>Added a better error message when there is an error fetching models.</li>
<li>When selecting a correct model in the options page, the field is no more highlighted in red [<a href="https://github.com/micz/ThunderAI/issues/100">#100</a>].</li>
<li>When using the ChatGPT API, the double quotes at the beginning and end of the response are removed [<a href="https://github.com/micz/ThunderAI/issues/99">#99</a>].</li>
@ -13,7 +14,7 @@
</ul>
<h2>Version 2.0.1 - 09/08/2024</h2>
<ul>
<li>No more notifying a missing API Key or model when using the web interface.</li>
<li><i>[ChatGPT Web]</i> No more notifying a missing API Key or model when using the web interface.</li>
</ul>
<h2>Version 2.0.0 - 30/07/2024</h2>
<ul>

View file

@ -207,8 +207,12 @@
"message": "Abgeschlossen!",
"description": ""
},
"chatgpt_win_job_completed_select": {
"message": "Text auswählen und auf die Schaltfläche klicken.",
"description": ""
},
"chatgpt_win_get_answer": {
"message": "Letzte Antwort verwenden",
"message": "Verwenden Sie die ausgewählte Antwort.",
"description": ""
},
"chatgpt_win_close": {
@ -295,14 +299,6 @@
"message": "Antworttyp",
"description": ""
},
"prefs_OptionText_chatpgt_keep_formatting": {
"message": "Behalte die Formatierung bei",
"description": ""
},
"prefs_OptionText_chatpgt_keep_formatting_info": {
"message": "Behalte die Formatierung und die Zahlen oder Aufzählungspunkte aus der ChatGPT-Antwort bei.",
"description": ""
},
"prefs_OptionText_chatpgt_use_gpt4": {
"message": "Verwenden Sie ChatGPT-4",
"description": ""

View file

@ -207,8 +207,12 @@
"message": "Completed!",
"description": ""
},
"chatgpt_win_job_completed_select": {
"message": "Select the text you want to use and click the button.",
"description": ""
},
"chatgpt_win_get_answer": {
"message": "Use last answer",
"message": "Use the selected answer",
"description": ""
},
"chatgpt_win_close": {
@ -295,14 +299,6 @@
"message": "Reply type",
"description": ""
},
"prefs_OptionText_chatpgt_keep_formatting": {
"message": "Keep formatting",
"description": ""
},
"prefs_OptionText_chatpgt_keep_formatting_info": {
"message": "Keep the formatting and numeral or bullet points from the ChatGPT response.",
"description": ""
},
"prefs_OptionText_chatpgt_use_gpt4": {
"message": "Use ChatGPT-4",
"description": ""

View file

@ -207,8 +207,12 @@
"message": "Terminé !",
"description": ""
},
"chatgpt_win_job_completed_select": {
"message": "Sélectionnez le texte que vous souhaitez utiliser et cliquez sur le bouton.",
"description": ""
},
"chatgpt_win_get_answer": {
"message": "Utiliser la dernière réponse",
"message": "Utilisez la réponse sélectionnée",
"description": ""
},
"chatgpt_win_close": {
@ -295,14 +299,6 @@
"message": "Type de réponse",
"description": ""
},
"prefs_OptionText_chatpgt_keep_formatting": {
"message": "Conserver la mise en forme",
"description": ""
},
"prefs_OptionText_chatpgt_keep_formatting_info": {
"message": "Conservez la mise en forme et les numéros ou les puces de la réponse de ChatGPT.",
"description": ""
},
"prefs_OptionText_chatpgt_use_gpt4": {
"message": "Utiliser ChatGPT-4",
"description": ""

View file

@ -207,8 +207,12 @@
"message": "Completato!",
"description": ""
},
"chatgpt_win_job_completed_select": {
"message": "Seleziona il testo che desideri utilizzare e clicca sul pulsante.",
"description": ""
},
"chatgpt_win_get_answer": {
"message": "Usa l'ultima risposta",
"message": "Usa la risposta selezionata",
"description": ""
},
"chatgpt_win_close": {
@ -295,14 +299,6 @@
"message": "Modalità di risposta",
"description": ""
},
"prefs_OptionText_chatpgt_keep_formatting": {
"message": "Mantieni la formattazione",
"description": ""
},
"prefs_OptionText_chatpgt_keep_formatting_info": {
"message": "Mantieni la formattazione del testo e gli elenchi puntati e numerati della risposta di ChatGPT.",
"description": ""
},
"prefs_OptionText_chatpgt_use_gpt4": {
"message": "Usa il modello ChatGPT-4",
"description": ""

View file

@ -23,6 +23,9 @@
export const mzta_script = `
let force_go = false;
let current_message = null;
let current_action = null;
let selectionChangeTimeout = null;
let isDragging = false;
async function chatgpt_sendMsg(msg, method ='') { // return -1 send button not found, -2 textarea not found
const textArea = document.querySelector('form textarea'),
@ -62,73 +65,6 @@ function chatgpt_getRegenerateButton() {
}
}
async function chatgpt_getFromDOM(pos) {
const responseDivs = document.querySelectorAll('div[data-testid*="conversation-turn"]:nth-child(odd)'),
strPos = pos.toString().toLowerCase();
//console.log(">>>>>>>>>>>>> responseDivs.length: "+ responseDivs.length);
let response = '';
if (responseDivs.length) {
if (/last|final/.test(strPos)){ // get last response
responseDivs[responseDivs.length - 1].innerHTML = responseDivs[responseDivs.length - 1].innerHTML.replace(/<\\/p>/g, '</p>\\n\\n').replace(/<br\\s*\\/?>/g, '<br>\\n');
// Removing the new buttons that let the user change model and insert a number (4 or 3.5 at the end of the text)
let parser = new DOMParser();
let doc = parser.parseFromString(responseDivs[responseDivs.length - 1].innerHTML, 'text/html');
if(!mztaKeepFormatting) { // Return only TEXT
// Select the div with class 'empty:hidden'
let correct_div = responseDivs[responseDivs.length - 1].querySelector('div[data-message-author-role="assistant"]');
response = correct_div.textContent;
//console.log(">>>>>>>>>> response: " + response);
response = response.replace(/^ChatGPT(?:ChatGPT)?/, ''); // strip sender name
response = response.trim().replace(/^"|"$/g, ''); // strip quotation marks
response = "<body><p>" + response + "</p></body>";
//console.log(">>>>>>>>> response: " + JSON.stringify(response));
let parser_2 = new DOMParser();
let doc_response = parser_2.parseFromString(response, 'text/html');
//console.log(">>>>>>>>> doc_response: " + JSON.stringify(doc_response.body.innerHTML));
replaceNewlinesWithBr(doc_response.body)
response = doc_response.body.innerHTML;
} else { // Return HTML
// Tags to exclude
//console.log(">>>>>>>>> doc.body.innerHTML original: " + doc.body.innerHTML);
const excludeTags = ['div', 'text', 'svg', 'path', 'button'];
const includeTags = ['p', 'ul'];
// removeTags(doc.body, excludeTags);
response = removeTagsAndReturnHTML(doc.body, excludeTags, includeTags)
//console.log(">>>>>>>>> doc.body.innerHTML final: " + doc.body.innerHTML);
// response = doc.body.innerHTML;
}
//console.log('chatgpt_getFromDOM final response: '+response);
//console.log('chatgpt_getFromDOM: [HTML] ' + responseDivs[responseDivs.length - 1].innerHTML.replace(/<div[^>]*>/gi, '').replace(/<\\/div>/gi, '').replace(/<svg[^>]*>/gi, '').replace(/<\\/svg>/gi, '').replace(/<path[^>]*>/gi, '').replace(/<\\/path>/gi, '').replace(/<text[^>]*>/gi, '').replace(/<\\/text>/gi, '').replace(/<span[^>]*>/gi, '').replace(/<\\/span>/gi, '').replace(/<button[^>]*>/gi, '').replace(/<\\/button>/gi, ''));
} else { // get nth response --- HERE ONLY TEXT FROM RESPONSE, NO HTML
const nthOfResponse = (
// Calculate base number
Number.isInteger(pos) ? pos : // do nothing for integers
/^\d+/.test(strPos) ? /^\d+/.exec(strPos)[0] : // extract first digits for strings w/ them
( // convert words to integers for digitless strings
/^(?:1|one|fir)(?:st)?$/.test(strPos) ? 1
: /^(?:2|tw(?:o|en|el(?:ve|f))|seco)(?:nd|t[yi])?(?:e?th)?$/.test(strPos) ? 2
: /^(?:3|th(?:ree|ir?))(?:rd|teen|t[yi])?(?:e?th)?$/.test(strPos) ? 3
: /^(?:4|fou?r)(?:teen|t[yi])?(?:e?th)?$/.test(strPos) ? 4
: /^(?:5|fi(?:ve|f))(?:teen|t[yi])?(?:e?th)?$/.test(strPos) ? 5
: /^(?:6|six)(?:teen|t[yi])?(?:e?th)?$/.test(strPos) ? 6
: /^(?:7|seven)(?:teen|t[yi])?(?:e?th)?$/.test(strPos) ? 7
: /^(?:8|eight?)(?:teen|t[yi])?(?:e?th)?$/.test(strPos) ? 8
: /^(?:9|nine?)(?:teen|t[yi])?(?:e?th)?$/.test(strPos) ? 9
: /^(?:10|ten)(?:th)?$/.test(strPos) ? 10 : 1 )
// Transform base number if suffixed
* ( /(ty|ieth)$/.test(strPos) ? 10 : 1 ) // x 10 if -ty/ieth
+ ( /teen(th)?$/.test(strPos) ? 10 : 0 ) // + 10 if -teen/teenth
);
response = responseDivs[nthOfResponse - 1].textContent;
}
//console.log('>>>>>>>>>>>>>> chatgpt_getFromDOM: ' + JSON.stringify(response));
}
return response;
}
function chatpgt_scrollToBottom () {
try { document.querySelector('button[class*="cursor"][class*="bottom"]').click(); }
catch (err) { console.error('[ThunderAI] ', err); }
@ -141,6 +77,8 @@ function addCustomDiv(prompt_action,tabId,mailMessageId) {
style.textContent += "body {padding-bottom: 100px;} [id^='headlessui-dialog-panel-:r']{padding-bottom: 100px;}";
style.textContent += ".mzta-btn {background-color: #007bff;border: none;color: white;padding: 8px 15px;text-align: center;text-decoration: none;display: inline-block;font-size: 16px;margin: 4px 2px;transition-duration: 0.4s;cursor: pointer;border-radius: 5px;}";
style.textContent += ".mzta-btn:hover {background-color:#0056b3;color:white;}";
style.textContent += ".btn_disabled {background-color: #6a829b !important;color: white !important;cursor: not-allowed;}";
style.textContent += ".btn_disabled:hover {background-color:#6a829b !important;color:white !important;}";
style.textContent += "#mzta-loading{height:50px;display:inline-block;}";
style.textContent += "#mzta-model_warn{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);max-height:100%px;min-width:30%;max-width:50%;padding:3px;border-radius:5px;text-align:center;background-color:#FFBABA;border:1px solid;font-size:13px;color:#D8000C;display:none;}#mzta-model_warn a{color:blue;text-decoration: underline;}";
style.textContent += "#mzta-btn_gpt35 {background-color: #007bff;border: none;color: white;padding: 2px 4px;text-align: center;text-decoration: none;display: none;font-size: 13px;margin-left: 4px;transition-duration: 0.4s;cursor: pointer;border-radius: 2px;}";
@ -225,18 +163,20 @@ function addCustomDiv(prompt_action,tabId,mailMessageId) {
};
break;
case "1": // do reply
btn_ok.disabled = true;
btn_ok.textContent = browser.i18n.getMessage("chatgpt_win_get_answer");
btn_ok.onclick = async function() {
const response = await chatgpt_getFromDOM('last');
const response = getSelectedHtml();
browser.runtime.sendMessage({command: "chatgpt_replyMessage", text: response, tabId: tabId, mailMessageId: mailMessageId});
//console.log(response);
browser.runtime.sendMessage({command: "chatgpt_close"});
};
break;
case "2": // replace text
btn_ok.disabled = true;
btn_ok.textContent = browser.i18n.getMessage("chatgpt_win_get_answer");
btn_ok.onclick = async function() {
const response = await chatgpt_getFromDOM('last');
const response = getSelectedHtml();
//console.log('replace text: '+tabId)
browser.runtime.sendMessage({command: "chatgpt_replaceSelectedText", text: response, tabId: tabId, mailMessageId: mailMessageId});
//console.log(response);
@ -320,6 +260,9 @@ function checkGPT4Model() {
function operation_done(){
let curr_msg = document.getElementById('mzta-curr_msg');
curr_msg.textContent = browser.i18n.getMessage("chatgpt_win_job_completed");
if(current_action != '0'){
curr_msg.textContent += " " + browser.i18n.getMessage("chatgpt_win_job_completed_select");
}
curr_msg.style.display = 'block';
document.getElementById('mzta-btn_ok').style.display = 'inline';
document.getElementById('mzta-loading').style.display = 'none';
@ -416,6 +359,113 @@ function replaceNewlinesWithBr(node) {
}
}
function getSelectedHtml() {
// Get the Selection object
var selection = window.getSelection();
if (selection.rangeCount > 0) {
// Get the first selected range
var range = selection.getRangeAt(0);
// Create a new temporary div
var tempDiv = document.createElement("div");
// Clone the contents of the range into the temporary div
tempDiv.appendChild(range.cloneContents());
// Return the HTML of the selected content
return tempDiv.innerHTML.replace(/^<p>&quot;/, '<p>').replace(/&quot;<\\/p>$/, '</p>'); // strip quotation marks;
}
return "";
}
function isSomethingSelected() {
// Get the Selection object
var selection = window.getSelection();
// Check if the selection range count is greater than 0 and the selection is not empty
return selection.rangeCount > 0 && !selection.isCollapsed;
}
document.addEventListener("selectionchange", function() {
// Clear any previous timeout to reset the delay
clearTimeout(selectionChangeTimeout);
if(current_action === '0'){
return;
}
// Set a timeout to delay the execution of the callback
selectionChangeTimeout = setTimeout(function() {
let btn_ok = document.getElementById('mzta-btn_ok');
if (isSomethingSelected()) {
btn_ok.disabled = false;
btn_ok.classList.remove('btn_disabled');
} else {
btn_ok.disabled = true;
btn_ok.classList.add('btn_disabled');
}
}, 300); // Delay in milliseconds
});
function selectContentOnMouseDown(event) {
// Reset the dragging flag when the mouse is pressed down
isDragging = false;
}
function selectContentOnMouseMove(event) {
// Set the dragging flag to true if the mouse moves
isDragging = true;
}
function selectContentOnMouseUp(event) {
var excludedArea = document.querySelector('.mzta-header-fixed');
if (excludedArea && excludedArea.contains(event.target)) {
// If the click was inside the excluded area, do nothing
return;
}
if ((!isDragging)&&(!isSomethingSelected())) {
// If no dragging has occurred, execute the selection code
selectContentOnClick(event);
}
// Remove the event listeners to prevent future executions
// document.removeEventListener('mousedown', selectContentOnMouseDown);
// document.removeEventListener('mousemove', selectContentOnMouseMove);
// document.removeEventListener('mouseup', selectContentOnMouseUp);
}
function selectContentOnClick(event) {
if(current_action === '0'){
return;
}
// Prevent the default behavior of the click
event.preventDefault();
// Get the element that was clicked
var clickedElement = event.target;
// Traverse the DOM upwards to find the nearest parent div
var parentDiv = clickedElement.closest('div');
if (parentDiv) {
// Create a range object
var range = document.createRange();
// Select the contents of the div
range.selectNodeContents(parentDiv);
// Get the selection object
var selection = window.getSelection();
// Clear any existing selections
selection.removeAllRanges();
// Add the new range to the selection
selection.addRange(range);
}
}
// In the content script
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
@ -424,6 +474,7 @@ browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
// User not logged in
alert(browser.i18n.getMessage("chatgpt_user_not_logged_in"));
}else{
current_action = message.action;
addCustomDiv(message.action,message.tabId,message.mailMessageId);
(async () => {
if(mztaDoCustomText === 1){
@ -432,6 +483,10 @@ browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
} 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);
})();
}
}

View file

@ -196,7 +196,6 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_
let mztaForceCompletionDesc="`+ browser.i18n.getMessage("chatgpt_force_completion") +`";
let mztaForceCompletionTitle="`+ browser.i18n.getMessage("chatgpt_force_completion_title") +`";
let mztaDoCustomText=`+ do_custom_text +`;
let mztaKeepFormatting=`+ prefs.chatgpt_keep_formatting +`;
let mztaPromptName="[`+ i18nConditionalGet(prompt_name) +`]";
`;

View file

@ -20,7 +20,6 @@ export const prefs_default = {
chatgpt_win_height: 800,
chatgpt_win_width: 700,
chatpgt_use_gpt4: false,
chatgpt_keep_formatting: false,
default_chatgpt_lang: '',
connection_type: 'chatgpt_web', //Other values: 'chatgpt_api'
chatgpt_api_key: '',

View file

@ -75,17 +75,6 @@
</td>
</tr>
<tr>
<tr class="conntype_chatgpt_web">
<td><label>
<span>__MSG_prefs_OptionText_chatpgt_keep_formatting__</span>
</label></td>
<td>
<label>
<input type="checkbox" id="chatgpt_keep_formatting" name="chatgpt_keep_formatting" class="option-input" />
&nbsp;<span>__MSG_prefs_OptionText_chatpgt_keep_formatting_info__</span>
</label>
</td>
</tr>
<tr class="conntype_chatgpt_web">
<td><label>
<span>__MSG_prefs_OptionText_chatpgt_use_gpt4__</span>

View file

@ -9,14 +9,15 @@
<div id="miczRelNotes"><h1>ThunderAI Release Notes</h1>
<h2>Version 2.0.2 - ??/??/2024</h2>
<ul>
<li>Added a better error message when there is an error fetching models.</li>
<li><i>[ChatGPT Web]</i> Now, the ChatGPT response must be selected by the user to be retrieved by ThunderAI. A single click on the text should work, but it's also possible to select the text manually [<a href="https://github.com/micz/ThunderAI/issues/104">#104</a>].</li>
<li><i>[ChatGPT API]</i> Added a better error message when there is an error fetching models.</li>
<li>When selecting a correct model in the options page, the field is no more highlighted in red [<a href="https://github.com/micz/ThunderAI/issues/100">#100</a>].</li>
<li>When using the ChatGPT API, the double quotes at the beginning and end of the response are removed [<a href="https://github.com/micz/ThunderAI/issues/99">#99</a>].</li>
<li><i>[ChatGPT API]</i> The double quotes at the beginning and end of the response are removed [<a href="https://github.com/micz/ThunderAI/issues/99">#99</a>].</li>
<li>...</li>
</ul>
<h2>Version 2.0.1 - 09/08/2024</h2>
<ul>
<li>No more notifying a missing API Key or model when using the web interface.</li>
<li><i>[ChatGPT Web]</i> No more notifying a missing API Key or model when using the web interface.</li>
</ul>
<h2>Version 2.0.0 - 30/07/2024</h2>
<ul>