diff --git a/background.js b/background.js index 16a5228..1ff8e7e 100644 --- a/background.js +++ b/background.js @@ -17,11 +17,17 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { }); return true; // Required to use sendResponse asynchronously } - else if(request.type === "getmodelType"){ + else if(request.type === "getModelType"){ chrome.storage.sync.get("modelType", (data) => { sendResponse({ modelType: data.modelType }); }); return true; // Required to use sendResponse asynchronously } + else if(request.type === "getHuggingfaceApiKey"){ + chrome.storage.sync.get("huggingfaceApiKey", (data) => { + sendResponse({ huggingfaceApiKey : data.huggingfaceApiKey}); + }) + return true; + } }); \ No newline at end of file diff --git a/content.js b/content.js index a09f8bd..a7e167c 100644 --- a/content.js +++ b/content.js @@ -21,11 +21,18 @@ async function getChecked() { } async function getmodelType() { return new Promise((resolve) => { - chrome.runtime.sendMessage({ type: "getmodelType" }, (response) => { + chrome.runtime.sendMessage({ type: "getModelType" }, (response) => { resolve(response.modelType); }); }); } +async function getHuggingfaceApiKey() { + return new Promise((resolve) => { + chrome.runtime.sendMessage({ type: "getHuggingfaceApiKey" }, (response) => { + resolve(response.huggingfaceApiKey) + }) + }) +} // Use a regular expression to match the content between triple backticks const codeBlockRegex = /```([\s\S]*)```/; @@ -37,10 +44,10 @@ async function sendToOpenAI(prompt) { const modelType = await getmodelType(); if (!apiKey) { // 总是忘记填写。。所以等了半天总是以为网络错误,改成了alert - alert("OpenAI API key not set."); + alert("OpenAI API key not set."); return; - }else if(!modelType) { - alert("modelType not set."); + } else if (!modelType) { + alert("modelType not set."); return; } const response = await fetch("https://api.openai.com/v1/completions", { @@ -61,21 +68,21 @@ async function sendToOpenAI(prompt) { const data = await response.json(); const suggestion = data.choices && data.choices[0] && data.choices[0].text; - + // don't know how many "```" exists, It is related to the token and also related to the model let count = (suggestion.match(/```/g) || []).length; let code = "" - switch(count){ - case 1: + switch (count) { + case 1: var match = suggestion.match(codeHalfBlockRegex) - code = match && match[1] ? match[1].replace(/^\n\s*/, '').replace(/\n.*$/, '').replace(/\u200B/g, ''):"" + code = match && match[1] ? match[1].replace(/^\n\s*/, '').replace(/\n.*$/, '').replace(/\u200B/g, '') : "" break; case 2: var match = suggestion.match(codeBlockRegex) - code = match && match[1] ? match[1].replace(/^\n\s*/, '').replace(/\n.*$/, '').replace(/\u200B/g, ''):"" + code = match && match[1] ? match[1].replace(/^\n\s*/, '').replace(/\n.*$/, '').replace(/\u200B/g, '') : "" break; - default:code = suggestion; + default: code = suggestion; } return code @@ -83,6 +90,7 @@ async function sendToOpenAI(prompt) { async function sendToOtherService(code) { const url = await getOtherServiceUrl(); + const token = await getHuggingfaceApiKey(); if (!url) { // 总是忘记填写。。所以等了半天总是以为网络错误,改成了alert alert("otherServiceUrl not set."); @@ -92,10 +100,12 @@ async function sendToOtherService(code) { const response = await fetch(url, { method: "POST", headers: { - "Content-Type": "application/json" + "Content-Type": "application/json", + "Authorization": `Bearer ${token}`, }, body: JSON.stringify({ inputs: prompt, + stream: false, parameters: { return_full_text: false } @@ -152,11 +162,14 @@ let isRequestSuccessful = false; // Textarea during the request (allows writing code in other cells while the request is in progress) let activeRequestTextarea = null; +let activeAnimationElement = null; + +let userInputIndex = 0 function insertSuggestion(suggestion) { // Focus the textarea, otherwise, it is not possible to insert the suggestion using the Tab key from another location activeRequestTextarea.focus(); - + // Get the current cursor position const cursorPosition = activeRequestTextarea.selectionStart; @@ -175,43 +188,45 @@ function insertSuggestion(suggestion) { // Trigger a keydown event with Tab key to perform auto-indentation const tabEvent = new KeyboardEvent('keydown', { key: 'Tab' }); activeRequestTextarea.dispatchEvent(tabEvent); + codeToFill = "" + userInputIndex = 0 } const getActiveCellPointerCode = (activeCell) => { - let leftContext = "" - let rightContext = "" + 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 + // 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] - } + // 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) { - leftContext += linesElement[i].textContent + "\n" - }else { - rightContext += linesElement[i].textContent + "\n" - } + for (let i = 0; i < linesElement.length; i++) { + if (i <= lineIndex) { + leftContext += linesElement[i].textContent + "\n" + } else { + rightContext += linesElement[i].textContent + "\n" } + } - return [leftContext, rightContext] + return [leftContext, rightContext] } @@ -226,7 +241,7 @@ function getCellContentText(activeCell) { // 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 && !rightContext){ + if (!leftContext && !rightContext) { return null } @@ -267,11 +282,84 @@ function extractTextFromCell(cell) { } +// Mount code hints elements +function mountAnimationElement(code) { + const activeTextarea = document.activeElement; + // Obtain the current input box (cell) from the Textarea of the current input box + const activeCell = activeTextarea.parentElement.parentElement + // get cursor element + const cursorElement = activeCell.querySelector('div.CodeMirror-cursor') + const style = window.getComputedStyle(cursorElement); + // Which line + const lineIndex = Math.round(parseFloat(style.getPropertyValue('top')) / 17) + // Obtain element for all line + const linesElement = activeCell.getElementsByClassName('CodeMirror-line') + const currectLineSpanList = linesElement[lineIndex].querySelectorAll('span span') + + // Set the animated font dom element when it waits + const animationElement = document.createElement('span'); + animationElement.innerHTML = code; + animationElement.classList.add("per-insert-code"); + animationElement.style.color = 'grey'; + + // If it is a blank line + if (currectLineSpanList.length == 0) { + const withAllCodeSpan = linesElement[lineIndex].querySelectorAll('span') + withAllCodeSpan[withAllCodeSpan.length - 1].appendChild(animationElement) + } else { + currectLineSpanList[currectLineSpanList.length - 1].insertAdjacentElement('afterend', animationElement); + } + +} // 开始等待动画,有30s等待时间,如果等待时间过了,出现“error”字体,返回两个值如下,接收:"const [animationInterval, animationElement] = startWaitingAnimation(activeCall)" // 1. animationInterval(interval, 动画计时器),可使用clearInterval(animationInterval)消除动画, 每次请求完毕必须要关掉 // 2. animationElement (dom, 动画字体节点), animationElement.innerHTML = xxx 来赋值 const startWaitingAnimation = (activeCell) => { + const inputElement = activeCell.parentElement.parentElement.parentElement; + // left animation css + var loadCss = ` + .before-content:before { + content: ""; + position: absolute; + top: 5px; + left: 10px; + right: 0; + bottom: 0; + border: 3px solid rgba(0, 0, 0, 0.1); + border-left-color: #000; + border-radius: 50%; + width: 20px; + height: 20px; + animation: spin 1s linear infinite; + } + + @keyframes spin { + to { + transform: rotate(360deg); + } + } + .paused:before { + content: ""; + position: absolute; + top: 5px; + left: 10px; + right: 0; + bottom: 0; + border: 3px solid rgba(0, 0, 0, 0.1); + border-radius: 50%; + width: 20px; + height: 20px; + // animation: spin 1s linear infinite; + border-left-color: red; + } + `; + // 创建新的