From 409d70972f01ee658b17b64c0d571546f766af5c Mon Sep 17 00:00:00 2001 From: ran Date: Thu, 18 May 2023 10:40:07 +0800 Subject: [PATCH 01/22] Modify the acquisition user code logic --- content.js | 348 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 207 insertions(+), 141 deletions(-) diff --git a/content.js b/content.js index fd1b362..ee4cc98 100644 --- a/content.js +++ b/content.js @@ -5,7 +5,7 @@ async function getOpenAIKey() { }); }); } -async function getOtherServiceUrl() { +async function getBigcodeServiceUrl() { return new Promise((resolve) => { chrome.runtime.sendMessage({ type: "getUrl" }, (response) => { resolve(response.otherServiceUrl); @@ -35,6 +35,19 @@ async function getHuggingfaceApiKey() { } +function removeOpenaiOutput(suggestion) { + let outPutIndex = suggestion.indexOf("\n\n§ Output") + + if (outPutIndex == -1){ + let outPutIndex = suggestion.indexOf("\n\n# Output") + + return outPutIndex == -1 ? suggestion:suggestion.substring(0, outPutIndex) + }else{ + return suggestion.substring(0, outPutIndex) + } + +} + // Function to send request to OpenAI API async function sendToOpenAI(prompt) { const apiKey = await getOpenAIKey(); @@ -70,18 +83,23 @@ async function sendToOpenAI(prompt) { // Remove invisible characters suggestion = suggestion.replace(/\u200B/g, ''); - // This is an example of a possible return: " print('Hello World!')\n\nhello_world()\n\n§ Output… : ['Hello World!\\n']\n\n \n§ Markdown\n\n### Exercise" - const outPutIndex = suggestion.indexOf("\n\n§ Output") - if(outPutIndex == -1){ - return suggestion - }else{ - return suggestion.substring(0,outPutIndex) + return removeOpenaiOutput(suggestion) +} + + +function removeJupyterOutput(str) { + const jupyterOutput = ''; + + if (str.endsWith(jupyterOutput)) { + return str.slice(0, -jupyterOutput.length); } + return str; } -async function sendToOtherService(code) { - const url = await getOtherServiceUrl(); + +async function sendToBigcode(code) { + const url = await getBigcodeServiceUrl(); const token = await getHuggingfaceApiKey(); if (!url) { @@ -117,19 +135,20 @@ async function sendToOtherService(code) { async function getCodeCompletion(code) { const checked = await getChecked(); + // If the user has not selected openai or bigcode if (!checked) { alert("The request method is not selected."); return; } - if (checked == "openaiApiKey") { - return await sendToOpenAI(code) - } else if (checked == "otherService") { - return await sendToOtherService(code) + switch(checked){ + case "openaiApiKey": return await sendToOpenAI(code); + case "otherService": return await sendToBigcode(code); + default: return "" } -} +} // Code to be filled in after request completion @@ -167,176 +186,218 @@ function insertSuggestion(suggestion) { } +const getActiveCellPointerCode = (activeCell, cellIndex) => { + let cellContent = [] -const getActiveCellPointerCode = (activeCell) => { - let leftContext = "" - let rightContext = "" - - // get cursor element - const cursorElement = activeCell.querySelector('div.CodeMirror-cursor') + // get cursor element + const cursorElement = activeCell.querySelector('div.CodeMirror-cursor') - const style = window.getComputedStyle(cursorElement); + const style = window.getComputedStyle(cursorElement); - // 指针所在位置的偏移量 - const cursorOffsetLeft = Math.round(parseFloat(style.getPropertyValue('left'))) + // 指针所在位置的偏移量 + const cursorOffsetLeft = Math.round(parseFloat(style.getPropertyValue('left'))) - // Which line - const lineIndex = Math.round(parseFloat(style.getPropertyValue('top')) / 17) - - // Obtain element for all line - const linesElement = activeCell.getElementsByClassName('CodeMirror-line') - // code dom element length in active line - const codeElementWdth = linesElement[lineIndex].querySelector("span").offsetWidth - - // Determine whether the pointer is at the end of a line, Because there is a left marring, so -4, but due to precision issues so -3 - if(cursorOffsetLeft - 3 < codeElementWdth){ - return [null, null] - } + // Which line + const lineIndex = Math.round(parseFloat(style.getPropertyValue('top')) / 17) - for (let i = 0; i < linesElement.length; i++) { + // Obtain element for all line + const linesElement = activeCell.getElementsByClassName('CodeMirror-line') + // code dom element length in active line + const codeElementWdth = linesElement[lineIndex].querySelector("span").offsetWidth - if(i < lineIndex) { - leftContext += linesElement[i].textContent + "\n" - }else if(i == lineIndex){ - leftContext += linesElement[i].textContent - }else{ - if(i == linesElement.length-1){ - rightContext += linesElement[i].textContent - }else{ - rightContext += linesElement[i].textContent + "\n" - } - } + // Determine whether the pointer is at the end of a line, Because there is a left marring, so -4, but due to precision issues so -3 + if (cursorOffsetLeft - 3 < codeElementWdth) { + return [null, null] + } + for (let i = 0; i < linesElement.length; i++) { + if (i == lineIndex) { + cellContent.push({ + "content": linesElement[i].textContent, + "cellIndex": cellIndex, + "isCursor": true, + "type": "code", + "lineIndex": i + }) + } else { + cellContent.push({ + "content": linesElement[i].textContent, + "cellIndex": cellIndex, + "isCursor": false, + "type": "code", + "lineIndex": i + }) } - - return [leftContext, rightContext] + } + const outputElement = activeCell.querySelector(`.${currctJupyterModel.requiredClassName.output}`); + if (outputElement && currentCellType == "code") { + cellContent.push({ + "content": linesElement[i].textContent, + "cellIndex": cellIndex, + "isCursor": false, + "type": "output", + "lineIndex": i + }) + } + return cellContent } -function getCellContentTextRequiredForOpenAI(activeCell) { - const cellElements = Array.from(document.querySelectorAll(`.${currctJupyterModel.requiredClassName.cell}`)); - const activeCellIndex = cellElements.findIndex(cell => cell.contains(activeCell)); - // Check if there are at least 3 cells before the active cell - let codeContent = ""; - - // LeftContext refers to the left side of the pointer, and vice versa, If both are null, it is determined that the pointer is not at the far right - const [leftContext, rightContext] = getActiveCellPointerCode(activeCell) - - if(!leftContext){ - return null - } +async function getCellContentText(activeCell){ + const result = await getChecked() - // Iterate through the last 3 cells before the active cell - const startIndex = 0; - for (let i = startIndex; i <= activeCellIndex; i++) { - if(i == activeCellIndex){ - codeContent += leftContext - break - }else{ - const cellElement = cellElements[i]; - if (cellElement.classList.contains(currctJupyterModel.requiredClassName.verify)) { - codeContent += extractTextFromCodeCell(cellElement); - } - } - codeContent += "\n" + if(result == "openaiApiKey"){ + return getCellContentTextRequiredForOpenAI(activeCell) + }else{ + return getCellContentTextRequiredForBigCode(activeCell) } - - return codeContent; } -function getCellContentTextRequiredForBigCode(activeCell) { - const cellElements = Array.from(document.querySelectorAll(`.${currctJupyterModel.requiredClassName.cell}`)); - const activeCellIndex = cellElements.findIndex(cell => cell.contains(activeCell)); - // Check if there are at least 3 cells before the active cell - let combinedContent = ""; +/* + Obtain information about the code in the cell and return it by line - // in active cell, LeftContext refers to the left side of the pointer, and vice versa, If both are null, it is determined that the pointer is not at the far right - const [leftContext, rightContext] = getActiveCellPointerCode(activeCell) + Params: + cellElement: cell dom element + cellIndex: index corresponding to the cell in the context - if(!leftContext && !rightContext){ - return null + Return: + Example: + [{"content": def hello_world():,"cellIndex": 0,"isCursor": false,"type": "code","lineIndex": 0}, ...] + - content: content of a line + - cellIndex: index corresponding to the cell in the context + - isCursor: is the mouse pointer in this line + - type: code | text(markdown) | output + - lineIndex: line number in this cell + +*/ +const getCellCode = (cellElement, cellIndex) => { + let currentCellType = "" + if (cellElement.classList.contains(currctJupyterModel.requiredClassName.verify)) { + currentCellType = "code" + } else if (cellElement.classList.contains(currctJupyterModel.requiredClassName.text)) { + currentCellType = "text" + } else { + return [] } + const cellContent = [] + const codeLines = cellElement.querySelectorAll('.CodeMirror-line') + for (let i = 0; i < codeLines.length; i++) { + cellContent.push({ + "content": codeLines[i].textContent, + "cellIndex": cellIndex, + "isCursor": false, + "type": currentCellType, + "lineIndex": i + }) + } - TODO: "The following code needs to add 'leftContext' and 'rightContext'" - // Iterate through the last 3 cells before the active cell - const startIndex = activeCellIndex - 3 < 0 ? 0 : activeCellIndex - 3; - - for (let i = startIndex; i <= activeCellIndex; i++) { - const cellElement = cellElements[i]; - - if (cellElement.classList.contains(currctJupyterModel.requiredClassName.verify)) { - const code = extractTextFromCodeCell(cellElement); - - combinedContent += `${code}`; - const outputElement = cellElement.querySelector(`.${currctJupyterModel.requiredClassName.output}`); - if (outputElement) { - if (i !== activeCellIndex) { - combinedContent += ``; - combinedContent += outputElement.textContent; - } - } - } else if (cellElement.classList.contains(currctJupyterModel.requiredClassName.text)) { - const text = extractTextFromTextCell(cellElement); - combinedContent += `${text}`; - } + const outputElement = cellElement.querySelector(`.${currctJupyterModel.requiredClassName.output}`); + if (outputElement && currentCellType == "code") { + cellContent.push({ + "content": outputElement.textContent, + "cellIndex": cellIndex, + "isCursor": false, + "type": "output", + "lineIndex": 0 + }) } - return combinedContent; + return cellContent; } +/* + Get Cell Context, returns a total of 5 cell, symmetrically based on the cell of the current focus + + Return: + Example: + [{"content": def hello_world():,"cellIndex": 0,"isCursor": false,"type": "code","lineIndex": 0}, ...] + - content: content of a line + - cellIndex: index corresponding to the cell in the context + - isCursor: is the mouse pointer in this line + - type: code | text(markdown) | output + - lineIndex: line number in this cell + +*/ +const getActiveContext = () => { + // Obtain the current input box (cell) from the Textarea of the current input box + const activeCell = document.activeElement.parentElement.parentElement; -async function getCellContentText(activeCell){ - const result = await getChecked() - - if(result == "openaiApiKey"){ - return getCellContentTextRequiredForOpenAI(activeCell) - }else{ - return getCellContentTextRequiredForBigCode(activeCell) + const cellElements = Array.from(document.querySelectorAll(`.${currctJupyterModel.requiredClassName.cell}`)); + const activeCellIndex = cellElements.findIndex(cell => cell.contains(activeCell)); + let context = [] + for (let i = 0; i < cellElements.length; i++) { + if (i == activeCellIndex) { + const activeCellContent = getActiveCellPointerCode(activeCell, i) + context = [...context, ...activeCellContent] + } else if (i >= activeCellIndex - 2 || i <= activeCellIndex + 2) { + const cellContent = getCellCode(cellElements[i], i) + context = [...context, ...cellContent] + } } + + return context } +// prompt required by openai +function getCellContentTextRequiredForOpenAI() { + const context = getActiveContext() + let code = "" -function extractTextFromCodeCell(cell){ - const codeMirrorLines = cell.querySelectorAll('.CodeMirror-code pre'); + for(let index = 0; index < context.length; index++){ + const lineInformation = context[index] - const content = []; + if(lineInformation.type == "code"){ + if(index == context.length - 1 || lineInformation.isCursor){ + return code + lineInformation.content + }else{ + code += lineInformation.content += "\n" + } + } - codeMirrorLines.forEach((line) => { - content.push(line.textContent); - }); - const content_str = content.join('\n'); + } - return content_str; } +function getBigcodeFormattPrefix(typeStr){ + switch(typeStr){ + case "code": return ""; + case "text": return ""; + case "output": return ""; + } +} -function extractTextFromTextCell(cell) { - const codeMirrorLines = cell.querySelectorAll(`.${currctJupyterModel.requiredClassName.textOutput} p`); - - const content = []; - - codeMirrorLines.forEach((line) => { - content.push(line.textContent); - }); - const content_str = content.join('\n'); +// prompt required by bigcode +function getCellContentTextRequiredForBigCode() { + const context = getActiveContext() - return content_str; -} + let code = "" + let cellCode = getBigcodeFormattPrefix(context[0].type) + + for(let index = 0; index < context.length; index++){ + const lineInformation = context[index] + if(index == context.length - 1 || lineInformation.isCursor){ + code += cellCode + lineInformation.content + break + } + const nextLineInformation = context[index + 1] -function removeJupyterOutput(str) { - const jupyterOutput = ''; + if(lineInformation.cellIndex != nextLineInformation.cellIndex || lineInformation.type != nextLineInformation.type){ + code += cellCode + lineInformation.content + cellCode = getBigcodeFormattPrefix(nextLineInformation.type) + }else{ + cellCode += lineInformation.content + "\n" + } - if (str.endsWith(jupyterOutput)) { - return str.slice(0, -jupyterOutput.length); } - return str; + return code += "" } + // left animation css const loadCss = ` .before-content:before { @@ -453,6 +514,7 @@ const addFillCodeKeyListener = (event) => { } }; + const mainProcess = async () => { //Obtain the Textarea of the current input box const activeTextarea = document.activeElement; @@ -465,6 +527,8 @@ const mainProcess = async () => { // Retrieve the content of the active cell const code = await getCellContentText(activeCell); + console.log("code",JSON.stringify(code)); + if (!code) return; if (activeCell) { @@ -473,10 +537,11 @@ const mainProcess = async () => { isRequestInProgress = true let suggestion; + // Deal with a series of problems such as network try{ suggestion = await getCodeCompletion(code) - }catch{ + }catch(err){ // cancel animation clearInterval(animationInterval) // cancel animation element @@ -493,6 +558,7 @@ const mainProcess = async () => { return } + if (suggestion) { clearInterval(animationInterval) // cancel animation element @@ -515,7 +581,7 @@ const montedEventListener = () => { if (event.ctrlKey && event.code === 'Space') { // Block default events event.preventDefault(); - + if (isRequestInProgress || isRequestSuccessful) { return } From e4872d36252a130215f7f7a466b70af9150b9d90 Mon Sep 17 00:00:00 2001 From: ran Date: Thu, 18 May 2023 10:44:51 +0800 Subject: [PATCH 02/22] remove log --- content.js | 2 +- examples/sklearn_digits.ipynb | 29 +++++++++++++++---- examples/starcoder_gpu_usage.ipynb | 46 ++++++++++++++++++++++++------ 3 files changed, 62 insertions(+), 15 deletions(-) diff --git a/content.js b/content.js index ee4cc98..fccdcb1 100644 --- a/content.js +++ b/content.js @@ -541,7 +541,7 @@ const mainProcess = async () => { // Deal with a series of problems such as network try{ suggestion = await getCodeCompletion(code) - }catch(err){ + }catch{ // cancel animation clearInterval(animationInterval) // cancel animation element diff --git a/examples/sklearn_digits.ipynb b/examples/sklearn_digits.ipynb index c5736c0..72c7f5d 100644 --- a/examples/sklearn_digits.ipynb +++ b/examples/sklearn_digits.ipynb @@ -2,12 +2,24 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "id": "1114df89", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "hello world!\n" + ] + } + ], "source": [ - "# load Digits Dataset from sklearn\n" + "def hello_world():\n", + " print(\"hello world!\")\n", + "def hello_world():\n", + " print(\"hello world!\")\n", + "hello_world()" ] }, { @@ -26,7 +38,9 @@ "id": "c164026e", "metadata": {}, "outputs": [], - "source": [] + "source": [ + "# print the shape of the images and labels data\n" + ] }, { "cell_type": "markdown", @@ -44,7 +58,10 @@ "id": "20657b9d", "metadata": {}, "outputs": [], - "source": [] + "source": [ + "# define subplots\n", + "fig, axes = plt.subplots(10, 10," + ] } ], "metadata": { @@ -63,7 +80,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.10" + "version": "3.10.11" } }, "nbformat": 4, diff --git a/examples/starcoder_gpu_usage.ipynb b/examples/starcoder_gpu_usage.ipynb index 79e62ce..21b26d3 100644 --- a/examples/starcoder_gpu_usage.ipynb +++ b/examples/starcoder_gpu_usage.ipynb @@ -2,14 +2,22 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "3aa18388", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "hello\n" + ] + } + ], "source": [ - "import pandas as pd\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt" + "def hello():\n", + " print(\"hello\")\n", + "hello()" ] }, { @@ -26,7 +34,10 @@ "id": "0997b28d", "metadata": {}, "outputs": [], - "source": [] + "source": [ + "import pandas as pd\n", + "df = pd.read_csv(\"usage_df.csv\")\n" + ] }, { "cell_type": "markdown", @@ -62,9 +73,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "e7e4b2e2", "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (2866948305.py, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[1;36m Cell \u001b[1;32mIn[6], line 1\u001b[1;36m\u001b[0m\n\u001b[1;33m code \"def hello():\\n print(\\\"hello\\\")\\nhello()hello\\nread the csv usage_df.csv\"\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "code \"def hello():\\n print(\\\"hello\\\")\\nhello()hello\\nread the csv usage_df.csv\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "77ba0a71", + "metadata": {}, "outputs": [], "source": [] } @@ -85,7 +115,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.10" + "version": "3.10.11" } }, "nbformat": 4, From 082b2926677c1d20c44e428146e04beb4d951777 Mon Sep 17 00:00:00 2001 From: ran Date: Thu, 18 May 2023 10:45:44 +0800 Subject: [PATCH 03/22] remove log --- content.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content.js b/content.js index ee4cc98..fccdcb1 100644 --- a/content.js +++ b/content.js @@ -541,7 +541,7 @@ const mainProcess = async () => { // Deal with a series of problems such as network try{ suggestion = await getCodeCompletion(code) - }catch(err){ + }catch{ // cancel animation clearInterval(animationInterval) // cancel animation element From fd2139531ce71753f69ecd3268029e6f804a2304 Mon Sep 17 00:00:00 2001 From: ran Date: Thu, 18 May 2023 10:46:33 +0800 Subject: [PATCH 04/22] remove log --- content.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/content.js b/content.js index fccdcb1..4ccaefe 100644 --- a/content.js +++ b/content.js @@ -527,8 +527,6 @@ const mainProcess = async () => { // Retrieve the content of the active cell const code = await getCellContentText(activeCell); - console.log("code",JSON.stringify(code)); - if (!code) return; if (activeCell) { From ab50241a53bdcb2eb58397ec5115e6e1ad6239a6 Mon Sep 17 00:00:00 2001 From: ran Date: Thu, 18 May 2023 10:49:54 +0800 Subject: [PATCH 05/22] Restore files that should not be submitted --- examples/sklearn_digits.ipynb | 29 ++++--------------- examples/starcoder_gpu_usage.ipynb | 46 ++++++------------------------ 2 files changed, 14 insertions(+), 61 deletions(-) diff --git a/examples/sklearn_digits.ipynb b/examples/sklearn_digits.ipynb index 72c7f5d..c5736c0 100644 --- a/examples/sklearn_digits.ipynb +++ b/examples/sklearn_digits.ipynb @@ -2,24 +2,12 @@ "cells": [ { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "id": "1114df89", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "hello world!\n" - ] - } - ], + "outputs": [], "source": [ - "def hello_world():\n", - " print(\"hello world!\")\n", - "def hello_world():\n", - " print(\"hello world!\")\n", - "hello_world()" + "# load Digits Dataset from sklearn\n" ] }, { @@ -38,9 +26,7 @@ "id": "c164026e", "metadata": {}, "outputs": [], - "source": [ - "# print the shape of the images and labels data\n" - ] + "source": [] }, { "cell_type": "markdown", @@ -58,10 +44,7 @@ "id": "20657b9d", "metadata": {}, "outputs": [], - "source": [ - "# define subplots\n", - "fig, axes = plt.subplots(10, 10," - ] + "source": [] } ], "metadata": { @@ -80,7 +63,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.11" + "version": "3.8.10" } }, "nbformat": 4, diff --git a/examples/starcoder_gpu_usage.ipynb b/examples/starcoder_gpu_usage.ipynb index 21b26d3..79e62ce 100644 --- a/examples/starcoder_gpu_usage.ipynb +++ b/examples/starcoder_gpu_usage.ipynb @@ -2,22 +2,14 @@ "cells": [ { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "3aa18388", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "hello\n" - ] - } - ], + "outputs": [], "source": [ - "def hello():\n", - " print(\"hello\")\n", - "hello()" + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt" ] }, { @@ -34,10 +26,7 @@ "id": "0997b28d", "metadata": {}, "outputs": [], - "source": [ - "import pandas as pd\n", - "df = pd.read_csv(\"usage_df.csv\")\n" - ] + "source": [] }, { "cell_type": "markdown", @@ -71,29 +60,10 @@ "outputs": [], "source": [] }, - { - "cell_type": "code", - "execution_count": 6, - "id": "e7e4b2e2", - "metadata": {}, - "outputs": [ - { - "ename": "SyntaxError", - "evalue": "invalid syntax (2866948305.py, line 1)", - "output_type": "error", - "traceback": [ - "\u001b[1;36m Cell \u001b[1;32mIn[6], line 1\u001b[1;36m\u001b[0m\n\u001b[1;33m code \"def hello():\\n print(\\\"hello\\\")\\nhello()hello\\nread the csv usage_df.csv\"\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m invalid syntax\n" - ] - } - ], - "source": [ - "code \"def hello():\\n print(\\\"hello\\\")\\nhello()hello\\nread the csv usage_df.csv\"" - ] - }, { "cell_type": "code", "execution_count": null, - "id": "77ba0a71", + "id": "e7e4b2e2", "metadata": {}, "outputs": [], "source": [] @@ -115,7 +85,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.11" + "version": "3.8.10" } }, "nbformat": 4, From 7e13770483533aac96953ac9379c5340369bb0e4 Mon Sep 17 00:00:00 2001 From: ran Date: Thu, 18 May 2023 11:40:55 +0800 Subject: [PATCH 06/22] fix jupyterlab bug --- content.js | 63 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/content.js b/content.js index 4ccaefe..6df866c 100644 --- a/content.js +++ b/content.js @@ -272,38 +272,47 @@ async function getCellContentText(activeCell){ */ const getCellCode = (cellElement, cellIndex) => { - let currentCellType = "" + const cellContent = [] + if (cellElement.classList.contains(currctJupyterModel.requiredClassName.verify)) { - currentCellType = "code" + const codeLines = cellElement.querySelectorAll('.CodeMirror-line') + for (let i = 0; i < codeLines.length; i++) { + cellContent.push({ + "content": codeLines[i].textContent, + "cellIndex": cellIndex, + "isCursor": false, + "type": "code", + "lineIndex": i + }) + } + + const outputElement = cellElement.querySelector(`.${currctJupyterModel.requiredClassName.output}`); + if (outputElement && outputElement.textContent) { + cellContent.push({ + "content": outputElement.textContent, + "cellIndex": cellIndex, + "isCursor": false, + "type": "output", + "lineIndex": 0 + }) + } + } else if (cellElement.classList.contains(currctJupyterModel.requiredClassName.text)) { - currentCellType = "text" + const textLines = cellElement.querySelectorAll(`.${currctJupyterModel.requiredClassName.textOutput} p`) + + for (let i = 0; i < textLines.length; i++) { + cellContent.push({ + "content": textLines[i].textContent, + "cellIndex": cellIndex, + "isCursor": false, + "type": "text", + "lineIndex": i + }) + } } else { return [] } - const cellContent = [] - const codeLines = cellElement.querySelectorAll('.CodeMirror-line') - for (let i = 0; i < codeLines.length; i++) { - cellContent.push({ - "content": codeLines[i].textContent, - "cellIndex": cellIndex, - "isCursor": false, - "type": currentCellType, - "lineIndex": i - }) - } - - const outputElement = cellElement.querySelector(`.${currctJupyterModel.requiredClassName.output}`); - if (outputElement && currentCellType == "code") { - cellContent.push({ - "content": outputElement.textContent, - "cellIndex": cellIndex, - "isCursor": false, - "type": "output", - "lineIndex": 0 - }) - } - return cellContent; } @@ -336,7 +345,7 @@ const getActiveContext = () => { context = [...context, ...cellContent] } } - + console.log(context); return context } From 732d5ed763375739ecf7dddad1d0b2f5c6620f19 Mon Sep 17 00:00:00 2001 From: ran Date: Thu, 18 May 2023 18:27:39 +0800 Subject: [PATCH 07/22] add fix bug --- content.js | 323 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 299 insertions(+), 24 deletions(-) diff --git a/content.js b/content.js index 6df866c..f7d1c75 100644 --- a/content.js +++ b/content.js @@ -87,18 +87,22 @@ async function sendToOpenAI(prompt) { } -function removeJupyterOutput(str) { +function removeJupyterOutput(suggestion) { const jupyterOutput = ''; - if (str.endsWith(jupyterOutput)) { - return str.slice(0, -jupyterOutput.length); + 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 str; + return unnecessaryTagIndex == -1 ? suggestion:suggestion.slice(0, unnecessaryTagIndex) } -async function sendToBigcode(code) { +async function sendToBigcode(code, isFixbug) { const url = await getBigcodeServiceUrl(); const token = await getHuggingfaceApiKey(); @@ -106,8 +110,19 @@ async function sendToBigcode(code) { alert("otherServiceUrl not set."); return; } - + const prompt = code.replace(/\u200B/g, '') + + const bodyData = { + inputs: prompt, + stream: false, + parameters: { + return_full_text: false + } + } + + isFixbug ? "":bodyData.parameters['stop'] = [""] + const response = await fetch(url, { method: "POST", @@ -115,14 +130,7 @@ async function sendToBigcode(code) { "Content-Type": "application/json", "Authorization": `Bearer ${token}`, }, - body: JSON.stringify({ - inputs: prompt, - stream: false, - parameters: { - return_full_text: false, - stop: [""] - } - }) + body: JSON.stringify(bodyData) }) const data = await response.json(); @@ -133,6 +141,7 @@ async function sendToBigcode(code) { } + async function getCodeCompletion(code) { const checked = await getChecked(); @@ -144,7 +153,7 @@ async function getCodeCompletion(code) { switch(checked){ case "openaiApiKey": return await sendToOpenAI(code); - case "otherService": return await sendToBigcode(code); + case "otherService": return await sendToBigcode(code, false); default: return "" } @@ -159,7 +168,8 @@ let isRequestInProgress = false; let isRequestSuccessful = false; // Textarea during the request (allows writing code in other cells while the request is in progress) let activeRequestTextarea = null; - +// Request method, fix bug or normal +let requestType = null function insertSuggestion(suggestion) { // Focus the textarea, otherwise, it is not possible to insert the suggestion using the Tab key from another location @@ -185,6 +195,34 @@ function insertSuggestion(suggestion) { activeRequestTextarea.dispatchEvent(tabEvent); } +function removeUserCellFullCode(){ + if(activeRequestTextarea){ + let event = new KeyboardEvent("keydown", { key: "Backspace", keyCode: 8, which: 8, code: "Backspace" }); + activeRequestTextarea.dispatchEvent(event); + } +} + +function insertSuggestionFixBug(suggestion){ + // Focus the textarea, otherwise, it is not possible to insert the suggestion using the Tab key from another location + activeRequestTextarea.focus(); + + for (let index = 0; index < suggestion.length; index++) { + removeUserCellFullCode() + } + enableCode() + + activeRequestTextarea.value = suggestion; + + // Trigger an input event on the textarea to update the CodeMirror instance + const event = new Event('input', { bubbles: true, cancelable: true }); + activeRequestTextarea.dispatchEvent(event); + + // Trigger a keydown event with Tab key to perform auto-indentation + const tabEvent = new KeyboardEvent('keydown', { key: 'Tab' }); + activeRequestTextarea.dispatchEvent(tabEvent); + +} + const getActiveCellPointerCode = (activeCell, cellIndex) => { let cellContent = [] @@ -229,14 +267,19 @@ const getActiveCellPointerCode = (activeCell, cellIndex) => { }) } } - const outputElement = activeCell.querySelector(`.${currctJupyterModel.requiredClassName.output}`); - if (outputElement && currentCellType == "code") { + + // Get complete cells + const fullCell = activeCell.parentElement.parentElement.parentElement.parentElement + + const outputElement = fullCell.querySelector(`.${currctJupyterModel.requiredClassName.output}`); + + if (outputElement) { cellContent.push({ - "content": linesElement[i].textContent, + "content": outputElement.textContent, "cellIndex": cellIndex, "isCursor": false, "type": "output", - "lineIndex": i + "lineIndex": 0 }) } return cellContent @@ -345,7 +388,7 @@ const getActiveContext = () => { context = [...context, ...cellContent] } } - console.log(context); + return context } @@ -407,6 +450,153 @@ function getCellContentTextRequiredForBigCode() { } + +function parseErrorFullmessage(message){ + const meassgeLines = message.split("\n").filter((line)=>{ + return line != "" && line != " " + }) + return meassgeLines[meassgeLines.length - 1] +} + + + +function formatCodeAndBugIllustrate(activeCell){ + const codeLineInformation = getActiveCellPointerCode(activeCell, 0) + + + let code = "" + let errorMessageIndex = -1 + for(let index = 0; index <= codeLineInformation.length-1; index++){ + const lineInformation = codeLineInformation[index] + + if(lineInformation.type == "output"){ + errorMessageIndex = index + break + } + + if(index == codeLineInformation.length - 1){ + code += lineInformation.content + break + }else{ + code += lineInformation.content + "\n" + } + } + + if (errorMessageIndex == -1){ + return "" + } + + return `${code}fix bug, ${parseErrorFullmessage(codeLineInformation[errorMessageIndex].content)}` +} + + + +const compareCodeLines = (codeLine1, codeLine2) => { + codeLine1 = codeLine1.toLowerCase(); + codeLine2 = codeLine2.toLowerCase(); + + const distance = levenshteinDistanceDP(codeLine1, codeLine2); + + const similarityScore = 1 - distance / Math.max(codeLine1.length, codeLine2.length); + + return similarityScore >= 0.8; +} + + +const levenshteinDistanceDP = (str1, str2) => { + const m = str1.length; + const n = str2.length; + const dp = Array(n + 1).fill(0); + + for (let j = 1; j <= n; j++) { + dp[j] = j; + } + + for (let i = 1; i <= m; i++) { + let prev = dp[0]; + dp[0] = i; + for (let j = 1; j <= n; j++) { + let temp = dp[j]; + if (str1[i - 1] === str2[j - 1]) { + dp[j] = prev; + } else { + dp[j] = Math.min(dp[j - 1], dp[j], prev) + 1; + } + prev = temp; + } + } + + return dp[n]; +} + + +const generateCompareCodes = (oldCode, newCode) => { + // Split the strings into lines and store them in separate arrays + const oldCodeLine = oldCode.split('\n'); + const newCodeLine = newCode.split('\n'); + + // Create an empty array to store the generated HTML + const html = []; + let newCodeIndex = 0 + let newCodeAssistIndex = 0 + + // Iterate over the lines and compare them + for (let i = 0; i < Math.max(oldCodeLine.length, newCodeLine.length); i++) { + newCodeAssistIndex = newCodeIndex + const oldLine = i < oldCodeLine.length ? oldCodeLine[i] : ''; + const newLine = newCodeIndex < newCodeLine.length ? newCodeLine[newCodeIndex] : ''; + + // If the lines are the same, generate a gray span + if (oldLine === newLine) { + html.push(`= ${oldLine}`); + newCodeIndex++; + }else if(compareCodeLines(oldLine, newLine)){//这里判断相似度 ,如果相似,视为代码错误,旧的标红,在下方新增(绿色) + html.push(`- ${oldLine}`) + html.push(`+ ${newLine}`) + newCodeIndex++ + } + else { // 如果完全不一样,则视为新代码段,直接在上方新增(绿色) + for( newCodeAssistIndex; newCodeAssistIndex < newCodeLine.length; newCodeAssistIndex++) { + if(oldLine == newCodeLine[newCodeAssistIndex + 1]){ + newCodeAssistIndex ++ + for(newCodeIndex ; newCodeIndex < newCodeAssistIndex ; newCodeIndex ++) { // 如果有多行新增代码则for 逐个push + html.push(`+ ${newCodeLine[newCodeIndex]}`) + i-- + } + }else{ + continue + } + } + } + } + // Join the generated HTML and return it + return html.join('\n'); +} + +const generateCompareCodesWrapper = (prompt, result)=>{ + const cutoffPositions = prompt.indexOf("") + preCodeFormat = prompt.slice(0, cutoffPositions) + preCode = preCodeFormat.replace("","") + return generateCompareCodes(preCode, result) +} + +const disableCode = () => { + const activeCell = activeRequestTextarea.parentElement.parentElement + const codeMirrorLines = activeCell.querySelectorAll('.CodeMirror-code pre'); + for (let i = 0; i < codeMirrorLines.length; i++) { + codeMirrorLines[i].style.display = "none" + } +} + +const enableCode = () => { + const activeCell = activeRequestTextarea.parentElement.parentElement + const codeMirrorLines = activeCell.querySelectorAll('.CodeMirror-code pre'); + for (let i = 0; i < codeMirrorLines.length; i++) { + codeMirrorLines[i].style.display = "block" + } +} + + // left animation css const loadCss = ` .before-content:before { @@ -512,10 +702,16 @@ const addFillCodeKeyListener = (event) => { // If the animated text element exists, it's assumed that the user wants to insert the code into the code block if (animationElementList.length === 1) { + // delete animation element animationElementList[0].remove() - insertSuggestion(codeToFill); + if (requestType == "normal"){ + insertSuggestion(codeToFill); + }else if(requestType == "fixBug"){ + insertSuggestionFixBug(codeToFill) + } + } // Reset the request successful flag @@ -524,6 +720,7 @@ const addFillCodeKeyListener = (event) => { }; + const mainProcess = async () => { //Obtain the Textarea of the current input box const activeTextarea = document.activeElement; @@ -548,7 +745,7 @@ const mainProcess = async () => { // Deal with a series of problems such as network try{ suggestion = await getCodeCompletion(code) - }catch{ + }catch(err){ // cancel animation clearInterval(animationInterval) // cancel animation element @@ -582,6 +779,75 @@ const mainProcess = async () => { } +const viewDiffCode = (activeCell, html)=>{ + const codeMirrorCode = activeCell.querySelector(".CodeMirror-code") + const codeMirrorCodeLine = document.createElement('pre'); + codeMirrorCodeLine.classList.add("CodeMirror-line") + + codeMirrorCodeLine.innerHTML = html + codeMirrorCode.appendChild(codeMirrorCodeLine) +} + + +const fixBugProcess = async () => { + //Obtain the Textarea of the current input box + const activeTextarea = document.activeElement; + + activeRequestTextarea = activeTextarea + + // Obtain the current input box (cell) from the Textarea of the current input box + const activeCell = activeTextarea.parentElement.parentElement + + // Retrieve the content of the active cell + const code = formatCodeAndBugIllustrate(activeCell); + + if (!code) return; + + if (activeCell) { + // Start Animation + const [animationInterval, animationElement, inputElement] = startWaitingAnimation(activeCell) + isRequestInProgress = true + + let suggestion; + + // Deal with a series of problems such as network + try{ + suggestion = await sendToBigcode(code, true) + }catch{ + // cancel animation + clearInterval(animationInterval) + // cancel animation element + inputElement.classList.remove('before-content') + // Add error animation + inputElement.classList.add('paused') + // The request is forbidden within 5s, and the animation lasts for 5s + const pausedTimeOut = setTimeout(() => { + inputElement.classList.remove('paused') + clearTimeout(pausedTimeOut) + isRequestInProgress = false + isRequestSuccessful = false + }, 5000) + return + } + + if (suggestion) { + clearInterval(animationInterval) + // cancel animation element + inputElement.classList.remove('before-content') + disableCode() + viewDiffCode(activeCell, generateCompareCodesWrapper(code, suggestion)) + isRequestSuccessful = true + isRequestInProgress = false + codeToFill = suggestion + + // // Replace the content of the text animation box with code + // animationElement.innerHTML = generateCompareCodesWrapper(code, suggestion) + } + + } + +} + const montedEventListener = () => { document.addEventListener('keydown', async (event) => { // Check if the Ctrl + Space keys were pressed @@ -592,9 +858,18 @@ const montedEventListener = () => { if (isRequestInProgress || isRequestSuccessful) { return } - + requestType = "normal" await mainProcess() + }else if(event.ctrlKey && event.code === 'Backquote'){ + // Block default events + event.preventDefault(); + + if (isRequestInProgress || isRequestSuccessful) { + return + } + requestType = "fixBug" + await fixBugProcess() } }); From 7293a70f4ad0951c1baa3bbe16b5c42b38c4ba18 Mon Sep 17 00:00:00 2001 From: ran Date: Thu, 18 May 2023 19:26:42 +0800 Subject: [PATCH 08/22] add explanatory note --- content.js | 141 +++++++++++++++++++++-------------------------------- 1 file changed, 55 insertions(+), 86 deletions(-) diff --git a/content.js b/content.js index f7d1c75..879d599 100644 --- a/content.js +++ b/content.js @@ -168,9 +168,10 @@ let isRequestInProgress = false; let isRequestSuccessful = false; // Textarea during the request (allows writing code in other cells while the request is in progress) let activeRequestTextarea = null; -// Request method, fix bug or normal +// Request type, fix bug or normal let requestType = null + function insertSuggestion(suggestion) { // Focus the textarea, otherwise, it is not possible to insert the suggestion using the Tab key from another location activeRequestTextarea.focus(); @@ -195,7 +196,7 @@ function insertSuggestion(suggestion) { activeRequestTextarea.dispatchEvent(tabEvent); } -function removeUserCellFullCode(){ +function simulateUserPressingBackspace(){ if(activeRequestTextarea){ let event = new KeyboardEvent("keydown", { key: "Backspace", keyCode: 8, which: 8, code: "Backspace" }); activeRequestTextarea.dispatchEvent(event); @@ -205,9 +206,12 @@ function removeUserCellFullCode(){ function insertSuggestionFixBug(suggestion){ // Focus the textarea, otherwise, it is not possible to insert the suggestion using the Tab key from another location activeRequestTextarea.focus(); + const cellContent = getActiveCellPointerCode(activeRequestTextarea.parentElement.parentElement, 0) - for (let index = 0; index < suggestion.length; index++) { - removeUserCellFullCode() + for (let index = 0; index < cellContent.length; index++) { + for (let j = 0; j < cellContent[index].content.length; j++){ + simulateUserPressingBackspace() + } } enableCode() @@ -472,7 +476,7 @@ function formatCodeAndBugIllustrate(activeCell){ if(lineInformation.type == "output"){ errorMessageIndex = index break - } + } if(index == codeLineInformation.length - 1){ code += lineInformation.content @@ -502,7 +506,7 @@ const compareCodeLines = (codeLine1, codeLine2) => { return similarityScore >= 0.8; } - +// Levenshtein distance, Obtain similarity based on distance const levenshteinDistanceDP = (str1, str2) => { const m = str1.length; const n = str2.length; @@ -518,8 +522,10 @@ const levenshteinDistanceDP = (str1, str2) => { for (let j = 1; j <= n; j++) { let temp = dp[j]; if (str1[i - 1] === str2[j - 1]) { + // Characters are equal and no action is required dp[j] = prev; } else { + // Characters are not equal, take the minimum value of adjacent position operands and add 1 dp[j] = Math.min(dp[j - 1], dp[j], prev) + 1; } prev = temp; @@ -550,16 +556,16 @@ const generateCompareCodes = (oldCode, newCode) => { if (oldLine === newLine) { html.push(`= ${oldLine}`); newCodeIndex++; - }else if(compareCodeLines(oldLine, newLine)){//这里判断相似度 ,如果相似,视为代码错误,旧的标红,在下方新增(绿色) + }else if(compareCodeLines(oldLine, newLine)){// Determine the similarity here. If it is similar, it will be considered a code error. The old one will be highlighted in red and added below (green) html.push(`- ${oldLine}`) html.push(`+ ${newLine}`) newCodeIndex++ } - else { // 如果完全不一样,则视为新代码段,直接在上方新增(绿色) + else { // If it is completely different, it will be considered as a new code snippet and added directly above (green) for( newCodeAssistIndex; newCodeAssistIndex < newCodeLine.length; newCodeAssistIndex++) { if(oldLine == newCodeLine[newCodeAssistIndex + 1]){ newCodeAssistIndex ++ - for(newCodeIndex ; newCodeIndex < newCodeAssistIndex ; newCodeIndex ++) { // 如果有多行新增代码则for 逐个push + for(newCodeIndex ; newCodeIndex < newCodeAssistIndex ; newCodeIndex ++) { // If there are multiple new lines of code, push them one by one for html.push(`+ ${newCodeLine[newCodeIndex]}`) i-- } @@ -573,13 +579,14 @@ const generateCompareCodes = (oldCode, newCode) => { return html.join('\n'); } +// Different HTML for generating code const generateCompareCodesWrapper = (prompt, result)=>{ - const cutoffPositions = prompt.indexOf("") - preCodeFormat = prompt.slice(0, cutoffPositions) - preCode = preCodeFormat.replace("","") + let preCode = prompt.slice(29) + preCode = preCode.slice(0, preCode.length - 14) return generateCompareCodes(preCode, result) } +// Hide all code for the active cell const disableCode = () => { const activeCell = activeRequestTextarea.parentElement.parentElement const codeMirrorLines = activeCell.querySelectorAll('.CodeMirror-code pre'); @@ -588,6 +595,7 @@ const disableCode = () => { } } +// Restore all code that hides the current cell const enableCode = () => { const activeCell = activeRequestTextarea.parentElement.parentElement const codeMirrorLines = activeCell.querySelectorAll('.CodeMirror-code pre'); @@ -706,6 +714,7 @@ const addFillCodeKeyListener = (event) => { // delete animation element animationElementList[0].remove() + // request type "normal" or "fixBug" if (requestType == "normal"){ insertSuggestion(codeToFill); }else if(requestType == "fixBug"){ @@ -720,6 +729,34 @@ const addFillCodeKeyListener = (event) => { }; +// Show different in the current cell +const viewDiffCode = (activeCell, html)=>{ + disableCode() + + // Due to the need to hide user code, the previous preview logic cannot be used + const codeMirrorCode = activeCell.querySelector(".CodeMirror-code") + const codeMirrorCodeLine = document.createElement('pre'); + codeMirrorCodeLine.classList.add("CodeMirror-line") + + codeMirrorCodeLine.innerHTML = html + codeMirrorCode.appendChild(codeMirrorCodeLine) +} + +const viewCodeResult = (codeFormat, suggestion, activeCell, animationElement) => { + codeToFill = suggestion + switch(requestType){ + case "normal": animationElement.innerHTML = suggestion + case "fixBug": viewDiffCode(activeCell, generateCompareCodesWrapper(codeFormat, suggestion)) + } +} + +const getCodeFormat = async (activeCell) => { + switch(requestType){ + case "normal": return await getCellContentText(activeCell); + case "fixBug": return formatCodeAndBugIllustrate(activeCell); + default: return "" + } +} const mainProcess = async () => { //Obtain the Textarea of the current input box @@ -731,7 +768,7 @@ const mainProcess = async () => { const activeCell = activeTextarea.parentElement.parentElement // Retrieve the content of the active cell - const code = await getCellContentText(activeCell); + let code = await getCodeFormat(activeCell) if (!code) return; @@ -770,84 +807,14 @@ const mainProcess = async () => { isRequestSuccessful = true isRequestInProgress = false - codeToFill = suggestion + + viewCodeResult(code, suggestion, activeCell, animationElement) - // Replace the content of the text animation box with code - animationElement.innerHTML = suggestion } } } -const viewDiffCode = (activeCell, html)=>{ - const codeMirrorCode = activeCell.querySelector(".CodeMirror-code") - const codeMirrorCodeLine = document.createElement('pre'); - codeMirrorCodeLine.classList.add("CodeMirror-line") - - codeMirrorCodeLine.innerHTML = html - codeMirrorCode.appendChild(codeMirrorCodeLine) -} - - -const fixBugProcess = async () => { - //Obtain the Textarea of the current input box - const activeTextarea = document.activeElement; - - activeRequestTextarea = activeTextarea - - // Obtain the current input box (cell) from the Textarea of the current input box - const activeCell = activeTextarea.parentElement.parentElement - - // Retrieve the content of the active cell - const code = formatCodeAndBugIllustrate(activeCell); - - if (!code) return; - - if (activeCell) { - // Start Animation - const [animationInterval, animationElement, inputElement] = startWaitingAnimation(activeCell) - isRequestInProgress = true - - let suggestion; - - // Deal with a series of problems such as network - try{ - suggestion = await sendToBigcode(code, true) - }catch{ - // cancel animation - clearInterval(animationInterval) - // cancel animation element - inputElement.classList.remove('before-content') - // Add error animation - inputElement.classList.add('paused') - // The request is forbidden within 5s, and the animation lasts for 5s - const pausedTimeOut = setTimeout(() => { - inputElement.classList.remove('paused') - clearTimeout(pausedTimeOut) - isRequestInProgress = false - isRequestSuccessful = false - }, 5000) - return - } - - if (suggestion) { - clearInterval(animationInterval) - // cancel animation element - inputElement.classList.remove('before-content') - disableCode() - viewDiffCode(activeCell, generateCompareCodesWrapper(code, suggestion)) - isRequestSuccessful = true - isRequestInProgress = false - codeToFill = suggestion - - // // Replace the content of the text animation box with code - // animationElement.innerHTML = generateCompareCodesWrapper(code, suggestion) - } - - } - -} - const montedEventListener = () => { document.addEventListener('keydown', async (event) => { // Check if the Ctrl + Space keys were pressed @@ -869,16 +836,18 @@ const montedEventListener = () => { return } requestType = "fixBug" - await fixBugProcess() + await mainProcess() } }); document.addEventListener('keydown', addFillCodeKeyListener); } + // Two options 'lab' and 'notebook' let currctJupyterModel = {} + const notebookModel = { name: "notebook", requiredClassName:{ From 2adea2cbc43bbea4012698d98fde1f9790d498f2 Mon Sep 17 00:00:00 2001 From: ran Date: Thu, 18 May 2023 22:28:29 +0800 Subject: [PATCH 09/22] fix request is hide bug --- content.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content.js b/content.js index 879d599..24e912e 100644 --- a/content.js +++ b/content.js @@ -745,8 +745,8 @@ const viewDiffCode = (activeCell, html)=>{ const viewCodeResult = (codeFormat, suggestion, activeCell, animationElement) => { codeToFill = suggestion switch(requestType){ - case "normal": animationElement.innerHTML = suggestion - case "fixBug": viewDiffCode(activeCell, generateCompareCodesWrapper(codeFormat, suggestion)) + case "normal": animationElement.innerHTML = suggestion;break; + case "fixBug": viewDiffCode(activeCell, generateCompareCodesWrapper(codeFormat, suggestion));break; } } From f0084446a11b3fd46fa156d9e05be82fdb4c666d Mon Sep 17 00:00:00 2001 From: ran Date: Tue, 23 May 2023 11:46:29 +0800 Subject: [PATCH 10/22] fix empty str bug --- content.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/content.js b/content.js index 24e912e..6a54fb2 100644 --- a/content.js +++ b/content.js @@ -496,6 +496,10 @@ function formatCodeAndBugIllustrate(activeCell){ const compareCodeLines = (codeLine1, codeLine2) => { + if (codeLine1 == codeLine1){ + return true + } + codeLine1 = codeLine1.toLowerCase(); codeLine2 = codeLine2.toLowerCase(); @@ -537,6 +541,8 @@ const levenshteinDistanceDP = (str1, str2) => { const generateCompareCodes = (oldCode, newCode) => { + console.log(oldCode); + console.log(newCode); // Split the strings into lines and store them in separate arrays const oldCodeLine = oldCode.split('\n'); const newCodeLine = newCode.split('\n'); @@ -581,8 +587,8 @@ const generateCompareCodes = (oldCode, newCode) => { // Different HTML for generating code const generateCompareCodesWrapper = (prompt, result)=>{ - let preCode = prompt.slice(29) - preCode = preCode.slice(0, preCode.length - 14) + const preCodeMesageSplit = prompt.split("") + const preCode = preCodeMesageSplit[0].slice(15) return generateCompareCodes(preCode, result) } @@ -769,7 +775,7 @@ const mainProcess = async () => { // Retrieve the content of the active cell let code = await getCodeFormat(activeCell) - + console.log("code",code); if (!code) return; if (activeCell) { From 7d72c81e20061e1f98d55dacc99d57e18fce3684 Mon Sep 17 00:00:00 2001 From: ran Date: Tue, 23 May 2023 11:47:16 +0800 Subject: [PATCH 11/22] remove log --- content.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/content.js b/content.js index 6a54fb2..3723c24 100644 --- a/content.js +++ b/content.js @@ -499,7 +499,7 @@ const compareCodeLines = (codeLine1, codeLine2) => { if (codeLine1 == codeLine1){ return true } - + codeLine1 = codeLine1.toLowerCase(); codeLine2 = codeLine2.toLowerCase(); @@ -541,8 +541,6 @@ const levenshteinDistanceDP = (str1, str2) => { const generateCompareCodes = (oldCode, newCode) => { - console.log(oldCode); - console.log(newCode); // Split the strings into lines and store them in separate arrays const oldCodeLine = oldCode.split('\n'); const newCodeLine = newCode.split('\n'); @@ -775,7 +773,7 @@ const mainProcess = async () => { // Retrieve the content of the active cell let code = await getCodeFormat(activeCell) - console.log("code",code); + if (!code) return; if (activeCell) { From be1e29c6a677518a6389b4df67f3ada1459c0a4c Mon Sep 17 00:00:00 2001 From: ran Date: Tue, 23 May 2023 12:47:04 +0800 Subject: [PATCH 12/22] fix empty str bug --- content.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/content.js b/content.js index 3723c24..bc72626 100644 --- a/content.js +++ b/content.js @@ -496,10 +496,6 @@ function formatCodeAndBugIllustrate(activeCell){ const compareCodeLines = (codeLine1, codeLine2) => { - if (codeLine1 == codeLine1){ - return true - } - codeLine1 = codeLine1.toLowerCase(); codeLine2 = codeLine2.toLowerCase(); @@ -541,6 +537,7 @@ const levenshteinDistanceDP = (str1, str2) => { const generateCompareCodes = (oldCode, newCode) => { + // Split the strings into lines and store them in separate arrays const oldCodeLine = oldCode.split('\n'); const newCodeLine = newCode.split('\n'); @@ -551,8 +548,13 @@ const generateCompareCodes = (oldCode, newCode) => { let newCodeAssistIndex = 0 // Iterate over the lines and compare them - for (let i = 0; i < Math.max(oldCodeLine.length, newCodeLine.length); i++) { + for (let i = 0; i < oldCodeLine.length - 1; i++) { newCodeAssistIndex = newCodeIndex + + if(i >= oldCodeLine.length && newCodeIndex >= newCodeLine.length ){ + break; + } + const oldLine = i < oldCodeLine.length ? oldCodeLine[i] : ''; const newLine = newCodeIndex < newCodeLine.length ? newCodeLine[newCodeIndex] : ''; @@ -571,14 +573,15 @@ const generateCompareCodes = (oldCode, newCode) => { newCodeAssistIndex ++ for(newCodeIndex ; newCodeIndex < newCodeAssistIndex ; newCodeIndex ++) { // If there are multiple new lines of code, push them one by one for html.push(`+ ${newCodeLine[newCodeIndex]}`) - i-- } + i-- }else{ continue } } } } + // Join the generated HTML and return it return html.join('\n'); } From 27896563ef027e9809f0aa7bc280c3aa45070af8 Mon Sep 17 00:00:00 2001 From: ran Date: Tue, 23 May 2023 16:10:38 +0800 Subject: [PATCH 13/22] optimized logic --- content.js | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/content.js b/content.js index bc72626..d5922a0 100644 --- a/content.js +++ b/content.js @@ -467,7 +467,6 @@ function parseErrorFullmessage(message){ function formatCodeAndBugIllustrate(activeCell){ const codeLineInformation = getActiveCellPointerCode(activeCell, 0) - let code = "" let errorMessageIndex = -1 for(let index = 0; index <= codeLineInformation.length-1; index++){ @@ -484,6 +483,7 @@ function formatCodeAndBugIllustrate(activeCell){ }else{ code += lineInformation.content + "\n" } + } if (errorMessageIndex == -1){ @@ -537,20 +537,19 @@ const levenshteinDistanceDP = (str1, str2) => { const generateCompareCodes = (oldCode, newCode) => { - // Split the strings into lines and store them in separate arrays const oldCodeLine = oldCode.split('\n'); const newCodeLine = newCode.split('\n'); + if (oldCodeLine[oldCodeLine.length-1] == "" ) oldCodeLine.pop() + // Create an empty array to store the generated HTML - const html = []; + let html = []; let newCodeIndex = 0 let newCodeAssistIndex = 0 // Iterate over the lines and compare them - for (let i = 0; i < oldCodeLine.length - 1; i++) { - newCodeAssistIndex = newCodeIndex - + for (let i = 0; i < oldCodeLine.length; i++) { if(i >= oldCodeLine.length && newCodeIndex >= newCodeLine.length ){ break; } @@ -566,19 +565,31 @@ const generateCompareCodes = (oldCode, newCode) => { html.push(`- ${oldLine}`) html.push(`+ ${newLine}`) newCodeIndex++ - } - else { // If it is completely different, it will be considered as a new code snippet and added directly above (green) - for( newCodeAssistIndex; newCodeAssistIndex < newCodeLine.length; newCodeAssistIndex++) { - if(oldLine == newCodeLine[newCodeAssistIndex + 1]){ - newCodeAssistIndex ++ - for(newCodeIndex ; newCodeIndex < newCodeAssistIndex ; newCodeIndex ++) { // If there are multiple new lines of code, push them one by one for - html.push(`+ ${newCodeLine[newCodeIndex]}`) + }else{ // If it is completely different, it will be considered as a new code snippet and added directly above (green) + newCodeAssistIndex = newCodeIndex + 1 + perInsertCode = [] + + for(newCodeAssistIndex; newCodeAssistIndex < newCodeLine.length; newCodeAssistIndex++) { + if(oldLine == newCodeLine[newCodeAssistIndex]){ + for(newCodeIndex ; newCodeIndex < newCodeAssistIndex; newCodeIndex ++) { // If there are multiple new lines of code, push them one by one for + perInsertCode.push(`+ ${newCodeLine[newCodeIndex]}`) } i-- - }else{ - continue + break + }else if(compareCodeLines(oldLine, newCodeLine[newCodeIndex])){ + html.push(`- ${oldLine}`) + for(newCodeIndex ; newCodeIndex < newCodeAssistIndex; newCodeIndex ++) { // If there are multiple new lines of code, push them one by one for + perInsertCode.push(`+ ${newCodeLine[newCodeIndex]}`) + } + break } } + + if(perInsertCode.length == 0){ + html.push(`- ${oldLine}`) + } + + html = [...html, ...perInsertCode] } } @@ -751,6 +762,7 @@ const viewDiffCode = (activeCell, html)=>{ const viewCodeResult = (codeFormat, suggestion, activeCell, animationElement) => { codeToFill = suggestion + switch(requestType){ case "normal": animationElement.innerHTML = suggestion;break; case "fixBug": viewDiffCode(activeCell, generateCompareCodesWrapper(codeFormat, suggestion));break; From 8e08acb8258a8c5ef147a22c83d08879eea04c3d Mon Sep 17 00:00:00 2001 From: ran Date: Tue, 23 May 2023 16:16:13 +0800 Subject: [PATCH 14/22] replace invisible str --- content.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/content.js b/content.js index d5922a0..64fcae4 100644 --- a/content.js +++ b/content.js @@ -535,8 +535,11 @@ const levenshteinDistanceDP = (str1, str2) => { return dp[n]; } - +// Due to the presence of a large number of invisible characters, replace them +let invisibleCodeReg = /[\u200B-\u200D\uFEFF]/g const generateCompareCodes = (oldCode, newCode) => { + oldCode = oldCode.replace(invisibleCodeReg, "") + newCode = newCode.replace(invisibleCodeReg, "") // Split the strings into lines and store them in separate arrays const oldCodeLine = oldCode.split('\n'); const newCodeLine = newCode.split('\n'); From 322ed2646a659c662cedb48f9118c2d18c7ff7e5 Mon Sep 17 00:00:00 2001 From: ran Date: Tue, 23 May 2023 16:48:30 +0800 Subject: [PATCH 15/22] replace invisible str --- content.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/content.js b/content.js index 64fcae4..0a5857c 100644 --- a/content.js +++ b/content.js @@ -88,6 +88,7 @@ async function sendToOpenAI(prompt) { function removeJupyterOutput(suggestion) { + suggestion = suggestion.replace("# -*- coding: utf-8 -*-\n\n", "") const jupyterOutput = ''; const unnecessaryTag = '<|endoftext|>' @@ -387,7 +388,7 @@ const getActiveContext = () => { if (i == activeCellIndex) { const activeCellContent = getActiveCellPointerCode(activeCell, i) context = [...context, ...activeCellContent] - } else if (i >= activeCellIndex - 2 || i <= activeCellIndex + 2) { + } else if (i >= activeCellIndex - 2 && i <= activeCellIndex + 2) { const cellContent = getCellCode(cellElements[i], i) context = [...context, ...cellContent] } @@ -434,6 +435,10 @@ function getCellContentTextRequiredForBigCode() { for(let index = 0; index < context.length; index++){ const lineInformation = context[index] + if(lineInformation.type == "output"){ + continue + } + if(index == context.length - 1 || lineInformation.isCursor){ code += cellCode + lineInformation.content break @@ -540,6 +545,7 @@ let invisibleCodeReg = /[\u200B-\u200D\uFEFF]/g const generateCompareCodes = (oldCode, newCode) => { oldCode = oldCode.replace(invisibleCodeReg, "") newCode = newCode.replace(invisibleCodeReg, "") + // Split the strings into lines and store them in separate arrays const oldCodeLine = oldCode.split('\n'); const newCodeLine = newCode.split('\n'); @@ -590,12 +596,21 @@ const generateCompareCodes = (oldCode, newCode) => { if(perInsertCode.length == 0){ html.push(`- ${oldLine}`) + for(newCodeIndex ; newCodeIndex < newCodeAssistIndex; newCodeIndex ++) { // If there are multiple new lines of code, push them one by one for + perInsertCode.push(`+ ${newCodeLine[newCodeIndex]}`) + } } html = [...html, ...perInsertCode] } } + if(newCodeIndex < newCodeLine.length ){ + for(newCodeIndex ; newCodeIndex < newCodeLine.length; newCodeIndex ++) { + html.push(`+ ${newCodeLine[newCodeIndex]}`) + } + } + // Join the generated HTML and return it return html.join('\n'); } From 9c83ddc6b0a4939c830b35847734a5949e7ff5c2 Mon Sep 17 00:00:00 2001 From: ran Date: Tue, 23 May 2023 16:51:46 +0800 Subject: [PATCH 16/22] add example --- examples/fixing_bug_example.ipynb | 260 ++++++++++++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 examples/fixing_bug_example.ipynb diff --git a/examples/fixing_bug_example.ipynb b/examples/fixing_bug_example.ipynb new file mode 100644 index 0000000..59001a5 --- /dev/null +++ b/examples/fixing_bug_example.ipynb @@ -0,0 +1,260 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 23, + "id": "1114df89", + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'pritn' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[23], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;66;03m# print \"Hello, World!\"\u001b[39;00m\n\u001b[1;32m----> 2\u001b[0m \u001b[43mpritn\u001b[49m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mHello, World!\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", + "\u001b[1;31mNameError\u001b[0m: name 'pritn' is not defined" + ] + } + ], + "source": [ + "# print \"Hello, World!\"\n", + "pritn(\"Hello, World!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "88fe6fb4", + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "expected ':' (3930893725.py, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[1;36m Cell \u001b[1;32mIn[35], line 1\u001b[1;36m\u001b[0m\n\u001b[1;33m if x == 5\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m expected ':'\n" + ] + } + ], + "source": [ + "if x == 5\n", + " print(\"x == 5\")" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "b73b834e", + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'y' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[30], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m x \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m10\u001b[39m\n\u001b[1;32m----> 2\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43my\u001b[49m)\n", + "\u001b[1;31mNameError\u001b[0m: name 'y' is not defined" + ] + } + ], + "source": [ + "x = 10\n", + "print(y)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "72409629", + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'calculate_sum' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[34], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mcalculate_sum\u001b[49m(\u001b[38;5;241m5\u001b[39m, \u001b[38;5;241m10\u001b[39m)\n", + "\u001b[1;31mNameError\u001b[0m: name 'calculate_sum' is not defined" + ] + } + ], + "source": [ + "calculate_sum(5, 10)" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "c0c74cd8", + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "can only concatenate str (not \"int\") to str", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[38], line 3\u001b[0m\n\u001b[0;32m 1\u001b[0m x \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mHello\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 2\u001b[0m y \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m5\u001b[39m\n\u001b[1;32m----> 3\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43mx\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[43m \u001b[49m\u001b[43my\u001b[49m)\n", + "\u001b[1;31mTypeError\u001b[0m: can only concatenate str (not \"int\") to str" + ] + } + ], + "source": [ + "x = \"Hello\"\n", + "y = 5\n", + "print(x + y)" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "3315c57c", + "metadata": {}, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'dict' object has no attribute 'city'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[44], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m person \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mname\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mAlice\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mage\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;241m30\u001b[39m}\n\u001b[1;32m----> 2\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43mperson\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcity\u001b[49m)\n", + "\u001b[1;31mAttributeError\u001b[0m: 'dict' object has no attribute 'city'" + ] + } + ], + "source": [ + "person = {\"name\": \"Alice\", \"age\": 30}\n", + "print(person.city)" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "bcd5e7b4", + "metadata": {}, + "outputs": [ + { + "ename": "ZeroDivisionError", + "evalue": "division by zero", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[48], line 3\u001b[0m\n\u001b[0;32m 1\u001b[0m x \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m10\u001b[39m\n\u001b[0;32m 2\u001b[0m y \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0\u001b[39m\n\u001b[1;32m----> 3\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mx\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m/\u001b[39;49m\u001b[43m \u001b[49m\u001b[43my\u001b[49m\n", + "\u001b[1;31mZeroDivisionError\u001b[0m: division by zero" + ] + } + ], + "source": [ + "x = 10\n", + "y = 0\n", + "result = x / y" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "1eb252b2", + "metadata": {}, + "outputs": [ + { + "ename": "KeyError", + "evalue": "'city'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[1], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m my_dict \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mname\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mAlice\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mage\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;241m30\u001b[39m}\n\u001b[1;32m----> 2\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43mmy_dict\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mcity\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m)\n", + "\u001b[1;31mKeyError\u001b[0m: 'city'" + ] + } + ], + "source": [ + "my_dict = {\"name\": \"Alice\", \"age\": 30}\n", + "print(my_dict[\"city\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "15c80109", + "metadata": {}, + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'module_name'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[2], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mmodule_name\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m nonexistent_function\n", + "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'module_name'" + ] + } + ], + "source": [ + "from module_name import nonexistent_function\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "8c67481d", + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "invalid literal for int() with base 10: 'abc'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[6], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m x \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mabc\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m----> 2\u001b[0m y \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mint\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mx\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;31mValueError\u001b[0m: invalid literal for int() with base 10: 'abc'" + ] + } + ], + "source": [ + "x = \"abc\"\n", + "y = int(x)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b076aeb0", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From c89e8776854e37c1f3c1d476163e9d84b7edbb61 Mon Sep 17 00:00:00 2001 From: ran Date: Tue, 23 May 2023 17:00:10 +0800 Subject: [PATCH 17/22] remove example --- content.js | 2 +- examples/fixing_bug_example.ipynb | 260 ------------------------------ 2 files changed, 1 insertion(+), 261 deletions(-) delete mode 100644 examples/fixing_bug_example.ipynb diff --git a/content.js b/content.js index 0a5857c..28c4cdd 100644 --- a/content.js +++ b/content.js @@ -605,7 +605,7 @@ const generateCompareCodes = (oldCode, newCode) => { } } - if(newCodeIndex < newCodeLine.length ){ + if( newCodeIndex < newCodeLine.length ){ for(newCodeIndex ; newCodeIndex < newCodeLine.length; newCodeIndex ++) { html.push(`+ ${newCodeLine[newCodeIndex]}`) } diff --git a/examples/fixing_bug_example.ipynb b/examples/fixing_bug_example.ipynb deleted file mode 100644 index 59001a5..0000000 --- a/examples/fixing_bug_example.ipynb +++ /dev/null @@ -1,260 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 23, - "id": "1114df89", - "metadata": {}, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'pritn' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[23], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;66;03m# print \"Hello, World!\"\u001b[39;00m\n\u001b[1;32m----> 2\u001b[0m \u001b[43mpritn\u001b[49m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mHello, World!\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", - "\u001b[1;31mNameError\u001b[0m: name 'pritn' is not defined" - ] - } - ], - "source": [ - "# print \"Hello, World!\"\n", - "pritn(\"Hello, World!\")" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "id": "88fe6fb4", - "metadata": {}, - "outputs": [ - { - "ename": "SyntaxError", - "evalue": "expected ':' (3930893725.py, line 1)", - "output_type": "error", - "traceback": [ - "\u001b[1;36m Cell \u001b[1;32mIn[35], line 1\u001b[1;36m\u001b[0m\n\u001b[1;33m if x == 5\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m expected ':'\n" - ] - } - ], - "source": [ - "if x == 5\n", - " print(\"x == 5\")" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "id": "b73b834e", - "metadata": {}, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'y' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[30], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m x \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m10\u001b[39m\n\u001b[1;32m----> 2\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43my\u001b[49m)\n", - "\u001b[1;31mNameError\u001b[0m: name 'y' is not defined" - ] - } - ], - "source": [ - "x = 10\n", - "print(y)" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "72409629", - "metadata": {}, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'calculate_sum' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[34], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mcalculate_sum\u001b[49m(\u001b[38;5;241m5\u001b[39m, \u001b[38;5;241m10\u001b[39m)\n", - "\u001b[1;31mNameError\u001b[0m: name 'calculate_sum' is not defined" - ] - } - ], - "source": [ - "calculate_sum(5, 10)" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "id": "c0c74cd8", - "metadata": {}, - "outputs": [ - { - "ename": "TypeError", - "evalue": "can only concatenate str (not \"int\") to str", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[38], line 3\u001b[0m\n\u001b[0;32m 1\u001b[0m x \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mHello\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 2\u001b[0m y \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m5\u001b[39m\n\u001b[1;32m----> 3\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43mx\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[43m \u001b[49m\u001b[43my\u001b[49m)\n", - "\u001b[1;31mTypeError\u001b[0m: can only concatenate str (not \"int\") to str" - ] - } - ], - "source": [ - "x = \"Hello\"\n", - "y = 5\n", - "print(x + y)" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "id": "3315c57c", - "metadata": {}, - "outputs": [ - { - "ename": "AttributeError", - "evalue": "'dict' object has no attribute 'city'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[44], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m person \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mname\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mAlice\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mage\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;241m30\u001b[39m}\n\u001b[1;32m----> 2\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43mperson\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcity\u001b[49m)\n", - "\u001b[1;31mAttributeError\u001b[0m: 'dict' object has no attribute 'city'" - ] - } - ], - "source": [ - "person = {\"name\": \"Alice\", \"age\": 30}\n", - "print(person.city)" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "id": "bcd5e7b4", - "metadata": {}, - "outputs": [ - { - "ename": "ZeroDivisionError", - "evalue": "division by zero", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[48], line 3\u001b[0m\n\u001b[0;32m 1\u001b[0m x \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m10\u001b[39m\n\u001b[0;32m 2\u001b[0m y \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0\u001b[39m\n\u001b[1;32m----> 3\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mx\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m/\u001b[39;49m\u001b[43m \u001b[49m\u001b[43my\u001b[49m\n", - "\u001b[1;31mZeroDivisionError\u001b[0m: division by zero" - ] - } - ], - "source": [ - "x = 10\n", - "y = 0\n", - "result = x / y" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "1eb252b2", - "metadata": {}, - "outputs": [ - { - "ename": "KeyError", - "evalue": "'city'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[1], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m my_dict \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mname\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mAlice\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mage\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;241m30\u001b[39m}\n\u001b[1;32m----> 2\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43mmy_dict\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mcity\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m)\n", - "\u001b[1;31mKeyError\u001b[0m: 'city'" - ] - } - ], - "source": [ - "my_dict = {\"name\": \"Alice\", \"age\": 30}\n", - "print(my_dict[\"city\"])" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "15c80109", - "metadata": {}, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'module_name'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[2], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mmodule_name\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m nonexistent_function\n", - "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'module_name'" - ] - } - ], - "source": [ - "from module_name import nonexistent_function\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "8c67481d", - "metadata": {}, - "outputs": [ - { - "ename": "ValueError", - "evalue": "invalid literal for int() with base 10: 'abc'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[6], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m x \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mabc\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m----> 2\u001b[0m y \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mint\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mx\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;31mValueError\u001b[0m: invalid literal for int() with base 10: 'abc'" - ] - } - ], - "source": [ - "x = \"abc\"\n", - "y = int(x)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b076aeb0", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.11" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From 84fd28bb18a1ff6fd71676f03e04cb3a6ea967e8 Mon Sep 17 00:00:00 2001 From: ran Date: Tue, 23 May 2023 17:07:55 +0800 Subject: [PATCH 18/22] fix left to lang bug --- content.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/content.js b/content.js index 28c4cdd..7b99efc 100644 --- a/content.js +++ b/content.js @@ -596,8 +596,10 @@ const generateCompareCodes = (oldCode, newCode) => { if(perInsertCode.length == 0){ html.push(`- ${oldLine}`) - for(newCodeIndex ; newCodeIndex < newCodeAssistIndex; newCodeIndex ++) { // If there are multiple new lines of code, push them one by one for - perInsertCode.push(`+ ${newCodeLine[newCodeIndex]}`) + for(i ; i < newCodeAssistIndex; i ++) { // If there are multiple new lines of code, push them one by one for + if(i+ ${newCodeLine[i]}`) + } } } From c6b4526b7274789769cbd8b00a003efb7a13d367 Mon Sep 17 00:00:00 2001 From: ran Date: Tue, 23 May 2023 17:10:48 +0800 Subject: [PATCH 19/22] add explanatory note --- content.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/content.js b/content.js index 7b99efc..98eecb4 100644 --- a/content.js +++ b/content.js @@ -575,25 +575,30 @@ const generateCompareCodes = (oldCode, newCode) => { html.push(`+ ${newLine}`) newCodeIndex++ }else{ // If it is completely different, it will be considered as a new code snippet and added directly above (green) + + // Define a new code pointer newCodeAssistIndex = newCodeIndex + 1 + // Prepare to insert code with HTML perInsertCode = [] + // Check which line of the new code is similar to the old one for(newCodeAssistIndex; newCodeAssistIndex < newCodeLine.length; newCodeAssistIndex++) { if(oldLine == newCodeLine[newCodeAssistIndex]){ - for(newCodeIndex ; newCodeIndex < newCodeAssistIndex; newCodeIndex ++) { // If there are multiple new lines of code, push them one by one for + for(newCodeIndex ; newCodeIndex < newCodeAssistIndex; newCodeIndex ++) { perInsertCode.push(`+ ${newCodeLine[newCodeIndex]}`) } i-- break }else if(compareCodeLines(oldLine, newCodeLine[newCodeIndex])){ html.push(`- ${oldLine}`) - for(newCodeIndex ; newCodeIndex < newCodeAssistIndex; newCodeIndex ++) { // If there are multiple new lines of code, push them one by one for + for(newCodeIndex ; newCodeIndex < newCodeAssistIndex; newCodeIndex ++) { perInsertCode.push(`+ ${newCodeLine[newCodeIndex]}`) } break } } + // If no similar code is found in the new code if(perInsertCode.length == 0){ html.push(`- ${oldLine}`) for(i ; i < newCodeAssistIndex; i ++) { // If there are multiple new lines of code, push them one by one for From d4f694067e0a1bc45afede11618b0d4b8433e0c8 Mon Sep 17 00:00:00 2001 From: ran Date: Wed, 24 May 2023 19:04:47 +0800 Subject: [PATCH 20/22] Fix request prompt bug --- content.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content.js b/content.js index 98eecb4..f702a00 100644 --- a/content.js +++ b/content.js @@ -455,7 +455,7 @@ function getCellContentTextRequiredForBigCode() { } - return code += "" + return code } From a64c30e4a3309cb75bc8aab44982f4fadca3b49f Mon Sep 17 00:00:00 2001 From: ran Date: Wed, 24 May 2023 20:59:31 +0800 Subject: [PATCH 21/22] fix view diff bug --- content.js | 129 ++++++++++++++++++++++++++--------------------------- 1 file changed, 64 insertions(+), 65 deletions(-) diff --git a/content.js b/content.js index f702a00..c1d400c 100644 --- a/content.js +++ b/content.js @@ -276,16 +276,18 @@ const getActiveCellPointerCode = (activeCell, cellIndex) => { // Get complete cells const fullCell = activeCell.parentElement.parentElement.parentElement.parentElement - const outputElement = fullCell.querySelector(`.${currctJupyterModel.requiredClassName.output}`); + const outputElement = fullCell.querySelectorAll(`.${currctJupyterModel.requiredClassName.output}`); if (outputElement) { - cellContent.push({ - "content": outputElement.textContent, - "cellIndex": cellIndex, - "isCursor": false, - "type": "output", - "lineIndex": 0 - }) + outputElement.forEach(element => { + cellContent.push({ + "content": element.textContent, + "cellIndex": cellIndex, + "isCursor": false, + "type": "output", + "lineIndex": 0 + }) + }); } return cellContent } @@ -428,7 +430,7 @@ function getBigcodeFormattPrefix(typeStr){ // prompt required by bigcode function getCellContentTextRequiredForBigCode() { const context = getActiveContext() - + let code = "" let cellCode = getBigcodeFormattPrefix(context[0].type) @@ -448,12 +450,12 @@ function getCellContentTextRequiredForBigCode() { if(lineInformation.cellIndex != nextLineInformation.cellIndex || lineInformation.type != nextLineInformation.type){ code += cellCode + lineInformation.content - cellCode = getBigcodeFormattPrefix(nextLineInformation.type) + cellCode = getBigcodeFormattPrefix(lineInformation.type) }else{ cellCode += lineInformation.content + "\n" } - } + } return code } @@ -474,19 +476,26 @@ function formatCodeAndBugIllustrate(activeCell){ let code = "" let errorMessageIndex = -1 - for(let index = 0; index <= codeLineInformation.length-1; index++){ + for(let index = 0; index < codeLineInformation.length; index++){ const lineInformation = codeLineInformation[index] - + if(lineInformation.type == "output"){ - errorMessageIndex = index + // Determine if the next one is also an output, there can only be two consecutive outputs at most + if (index < codeLineInformation.length - 1 && codeLineInformation[index+1].type == "output"){ + errorMessageIndex = index + 1 + }else{ + errorMessageIndex = index + } break } if(index == codeLineInformation.length - 1){ code += lineInformation.content break - }else{ + }else if(codeLineInformation[index+1].type != "output"){ code += lineInformation.content + "\n" + }else{ + code += lineInformation.content } } @@ -495,22 +504,11 @@ function formatCodeAndBugIllustrate(activeCell){ return "" } + return `${code}fix bug, ${parseErrorFullmessage(codeLineInformation[errorMessageIndex].content)}` } - -const compareCodeLines = (codeLine1, codeLine2) => { - codeLine1 = codeLine1.toLowerCase(); - codeLine2 = codeLine2.toLowerCase(); - - const distance = levenshteinDistanceDP(codeLine1, codeLine2); - - const similarityScore = 1 - distance / Math.max(codeLine1.length, codeLine2.length); - - return similarityScore >= 0.8; -} - // Levenshtein distance, Obtain similarity based on distance const levenshteinDistanceDP = (str1, str2) => { const m = str1.length; @@ -540,9 +538,24 @@ const levenshteinDistanceDP = (str1, str2) => { return dp[n]; } + +const compareCodeLines = (codeLine1, codeLine2) => { + codeLine1 = codeLine1.toLowerCase(); + codeLine2 = codeLine2.toLowerCase(); + + const distance = levenshteinDistanceDP(codeLine1, codeLine2); + + const similarityScore = 1 - distance / Math.max(codeLine1.length, codeLine2.length); + + return similarityScore >= 0.8; +} + + + // Due to the presence of a large number of invisible characters, replace them let invisibleCodeReg = /[\u200B-\u200D\uFEFF]/g const generateCompareCodes = (oldCode, newCode) => { + oldCode = oldCode.replace(invisibleCodeReg, "") newCode = newCode.replace(invisibleCodeReg, "") @@ -550,22 +563,24 @@ const generateCompareCodes = (oldCode, newCode) => { const oldCodeLine = oldCode.split('\n'); const newCodeLine = newCode.split('\n'); - if (oldCodeLine[oldCodeLine.length-1] == "" ) oldCodeLine.pop() - + // Create an empty array to store the generated HTML let html = []; let newCodeIndex = 0 - let newCodeAssistIndex = 0 // Iterate over the lines and compare them for (let i = 0; i < oldCodeLine.length; i++) { - if(i >= oldCodeLine.length && newCodeIndex >= newCodeLine.length ){ + + if(newCodeIndex == newCodeLine.length){ + for(i; i < oldCodeLine.length; i++){ + html.push(`- ${oldCodeLine[i]}`) + } break; } - const oldLine = i < oldCodeLine.length ? oldCodeLine[i] : ''; - const newLine = newCodeIndex < newCodeLine.length ? newCodeLine[newCodeIndex] : ''; - + const oldLine = oldCodeLine[i]; + const newLine = newCodeLine[newCodeIndex]; + // If the lines are the same, generate a gray span if (oldLine === newLine) { html.push(`= ${oldLine}`); @@ -574,56 +589,40 @@ const generateCompareCodes = (oldCode, newCode) => { html.push(`- ${oldLine}`) html.push(`+ ${newLine}`) newCodeIndex++ - }else{ // If it is completely different, it will be considered as a new code snippet and added directly above (green) - - // Define a new code pointer - newCodeAssistIndex = newCodeIndex + 1 + }else{ + // If it is completely different, it will be considered as a new code snippet and added directly above (green) + + let newCodeAssistIndex = newCodeIndex // Prepare to insert code with HTML - perInsertCode = [] + const perInsertCode = [] + let isAddedOldCode = false // Check which line of the new code is similar to the old one for(newCodeAssistIndex; newCodeAssistIndex < newCodeLine.length; newCodeAssistIndex++) { - if(oldLine == newCodeLine[newCodeAssistIndex]){ - for(newCodeIndex ; newCodeIndex < newCodeAssistIndex; newCodeIndex ++) { + if(oldLine == newCodeLine[newCodeAssistIndex] || compareCodeLines(oldLine, newCodeLine[newCodeIndex])){ + for(newCodeIndex; newCodeIndex < newCodeAssistIndex; newCodeIndex++){ perInsertCode.push(`+ ${newCodeLine[newCodeIndex]}`) } - i-- - break - }else if(compareCodeLines(oldLine, newCodeLine[newCodeIndex])){ - html.push(`- ${oldLine}`) - for(newCodeIndex ; newCodeIndex < newCodeAssistIndex; newCodeIndex ++) { - perInsertCode.push(`+ ${newCodeLine[newCodeIndex]}`) + }else{ + if (i < oldCodeLine.length){ + perInsertCode.push(`- ${oldCodeLine[i++]}`) + isAddedOldCode = true } - break + perInsertCode.push(`+ ${newCodeLine[newCodeIndex++]}`) } } - - // If no similar code is found in the new code - if(perInsertCode.length == 0){ - html.push(`- ${oldLine}`) - for(i ; i < newCodeAssistIndex; i ++) { // If there are multiple new lines of code, push them one by one for - if(i+ ${newCodeLine[i]}`) - } - } - } - + if (isAddedOldCode) i-- html = [...html, ...perInsertCode] } } - if( newCodeIndex < newCodeLine.length ){ - for(newCodeIndex ; newCodeIndex < newCodeLine.length; newCodeIndex ++) { - html.push(`+ ${newCodeLine[newCodeIndex]}`) - } - } - // Join the generated HTML and return it return html.join('\n'); } // Different HTML for generating code const generateCompareCodesWrapper = (prompt, result)=>{ + const preCodeMesageSplit = prompt.split("") const preCode = preCodeMesageSplit[0].slice(15) return generateCompareCodes(preCode, result) From ba8174d4c04554350b3f30b96fb1f1d5d1d5bf10 Mon Sep 17 00:00:00 2001 From: ran Date: Wed, 24 May 2023 21:00:40 +0800 Subject: [PATCH 22/22] add fix bug test ipynb --- examples/fixing_bug_example.ipynb | 240 ++++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 examples/fixing_bug_example.ipynb diff --git a/examples/fixing_bug_example.ipynb b/examples/fixing_bug_example.ipynb new file mode 100644 index 0000000..c925c95 --- /dev/null +++ b/examples/fixing_bug_example.ipynb @@ -0,0 +1,240 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 4, + "id": "1114df89", + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'printa' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[4], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;66;03m# print \"Hello, World!\"\u001b[39;00m\n\u001b[1;32m----> 2\u001b[0m \u001b[43mprinta\u001b[49m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mHello, World!\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", + "\u001b[1;31mNameError\u001b[0m: name 'printa' is not defined" + ] + } + ], + "source": [ + "# print \"Hello, World!\"\n", + "printa(\"Hello, World!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "88fe6fb4", + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "expected ':' (3930893725.py, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[1;36m Cell \u001b[1;32mIn[5], line 1\u001b[1;36m\u001b[0m\n\u001b[1;33m if x == 5\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m expected ':'\n" + ] + } + ], + "source": [ + "if x == 5\n", + " print(\"x == 5\")" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "b73b834e", + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'y' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[30], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m x \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m10\u001b[39m\n\u001b[1;32m----> 2\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43my\u001b[49m)\n", + "\u001b[1;31mNameError\u001b[0m: name 'y' is not defined" + ] + } + ], + "source": [ + "x = 10\n", + "print(y)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "72409629", + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'calculate_sum' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[39], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mcalculate_sum\u001b[49m(\u001b[38;5;241m5\u001b[39m, \u001b[38;5;241m10\u001b[39m)\n", + "\u001b[1;31mNameError\u001b[0m: name 'calculate_sum' is not defined" + ] + } + ], + "source": [ + "calculate_sum(5, 10)" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "c0c74cd8", + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "can only concatenate str (not \"int\") to str", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[40], line 3\u001b[0m\n\u001b[0;32m 1\u001b[0m x \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mHello\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 2\u001b[0m y \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m5\u001b[39m\n\u001b[1;32m----> 3\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43mx\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[43m \u001b[49m\u001b[43my\u001b[49m)\n", + "\u001b[1;31mTypeError\u001b[0m: can only concatenate str (not \"int\") to str" + ] + } + ], + "source": [ + "x = \"Hello\"\n", + "y = 5\n", + "print(x + y)" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "3315c57c", + "metadata": {}, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'dict' object has no attribute 'name'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[44], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m person \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mname\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mAlice\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mage\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;241m30\u001b[39m}\n\u001b[1;32m----> 2\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43mperson\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mname\u001b[49m)\n", + "\u001b[1;31mAttributeError\u001b[0m: 'dict' object has no attribute 'name'" + ] + } + ], + "source": [ + "person = {\"name\": \"Alice\", \"age\": 30}\n", + "print(person.name)" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "bcd5e7b4", + "metadata": {}, + "outputs": [ + { + "ename": "ZeroDivisionError", + "evalue": "division by zero", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[42], line 3\u001b[0m\n\u001b[0;32m 1\u001b[0m x \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m10\u001b[39m\n\u001b[0;32m 2\u001b[0m y \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0\u001b[39m\n\u001b[1;32m----> 3\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mx\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m/\u001b[39;49m\u001b[43m \u001b[49m\u001b[43my\u001b[49m\n", + "\u001b[1;31mZeroDivisionError\u001b[0m: division by zero" + ] + } + ], + "source": [ + "x = 10\n", + "y = 0\n", + "result = x / y" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "1eb252b2", + "metadata": {}, + "outputs": [ + { + "ename": "KeyError", + "evalue": "'city'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[1], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m my_dict \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mname\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mAlice\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mage\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;241m30\u001b[39m}\n\u001b[1;32m----> 2\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43mmy_dict\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mcity\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m)\n", + "\u001b[1;31mKeyError\u001b[0m: 'city'" + ] + } + ], + "source": [ + "my_dict = {\"name\": \"Alice\", \"age\": 30}\n", + "print(my_dict[\"city\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "b076aeb0", + "metadata": {}, + "outputs": [ + { + "ename": "ImportError", + "evalue": "cannot import name 'load_adigits' from 'sklearn.datasets' (C:\\Users\\redam\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\sklearn\\datasets\\__init__.py)", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mImportError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[30], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;66;03m# load Digits Dataset from sklearn\u001b[39;00m\n\u001b[1;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01msklearn\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdatasets\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m load_adigits\n\u001b[0;32m 3\u001b[0m digits \u001b[38;5;241m=\u001b[39m load_adigits()\n", + "\u001b[1;31mImportError\u001b[0m: cannot import name 'load_adigits' from 'sklearn.datasets' (C:\\Users\\redam\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\sklearn\\datasets\\__init__.py)" + ] + } + ], + "source": [ + "# load Digits Dataset from sklearn\n", + "from sklearn.datasets import load_adigits\n", + "digits = load_adigits()\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bf5758fd", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}