├── content.js ├── .gitignore ├── logo.png ├── manifest.json ├── README.md ├── popup.html ├── popup.js └── popup.css /content.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | env.js -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clark-pang/AskGPT/HEAD/logo.png -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "name": "Ask GPT", 4 | "version": "1.0", 5 | "manifest_version": 3, 6 | "action": { 7 | "default_title": "Ask GPT", 8 | "default_popup": "popup.html" 9 | }, 10 | "content_scripts": [ 11 | {"js": ["content.js"], 12 | "matches": [""]} 13 | ], 14 | "permissions": [ 15 | "activeTab", 16 | "scripting" 17 | ], 18 | "icons": { 19 | "16": "logo.png", 20 | "32": "logo.png", 21 | "48": "logo.png", 22 | "128": "logo.png" 23 | } 24 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Ask GPT is a Chrome extension that allows you to select any code snippet you see online and provides you with Chat GPT’s detailed explanation of what that code means and how it works. It also gives you the option of changing the depth of the response, as well as the possibility of translating that code into your preferred language. 2 | 3 | User must generate their own OpenAI API key and declare it as API_KEY in popup.js or their env. 4 | 5 | Developed with love by:
6 | 7 | Felipe Ocampo https://github.com/felipeaocampo
8 | Ryan Motamen https://github.com/ryanmotamen
9 | Clark Pang https://github.com/clark-pang
10 | -------------------------------------------------------------------------------- /popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |

Highlight code and Ask GPT to explain

14 |
15 | Verbosity 16 | 17 | 18 | 25 |
26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /popup.js: -------------------------------------------------------------------------------- 1 | // script is deferred in html 2 | 3 | // QUERIES 4 | const button = document.querySelector('button'); 5 | const loader = document.querySelector('.loader'); 6 | const slider = document.querySelector('.slider'); 7 | const select = document.querySelector('.language-select'); 8 | 9 | button.addEventListener("click", async () => { 10 | const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); 11 | let result; 12 | // get selected text from active tab 13 | try { 14 | [{ result }] = await chrome.scripting.executeScript({ 15 | target: { tabId: tab.id }, 16 | function: () => getSelection().toString(), 17 | }); 18 | } catch (e) { 19 | return; 20 | } 21 | const tokenNum = Number(slider.value); 22 | 23 | //if value of select = no 24 | // prompt assigned to explain this code in less than tokennum words 25 | //if value of select = anything else 26 | // prompt assigned to can you translate this code for me in ${selectLanguage} 27 | let prompt = ''; 28 | const language = select.value; 29 | if (language === 'no') { 30 | prompt = `Explain this code in less than ${tokenNum} words: ` + result; 31 | } else { 32 | prompt = `Can you translate this code into ${language} for me in less than ${tokenNum} words: ` + result; 33 | } 34 | 35 | const preface = document.createElement('p'); 36 | if (result.trim() === '') { 37 | preface.classList.add('error'); 38 | preface.innerHTML = 'Ya need to highlight some code 🤡'; 39 | document.body.append(preface); 40 | return; 41 | } 42 | try { 43 | const response = await fetchChatGPTResponse(prompt, tokenNum); 44 | preface.classList.add('preface'); 45 | preface.innerText = 'GPT says... '; 46 | document.body.append(preface); 47 | document.body.append(response); 48 | } catch (e) { 49 | preface.classList.add('error'); 50 | preface.innerHTML = 'Server Error: Too many requests 🥺'; 51 | document.body.append(preface); 52 | } 53 | }); 54 | 55 | async function fetchChatGPTResponse(prompt, tokenNum) { 56 | // start loading spinner 57 | loader.classList.toggle('hidden'); 58 | let response; 59 | try { 60 | response = await fetch('https://api.openai.com/v1/completions', { 61 | method: 'POST', 62 | headers: { 63 | 'Content-Type': 'application/json', 64 | 'Authorization': `Bearer ${API_KEY}` // declare your own API_KEY, either in env file or this one 65 | }, 66 | body: JSON.stringify({ 67 | model: 'text-davinci-003', 68 | prompt: prompt, 69 | temperature: 0, 70 | max_tokens: tokenNum 71 | }) 72 | }); 73 | } catch (e) { 74 | return e; 75 | } 76 | 77 | const json = await response.json(); 78 | //end loading spinner 79 | loader.classList.toggle('hidden'); 80 | return json.choices[0].text; 81 | } 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /popup.css: -------------------------------------------------------------------------------- 1 | /* resets */ 2 | body, html, *, body * { 3 | margin: 0; 4 | padding: 0; 5 | box-sizing: border-box; 6 | flex-direction: column; 7 | align-items: center; 8 | } 9 | 10 | html { 11 | font-size: 62.5%; /* reset base font to 10px or user-equiv */ 12 | } 13 | 14 | body { 15 | font-size: 1.6rem; /* rest body font to 16px or user-equiv, but now 1rem === 10px*/ 16 | font-weight: 200; 17 | font-family: 'Poppins', sans-serif; 18 | padding: 3rem; 19 | width: 50rem; 20 | display: flex; 21 | justify-content: center; 22 | overflow: scroll; 23 | line-height: 2.5rem; 24 | color:rgb(87, 77, 77); 25 | } 26 | 27 | /* container for user input controls */ 28 | .container { 29 | display: flex; 30 | flex-direction: column; 31 | justify-content: space-evenly; 32 | height: 10rem; 33 | } 34 | 35 | input[type='range'], 36 | input[type='range']:focus, 37 | input[type='range']:active, 38 | input[type='range']::-moz-focus-inner, 39 | input[type='range']:-moz-focusring { 40 | outline: none; 41 | } 42 | 43 | .slider { 44 | outline: none; 45 | border: solid 1px rgb(157, 139, 139); 46 | border-radius: 5px; 47 | outline: none; 48 | height: 5px; 49 | -webkit-appearance: none; 50 | position: relative; 51 | } 52 | 53 | /* Verbosity and translate labels */ 54 | small, .translate{ 55 | font-style: italic; 56 | font-weight: 400; 57 | font-size: 1.3rem; 58 | } 59 | 60 | /* override html range-slider native appearance, customize for our color scheme */ 61 | .slider::-webkit-slider-thumb { 62 | width: 1.4rem; 63 | height: 1.4rem; 64 | border-radius: 50%; 65 | -webkit-appearance: none; 66 | cursor: pointer; 67 | background: rgb(255, 103, 103); 68 | top: 50%; 69 | transform: translateY(-35%); 70 | transition: background .15s ease; 71 | } 72 | .slider::-webkit-slider-thumb:hover { 73 | background: rgb(255, 133, 133); 74 | } 75 | 76 | select, 77 | select:focus, 78 | select:active { 79 | outline: none; 80 | } 81 | 82 | /* gpt says ... */ 83 | .preface { 84 | align-self: flex-start; 85 | font-weight: 500; 86 | margin-bottom: 1.5rem; 87 | font-style: italic; 88 | } 89 | 90 | /* error messages */ 91 | .error { 92 | color: rgba(255, 103, 103, 0.799); 93 | font-weight: 400; 94 | } 95 | 96 | .preface, .error { 97 | margin-top: 2rem; 98 | } 99 | 100 | button { 101 | font-family: 'Poppins', sans-serif; 102 | padding: .5rem 1rem; 103 | width: 10rem; 104 | margin-top: 2rem; 105 | cursor: pointer; 106 | background-color: rgb(255, 103, 103); 107 | transition: background-color .2s ease, box-shadow .06s ease; 108 | border: none; 109 | border-radius: .3rem; 110 | color: white; 111 | font-weight: 200; 112 | box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.19), 0 2px 2px rgba(0, 0, 0, 0.23); 113 | } 114 | 115 | button:hover { 116 | background-color: rgb(255, 124, 124); 117 | } 118 | 119 | button:active, button:hover, button { 120 | outline: none; 121 | } 122 | 123 | button:active { 124 | box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.19), 125 | 0 2px 2px rgba(0, 0, 0, 0.23), inset 5px 5px 10px -3px rgba(0, 0, 0, 0.7); 126 | } 127 | 128 | /* loading spinner */ 129 | .loader { 130 | margin-top: 2rem; 131 | transform: rotateZ(45deg); 132 | perspective: 1000px; 133 | border-radius: 50%; 134 | width: 48px; 135 | height: 48px; 136 | color: rgb(101, 88, 88); 137 | } 138 | 139 | .loader:before, 140 | .loader:after { 141 | content: ''; 142 | display: block; 143 | position: absolute; 144 | top: 0; 145 | left: 0; 146 | width: inherit; 147 | height: inherit; 148 | border-radius: 50%; 149 | transform: rotateX(70deg); 150 | animation: 1s spin linear infinite; 151 | } 152 | 153 | .loader:after { 154 | color: #ff6767; 155 | transform: rotateY(70deg); 156 | animation-delay: .4s; 157 | } 158 | 159 | @keyframes rotate { 160 | 0% { 161 | transform: translate(-50%, -50%) rotateZ(0deg); 162 | } 163 | 164 | 100% { 165 | transform: translate(-50%, -50%) rotateZ(360deg); 166 | } 167 | } 168 | 169 | @keyframes rotateccw { 170 | 0% { 171 | transform: translate(-50%, -50%) rotate(0deg); 172 | } 173 | 174 | 100% { 175 | transform: translate(-50%, -50%) rotate(-360deg); 176 | } 177 | } 178 | 179 | @keyframes spin { 180 | 181 | 0%, 182 | 100% { 183 | box-shadow: .2em 0px 0 0px currentcolor; 184 | } 185 | 186 | 12% { 187 | box-shadow: .2em .2em 0 0 currentcolor; 188 | } 189 | 190 | 25% { 191 | box-shadow: 0 .2em 0 0px currentcolor; 192 | } 193 | 194 | 37% { 195 | box-shadow: -.2em .2em 0 0 currentcolor; 196 | } 197 | 198 | 50% { 199 | box-shadow: -.2em 0 0 0 currentcolor; 200 | } 201 | 202 | 62% { 203 | box-shadow: -.2em -.2em 0 0 currentcolor; 204 | } 205 | 206 | 75% { 207 | box-shadow: 0px -.2em 0 0 currentcolor; 208 | } 209 | 210 | 87% { 211 | box-shadow: .2em -.2em 0 0 currentcolor; 212 | } 213 | } 214 | 215 | .loader.hidden { 216 | display: none; 217 | } 218 | 219 | 220 | --------------------------------------------------------------------------------