diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c17867..cbd2985 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Removed langage - Added a button next to model to get the last ChatGPT version +- Added update message ## v1.0.0 diff --git a/README.md b/README.md index a0d4bd7..81114df 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ If MoodleGPT cannot complete one of your moodle quiz please provide the html cod ## Set up -Go to "Manage my extensions" on your browser, then click on "Load unpacked extension" and select the "extension" folder. Afterwards, click on the extension icons and enter the apiKey obtained from [openai](https://platform.openai.com/). Finally, enter a code that will activate the extension on your moodle page and click on the save button (The extension need to be configured before entering the moodle quiz). +Go to "Manage my extensions" on your browser, then click on "Load unpacked extension" and select the "extension" folder. Afterwards, click on the extension icons and enter the apiKey obtained from [openai](https://platform.openai.com/). Afterward, enter a code that will activate the extension on your moodle page. Finally, click one the reload button next to model and click on the save button (The extension need to be configured before entering the moodle quiz). ## Inject the code into the moodle @@ -38,7 +38,7 @@ Type back the code on the keyboard and the code will be removed from the - Api key: the openai api key. - Code: code that you will need to inject/remove the code. -- GPT Model: the gpt model you want to use (by default it's "gpt-3.5-turbo"). You can click on the reload button to get the latest version of available gpt model for your account but you need to enter the api key first. +- GPT Model: the gpt model you want to use. You can click on the reload button to get the latest version of available gpt model for your account but you need to enter the api key first. - Cursor indication: show a pointer cursor and a hourglass to know when the request is finished. - Title indication: show some informations into the title to know for example if the code have been injected.
![Injected](./assets/title-injected.png) diff --git a/assets/popup.png b/assets/popup.png index 0348af3..33be609 100644 Binary files a/assets/popup.png and b/assets/popup.png differ diff --git a/extension/popup/index.html b/extension/popup/index.html index da3c28b..c62ec07 100644 --- a/extension/popup/index.html +++ b/extension/popup/index.html @@ -6,7 +6,8 @@ MoodleGPT - + + icon -

MoodleGPT

+
+

MoodleGPT

+

+
@@ -36,7 +40,7 @@
- + (message.style.display = "none"), 5000); -} - -//save the configuration -saveBtn.addEventListener("click", function () { - const [apiKey, code, model] = inputsText.map((selector) => - document.querySelector("#" + selector).value.trim() - ); - const [logs, title, cursor, typing, mouseover, infinite, table, timeout] = - inputsCheckbox.map( - (selector) => document.querySelector("#" + selector).checked - ); - - if (!apiKey || !code || !model) { - showMessage("Please complete all the form"); - return; - } - - if (code.length < 3) { - showMessage("The code should at least contain 3 characters"); - return; - } - - chrome.storage.sync.set({ - moodleGPT: { - apiKey, - code, - model, - logs, - title, - cursor, - typing, - mouseover, - infinite, - table, - timeout, - }, - }); - - showMessage("Configuration saved", true); -}); - -//we load back the configuration -chrome.storage.sync.get(["moodleGPT"]).then(function (storage) { - const config = storage.moodleGPT; - - if (config) { - inputsText.forEach((key) => - config[key] - ? (document.querySelector("#" + key).value = config[key]) - : null - ); - inputsCheckbox.forEach( - (key) => (document.querySelector("#" + key).checked = config[key] || "") - ); - } - - //getting the last chatgpt version - const apiKeySelector = document.querySelector("#apiKey"); - const reloadModel = document.querySelector("#reloadModel"); - - let apiKey = apiKeySelector.value; - - function checkFiledApiKey() { - if (apiKey) { - reloadModel.removeAttribute("disabled"); - reloadModel.setAttribute("title", "Get last ChatGPT version"); - return; - } - - reloadModel.setAttribute("disabled", true); - reloadModel.setAttribute("title", "Provide an api key first"); - } - - checkFiledApiKey(); - - apiKeySelector.addEventListener("change", function (event) { - apiKey = apiKeySelector.value.trim(); - checkFiledApiKey(); - }); - - reloadModel.addEventListener("click", async function () { - if (!apiKey) return; - try { - const req = await fetch("https://api.openai.com/v1/models", { - headers: { - Authorization: `Bearer ${apiKey}`, - }, - }); - const rep = await req.json(); - const model = rep.data.find((model) => model.id.includes("gpt")); - document.querySelector("#model").value = model.root; - } catch (err) { - console.error(err); - showMessage("Failed to fetch last ChatGPT version"); - } - }); -}); +const saveBtn = document.querySelector(".save"); +const message = document.querySelector("#message"); + +const inputsText = ["apiKey", "code", "model"]; +const inputsCheckbox = [ + "logs", + "title", + "cursor", + "typing", + "mouseover", + "infinite", + "table", + "timeout", +]; + +function showMessage(messageTxt, valide) { + message.style.color = valide ? "limegreen" : "red"; + message.textContent = messageTxt; + message.style.display = "block"; + setTimeout(() => (message.style.display = "none"), 5000); +} + +//save the configuration +saveBtn.addEventListener("click", function () { + const [apiKey, code, model] = inputsText.map((selector) => + document.querySelector("#" + selector).value.trim() + ); + const [logs, title, cursor, typing, mouseover, infinite, table, timeout] = + inputsCheckbox.map( + (selector) => document.querySelector("#" + selector).checked + ); + + if (!apiKey || !code || !model) { + showMessage("Please complete all the form"); + return; + } + + if (code.length < 3) { + showMessage("The code should at least contain 3 characters"); + return; + } + + chrome.storage.sync.set({ + moodleGPT: { + apiKey, + code, + model, + logs, + title, + cursor, + typing, + mouseover, + infinite, + table, + timeout, + }, + }); + + showMessage("Configuration saved", true); +}); + +//we load back the configuration +chrome.storage.sync.get(["moodleGPT"]).then(function (storage) { + const config = storage.moodleGPT; + + if (config) { + inputsText.forEach((key) => + config[key] + ? (document.querySelector("#" + key).value = config[key]) + : null + ); + inputsCheckbox.forEach( + (key) => (document.querySelector("#" + key).checked = config[key] || "") + ); + } + + getLastChatGPTVersion(); +}); + +//getting the last chatgpt version +function getLastChatGPTVersion() { + const apiKeySelector = document.querySelector("#apiKey"); + const reloadModel = document.querySelector("#reloadModel"); + + let apiKey = apiKeySelector.value; + + function checkFiledApiKey() { + if (apiKey) { + reloadModel.removeAttribute("disabled"); + reloadModel.setAttribute("title", "Get last ChatGPT version"); + return; + } + + reloadModel.setAttribute("disabled", true); + reloadModel.setAttribute("title", "Provide an api key first"); + } + + checkFiledApiKey(); + + apiKeySelector.addEventListener("change", function (event) { + apiKey = apiKeySelector.value.trim(); + checkFiledApiKey(); + }); + + reloadModel.addEventListener("click", async function () { + if (!apiKey) return; + try { + const req = await fetch("https://api.openai.com/v1/models", { + headers: { + Authorization: `Bearer ${apiKey}`, + }, + }); + const rep = await req.json(); + const model = rep.data.find((model) => model.id.includes("gpt")); + document.querySelector("#model").value = model.root; + } catch (err) { + console.error(err); + showMessage("Failed to fetch last ChatGPT version"); + } + }); +} diff --git a/extension/popup/js/version.js b/extension/popup/js/version.js new file mode 100644 index 0000000..b40a183 --- /dev/null +++ b/extension/popup/js/version.js @@ -0,0 +1,39 @@ +const currentVersion = "1.0.1"; +const versionDisplay = document.querySelector("#version"); + +async function getLastVersion() { + const req = await fetch( + "https://raw.githubusercontent.com/yoannchb-pro/MoodleGPT/main/package.json" + ); + const rep = await req.json(); + return rep.version; +} + +function setVersion(version, isCurrent = true) { + if (isCurrent) { + versionDisplay.textContent = "v" + version; + return; + } + + const link = document.createElement("a"); + link.href = "https://github.com/yoannchb-pro/MoodleGPT"; + link.rel = "noopener noreferrer"; + link.target = "_blank"; + link.textContent = "v" + version; + versionDisplay.appendChild(link); + versionDisplay.appendChild(document.createTextNode(" is now available !")); +} + +async function notifyUpdate() { + const lastVersion = await getLastVersion().catch((err) => { + console.error(err); + return currentVersion; + }); + if (currentVersion !== lastVersion) { + setVersion(lastVersion, false); + } else { + setVersion(currentVersion); + } +} + +notifyUpdate(); diff --git a/extension/popup/style.css b/extension/popup/style.css index ecf51c8..afba749 100644 --- a/extension/popup/style.css +++ b/extension/popup/style.css @@ -40,7 +40,7 @@ img { margin-top: 0.75rem; } -h1 { +.title { margin-top: 0.75rem; margin-bottom: 0.75rem; } @@ -98,6 +98,10 @@ a { margin-bottom: 0.75rem; } +#version { + font-size: 0.75rem; +} + #message { display: none; margin-top: 0.75rem;