Textbox, question to answser mode and clipboard mode is not formatted anymore

This commit is contained in:
yoannchb-pro
2023-06-20 14:29:29 -04:00
parent 6f40acd45f
commit 305f3e452d
15 changed files with 177 additions and 108 deletions
+3
View File
@@ -3,6 +3,9 @@
## v1.0.3
- Removed the option `table formating` because it will now set to true by default
- Adjusted the abort timeout to 15seconds
- If an error occur the user can now click back on the question
- `Textbox, question to answser mode and clipboard mode` is not formatted anymore
## v1.0.2
+1 -1
View File
@@ -3,7 +3,7 @@
## Priority: 1
- [ ] Increment question when there is statement
- [ ] Allow click back on question if timeout
- [ ] Original answer for text, clipboard and text to answer
## Priority: 3 (because hard to make)
+65 -43
View File
@@ -99,7 +99,10 @@
clearTimeout(timeoutControler);
const rep = yield req.json();
const response = rep.choices[0].message.content;
return normalizeText(response);
return {
response,
normalizedResponse: normalizeText(response),
};
});
}
@@ -155,15 +158,15 @@
* Handle checkbox and input elements
* @param config
* @param inputList
* @param response
* @param gptAnswer
*/
function handleRadioAndCheckbox(config, inputList, response) {
function handleRadioAndCheckbox(config, inputList, gptAnswer) {
const input = inputList === null || inputList === void 0 ? void 0 : inputList[0];
if (!input || (input.type !== "checkbox" && input.type !== "radio"))
return false;
for (const input of inputList) {
const content = normalizeText(input.parentNode.textContent);
const valide = response.includes(content);
const valide = gptAnswer.normalizedResponse.includes(content);
if (config.logs)
Logs.responseTry(content, valide);
if (valide) {
@@ -184,15 +187,15 @@
* Handle select elements (and put in order select)
* @param config
* @param inputList
* @param response
* @param gptAnswer
* @returns
*/
function handleSelect(config, inputList, response) {
function handleSelect(config, inputList, gptAnswer) {
if (inputList.length === 0 || inputList[0].tagName !== "SELECT")
return false;
let correct = response.split("\n");
let correct = gptAnswer.normalizedResponse.split("\n");
if (correct.length === 1 && correct.length !== inputList.length)
correct = response.split(",");
correct = gptAnswer.normalizedResponse.split(",");
if (config.logs)
Logs.array(correct);
for (let j = 0; j < inputList.length; ++j) {
@@ -248,10 +251,10 @@
* Handle textbox
* @param config
* @param inputList
* @param response
* @param gptAnswer
* @returns
*/
function handleTextbox(config, inputList, response) {
function handleTextbox(config, inputList, gptAnswer) {
const input = inputList[0];
if (inputList.length !== 1 ||
(input.tagName !== "TEXTAREA" && input.type !== "text"))
@@ -260,15 +263,15 @@
let index = 0;
input.addEventListener("keydown", function (event) {
if (event.key === "Backspace")
index = response.length + 1;
if (index > response.length)
index = gptAnswer.response.length + 1;
if (index > gptAnswer.response.length)
return;
event.preventDefault();
input.value = response.slice(0, ++index);
input.value = gptAnswer.response.slice(0, ++index);
});
}
else {
input.value = response;
input.value = gptAnswer.response;
}
return true;
}
@@ -276,30 +279,28 @@
/**
* Copy the response in the clipboard if we can automaticaly fill the question
* @param config
* @param inputList
* @param response
* @param force Force the copy to clipboard
* @returns
* @param gptAnswer
*/
function handleClipboard(config, response) {
function handleClipboard(config, gptAnswer) {
if (config.title)
titleIndications("Copied to clipboard");
navigator.clipboard.writeText(response);
navigator.clipboard.writeText(gptAnswer.response);
}
/**
* Handle number input
* @param config
* @param inputList
* @param response
* @param gptAnswer
* @returns
*/
function handleNumber(config, inputList, response) {
function handleNumber(config, inputList, gptAnswer) {
var _a, _b;
const input = inputList[0];
if (inputList.length !== 1 || input.type !== "number")
return false;
const number = (_b = (_a = response.match(/\d+([,\.]\d+)?/gi)) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.replace(",", ".");
const number = (_b = (_a = gptAnswer.normalizedResponse
.match(/\d+([,\.]\d+)?/gi)) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.replace(",", ".");
if (!number)
return false;
if (config.typing) {
@@ -321,7 +322,14 @@
return true;
}
function handleContentEditable(config, inputList, response) {
/**
* Hanlde contenteditable elements
* @param config
* @param inputList
* @param gptAnswer
* @returns
*/
function handleContentEditable(config, inputList, gptAnswer) {
const input = inputList[0];
if (inputList.length !== 1 ||
input.getAttribute("contenteditable") !== "true")
@@ -330,11 +338,11 @@
let index = 0;
input.addEventListener("keydown", function (event) {
if (event.key === "Backspace")
index = response.length + 1;
if (index > response.length)
index = gptAnswer.response.length + 1;
if (index > gptAnswer.response.length)
return;
event.preventDefault();
input.textContent = response.slice(0, ++index);
input.textContent = gptAnswer.response.slice(0, ++index);
/* Put the cursor at the end of the typed text */
input.focus();
const range = document.createRange();
@@ -346,7 +354,7 @@
});
}
else {
input.textContent = response;
input.textContent = gptAnswer.response;
}
return true;
}
@@ -365,33 +373,41 @@
hiddenButton.style.cursor = "wait";
const question = createQuestion(config, form);
const inputList = form.querySelectorAll(query);
const response = yield getChatGPTResponse(config, question).catch((error) => ({
const gptAnswer = yield getChatGPTResponse(config, question).catch((error) => ({
error,
}));
const haveError = typeof response === "object" && "error" in response;
const haveError = typeof gptAnswer === "object" && "error" in gptAnswer;
if (config.cursor)
hiddenButton.style.cursor =
config.infinite || haveError ? "pointer" : "initial";
if (haveError) {
console.error(response.error);
console.error(gptAnswer.error);
return;
}
if (config.logs) {
Logs.question(question);
Logs.response(response);
Logs.response("Original: " + gptAnswer.response);
Logs.response("Normalized: " + gptAnswer.normalizedResponse);
}
/* Handle clipboard mode */
if (config.mode === "clipboard") {
return handleClipboard(config, response);
if (!config.infinite)
removeListener(hiddenButton);
return handleClipboard(config, gptAnswer);
}
/* Handle question to answer mode */
if (config.mode === "question-to-answer") {
removeListener(hiddenButton);
const questionBackup = form.textContent;
const questionContainer = form.querySelector(".qtext");
questionContainer.textContent = response;
questionContainer.textContent = gptAnswer.response;
questionContainer.style.whiteSpace = "pre-wrap";
questionContainer.addEventListener("click", function () {
questionContainer.textContent =
questionContainer.textContent === questionBackup
? response
: questionBackup;
const isNotResponse = questionContainer.textContent === questionBackup;
questionContainer.style.whiteSpace = isNotResponse ? "pre-wrap" : null;
questionContainer.textContent = isNotResponse
? gptAnswer.response
: questionBackup;
});
return;
}
@@ -403,18 +419,17 @@
handleRadioAndCheckbox,
];
for (const handler of handlers) {
if (handler(config, inputList, response))
if (handler(config, inputList, gptAnswer))
return;
}
/* In the case we can't auto complete the question */
handleClipboard(config, response);
handleClipboard(config, gptAnswer);
/* Better then set once on the event because if there is an error the user can click an other time on the question */
if (!config.infinite)
hiddenButton.removeEventListener("click", injectionFunction);
removeListener(hiddenButton);
});
}
let injectionFunction = null;
const pressedKeys = [];
const listeners = [];
/**
@@ -460,13 +475,20 @@
const hiddenButton = form.querySelector(".qtext");
if (config.cursor)
hiddenButton.style.cursor = "pointer";
injectionFunction = reply.bind(null, config, hiddenButton, form, query);
const injectionFunction = reply.bind(null, config, hiddenButton, form, query);
listeners.push({ element: hiddenButton, fn: injectionFunction });
hiddenButton.addEventListener("click", injectionFunction);
}
if (config.title)
titleIndications("Injected");
}
function removeListener(element) {
const index = listeners.findIndex((listener) => listener.element === element);
if (index !== -1) {
const listener = listeners.splice(index, 1)[0];
listener.element.removeEventListener("click", listener.fn);
}
}
chrome.storage.sync.get(["moodleGPT"]).then(function (storage) {
const config = storage.moodleGPT;
File diff suppressed because one or more lines are too long
+16 -3
View File
@@ -2,7 +2,6 @@ import Config from "../types/config";
import titleIndications from "../utils/title-indications";
import reply from "./reply";
let injectionFunction: (this: HTMLElement, ev: MouseEvent) => any = null;
const pressedKeys: string[] = [];
const listeners: {
element: HTMLElement;
@@ -53,7 +52,13 @@ function setUpMoodleGpt(config: Config) {
if (config.cursor) hiddenButton.style.cursor = "pointer";
injectionFunction = reply.bind(null, config, hiddenButton, form, query);
const injectionFunction = reply.bind(
null,
config,
hiddenButton,
form,
query
);
listeners.push({ element: hiddenButton, fn: injectionFunction });
hiddenButton.addEventListener("click", injectionFunction);
}
@@ -61,4 +66,12 @@ function setUpMoodleGpt(config: Config) {
if (config.title) titleIndications("Injected");
}
export { injectionFunction, codeListener };
function removeListener(element: HTMLElement) {
const index = listeners.findIndex((listener) => listener.element === element);
if (index !== -1) {
const listener = listeners.splice(index, 1)[0];
listener.element.removeEventListener("click", listener.fn);
}
}
export { codeListener, removeListener };
+6 -2
View File
@@ -1,4 +1,5 @@
import Config from "../types/config";
import GPTAnswer from "../types/gptAnswer";
import normalizeText from "../utils/normalize-text";
/**
@@ -10,7 +11,7 @@ import normalizeText from "../utils/normalize-text";
async function getChatGPTResponse(
config: Config,
question: string
): Promise<string> {
): Promise<GPTAnswer> {
const controller = new AbortController();
const timeoutControler = setTimeout(() => controller.abort(), 15000);
const req = await fetch("https://api.openai.com/v1/chat/completions", {
@@ -32,7 +33,10 @@ async function getChatGPTResponse(
clearTimeout(timeoutControler);
const rep = await req.json();
const response = rep.choices[0].message.content;
return normalizeText(response);
return {
response,
normalizedResponse: normalizeText(response),
};
}
export default getChatGPTResponse;
+4 -6
View File
@@ -1,17 +1,15 @@
import Config from "../../types/config";
import GPTAnswer from "../../types/gptAnswer";
import titleIndications from "../../utils/title-indications";
/**
* Copy the response in the clipboard if we can automaticaly fill the question
* @param config
* @param inputList
* @param response
* @param force Force the copy to clipboard
* @returns
* @param gptAnswer
*/
function handleClipboard(config: Config, response: string) {
function handleClipboard(config: Config, gptAnswer: GPTAnswer) {
if (config.title) titleIndications("Copied to clipboard");
navigator.clipboard.writeText(response);
navigator.clipboard.writeText(gptAnswer.response);
}
export default handleClipboard;
+13 -5
View File
@@ -1,9 +1,17 @@
import Config from "../../types/config";
import GPTAnswer from "../../types/gptAnswer";
/**
* Hanlde contenteditable elements
* @param config
* @param inputList
* @param gptAnswer
* @returns
*/
function handleContentEditable(
config: Config,
inputList: NodeListOf<HTMLElement>,
response: string
gptAnswer: GPTAnswer
): boolean {
const input = inputList[0];
@@ -16,10 +24,10 @@ function handleContentEditable(
if (config.typing) {
let index = 0;
input.addEventListener("keydown", function (event: KeyboardEvent) {
if (event.key === "Backspace") index = response.length + 1;
if (index > response.length) return;
if (event.key === "Backspace") index = gptAnswer.response.length + 1;
if (index > gptAnswer.response.length) return;
event.preventDefault();
input.textContent = response.slice(0, ++index);
input.textContent = gptAnswer.response.slice(0, ++index);
/* Put the cursor at the end of the typed text */
input.focus();
@@ -31,7 +39,7 @@ function handleContentEditable(
selection.addRange(range);
});
} else {
input.textContent = response;
input.textContent = gptAnswer.response;
}
return true;
+6 -3
View File
@@ -1,22 +1,25 @@
import Config from "../../types/config";
import GPTAnswer from "../../types/gptAnswer";
/**
* Handle number input
* @param config
* @param inputList
* @param response
* @param gptAnswer
* @returns
*/
function handleNumber(
config: Config,
inputList: NodeListOf<HTMLElement>,
response: string
gptAnswer: GPTAnswer
): boolean {
const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;
if (inputList.length !== 1 || input.type !== "number") return false;
const number = response.match(/\d+([,\.]\d+)?/gi)?.[0]?.replace(",", ".");
const number = gptAnswer.normalizedResponse
.match(/\d+([,\.]\d+)?/gi)?.[0]
?.replace(",", ".");
if (!number) return false;
+4 -3
View File
@@ -1,4 +1,5 @@
import Config from "../../types/config";
import GPTAnswer from "../../types/gptAnswer";
import Logs from "../../utils/logs";
import normalizeText from "../../utils/normalize-text";
@@ -6,12 +7,12 @@ import normalizeText from "../../utils/normalize-text";
* Handle checkbox and input elements
* @param config
* @param inputList
* @param response
* @param gptAnswer
*/
function handleRadioAndCheckbox(
config: Config,
inputList: NodeListOf<HTMLElement>,
response: string
gptAnswer: GPTAnswer
): boolean {
const input = inputList?.[0] as HTMLInputElement;
@@ -20,7 +21,7 @@ function handleRadioAndCheckbox(
for (const input of inputList as NodeListOf<HTMLInputElement>) {
const content = normalizeText(input.parentNode.textContent);
const valide = response.includes(content);
const valide = gptAnswer.normalizedResponse.includes(content);
if (config.logs) Logs.responseTry(content, valide);
if (valide) {
if (config.mouseover) {
+5 -4
View File
@@ -1,4 +1,5 @@
import Config from "../../types/config";
import GPTAnswer from "../../types/gptAnswer";
import Logs from "../../utils/logs";
import normalizeText from "../../utils/normalize-text";
@@ -6,19 +7,19 @@ import normalizeText from "../../utils/normalize-text";
* Handle select elements (and put in order select)
* @param config
* @param inputList
* @param response
* @param gptAnswer
* @returns
*/
function handleSelect(
config: Config,
inputList: NodeListOf<HTMLElement>,
response: string
gptAnswer: GPTAnswer
): boolean {
if (inputList.length === 0 || inputList[0].tagName !== "SELECT") return false;
let correct = response.split("\n");
let correct = gptAnswer.normalizedResponse.split("\n");
if (correct.length === 1 && correct.length !== inputList.length)
correct = response.split(",");
correct = gptAnswer.normalizedResponse.split(",");
if (config.logs) Logs.array(correct);
+7 -6
View File
@@ -1,16 +1,17 @@
import Config from "../../types/config";
import GPTAnswer from "../../types/gptAnswer";
/**
* Handle textbox
* @param config
* @param inputList
* @param response
* @param gptAnswer
* @returns
*/
function handleTextbox(
config: Config,
inputList: NodeListOf<HTMLElement>,
response: string
gptAnswer: GPTAnswer
): boolean {
const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;
@@ -23,13 +24,13 @@ function handleTextbox(
if (config.typing) {
let index = 0;
input.addEventListener("keydown", function (event: KeyboardEvent) {
if (event.key === "Backspace") index = response.length + 1;
if (index > response.length) return;
if (event.key === "Backspace") index = gptAnswer.response.length + 1;
if (index > gptAnswer.response.length) return;
event.preventDefault();
input.value = response.slice(0, ++index);
input.value = gptAnswer.response.slice(0, ++index);
});
} else {
input.value = response;
input.value = gptAnswer.response;
}
return true;
+25 -16
View File
@@ -8,7 +8,7 @@ import handleTextbox from "./questions/textbox";
import handleClipboard from "./questions/clipboard";
import handleNumber from "./questions/number";
import handleContentEditable from "./questions/contenteditable";
import { injectionFunction } from "./code-listener";
import { removeListener } from "./code-listener";
/**
* Reply to the question
@@ -29,41 +29,51 @@ async function reply(
const question = createQuestion(config, form);
const inputList: NodeListOf<HTMLElement> = form.querySelectorAll(query);
const response = await getChatGPTResponse(config, question).catch(
const gptAnswer = await getChatGPTResponse(config, question).catch(
(error) => ({
error,
})
);
const haveError = typeof response === "object" && "error" in response;
const haveError = typeof gptAnswer === "object" && "error" in gptAnswer;
if (config.cursor)
hiddenButton.style.cursor =
config.infinite || haveError ? "pointer" : "initial";
if (haveError) {
console.error(response.error);
console.error(gptAnswer.error);
return;
}
if (config.logs) {
Logs.question(question);
Logs.response(response);
Logs.response("Original: " + gptAnswer.response);
Logs.response("Normalized: " + gptAnswer.normalizedResponse);
}
/* Handle clipboard mode */
if (config.mode === "clipboard") {
return handleClipboard(config, response);
if (!config.infinite) removeListener(hiddenButton);
return handleClipboard(config, gptAnswer);
}
/* Handle question to answer mode */
if (config.mode === "question-to-answer") {
removeListener(hiddenButton);
const questionBackup = form.textContent;
const questionContainer = form.querySelector(".qtext");
questionContainer.textContent = response;
const questionContainer = form.querySelector<HTMLElement>(".qtext");
questionContainer.textContent = gptAnswer.response;
questionContainer.style.whiteSpace = "pre-wrap";
questionContainer.addEventListener("click", function () {
questionContainer.textContent =
questionContainer.textContent === questionBackup
? response
: questionBackup;
const isNotResponse = questionContainer.textContent === questionBackup;
questionContainer.style.whiteSpace = isNotResponse ? "pre-wrap" : null;
questionContainer.textContent = isNotResponse
? gptAnswer.response
: questionBackup;
});
return;
}
@@ -77,15 +87,14 @@ async function reply(
];
for (const handler of handlers) {
if (handler(config, inputList, response)) return;
if (handler(config, inputList, gptAnswer)) return;
}
/* In the case we can't auto complete the question */
handleClipboard(config, response);
handleClipboard(config, gptAnswer);
/* Better then set once on the event because if there is an error the user can click an other time on the question */
if (!config.infinite)
hiddenButton.removeEventListener("click", injectionFunction);
if (!config.infinite) removeListener(hiddenButton);
}
export default reply;
+15 -15
View File
@@ -1,15 +1,15 @@
type Config = {
apiKey: string;
code: string;
model?: string;
infinite?: boolean;
typing?: boolean;
mouseover?: boolean;
cursor?: boolean;
logs?: boolean;
title?: boolean;
timeout?: boolean;
mode?: "autocomplete" | "question-to-answer" | "clipboard";
};
export default Config;
type Config = {
apiKey: string;
code: string;
model?: string;
infinite?: boolean;
typing?: boolean;
mouseover?: boolean;
cursor?: boolean;
logs?: boolean;
title?: boolean;
timeout?: boolean;
mode?: "autocomplete" | "question-to-answer" | "clipboard";
};
export default Config;
+6
View File
@@ -0,0 +1,6 @@
type GPTAnswer = {
response: string;
normalizedResponse: string;
};
export default GPTAnswer;