From 9a19173f41491c084054d6002a9f58cfdebefe81 Mon Sep 17 00:00:00 2001 From: ran Date: Wed, 31 May 2023 16:27:54 +0800 Subject: [PATCH 01/37] adjustment structure --- background.js | 6 +- manifest.json | 23 +++-- options/options.html | 208 +++++++++++++++++++++++++++++++++++++++++++ options/options.js | 86 ++++++++++++++++++ options/styles.css | 3 + src/animation.js | 115 ++++++++++++++++++++++++ src/api.js | 96 ++++++++++++++++++++ src/content.js | 181 +++++++++++++++++++++++++++++++++++++ src/preferences.js | 57 ++++++++++++ src/state.js | 14 +++ src/utility.js | 199 +++++++++++++++++++++++++++++++++++++++++ 11 files changed, 980 insertions(+), 8 deletions(-) create mode 100644 options/options.html create mode 100644 options/options.js create mode 100644 options/styles.css create mode 100644 src/animation.js create mode 100644 src/api.js create mode 100644 src/content.js create mode 100644 src/preferences.js create mode 100644 src/state.js create mode 100644 src/utility.js diff --git a/background.js b/background.js index 1ff8e7e..811f4cd 100644 --- a/background.js +++ b/background.js @@ -5,19 +5,19 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { }); return true; // Required to use sendResponse asynchronously } - else if (request.type === "getUrl"){ + else if (request.type === "getBigcodeServiceUrl"){ chrome.storage.sync.get("otherService", (data) => { sendResponse({ otherServiceUrl: data.otherService }); }); return true; // Required to use sendResponse asynchronously } - else if(request.type === "getChecked"){ + else if(request.type === "getCheckedMode"){ chrome.storage.sync.get("checked", (data) => { sendResponse({ checked: data.checked }); }); return true; // Required to use sendResponse asynchronously } - else if(request.type === "getModelType"){ + else if(request.type === "getGPTModelType"){ chrome.storage.sync.get("modelType", (data) => { sendResponse({ modelType: data.modelType }); }); diff --git a/manifest.json b/manifest.json index d60554f..33e8a68 100644 --- a/manifest.json +++ b/manifest.json @@ -12,17 +12,30 @@ "storage" ], "action": { - "default_popup": "options.html" + "default_popup": "options/options.html" }, "background": { "service_worker": "background.js" }, "content_scripts": [ { - "matches": ["*://*.jupyter.org/*", "*://localhost:*/*", "*://127.0.0.1:*/*"], - "js": ["content.js"], - "css": ["styles.css"], + "matches": [ + "*://*.jupyter.org/*", + "*://localhost:*/*", + "*://127.0.0.1:*/*" + ], + "js": [ + "src/api.js", + "src/state.js", + "src/preferences.js", + "src/utility.js", + "src/animation.js", + "src/content.js" + ], + "css": [ + "options/styles.css" + ], "run_at": "document_end" } ] -} +} \ No newline at end of file diff --git a/options/options.html b/options/options.html new file mode 100644 index 0000000..ab4632c --- /dev/null +++ b/options/options.html @@ -0,0 +1,208 @@ + + + + + + + + + +
+
+ Jupyter Coder +
+
+
BigCode Url:
+
+
Huggingface Api Key:
+
+
+ +
+
OpenAI API Key:
+
+ + + +
+ + +
+ + + + + + +
+ + + +
+ + + + + + \ No newline at end of file diff --git a/options/options.js b/options/options.js new file mode 100644 index 0000000..25f7ce6 --- /dev/null +++ b/options/options.js @@ -0,0 +1,86 @@ +// 获取所有的单选框 +const radioButtons = document.querySelectorAll('input[type="radio"]'); +const select = document.querySelector('select'); + +// 获取当前被选中的单选框的值 +function getSelectedRadioValue() { + let selectedValue = null; + + radioButtons.forEach(radioButton => { + if (radioButton.checked) { + selectedValue = radioButton.id; + } + }); + + return selectedValue; +} + + +// Save the API key when the Save button is clicked +document.getElementById("save").addEventListener("click", () => { + chrome.storage.sync.set({ + openaiApiKey: document.getElementById("apiKey").value, + otherService: document.getElementById("otherServiceUrl").value, + huggingfaceApiKey: document.getElementById("huggingfaceApiKey").value, + modelType: select.value, + checked: getSelectedRadioValue() + }, () => { + alert("API key saved."); + }) +}); + +chrome.storage.sync.get("openaiApiKey", (data) => { + if (data.openaiApiKey) { + document.getElementById("apiKey").value = data.openaiApiKey; + } +}); + +chrome.storage.sync.get("huggingfaceApiKey", (data) => { + if (data.huggingfaceApiKey) { + document.getElementById("huggingfaceApiKey").value = data.huggingfaceApiKey; + } +}); + +chrome.storage.sync.get("otherService", (data) => { + if (data.otherService) { + document.getElementById("otherServiceUrl").value = data.otherService; + } else { + document.getElementById("otherServiceUrl").value = "https://api-inference.huggingface.co/models/bigcode/starcoderbase/" + } +}); + +chrome.storage.sync.get("modelType", (data) => { + if (data.modelType) { + select.value = data.modelType + } +}) + +chrome.storage.sync.get("checked", (data) => { + if (data.checked && data.checked == "openaiApiKey") { + document.getElementsByClassName('input-key')[0].classList.toggle("input-hidden") + document.getElementsByClassName('input-key')[1].classList.toggle("input-hidden") + var optionsElement = document.getElementsByName('options') + if(optionsElement[0].checked){ + optionsElement[0].checked = false + }else{ + optionsElement[0].checked = true + } + if(optionsElement[1].checked){ + optionsElement[1].checked = false + }else{ + optionsElement[1].checked = true + } + } +}) + +// 为每个单选框添加事件监听器 +radioButtons.forEach(radioButton => { + radioButton.addEventListener('change', function (event) { + if (event.target.checked) { + document.getElementsByClassName('input-key')[0].classList.toggle("input-hidden") + document.getElementsByClassName('input-key')[1].classList.toggle("input-hidden") + } + }); +}); + + diff --git a/options/styles.css b/options/styles.css new file mode 100644 index 0000000..316ecf2 --- /dev/null +++ b/options/styles.css @@ -0,0 +1,3 @@ +.greyed-suggestion { + color: #888; +} diff --git a/src/animation.js b/src/animation.js new file mode 100644 index 0000000..81cc57f --- /dev/null +++ b/src/animation.js @@ -0,0 +1,115 @@ +const animation = { + /* + Start requested animation + + Params: + activeTextarea: Textarea in active cell + + Returns: list, len == 3 + 0. animationInterval: Animation interval, can be cleared using the 'clearInterval' function + 1. animationElement: Animation dom element + 2. activeCellElement: The parent dom of the current cell + + */ + startWaitingAnimation(activeTextarea) { }, +} + + + +// left animation css +const loadCss = ` + .before-content:before { + content: ""; + position: absolute; + top: 5px; + left: 10px; + right: 0; + bottom: 0; + border: 3px solid rgba(0, 0, 0, 0.1); + border-left-color: #000; + border-radius: 50%; + width: 15px; + height: 15px; + animation: spin 1s linear infinite; + } + + @keyframes spin { + to { + transform: rotate(360deg); + } + } + .paused:before { + content: ""; + position: absolute; + top: 5px; + left: 10px; + right: 0; + bottom: 0; + border: 3px solid rgba(0, 0, 0, 0.1); + border-radius: 50%; + width: 15px; + height: 15px; + // animation: spin 1s linear infinite; + border-left-color: red; + } +`; + + + +animation.startWaitingAnimation = (activeTextarea) => { + const activeCellParentElement = activeTextarea.parentElement.parentElement.parentElement; + + // Create a new - - - - -
-
- Jupyter Coder -
-
-
BigCode Url:
-
-
Huggingface Api Key:
-
-
- -
-
OpenAI API Key:
-
- - - -
- - -
- - - - - - -
- - - -
- - - - - - \ No newline at end of file diff --git a/options.js b/options.js deleted file mode 100644 index 25f7ce6..0000000 --- a/options.js +++ /dev/null @@ -1,86 +0,0 @@ -// 获取所有的单选框 -const radioButtons = document.querySelectorAll('input[type="radio"]'); -const select = document.querySelector('select'); - -// 获取当前被选中的单选框的值 -function getSelectedRadioValue() { - let selectedValue = null; - - radioButtons.forEach(radioButton => { - if (radioButton.checked) { - selectedValue = radioButton.id; - } - }); - - return selectedValue; -} - - -// Save the API key when the Save button is clicked -document.getElementById("save").addEventListener("click", () => { - chrome.storage.sync.set({ - openaiApiKey: document.getElementById("apiKey").value, - otherService: document.getElementById("otherServiceUrl").value, - huggingfaceApiKey: document.getElementById("huggingfaceApiKey").value, - modelType: select.value, - checked: getSelectedRadioValue() - }, () => { - alert("API key saved."); - }) -}); - -chrome.storage.sync.get("openaiApiKey", (data) => { - if (data.openaiApiKey) { - document.getElementById("apiKey").value = data.openaiApiKey; - } -}); - -chrome.storage.sync.get("huggingfaceApiKey", (data) => { - if (data.huggingfaceApiKey) { - document.getElementById("huggingfaceApiKey").value = data.huggingfaceApiKey; - } -}); - -chrome.storage.sync.get("otherService", (data) => { - if (data.otherService) { - document.getElementById("otherServiceUrl").value = data.otherService; - } else { - document.getElementById("otherServiceUrl").value = "https://api-inference.huggingface.co/models/bigcode/starcoderbase/" - } -}); - -chrome.storage.sync.get("modelType", (data) => { - if (data.modelType) { - select.value = data.modelType - } -}) - -chrome.storage.sync.get("checked", (data) => { - if (data.checked && data.checked == "openaiApiKey") { - document.getElementsByClassName('input-key')[0].classList.toggle("input-hidden") - document.getElementsByClassName('input-key')[1].classList.toggle("input-hidden") - var optionsElement = document.getElementsByName('options') - if(optionsElement[0].checked){ - optionsElement[0].checked = false - }else{ - optionsElement[0].checked = true - } - if(optionsElement[1].checked){ - optionsElement[1].checked = false - }else{ - optionsElement[1].checked = true - } - } -}) - -// 为每个单选框添加事件监听器 -radioButtons.forEach(radioButton => { - radioButton.addEventListener('change', function (event) { - if (event.target.checked) { - document.getElementsByClassName('input-key')[0].classList.toggle("input-hidden") - document.getElementsByClassName('input-key')[1].classList.toggle("input-hidden") - } - }); -}); - - diff --git a/styles.css b/styles.css deleted file mode 100644 index 316ecf2..0000000 --- a/styles.css +++ /dev/null @@ -1,3 +0,0 @@ -.greyed-suggestion { - color: #888; -} From f2bba1f2698681a1beeee23ee53141c6448bc75a Mon Sep 17 00:00:00 2001 From: ran Date: Wed, 31 May 2023 16:39:10 +0800 Subject: [PATCH 03/37] Modify comments --- src/utility.js | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/utility.js b/src/utility.js index 21825cb..eea3b47 100644 --- a/src/utility.js +++ b/src/utility.js @@ -1,18 +1,26 @@ const utility = { /* - Start requested animation + Get Context Code text Params: - activeTextarea: Textarea in active cell - - Returns: list, len == 3 - 0. animationInterval: Animation interval, can be cleared using the 'clearInterval' function - 1. animationElement: Animation dom element - 2. activeCellElement: The parent dom of the current cell + activeCell: The cell dom that the user is operating on + checkedMode: openai or bigcode + currctJupyterModel: lab or notebook + Returns: str + Returns the corresponding formatting code based on the request mode selected by the current user */ + getCellContentText(activeCell, checkedMode, currctJupyterModel) { }, - insertSuggestion(suggestion) { }, + + /* + Insert the code after the request + + Params: + suggestion: code after the request + activeRequestTextarea: The textarea dom that the user is operating on + */ + insertSuggestion(suggestion, activeRequestTextarea) { }, } From 6557afd7fb88c2588c2f598e4eaad89458975b54 Mon Sep 17 00:00:00 2001 From: ran Date: Wed, 31 May 2023 16:43:59 +0800 Subject: [PATCH 04/37] adjustment structure --- src/content.js | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/content.js b/src/content.js index eafc910..e1fe1ff 100644 --- a/src/content.js +++ b/src/content.js @@ -100,7 +100,7 @@ } // Adds an event listener for filling in code after the request is completed - const addFillCodeKeyListener = (event) => { + const fillCodeKeyListener = (event) => { if (event.ctrlKey && !state.isRequestInProgress && state.isRequestSuccessful) { event.preventDefault(); @@ -121,24 +121,22 @@ } }; + const requestCodeKeyListener = async (event) => { + // Check if the Ctrl + Space keys were pressed + if (event.ctrlKey && event.code === 'Space') { + // Block default events + event.preventDefault(); - const montedEventListener = () => { - document.addEventListener('keydown', async (event) => { - // Check if the Ctrl + Space keys were pressed - if (event.ctrlKey && event.code === 'Space') { - // Block default events - event.preventDefault(); - - if (state.isRequestInProgress || state.isRequestSuccessful) { - return - } - - await mainProcess() - + if (state.isRequestInProgress || state.isRequestSuccessful) { + return } + await mainProcess() + } + } - }); - document.addEventListener('keydown', addFillCodeKeyListener); + const montedEventListener = () => { + document.addEventListener('keydown', requestCodeKeyListener); + document.addEventListener('keydown', fillCodeKeyListener); } @@ -146,7 +144,7 @@ if (document.querySelector('body.notebook_app')) { montedEventListener() state.currctJupyterModel = notebookModel - + } else { // Create a new MutationObserver, This object will listen for changes in elements in the DOM and execute callback functions when changes occur const bodyObserver = new MutationObserver(function (mutations) { From 4d8b50317e18ddec67cdb6d530ab77d3fda3bcfa Mon Sep 17 00:00:00 2001 From: ran Date: Wed, 31 May 2023 19:54:06 +0800 Subject: [PATCH 05/37] fix removeJupyterOutput bug --- src/api.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/api.js b/src/api.js index 1fa4262..104212e 100644 --- a/src/api.js +++ b/src/api.js @@ -6,19 +6,19 @@ const api = { const removeJupyterOutput = (suggestion) => { suggestion = suggestion.replace("# -*- coding: utf-8 -*-\n\n", "") - const jupyterOutput = ''; + let outPutIndex = suggestion.indexOf('') + + if (outPutIndex != -1){ + suggestion = suggestion.slice(0, outPutIndex) + } const unnecessaryTag = '<|endoftext|>' const unnecessaryTagIndex = suggestion.indexOf(unnecessaryTag) - if (suggestion.endsWith(jupyterOutput)) { - let removedOutpoutSuggestion = suggestion.slice(0, -jupyterOutput.length); - return unnecessaryTagIndex == -1 ? removedOutpoutSuggestion : removedOutpoutSuggestion.slice(0, unnecessaryTagIndex) - } - return unnecessaryTagIndex == -1 ? suggestion : suggestion.slice(0, unnecessaryTagIndex) } + const removeOpenaiOutput = (suggestion) => { let outPutIndex = suggestion.indexOf("\n\n§ Output") From 651bd5e20b285e55e0fafa53c15297fad3f2ea09 Mon Sep 17 00:00:00 2001 From: ran Date: Wed, 31 May 2023 19:57:09 +0800 Subject: [PATCH 06/37] fix removeJupyterOutput bug --- src/api.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api.js b/src/api.js index 104212e..c90841f 100644 --- a/src/api.js +++ b/src/api.js @@ -72,7 +72,8 @@ api.sendToBigcode = async (code, url, token) => { inputs: prompt, stream: false, parameters: { - return_full_text: false + return_full_text: false, + stop: [""] } } From 0449e972f3a82afabdab32c049f4566235b62f85 Mon Sep 17 00:00:00 2001 From: ran Date: Wed, 31 May 2023 20:01:19 +0800 Subject: [PATCH 07/37] Modifying Fixbugs --- examples/sklearn_digits.ipynb | 26 +++++++++++++++++++++----- src/content.js | 13 +++++++++++++ src/state.js | 1 + 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/examples/sklearn_digits.ipynb b/examples/sklearn_digits.ipynb index c5736c0..76b09bc 100644 --- a/examples/sklearn_digits.ipynb +++ b/examples/sklearn_digits.ipynb @@ -7,7 +7,11 @@ "metadata": {}, "outputs": [], "source": [ - "# load Digits Dataset from sklearn\n" + "# load Digits Dataset from sklearn\n", + "from sklearn.datasets import load_digits\n", + "\n", + "# load dataset\n", + "digits = load_digits()" ] }, { @@ -22,11 +26,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "c164026e", "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(1797, 8, 8)\n" + ] + } + ], + "source": [ + "# print the shape of the images and labels\n", + "print(digits.images.shape)\n", + "print(digits.target.shape)" + ] }, { "cell_type": "markdown", @@ -63,7 +79,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.10" + "version": "3.10.11" } }, "nbformat": 4, diff --git a/src/content.js b/src/content.js index e1fe1ff..e268086 100644 --- a/src/content.js +++ b/src/content.js @@ -130,8 +130,21 @@ if (state.isRequestInProgress || state.isRequestSuccessful) { return } + + state.requestType = "normal" await mainProcess() + + }else if(event.ctrlKey && event.code === 'Backquote'){ + // Block default events + event.preventDefault(); + + if (state.isRequestInProgress || state.isRequestSuccessful) { + return + } + state.requestType = "fixBug" + await mainProcess() } + } const montedEventListener = () => { diff --git a/src/state.js b/src/state.js index 3f908ab..8415157 100644 --- a/src/state.js +++ b/src/state.js @@ -9,6 +9,7 @@ const state = { isRequestSuccessful: false, // Code to be filled in after request completion codeToFill: "", + requestType: "", } window.state = state \ No newline at end of file From 10cff1b6906e147d30d1ebc8f041678811aa7b23 Mon Sep 17 00:00:00 2001 From: ran Date: Wed, 31 May 2023 23:45:37 +0800 Subject: [PATCH 08/37] Change the new structure --- options/options.html | 15 ++- options/options.js | 33 +++--- src/api.js | 2 + src/content.js | 23 ++-- src/preferences.js | 12 +-- src/state.js | 1 - src/utility.js | 250 ++++++++++++++++++++++++++++--------------- 7 files changed, 201 insertions(+), 135 deletions(-) diff --git a/options/options.html b/options/options.html index ab4632c..6d39b96 100644 --- a/options/options.html +++ b/options/options.html @@ -164,9 +164,9 @@
BigCode Url:
-
-
Huggingface Api Key:
-
+
+
Huggingface Access Token:
+
@@ -183,15 +183,14 @@
- - -