-
Notifications
You must be signed in to change notification settings - Fork 923
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a new Chrome extension example using WebGPU and service worker (#296
) - Chrome has added WebGPU support in Service Worker in this [commit](https://chromium-review.googlesource.com/c/chromium/src/+/5190750). This example shows how we can create a Chrome extension using WebGPU and service worker. The project structure is as follows: - `manifest.json`: A required file that lists important information about the structure and behavior of that extension. Here we are using manifest V3. - `popup.ts`: Script of the extension pop-up window. - `background.ts`: Script of the service worker. An extension service worker is loaded when it is needed, and unloaded when it goes dormant. - `content.js`: Content script that interacts with DOM. - To run the extension, first make sure you are on [Google Chrome Canary](https://www.google.com/chrome/canary/). - In Chrome Canary, go to `chrome://flags/#enable-experimental-web-platform-features` and enable the `#enable-experimental-web-platform-features` flag. **Relaunch the browser**. - Run ```bash npm install npm run build ``` This will create a new directory at `./dist/`. To load the extension into Chrome, go to Extensions > Manage Extensions and select Load Unpacked. Add the `./dist/` directory. You can now pin the extension to your toolbar and use it to chat with your favorite model! **Note**: This example disables chatting using the contents of the active tab by default. To enable it, set `useContext` in `popup.ts` to `true`. More info about this feature can be found [here](#190). However, if the web content is too large, it might run into issues. We recommend using `example.html` to test this feature.
- Loading branch information
Showing
14 changed files
with
572 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# WebLLM Chrome Extension using WebGPU Running on Service Worker | ||
|
||
![Chrome Extension](https://github.com/mlc-ai/mlc-llm/assets/11940172/0d94cc73-eff1-4128-a6e4-70dc879f04e0) | ||
|
||
- Chrome has added WebGPU support in Service Worker in this [commit](https://chromium-review.googlesource.com/c/chromium/src/+/5190750). This example shows how we can create a Chrome extension using WebGPU and service worker. | ||
The project structure is as follows: | ||
- `manifest.json`: A required file that lists important information about the structure and behavior of that extension. Here we are using manifest V3. | ||
- `popup.ts`: Script of the extension pop-up window. | ||
- `background.ts`: Script of the service worker. An extension service worker is loaded when it is needed, and unloaded when it goes dormant. | ||
- `content.js`: Content script that interacts with DOM. | ||
- To run the extension, first make sure you are on [Google Chrome Canary](https://www.google.com/chrome/canary/). | ||
- In Chrome Canary, go to `chrome://flags/#enable-experimental-web-platform-features` and enable the `#enable-experimental-web-platform-features` flag. **Relaunch the browser**. | ||
- Run | ||
```bash | ||
npm install | ||
npm run build | ||
``` | ||
|
||
This will create a new directory at `./dist/`. To load the extension into Chrome, go to Extensions > Manage Extensions and select Load Unpacked. Add the `./dist/` directory. You can now pin the extension to your toolbar and use it to chat with your favorite model! | ||
|
||
**Note**: This example disables chatting using the contents of the active tab by default. | ||
To enable it, set `useContext` in `popup.ts` to `true`. More info about this feature can be found | ||
[here](https://github.com/mlc-ai/web-llm/pull/190). | ||
However, if the web content is too large, it might run into issues. We recommend using `example.html` to | ||
test this feature. |
23 changes: 23 additions & 0 deletions
23
examples/chrome-extension-webgpu-service-worker/package.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
{ | ||
"name": "chrome-extension", | ||
"version": "1.0.0", | ||
"description": "", | ||
"private": true, | ||
"scripts": { | ||
"build": "parcel build src/manifest.json --config @parcel/config-webextension" | ||
}, | ||
"author": "", | ||
"license": "ISC", | ||
"devDependencies": { | ||
"@parcel/config-webextension": "^2.9.3", | ||
"@types/chrome": "^0.0.242", | ||
"buffer": "^6.0.3", | ||
"parcel": "^2.9.3", | ||
"process": "^0.11.10", | ||
"url": "^0.11.1" | ||
}, | ||
"dependencies": { | ||
"@mlc-ai/web-llm": "^0.2.18", | ||
"progressbar.js": "^1.1.0" | ||
} | ||
} |
52 changes: 52 additions & 0 deletions
52
examples/chrome-extension-webgpu-service-worker/src/background.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import {ChatRestModule, ChatInterface, ChatModule, InitProgressReport} from "@mlc-ai/web-llm"; | ||
|
||
// TODO: Surface this as an option to the user | ||
const useWebGPU = true; | ||
var model_loaded = false; | ||
|
||
var cm: ChatInterface; | ||
if (!useWebGPU) { | ||
cm = new ChatRestModule(); | ||
} else { | ||
cm = new ChatModule(); | ||
} | ||
|
||
// Set reponse callback for chat module | ||
const generateProgressCallback = (_step: number, message: string) => { | ||
// send the answer back to the content script | ||
chrome.runtime.sendMessage({ answer: message }); | ||
}; | ||
|
||
var context = ""; | ||
chrome.runtime.onMessage.addListener(async function (request) { | ||
// check if the request contains a message that the user sent a new message | ||
if (request.input) { | ||
var inp = request.input; | ||
if (context.length > 0) { | ||
inp = "Use only the following context when answering the question at the end. Don't use any other knowledge.\n"+ context + "\n\nQuestion: " + request.input + "\n\nHelpful Answer: "; | ||
} | ||
console.log("Input:", inp); | ||
const response = await cm.generate(inp, generateProgressCallback); | ||
} | ||
if (request.context) { | ||
context = request.context; | ||
console.log("Got context:", context); | ||
} | ||
if (request.reload) { | ||
if (!model_loaded) { | ||
var appConfig = request.reload; | ||
console.log("Got appConfig: ", appConfig); | ||
|
||
cm.setInitProgressCallback((report: InitProgressReport) => { | ||
console.log(report.text, report.progress); | ||
chrome.runtime.sendMessage({ initProgressReport: report.progress}); | ||
}); | ||
|
||
await cm.reload("Mistral-7B-Instruct-v0.2-q4f16_1", undefined, appConfig); | ||
console.log("Model loaded"); | ||
model_loaded = true; | ||
} else { | ||
chrome.runtime.sendMessage({ initProgressReport: 1.0}); | ||
} | ||
} | ||
}); |
6 changes: 6 additions & 0 deletions
6
examples/chrome-extension-webgpu-service-worker/src/content.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// Only the content script is able to access the DOM | ||
chrome.runtime.onConnect.addListener(function(port) { | ||
port.onMessage.addListener(function(msg) { | ||
port.postMessage({contents: document.body.innerHTML}); | ||
}); | ||
}); |
11 changes: 11 additions & 0 deletions
11
examples/chrome-extension-webgpu-service-worker/src/example.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
In the year 2154, humanity had colonized several planets in the distant reaches of the galaxy. The planet of Xylophia-IV was one of the most remote and inhospitable, with temperatures often dropping to -200 degrees Celsius. Despite these harsh conditions, a team of scientists had established a research station on the planet to study the unique geological formations and exotic flora and fauna. | ||
|
||
One day, while conducting a routine survey of the planet's surface, the team discovered an strange object buried deep in the ice. As they examined it closer, they realized it was a small, metallic capsule with a glowing blue symbol etched onto its surface. | ||
|
||
The team's leader, a brilliant scientist named Dr. Maria Rodriguez, was immediately intrigued by the capsule's mysterious origins. She ordered her team to bring it back to the research station for further analysis. | ||
|
||
After weeks of studying the capsule, the team finally cracked the code to the symbol etched onto its surface. It was a message from an alien race, warning Earth of an impending attack from an unknown threat. | ||
|
||
The team was shocked and dismayed by the news, but they knew they had to act quickly to warn the rest of humanity. They transmitted the message to the nearest space station, which relayed it to Earth's government. | ||
|
||
As the threat of attack loomed near, the team remained on high alert, ready to face whatever dangers lay ahead. They had uncovered a secrets of the universe, and now they were determined to protect their planet and its inhabitants at all costs. |
Binary file added
BIN
+3.71 KB
examples/chrome-extension-webgpu-service-worker/src/icons/icon-128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+581 Bytes
examples/chrome-extension-webgpu-service-worker/src/icons/icon-16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+1.03 KB
examples/chrome-extension-webgpu-service-worker/src/icons/icon-32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+1.93 KB
examples/chrome-extension-webgpu-service-worker/src/icons/icon-64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 34 additions & 0 deletions
34
examples/chrome-extension-webgpu-service-worker/src/manifest.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
{ | ||
"manifest_version": 3, | ||
"name": "MLCBot", | ||
"version": "0.1.0", | ||
"description": "Chat with your browser", | ||
"icons": { | ||
"16": "icons/icon-16.png", | ||
"32": "icons/icon-32.png", | ||
"64": "icons/icon-64.png", | ||
"128": "icons/icon-128.png" | ||
}, | ||
"content_security_policy": { | ||
"extension_pages": "style-src-elem 'self' https://cdnjs.cloudflare.com; font-src 'self' https://cdnjs.cloudflare.com; script-src 'self' 'wasm-unsafe-eval'; default-src 'self' data:; connect-src 'self' data: http://localhost:8000 https://huggingface.co https://cdn-lfs.huggingface.co https://cdn-lfs-us-1.huggingface.co https://raw.githubusercontent.com" | ||
}, | ||
"action": { | ||
"default_title": "MLCBot", | ||
"default_popup": "popup.html" | ||
}, | ||
"content_scripts": [ | ||
{ | ||
"matches": ["<all_urls>"], | ||
"js": ["content.js"] | ||
} | ||
], | ||
"background": { | ||
"service_worker": "background.ts", | ||
"type": "module" | ||
}, | ||
"permissions": [ | ||
"storage", | ||
"tabs", | ||
"webNavigation" | ||
] | ||
} |
235 changes: 235 additions & 0 deletions
235
examples/chrome-extension-webgpu-service-worker/src/popup.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
*, | ||
*::before, | ||
*::after { | ||
margin: 0; | ||
padding: 0; | ||
box-sizing: border-box; | ||
} | ||
|
||
html { | ||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, | ||
sans-serif; | ||
color: #222; | ||
} | ||
|
||
body { | ||
margin: 0; | ||
padding: 0.5rem; | ||
background-color: #778da9; | ||
width: 320px; | ||
font-size: small; | ||
} | ||
|
||
p { | ||
margin: 0; | ||
} | ||
|
||
/* LOADING BAR */ | ||
#loadingContainer { | ||
margin-bottom: 15px; | ||
width: 300px; | ||
height: 8px; | ||
} | ||
|
||
/* INPUT AREA */ | ||
#query-input { | ||
border: 1px solid #ccc; | ||
border-radius: 4px; | ||
} | ||
|
||
.input-container { | ||
display: flex; | ||
flex-direction: row; | ||
align-items: center; | ||
} | ||
|
||
.input-container input { | ||
width: 100%; | ||
outline: none; | ||
padding: 0.5rem; | ||
margin-right: 0.5rem; | ||
} | ||
|
||
/* SUBMIT BUTTON */ | ||
.btn { | ||
background-color: #1b263b; | ||
color: white; | ||
font-size: small; | ||
cursor: pointer; | ||
border-radius: 4px; | ||
border: none; | ||
padding: 0.5rem; | ||
} | ||
|
||
.btn:hover { | ||
background-color: #d0d0d0; | ||
} | ||
|
||
.btn:disabled { | ||
background-color: #a7a7a7; | ||
color: rgb(255, 255, 255); | ||
cursor: default; | ||
} | ||
|
||
.btn img { | ||
width: 1rem; | ||
height: 1rem; | ||
} | ||
|
||
/* LOADING */ | ||
|
||
.stage { | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
position: relative; | ||
margin: 0 -5%; | ||
overflow: hidden; | ||
} | ||
|
||
#loading-indicator { | ||
display: none; | ||
color: white; | ||
margin-top: 0.5rem; | ||
} | ||
|
||
.dot-flashing { | ||
position: relative; | ||
width: 10px; | ||
height: 10px; | ||
border-radius: 5px; | ||
background-color: #1b263b; | ||
color: #1b263b; | ||
animation: dot-flashing 0.4s infinite linear alternate; | ||
animation-delay: 0.2s; | ||
} | ||
|
||
.dot-flashing::before, | ||
.dot-flashing::after { | ||
content: ""; | ||
display: inline-block; | ||
position: absolute; | ||
top: 0; | ||
} | ||
|
||
.dot-flashing::before { | ||
left: -15px; | ||
width: 10px; | ||
height: 10px; | ||
border-radius: 5px; | ||
background-color: #1b263b; | ||
color: #1b263b; | ||
animation: dot-flashing 0.4s infinite alternate; | ||
animation-delay: 0s; | ||
} | ||
|
||
.dot-flashing::after { | ||
left: 15px; | ||
width: 10px; | ||
height: 10px; | ||
border-radius: 5px; | ||
background-color: #1b263b; | ||
color: #1b263b; | ||
animation: dot-flashing 0.4s infinite alternate; | ||
animation-delay: 0.4s; | ||
} | ||
|
||
@keyframes dot-flashing { | ||
0% { | ||
background-color: #1b263b; | ||
} | ||
|
||
50%, | ||
100% { | ||
background-color: #415a77; | ||
} | ||
} | ||
|
||
/* ANSWERS */ | ||
#queriesAnswersContainer { | ||
display: block; | ||
color: white; | ||
margin-top: 0.5rem; | ||
} | ||
|
||
#answer { | ||
color: #333333; | ||
} | ||
|
||
#answerWrapper { | ||
display: none; | ||
background-color: #ffd166; | ||
border-radius: 8px; | ||
padding: 0.5rem; | ||
margin-top: 0.5rem; | ||
} | ||
|
||
.queriesAnswers { | ||
border-radius: 8px; | ||
background-color: #ffd166;; | ||
padding: 0.5rem; | ||
color: #333333; | ||
} | ||
|
||
#lastQuery { | ||
color: rgb(188, 188, 188); | ||
} | ||
|
||
#lastAnswer { | ||
color: white; | ||
margin-top: 0.5rem; | ||
} | ||
|
||
#lastRequest { | ||
padding: 0.5rem; | ||
margin-top: 0.5rem; | ||
background-color: #333333; | ||
border-radius: 4px; | ||
} | ||
|
||
/* ANSWER OPTIONS */ | ||
.timeStamp { | ||
color: #9a8c98; | ||
} | ||
|
||
.copyRow { | ||
display: flex; | ||
flex-direction: row; | ||
align-items: end; | ||
justify-content: space-between; | ||
color: #a7a7a7; | ||
margin-top: 0.5rem; | ||
} | ||
|
||
.copyText { | ||
display: none; | ||
color: #a7a7a7; | ||
margin-right: 0.5rem; | ||
} | ||
|
||
.copyButton { | ||
color: #415a77; | ||
background-color: transparent; | ||
border: none; | ||
cursor: pointer; | ||
padding: 0; | ||
margin-left: 0.5rem; | ||
} | ||
|
||
.copyButton:hover { | ||
color: #5e80a7; | ||
background-color: transparent; | ||
} | ||
|
||
.removeButton { | ||
color: #415a77; | ||
background-color: transparent; | ||
border: none; | ||
cursor: pointer; | ||
padding: 0; | ||
} | ||
|
||
.removeButton:hover { | ||
color: #5e80a7; | ||
background-color: transparent; | ||
} |
Oops, something went wrong.