├── .gitignore ├── LICENSE ├── README.md ├── background.js ├── chats ├── ChatGPT-Completing_insertSuggestion_Function.md ├── ChatGPT-Jupyter_data_capture_extension.md └── ChatGPT-Managing_Chrome_Extension_Requests.md ├── examples ├── denoisingwav_2_wavelet_2d.ipynb ├── fixing_bug_example.ipynb ├── sklearn_digits.ipynb └── starcoder_gpu_usage.ipynb ├── icons ├── flow.png ├── flow_128.png ├── flow_256.png └── flow_64.png ├── manifest.json ├── options ├── options.html ├── options.js └── styles.css └── src ├── animation.js ├── api.js ├── content.js ├── diff.js ├── preferences.js ├── state.js └── utility.js /.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Jupyter Coder 2 | Jupyter Coder is a jupyter plugin based on [Starcoder](https://github.com/bigcode-project/starcoder) 3 | Starcoder has its unique capacity to leverage the jupyter notebook structure to produce code under instruction. This plugin enable you to use starcoder in your notebook. 4 | 5 | ## Key features 6 | ### code completition 7 | In a cell, press "ctrl + space" to trigger 8 |  9 | 10 | Press "ctrl" to accpet the proposition. 11 | 12 | ### Bug fix 13 | In a cell with error message, press "ctrl + `" to trigger the bug fix mode 14 |  15 | 16 | Press ctrl to accept 17 | 18 | ## Install the chrome extension 19 | https://chrome.google.com/webstore/detail/jupyter-coder/kbedojkmlknhepcaggkdimefcbiifkjf 20 | 21 | ## Installation from github (skip if you install from chrome store) 22 | ```bash 23 | git clone https://github.com/bigcode-project/jupytercoder.git 24 | ``` 25 | 26 | Open chrome://extensions/ in your browser and enable developer mode. 27 |  28 | 29 | Then click on "Load unpacked" and select the folder where you cloned this repository. 30 |  31 | 32 | ## Add API key 33 | Then click on the extension icon to enable it, you will need to enter the bigcode model endpoint url https://api-inference.huggingface.co/models/bigcode/starcoderbase/ and your hf readonlys api key. Click save to activate this mode. 34 |  35 | 36 | ## Demo 37 | ```bash 38 | cd examples 39 | jupyter notebook 40 | ``` 41 | 42 | In case you encounter issue, you might want to install the same jupyter notebook version 43 | ```bash 44 | jupyter notebook --version 45 | >>> 6.5.2 46 | ``` 47 | 48 | Open the notebook sklearn_digits.ipynb and try it out. 49 | Type ctrl+space to trigger the code completion when you are in a code cell, then ctrl to accept it (welcome your thought on the key binding!). 50 | -------------------------------------------------------------------------------- /background.js: -------------------------------------------------------------------------------- 1 | chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { 2 | if (request.type === "getOpenAIKey") { 3 | chrome.storage.sync.get("openAIKey", (data) => { 4 | sendResponse({ openAIKey: data.openAIKey }); 5 | }); 6 | return true; // Required to use sendResponse asynchronously 7 | } 8 | else if (request.type === "getBigcodeServiceUrl"){ 9 | chrome.storage.sync.get("bigcodeServiceUrl", (data) => { 10 | sendResponse({ bigcodeServiceUrl: data.bigcodeServiceUrl }); 11 | }); 12 | return true; // Required to use sendResponse asynchronously 13 | } 14 | else if(request.type === "getCheckedMode"){ 15 | chrome.storage.sync.get("checkedMode", (data) => { 16 | sendResponse({ checkedMode: data.checkedMode }); 17 | }); 18 | return true; // Required to use sendResponse asynchronously 19 | } 20 | else if(request.type === "getGPTModelType"){ 21 | chrome.storage.sync.get("modelType", (data) => { 22 | sendResponse({ modelType: data.modelType }); 23 | }); 24 | return true; // Required to use sendResponse asynchronously 25 | } 26 | else if(request.type === "getHuggingfaceAccessToken"){ 27 | chrome.storage.sync.get("huggingfaceAccessToken", (data) => { 28 | sendResponse({ huggingfaceAccessToken : data.huggingfaceAccessToken}); 29 | }) 30 | return true; 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /chats/ChatGPT-Completing_insertSuggestion_Function.md: -------------------------------------------------------------------------------- 1 | # Completing insertSuggestion Function 2 | 3 | #### You: 4 | I am trying to insert suggestion into a jupyter notebook. Here is the js code 5 | // Check if the current page is a Jupyter Notebook 6 | if (document.querySelector('body.notebook_app')) { 7 | document.addEventListener('keydown', (event) => { 8 | // Check if the Ctrl + Space keys were pressed 9 | if (event.ctrlKey && event.code === 'Space') { 10 | event.preventDefault(); 11 | 12 | // Find the active cell in the Jupyter Notebook 13 | const activeCell = document.querySelector('.cell.selected .input_area .CodeMirror'); 14 | if (activeCell) { 15 | // Retrieve the content of the active cell 16 | const cellContent = getCellContent(activeCell); 17 | 18 | // Log the cell content to the console 19 | console.log("[CELL CONTENT]", cellContent); 20 | console.log(activeCell); 21 | 22 | // Suggestion handling 23 | const suggestion = 'your_suggestion_here'; // Replace with your actual suggestion 24 | insertSuggestion(activeCell, suggestion); 25 | } 26 | } 27 | 28 | }); 29 | 30 | function getCellContent(cell) { 31 | const codeMirrorLines = cell.querySelectorAll('.CodeMirror-code pre'); 32 | const content = []; 33 | 34 | codeMirrorLines.forEach((line) => { 35 | content.push(line.textContent); 36 | }); 37 | 38 | return content.join('\n'); 39 | } 40 | } 41 | 42 | function insertSuggestion(cell, suggestion) { 43 | 44 | } 45 | please complete the insertSuggestion function 46 | 47 | #### ChatGPT: 48 | To complete the `insertSuggestion` function, you need to access the CodeMirror instance associated with the given cell and then insert the suggestion at the current cursor position. Here's the modified code: 49 | 50 | ```javascript 51 | // Check if the current page is a Jupyter Notebook 52 | if (document.querySelector('body.notebook_app')) { 53 | document.addEventListener('keydown', (event) => { 54 | // Check if the Ctrl + Space keys were pressed 55 | if (event.ctrlKey && event.code === 'Space') { 56 | event.preventDefault(); 57 | 58 | // Find the active cell in the Jupyter Notebook 59 | const activeCell = document.querySelector('.cell.selected .input_area .CodeMirror'); 60 | if (activeCell) { 61 | // Retrieve the content of the active cell 62 | const cellContent = getCellContent(activeCell); 63 | 64 | // Log the cell content to the console 65 | console.log("[CELL CONTENT]", cellContent); 66 | console.log(activeCell); 67 | 68 | // Suggestion handling 69 | const suggestion = 'your_suggestion_here'; // Replace with your actual suggestion 70 | insertSuggestion(activeCell, suggestion); 71 | } 72 | } 73 | 74 | }); 75 | 76 | function getCellContent(cell) { 77 | const codeMirrorLines = cell.querySelectorAll('.CodeMirror-code pre'); 78 | const content = []; 79 | 80 | codeMirrorLines.forEach((line) => { 81 | content.push(line.textContent); 82 | }); 83 | 84 | return content.join('\n'); 85 | } 86 | } 87 | 88 | function insertSuggestion(cell, suggestion) { 89 | // Get the CodeMirror instance from the cell element 90 | const codeMirrorInstance = cell.CodeMirror; 91 | 92 | // Get the current cursor position 93 | const cursorPosition = codeMirrorInstance.getCursor(); 94 | 95 | // Insert the suggestion at the cursor position 96 | codeMirrorInstance.replaceRange(suggestion, cursorPosition); 97 | 98 | // Refresh the CodeMirror instance 99 | codeMirrorInstance.refresh(); 100 | } 101 | ``` 102 | 103 | Now, when you press Ctrl + Space, the `insertSuggestion` function will insert the specified suggestion at the current cursor position in the active cell of the Jupyter Notebook. 104 | 105 | 106 | #### You: 107 | I do not believe we have access to getCursor. Why do you think that ? 108 | 109 | #### ChatGPT: 110 | I apologize for the confusion. I mistakenly assumed that you have access to CodeMirror's API directly. Since you are working with the DOM, we need to find an alternative way to insert the suggestion at the cursor position. Here's the modified `insertSuggestion` function that should work in this case: 111 | 112 | ```javascript 113 | function insertSuggestion(cell, suggestion) { 114 | // Get the line element with the cursor 115 | const cursorLine = cell.querySelector('.CodeMirror-cursor').parentNode; 116 | 117 | // Get the index of the cursor within the line element 118 | const cursorIndex = Array.from(cursorLine.childNodes).findIndex( 119 | (child) => child.classList && child.classList.contains('CodeMirror-cursor') 120 | ); 121 | 122 | // Create a new text node with the suggestion 123 | const suggestionNode = document.createTextNode(suggestion); 124 | 125 | // Insert the suggestion node at the cursor index 126 | if (cursorIndex >= 0) { 127 | cursorLine.insertBefore(suggestionNode, cursorLine.childNodes[cursorIndex]); 128 | } else { 129 | cursorLine.appendChild(suggestionNode); 130 | } 131 | 132 | // Trigger a change event on the CodeMirror instance to update its internal state 133 | const event = new Event('change', { bubbles: true, cancelable: true }); 134 | cell.dispatchEvent(event); 135 | } 136 | ``` 137 | 138 | This modified function should insert the suggestion at the cursor position without using the CodeMirror API. However, this approach is less robust than using the API directly, and it might not work correctly in all situations. It would be better to use the CodeMirror API if possible. To do that, you can try to access the `Jupyter.notebook` object and find the CodeMirror instance from there. 139 | 140 | Here's an example of how to access the CodeMirror instance from the `Jupyter.notebook` object: 141 | 142 | ```javascript 143 | function insertSuggestion(cell, suggestion) { 144 | // Get the active cell in the Jupyter Notebook 145 | const activeCell = Jupyter.notebook.get_selected_cell(); 146 | 147 | // Check if the cell type is 'code' 148 | if (activeCell.cell_type === 'code') { 149 | // Get the CodeMirror instance from the active cell 150 | const codeMirrorInstance = activeCell.code_mirror; 151 | 152 | // Get the current cursor position 153 | const cursorPosition = codeMirrorInstance.getCursor(); 154 | 155 | // Insert the suggestion at the cursor position 156 | codeMirrorInstance.replaceRange(suggestion, cursorPosition); 157 | 158 | // Refresh the CodeMirror instance 159 | codeMirrorInstance.refresh(); 160 | } 161 | } 162 | ``` 163 | 164 | This approach requires you to have access to the `Jupyter.notebook` object and is more robust than working with the DOM directly. 165 | 166 | 167 | #### You: 168 |
169 | This is the div with textarea. Can we simulate the user behavior to insert suggestion 170 | 171 | #### ChatGPT: 172 | Given the structure of the div containing the textarea, you can simulate user behavior by inserting the suggestion text directly into the textarea. Here's an updated `insertSuggestion` function that inserts the suggestion into the textarea: 173 | 174 | ```javascript 175 | function insertSuggestion(cell, suggestion) { 176 | // Get the textarea inside the div 177 | const textarea = cell.querySelector('textarea'); 178 | 179 | if (textarea) { 180 | // Get the current cursor position 181 | const cursorPosition = textarea.selectionStart; 182 | 183 | // Insert the suggestion at the cursor position 184 | const newValue = textarea.value.slice(0, cursorPosition) + suggestion + textarea.value.slice(cursorPosition); 185 | textarea.value = newValue; 186 | 187 | // Update the cursor position after inserting the suggestion 188 | textarea.selectionStart = textarea.selectionEnd = cursorPosition + suggestion.length; 189 | 190 | // Trigger a change event on the textarea to update the CodeMirror instance 191 | const event = new Event('input', { bubbles: true, cancelable: true }); 192 | textarea.dispatchEvent(event); 193 | } 194 | } 195 | ``` 196 | 197 | This function should work for the provided div structure. It inserts the suggestion text at the current cursor position in the textarea and updates the cursor position accordingly. Finally, it dispatches an 'input' event to notify the CodeMirror instance of the change. 198 | 199 | 200 | #### You: 201 | Here is the updated script 202 | // Check if the current page is a Jupyter Notebook 203 | if (document.querySelector('body.notebook_app')) { 204 | document.addEventListener('keydown', (event) => { 205 | // Check if the Ctrl + Space keys were pressed 206 | if (event.ctrlKey && event.code === 'Space') { 207 | event.preventDefault(); 208 | 209 | // Find the active cell in the Jupyter Notebook 210 | const activeCell = document.querySelector('.cell.selected .input_area .CodeMirror'); 211 | if (activeCell) { 212 | // Retrieve the content of the active cell 213 | const cellContent = getCellContent(activeCell); 214 | const contextContent = getPreviousCellsContent(...); 215 | // Log the cell content to the console 216 | console.log(contextContent); 217 | 218 | // Suggestion handling 219 | const suggestion = 'your_suggestion_here'; // Replace with your actual suggestion 220 | insertSuggestion(activeCell, suggestion); 221 | } 222 | } 223 | }); 224 | 225 | function getCellContent(cell) { 226 | const codeMirrorLines = cell.querySelectorAll('.CodeMirror-code pre'); 227 | const content = []; 228 | 229 | codeMirrorLines.forEach((line) => { 230 | content.push(line.textContent); 231 | }); 232 | 233 | return content.join('\n'); 234 | } 235 | } 236 | 237 | function insertSuggestion(cell, suggestion) { 238 | // Get the textarea inside the div 239 | const textarea = cell.querySelector('textarea'); 240 | 241 | if (textarea) { 242 | // Get the current cursor position 243 | const cursorPosition = textarea.selectionStart; 244 | 245 | // Insert the suggestion at the cursor position 246 | const newValue = textarea.value.slice(0, cursorPosition) + suggestion + textarea.value.slice(cursorPosition); 247 | textarea.value = newValue; 248 | 249 | // Update the cursor position after inserting the suggestion 250 | textarea.selectionStart = textarea.selectionEnd = cursorPosition + suggestion.length; 251 | 252 | // Trigger a change event on the textarea to update the CodeMirror instance 253 | const event = new Event('input', { bubbles: true, cancelable: true }); 254 | textarea.dispatchEvent(event); 255 | } 256 | } 257 | now write the getPreviousCellsContent function 258 | 259 | #### ChatGPT: 260 | The `getPreviousCellsContent` function should collect the content of all code cells before the active cell in the Jupyter Notebook. Here's the function: 261 | 262 | ```javascript 263 | function getPreviousCellsContent() { 264 | const activeCell = document.querySelector('.cell.selected .input_area .CodeMirror'); 265 | const allCells = document.querySelectorAll('.cell .input_area .CodeMirror'); 266 | const previousCellsContent = []; 267 | 268 | for (const cell of allCells) { 269 | // Stop when the active cell is reached 270 | if (cell === activeCell) break; 271 | 272 | // Check if the cell is a code cell 273 | const isCodeCell = cell.closest('.cell').classList.contains('code_cell'); 274 | if (isCodeCell) { 275 | const cellContent = getCellContent(cell); 276 | previousCellsContent.push(cellContent); 277 | } 278 | } 279 | 280 | return previousCellsContent.join('\n'); 281 | } 282 | ``` 283 | 284 | This function first selects the active cell and all cells in the notebook. Then, it iterates through all cells and checks if each cell is a code cell. If the cell is a code cell, it collects its content and adds it to the `previousCellsContent` array. The iteration stops when the active cell is reached. The function returns the content of all previous code cells as a single string, joined by newlines. 285 | 286 | 287 | #### You: 288 | change it to get only the three previous cells 289 | 290 | #### ChatGPT: 291 | To modify the `getPreviousCellsContent` function to get only the three previous cells, you can use a counter variable to track how many code cells have been processed. Here's the updated function: 292 | 293 | ```javascript 294 | function getPreviousCellsContent() { 295 | const activeCell = document.querySelector('.cell.selected .input_area .CodeMirror'); 296 | const allCells = document.querySelectorAll('.cell .input_area .CodeMirror'); 297 | const previousCellsContent = []; 298 | let codeCellCount = 0; 299 | 300 | for (const cell of allCells) { 301 | // Stop when the active cell is reached or when three code cells have been processed 302 | if (cell === activeCell || codeCellCount >= 3) break; 303 | 304 | // Check if the cell is a code cell 305 | const isCodeCell = cell.closest('.cell').classList.contains('code_cell'); 306 | if (isCodeCell) { 307 | const cellContent = getCellContent(cell); 308 | previousCellsContent.unshift(cellContent); // Add the content to the beginning of the array 309 | codeCellCount++; 310 | } 311 | } 312 | 313 | // If there are more than three code cells, get only the last three 314 | const lastThreeCellsContent = previousCellsContent.slice(-3); 315 | 316 | return lastThreeCellsContent.join('\n'); 317 | } 318 | ``` 319 | 320 | This function now uses the `codeCellCount` variable to keep track of how many code cells have been processed. It stops when the active cell is reached or when three code cells have been processed. The cell content is added to the beginning of the `previousCellsContent` array using the `unshift()` method. Finally, if there are more than three code cells, the function returns only the content of the last three code cells. 321 | 322 | 323 | #### You: 324 | It is giving me the first three cells 325 | 326 | #### ChatGPT: 327 | Apologies for the confusion. I made a mistake in the previous implementation. To get the content of the last three cells before the active cell, you can iterate through the cells in reverse order. Here's the corrected `getPreviousCellsContent` function: 328 | 329 | ```javascript 330 | function getPreviousCellsContent() { 331 | const activeCell = document.querySelector('.cell.selected .input_area .CodeMirror'); 332 | const allCells = Array.from(document.querySelectorAll('.cell .input_area .CodeMirror')).reverse(); 333 | const previousCellsContent = []; 334 | let codeCellCount = 0; 335 | 336 | for (const cell of allCells) { 337 | // Stop when the active cell is reached or when three code cells have been processed 338 | if (cell === activeCell || codeCellCount >= 3) break; 339 | 340 | // Check if the cell is a code cell 341 | const isCodeCell = cell.closest('.cell').classList.contains('code_cell'); 342 | if (isCodeCell) { 343 | const cellContent = getCellContent(cell); 344 | previousCellsContent.push(cellContent); // Add the content to the end of the array 345 | codeCellCount++; 346 | } 347 | } 348 | 349 | // Reverse the array to have the content in the correct order 350 | const lastThreeCellsContent = previousCellsContent.reverse(); 351 | 352 | return lastThreeCellsContent.join('\n'); 353 | } 354 | ``` 355 | 356 | In this updated implementation, I've converted the `NodeList` returned by `querySelectorAll` into an array using `Array.from()` and reversed the order of the cells using the `reverse()` method. This way, the loop iterates through the cells in reverse order. After collecting the content of the last three code cells, the `previousCellsContent` array is reversed again to have the content in the correct order. 357 | -------------------------------------------------------------------------------- /chats/ChatGPT-Jupyter_data_capture_extension.md: -------------------------------------------------------------------------------- 1 | # Jupyter data capture extension. 2 | 3 | #### You: 4 | Write a chrome extension to catch data in a jupyter notebook: 5 | - each time user hit ctrl + space, the extension catch the content of the current cell, then post the content to a remote server 6 | 7 | #### ChatGPT: 8 | To create a Chrome extension that captures data from a Jupyter Notebook cell when the user presses Ctrl + Space, you'll need to follow these steps: 9 | 10 | 1. Set up the extension's structure 11 | 2. Create a content script that listens for key events in Jupyter Notebook cells 12 | 3. Send the captured data to a remote server using an XMLHttpRequest 13 | 14 | Here's the structure and code for the Chrome extension: 15 | 16 | 1. Extension structure: 17 | 18 | ``` 19 | jupyter-data-capture/ 20 | │ 21 | ├── manifest.json 22 | └── content.js 23 | ``` 24 | 25 | 2. Create a `manifest.json` file with the following content: 26 | 27 | ```json 28 | { 29 | "manifest_version": 3, 30 | "name": "Jupyter Data Capture", 31 | "version": "1.0", 32 | "description": "Capture data in Jupyter Notebook cells and send to a remote server.", 33 | "permissions": [ 34 | "activeTab", 35 | "https://your-remote-server-url.com/" 36 | ], 37 | "content_scripts": [ 38 | { 39 | "matches": ["*://*/*"], 40 | "js": ["content.js"], 41 | "run_at": "document_end" 42 | } 43 | ] 44 | } 45 | ``` 46 | 47 | Make sure to replace `your-remote-server-url.com` with the actual URL of your remote server. 48 | 49 | 3. Create a `content.js` file with the following content: 50 | 51 | ```javascript 52 | // Check if the current page is a Jupyter Notebook 53 | if (document.querySelector('body.notebook_app')) { 54 | // 55 | ``` 56 | 57 | 58 | #### You: 59 | write the content.js 60 | 61 | #### ChatGPT: 62 | Here's the `content.js` file for the Chrome extension: 63 | 64 | ```javascript 65 | // Check if the current page is a Jupyter Notebook 66 | if (document.querySelector('body.notebook_app')) { 67 | document.addEventListener('keydown', (event) => { 68 | // Check if the Ctrl + Space keys were pressed 69 | if (event.ctrlKey && event.code === 'Space') { 70 | event.preventDefault(); 71 | 72 | // Find the active cell in the Jupyter Notebook 73 | const activeCell = document.querySelector('.cell.selected .CodeMirror'); 74 | if (activeCell) { 75 | // Retrieve the content of the active cell 76 | const cellContent = activeCell.CodeMirror.getValue(); 77 | 78 | // Send the cell content to the remote server 79 | sendToServer(cellContent); 80 | } 81 | } 82 | }); 83 | } 84 | 85 | function sendToServer(cellContent) { 86 | const xhr = new XMLHttpRequest(); 87 | const serverURL = 'https://your-remote-server-url.com/endpoint'; 88 | 89 | // Configure the request 90 | xhr.open('POST', serverURL, true); 91 | xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8'); 92 | 93 | // Set up the request's callback 94 | xhr.onreadystatechange = function () { 95 | if (xhr.readyState === 4 && xhr.status === 200) { 96 | console.log('Data sent successfully'); 97 | } else if (xhr.readyState === 4) { 98 | console.error('Error sending data to the server'); 99 | } 100 | }; 101 | 102 | // Send the request 103 | const data = JSON.stringify({ cellContent: cellContent }); 104 | xhr.send(data); 105 | } 106 | ``` 107 | 108 | Make sure to replace `your-remote-server-url.com/endpoint` with the actual URL and endpoint of 109 | 110 | 111 | #### You: 112 | for now just do a console.log instead of actually sending the data to server 113 | 114 | #### ChatGPT: 115 | Here's the updated `content.js` file that logs the cell content to the console instead of sending it to a server: 116 | 117 | ```javascript 118 | // Check if the current page is a Jupyter Notebook 119 | if (document.querySelector('body.notebook_app')) { 120 | document.addEventListener('keydown', (event) => { 121 | // Check if the Ctrl + Space keys were pressed 122 | if (event.ctrlKey && event.code === 'Space') { 123 | event.preventDefault(); 124 | 125 | // Find the active cell in the Jupyter Notebook 126 | const activeCell = document.querySelector('.cell.selected .CodeMirror'); 127 | if (activeCell) { 128 | // Retrieve the content of the active cell 129 | const cellContent = activeCell.CodeMirror.getValue(); 130 | 131 | // Log the cell content to the console 132 | console.log(cellContent); 133 | } 134 | } 135 | }); 136 | } 137 | ``` 138 | 139 | This script checks if the current page is a Jupyter Notebook and listens for the Ctrl + Space key combination. When the key combination is detected, it retrieves the content of the currently active cell and logs it to the console. 140 | 141 | 142 | #### You: 143 | content.js:12 Uncaught TypeError: Cannot read properties of undefined (reading 'getValue') 144 | at HTMLDocument.prompt = """
import pandas as pd
import numpy as np
df = pd.read_csv("data.csv")
all_outputs = [pd.DataFrame()]
'''<class 'pandas.core.frame.DataFrame'>
RangeIndex: 9 entries, 0 to 8
Data columns (total 2 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 reference 9 non-null int64
1 prediction 9 non-null float64
dtypes: float64(1), int64(1)
memory usage: 272.0 bytes
'''
# threshold prediction at 0.5
df['prediction'] = df['prediction'].apply(lambda x: 1 if x > 0.5 else 0)
# compute the confusion matrix
"""
x
prompt = """
import pandas as pd
import numpy as np
df = pd.read_csv("data.csv")
all_outputs = [pd.DataFrame()]
'''<class 'pandas.core.frame.DataFrame'>
RangeIndex: 9 entries, 0 to 8
Data columns (total 2 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 reference 9 non-null int64
1 prediction 9 non-null float64
dtypes: float64(1), int64(1)
memory usage: 272.0 bytes
'''
# threshold prediction at 0.5
df['prediction'] = df['prediction'].apply(lambda x: 1 if x > 0.5 else 0)
# compute the confusion matrix
"""
` element to display the response. 85 | 86 | 2. Create a JavaScript file (`popup.js`) to handle the button click and make the HTTP GET request: 87 | 88 | ```js 89 | document.getElementById('getRequestButton').addEventListener('click', () => { 90 | // URL to make the GET request to 91 | const url = 'https://jsonplaceholder.typicode.com/todos/1'; 92 | 93 | // Make the GET request using the fetch API 94 | fetch(url) 95 | .then((response) => { 96 | // Check if the response is successful 97 | if (!response.ok) { 98 | throw new Error('Network response was not ok'); 99 | } 100 | // Parse the response as JSON 101 | return response.json(); 102 | }) 103 | .then((data) => { 104 | // Display the response data as a JSON string 105 | document.getElementById('responseContainer').textContent = JSON.stringify(data, null, 2); 106 | }) 107 | .catch((error) => { 108 | // Handle any errors that occurred during the fetch 109 | console.error('There was a problem with the fetch operation:', error); 110 | document.getElementById('responseContainer').textContent = 'Error: ' + error.message; 111 | }); 112 | }); 113 | ``` 114 | 115 | In this example, we add an event listener to the button to handle the click event. When the button is clicked, we use the `fetch` API to make an HTTP GET request to the specified URL. We then parse the response as JSON and display it in the `responseContainer` element. If any errors occur, we handle them and display an error message. 116 | 117 | 3. Update the `manifest.json` file to include the popup and permissions: 118 | 119 | ```json 120 | { 121 | "manifest_version": 3, 122 | "name": "HTTP GET Request Example", 123 | "version": "1.0", 124 | "permissions": ["https://jsonplaceholder.typicode.com/*"], 125 | "action": { 126 | "default_popup": "popup.html" 127 | } 128 | } 129 | ``` 130 | 131 | In this example, we specify the `default_popup` property to point to the `popup.html` file we created earlier. We also declare the necessary permissions for the URL we are making the request to. 132 | 133 | After creating these files, you can load the extension into Chrome, and when you click the extension's icon, the popup will appear with the "Make GET Request" button. Clicking the button will make the HTTP GET request and display the response in the popup. 134 | 135 | 136 | #### You: 137 | how to handle promise in chrome extension 138 | 139 | #### ChatGPT: 140 | In a Chrome extension, handling promises is similar to handling promises in regular JavaScript code. Promises are used to represent the eventual completion (or failure) of an asynchronous operation and its resulting value. Here's how you can handle promises in a Chrome extension: 141 | 142 | 1. Creating and Using a Promise: 143 | 144 | ```js 145 | // Create a function that returns a promise 146 | function getData() { 147 | return new Promise((resolve, reject) => { 148 | // Simulate an asynchronous operation (e.g., fetching data) 149 | setTimeout(() => { 150 | const data = 'Sample data'; 151 | resolve(data); // Resolve the promise with the data 152 | }, 1000); 153 | }); 154 | } 155 | 156 | // Use the promise 157 | getData() 158 | .then((data) => { 159 | // Handle the resolved data 160 | console.log('Data:', data); 161 | }) 162 | .catch((error) => { 163 | // Handle any errors 164 | console.error('Error:', error); 165 | }); 166 | ``` 167 | 168 | 2. Using `async/await` with Promises: 169 | 170 | ```js 171 | // Create an async function that uses await to handle the promise 172 | async function fetchData() { 173 | try { 174 | const data = await getData(); // Use await to handle the promise 175 | console.log('Data:', data); 176 | } catch (error) { 177 | console.error('Error:', error); 178 | } 179 | } 180 | 181 | // Call the async function 182 | fetchData(); 183 | ``` 184 | 185 | 3. Handling Promises Returned by APIs: 186 | Many APIs return promises, and you can handle them in a similar way. For example, the `fetch` API returns a promise that resolves with the Response object representing the response to the request: 187 | 188 | ```js 189 | // Make a GET request using the fetch API 190 | fetch('https://jsonplaceholder.typicode.com/todos/1') 191 | .then((response) => { 192 | // Check if the response is successful 193 | if (!response.ok) { 194 | throw new Error('Network response was not ok'); 195 | } 196 | // Parse the response as JSON 197 | return response.json(); 198 | }) 199 | .then((data) => { 200 | // Handle the resolved data 201 | console.log('Data:', data); 202 | }) 203 | .catch((error) => { 204 | // Handle any errors 205 | console.error('Error:', error); 206 | }); 207 | ``` 208 | 209 | 4. Using `async/await` with APIs Returning Promises: 210 | 211 | ```js 212 | // Create an async function to fetch data using the fetch API 213 | async function fetchData() { 214 | try { 215 | const response = await fetch('https://jsonplaceholder.typicode.com/todos/1'); 216 | if (!response.ok) { 217 | throw new Error('Network response was not ok'); 218 | } 219 | const data = await response.json(); 220 | console.log('Data:', data); 221 | } catch (error) { 222 | console.error('Error:', error); 223 | } 224 | } 225 | 226 | // Call the async function 227 | fetchData(); 228 | ``` 229 | 230 | These examples demonstrate how to handle promises in a Chrome extension, whether you create your own promises, use promises returned by APIs, or use the `async/await` syntax for more concise and readable code. 231 | 232 | 233 | #### You: 234 | I write this 235 | getCodeCompletion(code).then((suggestion) => { 236 | console.log(suggestion); 237 | insertSuggestion(activeCell, suggestion); 238 | } 239 | suggestion is undefined 240 | 241 | #### ChatGPT: 242 | If `suggestion` is `undefined` in the `.then()` block, it means that the promise returned by the `getCodeCompletion(code)` function is resolving with an `undefined` value. There are a few possible reasons for this: 243 | 244 | 1. The `getCodeCompletion(code)` function is not returning a value, or it is explicitly returning `undefined`. 245 | 2. The function that resolves the promise inside `getCodeCompletion(code)` is not providing a value when calling the `resolve` function. 246 | 3. There is an error or exception occurring inside `getCodeCompletion(code)` that prevents the promise from being resolved with a value. 247 | 248 | To troubleshoot this issue, you need to examine the implementation of the `getCodeCompletion(code)` function. Here's what you should look for: 249 | 250 | 1. Check the `getCodeCompletion(code)` function to ensure that it returns a promise. 251 | 2. If the promise is created using the `Promise` constructor, make sure that the `resolve` function is called with the desired value. 252 | 3. If the promise is created using an API or another function that returns a promise, make sure that the value is being passed correctly to the `.then()` block. 253 | 254 | Here's an example of a correctly implemented `getCodeCompletion(code)` function: 255 | 256 | ```js 257 | function getCodeCompletion(code) { 258 | return new Promise((resolve, reject) => { 259 | // Simulate an asynchronous operation 260 | setTimeout(() => { 261 | // Example: Generate a suggestion based on the input code 262 | const suggestion = code + ' SUGGESTION'; 263 | resolve(suggestion); // Resolve the promise with the suggestion 264 | }, 1000); 265 | }); 266 | } 267 | 268 | // Usage 269 | getCodeCompletion('Sample code').then((suggestion) => { 270 | console.log(suggestion); 271 | // insertSuggestion(activeCell, suggestion); 272 | }); 273 | ``` 274 | 275 | In this example, the `getCodeCompletion(code)` function returns a promise that resolves with a suggestion based on the input code. The suggestion is then logged to the console in the `.then()` block. 276 | 277 | If you're still having trouble, please provide more context or share the implementation of the `getCodeCompletion(code)` function so that I can provide more specific guidance. 278 | 279 | 280 | #### You: 281 | Here is getcodecompletion 282 | async function getCodeCompletion(code) { 283 | const prompt = ` 284 | I have the following code: 285 | 286 | \`\`\` 287 | ${code} 288 | \`\`\` 289 | 290 | Please provide the missing code to complete the task. 291 | `; 292 | 293 | return await sendToOpenAI(prompt); 294 | } 295 | 296 | #### ChatGPT: 297 | The `getCodeCompletion` function is an `async` function that takes `code` as an input, constructs a prompt, and then calls the `sendToOpenAI` function with the prompt. The function returns the result of `sendToOpenAI`. 298 | 299 | To troubleshoot the issue of `suggestion` being `undefined`, we need to examine the implementation of the `sendToOpenAI` function. Specifically, we need to check whether `sendToOpenAI` returns a value (the suggestion) when it resolves. 300 | 301 | Here's what you should look for in the `sendToOpenAI` function: 302 | 303 | 1. Ensure that `sendToOpenAI` returns a promise that resolves with the desired suggestion value. 304 | 2. Check how the response from the OpenAI API is parsed and how the suggestion is extracted from the response. 305 | 306 | If you can provide the implementation of the `sendToOpenAI` function, I can provide more specific guidance. In the meantime, here's a simplified example of how the `sendToOpenAI` function might be implemented: 307 | 308 | ```js 309 | async function sendToOpenAI(prompt) { 310 | // Simulate an API call to OpenAI 311 | const response = await fetch('https://api.openai.com/v1/...', { 312 | method: 'POST', 313 | headers: { 'Content-Type': 'application/json' }, 314 | body: JSON.stringify({ prompt: prompt }) 315 | }); 316 | 317 | // Check if the response is successful 318 | if (!response.ok) { 319 | throw new Error('API response was not ok'); 320 | } 321 | 322 | // Parse the response as JSON 323 | const data = await response.json(); 324 | 325 | // Extract the suggestion from the API response (this depends on the API's response structure) 326 | const suggestion = data.choices[0]?.text; 327 | 328 | return suggestion; 329 | } 330 | 331 | // Usage 332 | getCodeCompletion('Sample code').then((suggestion) => { 333 | console.log(suggestion); 334 | // insertSuggestion(activeCell, suggestion); 335 | }); 336 | ``` 337 | 338 | In this example, the `sendToOpenAI` function makes an API call to OpenAI, parses the response, extracts the suggestion, and returns it. The `getCodeCompletion` function then uses this suggestion in the `.then()` block. Note that the structure of the API response and the way the suggestion is extracted may vary depending on the actual OpenAI API you are using. 339 | 340 | 341 | #### You: 342 | Here is sendtoopenai 343 | 344 | // Function to send request to OpenAI API 345 | async function sendToOpenAI(prompt) { 346 | const response = await fetch("https://api.openai.com/v1/chat/completions", { 347 | method: "POST", 348 | headers: { 349 | "Content-Type": "application/json", 350 | "Authorization": `Bearer ${OPENAI_API_KEY}`, 351 | }, 352 | body: JSON.stringify({ 353 | model: "gpt-3.5-turbo", 354 | messages: [{ role: "user", content: prompt }], 355 | }), 356 | }); 357 | const data = await response.json(); 358 | return data.choices && data.choices[0] && data.choices[0].message.text; 359 | } 360 | 361 | #### ChatGPT: 362 | The `sendToOpenAI` function sends a request to the OpenAI API using the GPT-3.5-turbo model and returns the text of the first choice from the API response. The function appears to be implemented correctly, and it returns the text of the first choice if it exists. 363 | 364 | If `suggestion` is `undefined` in the `.then()` block, it could be because the API response does not contain any choices, or the first choice does not have a `message.text` property. To handle this case, you can add a check to ensure that `suggestion` is defined before using it: 365 | 366 | ```js 367 | getCodeCompletion(code).then((suggestion) => { 368 | if (suggestion) { 369 | console.log(suggestion); 370 | insertSuggestion(activeCell, suggestion); 371 | } else { 372 | console.log('No suggestion received from the API.'); 373 | } 374 | }).catch((error) => { 375 | console.error('Error:', error); 376 | }); 377 | ``` 378 | 379 | In this updated code, we check if `suggestion` is defined before using it. If it is not defined, we log a message indicating that no suggestion was received from the API. Additionally, we added a `.catch()` block to handle any errors that may occur during the process. 380 | 381 | If you are still experiencing issues, you may want to log the entire API response (`data`) inside the `sendToOpenAI` function to inspect its structure and verify that it contains the expected information: 382 | 383 | ```js 384 | async function sendToOpenAI(prompt) { 385 | // ... 386 | const data = await response.json(); 387 | console.log('API response:', data); // Log the entire API response 388 | return data.choices && data.choices[0] && data.choices[0].message.text; 389 | } 390 | ``` 391 | 392 | By logging the entire API response, you can check whether the response contains the expected `choices` array and whether the first choice contains a `message.text` property. 393 | 394 | 395 | #### You: 396 | Here is the response 397 | {"id":"chatcmpl-72Zc1o5foPTSCqz4FA2UR0PArwDiw","object":"chat.completion","created":1680847905,"model":"gpt-3.5-turbo-0301","usage":{"prompt_tokens":201,"completion_tokens":232,"total_tokens":433},"choices":[{"message":{"role":"assistant","content":"```\n\"\"\"read the csv usage_df.csv\n\"\"\"\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n# read the csv\ndf = pd.read_csv('usage_df.csv', index_col=0)\n# df.index = df.date\ndf\n\"\"\"usage_df has two column:\n1.date: a string like \"2022-03-01\"\n2.gpu_usage: a float indicating the average gpu uage\nData columns (total 2 columns):\n # Column Non-Null Count Dtype \n--- ------ -------------- ----- \n 0 date 365 non-null object \n 1 gpu_usage 365 non-null float64\nplot the daily usage of month 2022-03\n\"\"\"\n# plot the daily usage of month 2022-03\ndf['date'] = pd.to_datetime(df['date'])\ndf.set_index('date', inplace=True)\ndf.loc['2022-03']['gpu_usage'].plot()\nplt.title('GPU Usage in March 2022')\nplt.xlabel('Date')\nplt.ylabel('GPU Usage')\nplt.show()\n```"},"finish_reason":"stop","index":0}]} 398 | 399 | 400 | #### ChatGPT: 401 | The response from the OpenAI API contains a `choices` array with one element, and the `message` object inside the choice has a `role` property set to `"assistant"` and a `content` property that contains the generated text. The `content` property is what you want to extract as the suggestion. 402 | 403 | Based on the response structure, you can extract the suggestion as follows: 404 | 405 | ```js 406 | async function sendToOpenAI(prompt) { 407 | const response = await fetch("https://api.openai.com/v1/chat/completions", { 408 | method: "POST", 409 | headers: { 410 | "Content-Type": "application/json", 411 | "Authorization": `Bearer ${OPENAI_API_KEY}`, 412 | }, 413 | body: JSON.stringify({ 414 | model: "gpt-3.5-turbo", 415 | messages: [{ role: "user", content: prompt }], 416 | }), 417 | }); 418 | const data = await response.json(); 419 | return data.choices && data.choices[0] && data.choices[0].message.content; 420 | } 421 | ``` 422 | 423 | The key change here is to use `data.choices[0].message.content` instead of `data.choices[0].message.text` to extract the suggestion from the API response. 424 | 425 | With this change, the `suggestion` variable in the `.then()` block should contain the generated text from the API: 426 | 427 | ```js 428 | getCodeCompletion(code).then((suggestion) => { 429 | if (suggestion) { 430 | console.log(suggestion); 431 | insertSuggestion(activeCell, suggestion); 432 | } else { 433 | console.log('No suggestion received from the API.'); 434 | } 435 | }).catch((error) => { 436 | console.error('Error:', error); 437 | }); 438 | ``` 439 | 440 | This should resolve the issue of `suggestion` being `undefined`, and you should now be able to see the generated text in the console and use it in the `insertSuggestion` function. 441 | 442 | 443 | #### You: 444 | getCodeCompletion(code).then((suggestion) => { 445 | if (suggestion) { 446 | console.log("[PROMPT]\n" + code) 447 | console.log("[RESPONSE]\n" + suggestion); 448 | insertSuggestion(activeCell, suggestion); 449 | } else { 450 | console.log('No suggestion received from the API.'); 451 | } 452 | }).catch((error) => { 453 | console.error('Error:', error); 454 | }); 455 | Parse the suggestion to identify code block and remove ``` 456 | Here is an example 457 | ``` 458 | # convert the date column to datetime object 459 | df['date'] = pd.to_datetime(df['date']) 460 | 461 | # sort the dataframe by date 462 | df = df.sort_values('date') 463 | 464 | # plot the data 465 | plt.plot(df['date'], df['gpu_usage']) 466 | plt.xlabel('Date') 467 | plt.ylabel('GPU Usage') 468 | plt.title('Daily GPU Usage in March 2022') 469 | plt.show() 470 | ``` 471 | 472 | #### ChatGPT: 473 | To parse the suggestion and extract the code block while removing the triple backticks (\`\`\`), you can use a regular expression to match the content between the backticks. Here's how you can do it: 474 | 475 | ````js 476 | getCodeCompletion(code).then((suggestion) => { 477 | if (suggestion) { 478 | console.log("[PROMPT]\n" + code); 479 | console.log("[RESPONSE]\n" + suggestion); 480 | 481 | // Use a regular expression to match the content between triple backticks 482 | const codeBlockRegex = /```([\s\S]*?)```/g; 483 | const match = codeBlockRegex.exec(suggestion); 484 | const extractedCode = match && match[1] ? match[1].trim() : ''; 485 | 486 | // Log the extracted code block 487 | console.log("[EXTRACTED CODE]\n" + extractedCode); 488 | 489 | insertSuggestion(activeCell, extractedCode); 490 | } else { 491 | console.log('No suggestion received from the API.'); 492 | } 493 | }).catch((error) => { 494 | console.error('Error:', error); 495 | }); 496 | ```` 497 | 498 | In this code, we use the regular expression `/```([\s\S]*?)```/g` to match the content between triple backticks. The expression `([\s\S]*?)` captures any characters, including newlines, between the backticks. We then use the `exec` method to find the match and extract the captured group (the code block) using `match[1]`. We also use the `trim` method to remove any leading or trailing whitespace from the extracted code block. 499 | 500 | The variable `extractedCode` contains the code block without the triple backticks, and you can use it in the `insertSuggestion` function or for any other purpose. 501 | -------------------------------------------------------------------------------- /examples/fixing_bug_example.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 4, 6 | "id": "1114df89", 7 | "metadata": {}, 8 | "outputs": [ 9 | { 10 | "ename": "NameError", 11 | "evalue": "name 'printa' is not defined", 12 | "output_type": "error", 13 | "traceback": [ 14 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 15 | "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", 16 | "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", 17 | "\u001b[1;31mNameError\u001b[0m: name 'printa' is not defined" 18 | ] 19 | } 20 | ], 21 | "source": [ 22 | "# print \"Hello, World!\"\n", 23 | "printa(\"Hello, World!\")" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 5, 29 | "id": "88fe6fb4", 30 | "metadata": {}, 31 | "outputs": [ 32 | { 33 | "ename": "SyntaxError", 34 | "evalue": "expected ':' (3930893725.py, line 1)", 35 | "output_type": "error", 36 | "traceback": [ 37 | "\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" 38 | ] 39 | } 40 | ], 41 | "source": [ 42 | "if x == 5\n", 43 | " print(\"x == 5\")" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": 30, 49 | "id": "b73b834e", 50 | "metadata": {}, 51 | "outputs": [ 52 | { 53 | "ename": "NameError", 54 | "evalue": "name 'y' is not defined", 55 | "output_type": "error", 56 | "traceback": [ 57 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 58 | "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", 59 | "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", 60 | "\u001b[1;31mNameError\u001b[0m: name 'y' is not defined" 61 | ] 62 | } 63 | ], 64 | "source": [ 65 | "x = 10\n", 66 | "print(y)" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": 39, 72 | "id": "72409629", 73 | "metadata": {}, 74 | "outputs": [ 75 | { 76 | "ename": "NameError", 77 | "evalue": "name 'calculate_sum' is not defined", 78 | "output_type": "error", 79 | "traceback": [ 80 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 81 | "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", 82 | "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", 83 | "\u001b[1;31mNameError\u001b[0m: name 'calculate_sum' is not defined" 84 | ] 85 | } 86 | ], 87 | "source": [ 88 | "calculate_sum(5, 10)" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 40, 94 | "id": "c0c74cd8", 95 | "metadata": {}, 96 | "outputs": [ 97 | { 98 | "ename": "TypeError", 99 | "evalue": "can only concatenate str (not \"int\") to str", 100 | "output_type": "error", 101 | "traceback": [ 102 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 103 | "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", 104 | "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", 105 | "\u001b[1;31mTypeError\u001b[0m: can only concatenate str (not \"int\") to str" 106 | ] 107 | } 108 | ], 109 | "source": [ 110 | "x = \"Hello\"\n", 111 | "y = 5\n", 112 | "print(x + y)" 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": 44, 118 | "id": "3315c57c", 119 | "metadata": {}, 120 | "outputs": [ 121 | { 122 | "ename": "AttributeError", 123 | "evalue": "'dict' object has no attribute 'name'", 124 | "output_type": "error", 125 | "traceback": [ 126 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 127 | "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", 128 | "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", 129 | "\u001b[1;31mAttributeError\u001b[0m: 'dict' object has no attribute 'name'" 130 | ] 131 | } 132 | ], 133 | "source": [ 134 | "person = {\"name\": \"Alice\", \"age\": 30}\n", 135 | "print(person.name)" 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": 42, 141 | "id": "bcd5e7b4", 142 | "metadata": {}, 143 | "outputs": [ 144 | { 145 | "ename": "ZeroDivisionError", 146 | "evalue": "division by zero", 147 | "output_type": "error", 148 | "traceback": [ 149 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 150 | "\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", 151 | "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", 152 | "\u001b[1;31mZeroDivisionError\u001b[0m: division by zero" 153 | ] 154 | } 155 | ], 156 | "source": [ 157 | "x = 10\n", 158 | "y = 0\n", 159 | "result = x / y" 160 | ] 161 | }, 162 | { 163 | "cell_type": "code", 164 | "execution_count": 1, 165 | "id": "1eb252b2", 166 | "metadata": {}, 167 | "outputs": [ 168 | { 169 | "ename": "KeyError", 170 | "evalue": "'city'", 171 | "output_type": "error", 172 | "traceback": [ 173 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 174 | "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", 175 | "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", 176 | "\u001b[1;31mKeyError\u001b[0m: 'city'" 177 | ] 178 | } 179 | ], 180 | "source": [ 181 | "my_dict = {\"name\": \"Alice\", \"age\": 30}\n", 182 | "print(my_dict[\"city\"])" 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "execution_count": 30, 188 | "id": "b076aeb0", 189 | "metadata": {}, 190 | "outputs": [ 191 | { 192 | "ename": "ImportError", 193 | "evalue": "cannot import name 'load_adigits' from 'sklearn.datasets' (C:\\Users\\redam\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\sklearn\\datasets\\__init__.py)", 194 | "output_type": "error", 195 | "traceback": [ 196 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 197 | "\u001b[1;31mImportError\u001b[0m Traceback (most recent call last)", 198 | "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", 199 | "\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)" 200 | ] 201 | } 202 | ], 203 | "source": [ 204 | "# load Digits Dataset from sklearn\n", 205 | "from sklearn.datasets import load_adigits\n", 206 | "digits = load_adigits()\n", 207 | "\n" 208 | ] 209 | }, 210 | { 211 | "cell_type": "code", 212 | "execution_count": null, 213 | "id": "bf5758fd", 214 | "metadata": {}, 215 | "outputs": [], 216 | "source": [] 217 | } 218 | ], 219 | "metadata": { 220 | "kernelspec": { 221 | "display_name": "Python 3 (ipykernel)", 222 | "language": "python", 223 | "name": "python3" 224 | }, 225 | "language_info": { 226 | "codemirror_mode": { 227 | "name": "ipython", 228 | "version": 3 229 | }, 230 | "file_extension": ".py", 231 | "mimetype": "text/x-python", 232 | "name": "python", 233 | "nbconvert_exporter": "python", 234 | "pygments_lexer": "ipython3", 235 | "version": "3.10.11" 236 | } 237 | }, 238 | "nbformat": 4, 239 | "nbformat_minor": 5 240 | } 241 | -------------------------------------------------------------------------------- /examples/sklearn_digits.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "1114df89", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "# load Digits Dataset from sklearn\n" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "id": "bdc6d694", 16 | "metadata": {}, 17 | "source": [ 18 | "Print to show there are 1797 images (8 by 8 images for a dimensionality of 64)\n", 19 | "\n", 20 | "Print to show there are 1797 labels (integers from 0–9)" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": null, 26 | "id": "c164026e", 27 | "metadata": {}, 28 | "outputs": [], 29 | "source": [] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "id": "f3c71c94", 34 | "metadata": {}, 35 | "source": [ 36 | "Showing the Images and the Labels (Digits Dataset)\n", 37 | "\n", 38 | "This section is really just to show what the images and labels look like. It usually helps to visualize your data to see what you are working with.\n" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": null, 44 | "id": "20657b9d", 45 | "metadata": {}, 46 | "outputs": [], 47 | "source": [] 48 | } 49 | ], 50 | "metadata": { 51 | "kernelspec": { 52 | "display_name": "Python 3 (ipykernel)", 53 | "language": "python", 54 | "name": "python3" 55 | }, 56 | "language_info": { 57 | "codemirror_mode": { 58 | "name": "ipython", 59 | "version": 3 60 | }, 61 | "file_extension": ".py", 62 | "mimetype": "text/x-python", 63 | "name": "python", 64 | "nbconvert_exporter": "python", 65 | "pygments_lexer": "ipython3", 66 | "version": "3.8.10" 67 | } 68 | }, 69 | "nbformat": 4, 70 | "nbformat_minor": 5 71 | } 72 | -------------------------------------------------------------------------------- /examples/starcoder_gpu_usage.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "id": "3aa18388", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import pandas as pd\n", 11 | "import numpy as np\n", 12 | "import matplotlib.pyplot as plt" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "id": "50ed5565", 18 | "metadata": {}, 19 | "source": [ 20 | "read the csv usage_df.csv" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": null, 26 | "id": "0997b28d", 27 | "metadata": {}, 28 | "outputs": [], 29 | "source": [] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "id": "25867be0", 34 | "metadata": {}, 35 | "source": [ 36 | "plot the daily usage of month 2022-03" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": null, 42 | "id": "e7fed4a1", 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [] 46 | }, 47 | { 48 | "cell_type": "markdown", 49 | "id": "9dd0a765", 50 | "metadata": {}, 51 | "source": [ 52 | "Calculate the average monthly usage and plot the data" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": null, 58 | "id": "e0e304b0", 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": null, 66 | "id": "e7e4b2e2", 67 | "metadata": {}, 68 | "outputs": [], 69 | "source": [] 70 | } 71 | ], 72 | "metadata": { 73 | "kernelspec": { 74 | "display_name": "Python 3 (ipykernel)", 75 | "language": "python", 76 | "name": "python3" 77 | }, 78 | "language_info": { 79 | "codemirror_mode": { 80 | "name": "ipython", 81 | "version": 3 82 | }, 83 | "file_extension": ".py", 84 | "mimetype": "text/x-python", 85 | "name": "python", 86 | "nbconvert_exporter": "python", 87 | "pygments_lexer": "ipython3", 88 | "version": "3.8.10" 89 | } 90 | }, 91 | "nbformat": 4, 92 | "nbformat_minor": 5 93 | } 94 | -------------------------------------------------------------------------------- /icons/flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigcode-project/jupytercoder/a2e0aafaad4ce276876526b97023d8eee2cc12a7/icons/flow.png -------------------------------------------------------------------------------- /icons/flow_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigcode-project/jupytercoder/a2e0aafaad4ce276876526b97023d8eee2cc12a7/icons/flow_128.png -------------------------------------------------------------------------------- /icons/flow_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigcode-project/jupytercoder/a2e0aafaad4ce276876526b97023d8eee2cc12a7/icons/flow_256.png -------------------------------------------------------------------------------- /icons/flow_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigcode-project/jupytercoder/a2e0aafaad4ce276876526b97023d8eee2cc12a7/icons/flow_64.png -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "Jupyter Coder", 4 | "version": "0.2.0.0", 5 | "description": "Capture data in Jupyter Notebook cells and send to a remote server.", 6 | "icons": { 7 | "32": "icons/flow_64.png", 8 | "48": "icons/flow_128.png", 9 | "128": "icons/flow_256.png" 10 | }, 11 | "permissions": [ 12 | "storage" 13 | ], 14 | "action": { 15 | "default_popup": "options/options.html" 16 | }, 17 | "background": { 18 | "service_worker": "background.js" 19 | }, 20 | "content_scripts": [ 21 | { 22 | "matches": [ 23 | "*://*.jupyter.org/*", 24 | "*://localhost:*/*", 25 | "*://127.0.0.1:*/*" 26 | ], 27 | "js": [ 28 | "src/api.js", 29 | "src/state.js", 30 | "src/preferences.js", 31 | "src/utility.js", 32 | "src/animation.js", 33 | "src/diff.js", 34 | "src/content.js" 35 | ], 36 | "css": [ 37 | "options/styles.css" 38 | ], 39 | "run_at": "document_end" 40 | } 41 | ] 42 | } -------------------------------------------------------------------------------- /options/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 157 | 158 | 159 | 160 | 161 |162 |202 | 203 | 204 | 205 | 206 | 207 | -------------------------------------------------------------------------------- /options/options.js: -------------------------------------------------------------------------------- 1 | // 获取所有的单选框 2 | const radioButtons = document.querySelectorAll('input[type="radio"]'); 3 | const select = document.querySelector('select'); 4 | 5 | // 获取当前被选中的单选框的值 6 | function getSelectedRadioValue() { 7 | let selectedValue = null; 8 | 9 | radioButtons.forEach(radioButton => { 10 | if (radioButton.checked) { 11 | selectedValue = radioButton.id; 12 | } 13 | }); 14 | 15 | return selectedValue; 16 | } 17 | 18 | 19 | // Save the API key when the Save button is clicked 20 | document.getElementById("save").addEventListener("click", () => { 21 | chrome.storage.sync.set({ 22 | openAIKey: document.getElementById("apiKey").value, 23 | bigcodeServiceUrl: document.getElementById("bigcodeServiceUrl").value, 24 | huggingfaceAccessToken: document.getElementById("huggingfaceAccessToken").value, 25 | modelType: select.value, 26 | checkedMode: getSelectedRadioValue() 27 | }, () => { 28 | alert("API key saved."); 29 | }) 30 | }); 31 | 32 | chrome.storage.sync.get("openAIKey", (data) => { 33 | if (data.openAIKey) { 34 | document.getElementById("apiKey").value = data.openAIKey; 35 | } 36 | }); 37 | 38 | chrome.storage.sync.get("huggingfaceAccessToken", (data) => { 39 | if (data.huggingfaceAccessToken) { 40 | document.getElementById("huggingfaceAccessToken").value = data.huggingfaceAccessToken; 41 | } 42 | }); 43 | 44 | chrome.storage.sync.get("bigcodeServiceUrl", (data) => { 45 | if (data.bigcodeServiceUrl) { 46 | document.getElementById("bigcodeServiceUrl").value = data.bigcodeServiceUrl; 47 | } else { 48 | document.getElementById("bigcodeServiceUrl").value = "https://api-inference.huggingface.co/models/bigcode/starcoderbase/" 49 | } 50 | }); 51 | 52 | chrome.storage.sync.get("modelType", (data) => { 53 | if (data.modelType) { 54 | select.value = data.modelType 55 | } 56 | }) 57 | 58 | chrome.storage.sync.get("checkedMode", (data) => { 59 | if (data.checkedMode && data.checkedMode == "OpenAI") { 60 | document.getElementsByClassName('input-key')[0].classList.toggle("input-hidden") 61 | document.getElementsByClassName('input-key')[1].classList.toggle("input-hidden") 62 | 63 | var optionsElement = document.getElementsByName('options') 64 | if(optionsElement[0].checked){ 65 | optionsElement[0].checked = false 66 | }else{ 67 | optionsElement[0].checked = true 68 | } 69 | if(optionsElement[1].checked){ 70 | optionsElement[1].checked = false 71 | }else{ 72 | optionsElement[1].checked = true 73 | } 74 | } 75 | }) 76 | 77 | // 为每个单选框添加事件监听器 78 | radioButtons.forEach(radioButton => { 79 | radioButton.addEventListener('change', function (event) { 80 | if (event.target.checked) { 81 | document.getElementsByClassName('input-key')[0].classList.toggle("input-hidden") 82 | document.getElementsByClassName('input-key')[1].classList.toggle("input-hidden") 83 | } 84 | }); 85 | }); 86 | 87 | 88 | -------------------------------------------------------------------------------- /options/styles.css: -------------------------------------------------------------------------------- 1 | .greyed-suggestion { 2 | color: #888; 3 | } 4 | -------------------------------------------------------------------------------- /src/animation.js: -------------------------------------------------------------------------------- 1 | const animation = { 2 | /* 3 | Start requested animation 4 | 5 | Params: 6 | activeTextarea: Textarea in active cell 7 | 8 | Returns: list, len == 3 9 | 0. animationInterval: Animation interval, can be cleared using the 'clearInterval' function 10 | 1. animationElement: Animation dom element 11 | 2. activeCellElement: The parent dom of the current cell 12 | 13 | */ 14 | startWaitingAnimation(activeTextarea) { }, 15 | } 16 | 17 | 18 | 19 | // left animation css 20 | const loadCss = ` 21 | .before-content:before { 22 | content: ""; 23 | position: absolute; 24 | top: 5px; 25 | left: 10px; 26 | right: 0; 27 | bottom: 0; 28 | border: 3px solid rgba(0, 0, 0, 0.1); 29 | border-left-color: #000; 30 | border-radius: 50%; 31 | width: 15px; 32 | height: 15px; 33 | animation: spin 1s linear infinite; 34 | } 35 | 36 | @keyframes spin { 37 | to { 38 | transform: rotate(360deg); 39 | } 40 | } 41 | .paused:before { 42 | content: ""; 43 | position: absolute; 44 | top: 5px; 45 | left: 10px; 46 | right: 0; 47 | bottom: 0; 48 | border: 3px solid rgba(0, 0, 0, 0.1); 49 | border-radius: 50%; 50 | width: 15px; 51 | height: 15px; 52 | // animation: spin 1s linear infinite; 53 | border-left-color: red; 54 | } 55 | `; 56 | 57 | 58 | 59 | animation.startWaitingAnimation = (activeTextarea) => { 60 | const activeCellParentElement = activeTextarea.parentElement.parentElement.parentElement; 61 | 62 | // Create a new163 | Jupyter Coder 164 | 165 |166 |171 | 172 |BigCode Url:167 | 168 |Huggingface Access Token:169 | 170 |173 |183 | 184 | 185 |OpenAI API Key:174 | 175 | 176 | 181 | 182 |186 | 187 | 191 | 192 | 193 | 197 |198 | 199 | 200 | 201 |