Skip to content

Commit 8188d75

Browse files
authored
feat: add Vercel AI SDK example (#70)
* feat: add Vercel AI SDK example * add one more model, minor UI fixes * chore: prettier * refactor: wording
1 parent 9c6b7f9 commit 8188d75

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+12814
-177
lines changed

electron/README.md

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,34 @@
1-
21
# Transformers.js - Sample Electron application
32

43
An example project to show how to run 🤗 Transformers in an [Electron](https://www.electronjs.org/) application.
54

65
## Getting Started
6+
77
1. Clone the repo and enter the project directory:
8-
```bash
9-
git clone https://github.com/huggingface/transformers.js-examples.git
10-
cd transformers.js-examples/electron/
11-
```
8+
9+
```bash
10+
git clone https://github.com/huggingface/transformers.js-examples.git
11+
cd transformers.js-examples/electron/
12+
```
1213

1314
1. Install the necessary dependencies:
14-
```bash
15-
npm install
16-
```
15+
16+
```bash
17+
npm install
18+
```
1719

1820
1. Run the application:
19-
```bash
20-
npm run start
21-
```
2221

23-
After a few seconds, a new window should pop up on your screen!
22+
```bash
23+
npm run start
24+
```
2425

26+
After a few seconds, a new window should pop up on your screen!
2527

2628
## Editing the template
2729

2830
All source code can be found in `./src/`:
31+
2932
- `index.js` - Serves as the entry point for the application's main process. When an Electron app is launched, this is the first file that gets executed, and it is responsible for setting up the main process of the application. You will need to restart the application after editing this file for your changes to take effect.
3033
- `preload.js` - Used to preload scripts and modules in a renderer process before any other scripts run. In our case, we use the `contextBridge` API to expose the `classify` function to the renderer, which runs the model in the background. You will need to restart the application after editing this file for your changes to take effect.
3134
- `classify.js` - Contains logic for loading the model and running predictions via the `classify` function. You will need to restart the application after editing this file for your changes to take effect.

electron/forge.config.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
const { FusesPlugin } = require('@electron-forge/plugin-fuses');
2-
const { FuseV1Options, FuseVersion } = require('@electron/fuses');
1+
const { FusesPlugin } = require("@electron-forge/plugin-fuses");
2+
const { FuseV1Options, FuseVersion } = require("@electron/fuses");
33

44
module.exports = {
55
packagerConfig: {
@@ -12,25 +12,25 @@ module.exports = {
1212
rebuildConfig: {},
1313
makers: [
1414
{
15-
name: '@electron-forge/maker-squirrel',
15+
name: "@electron-forge/maker-squirrel",
1616
config: {},
1717
},
1818
{
19-
name: '@electron-forge/maker-zip',
20-
platforms: ['darwin'],
19+
name: "@electron-forge/maker-zip",
20+
platforms: ["darwin"],
2121
},
2222
{
23-
name: '@electron-forge/maker-deb',
23+
name: "@electron-forge/maker-deb",
2424
config: {},
2525
},
2626
{
27-
name: '@electron-forge/maker-rpm',
27+
name: "@electron-forge/maker-rpm",
2828
config: {},
2929
},
3030
],
3131
plugins: [
3232
{
33-
name: '@electron-forge/plugin-auto-unpack-natives',
33+
name: "@electron-forge/plugin-auto-unpack-natives",
3434
config: {},
3535
},
3636
// Fuses are used to enable/disable various Electron functionality

electron/src/classify.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import { pipeline } from "@huggingface/transformers";
22

33
let classifierPromise;
44
async function classify(event, text) {
5-
classifierPromise ??= pipeline(
6-
"text-classification",
7-
"Xenova/distilbert-base-uncased-finetuned-sst-2-english",
8-
{ dtype: "q8" },
9-
);
10-
const classifier = await classifierPromise;
11-
return await classifier(text);
5+
classifierPromise ??= pipeline(
6+
"text-classification",
7+
"Xenova/distilbert-base-uncased-finetuned-sst-2-english",
8+
{ dtype: "q8" },
9+
);
10+
const classifier = await classifierPromise;
11+
return await classifier(text);
1212
}
1313

1414
export { classify };

electron/src/index.css

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
padding: 0;
55
margin: 0;
66
box-sizing: border-box;
7-
font-family: 'Roboto', sans-serif;
7+
font-family: "Roboto", sans-serif;
88
}
99

1010
h1 {
@@ -44,6 +44,6 @@ body {
4444

4545
#output {
4646
font-size: 20px;
47-
font-family: 'Roboto Mono', monospace;
47+
font-family: "Roboto Mono", monospace;
4848
height: 100px;
49-
}
49+
}

electron/src/index.html

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!DOCTYPE html>
1+
<!doctype html>
22
<html>
33
<head>
44
<meta charset="UTF-8" />
@@ -8,24 +8,24 @@
88

99
<body>
1010
<div class="container">
11-
<h1>Transformers.js</h1>
12-
<h2>Run 🤗 Transformers.js in Electron!</h2>
13-
<input id="text" placeholder="Enter text here">
14-
<pre id="output"></pre>
11+
<h1>Transformers.js</h1>
12+
<h2>Run 🤗 Transformers.js in Electron!</h2>
13+
<input id="text" placeholder="Enter text here" />
14+
<pre id="output"></pre>
1515
</div>
1616

1717
<script>
18-
const inputElement = document.getElementById('text');
19-
const outputElement = document.getElementById('output');
18+
const inputElement = document.getElementById("text");
19+
const outputElement = document.getElementById("output");
2020

2121
// 1. Send input data to the worker thread when it changes.
22-
inputElement.addEventListener('input', async (event) => {
23-
// 2. Await the result from the worker thread.
24-
const result = await window.electronAPI.classify(event.target.value);
22+
inputElement.addEventListener("input", async (event) => {
23+
// 2. Await the result from the worker thread.
24+
const result = await window.electronAPI.classify(event.target.value);
2525

26-
// 3. Update the UI.
27-
outputElement.innerText = JSON.stringify(result, null, 2);
26+
// 3. Update the UI.
27+
outputElement.innerText = JSON.stringify(result, null, 2);
2828
});
2929
</script>
30-
</body>
30+
</body>
3131
</html>

electron/src/index.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
const { app, BrowserWindow, ipcMain } = require('electron');
2-
const path = require('node:path');
3-
const { classify } = require('./classify.js');
1+
const { app, BrowserWindow, ipcMain } = require("electron");
2+
const path = require("node:path");
3+
const { classify } = require("./classify.js");
44

55
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
6-
if (require('electron-squirrel-startup')) {
6+
if (require("electron-squirrel-startup")) {
77
app.quit();
88
}
99

@@ -13,12 +13,12 @@ const createWindow = () => {
1313
width: 800,
1414
height: 600,
1515
webPreferences: {
16-
preload: path.join(__dirname, 'preload.js'),
16+
preload: path.join(__dirname, "preload.js"),
1717
},
1818
});
1919

2020
// and load the index.html of the app.
21-
mainWindow.loadFile(path.join(__dirname, 'index.html'));
21+
mainWindow.loadFile(path.join(__dirname, "index.html"));
2222

2323
// Open the DevTools.
2424
mainWindow.webContents.openDevTools();
@@ -31,13 +31,13 @@ app.whenReady().then(() => {
3131
// Add a handler for the `transformers:classify` event. This enables 2-way communication
3232
// between the renderer process (UI) and the main process (processing).
3333
// https://www.electronjs.org/docs/latest/tutorial/ipc#pattern-2-renderer-to-main-two-way
34-
ipcMain.handle('transformers:classify', classify)
34+
ipcMain.handle("transformers:classify", classify);
3535

3636
createWindow();
3737

3838
// On OS X it's common to re-create a window in the app when the
3939
// dock icon is clicked and there are no other windows open.
40-
app.on('activate', () => {
40+
app.on("activate", () => {
4141
if (BrowserWindow.getAllWindows().length === 0) {
4242
createWindow();
4343
}
@@ -47,8 +47,8 @@ app.whenReady().then(() => {
4747
// Quit when all windows are closed, except on macOS. There, it's common
4848
// for applications and their menu bar to stay active until the user quits
4949
// explicitly with Cmd + Q.
50-
app.on('window-all-closed', () => {
51-
if (process.platform !== 'darwin') {
50+
app.on("window-all-closed", () => {
51+
if (process.platform !== "darwin") {
5252
app.quit();
5353
}
5454
});

electron/src/preload.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
// See the Electron documentation for details on how to use preload scripts:
22
// https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts
33

4-
const { contextBridge, ipcRenderer } = require('electron');
4+
const { contextBridge, ipcRenderer } = require("electron");
55

66
// Here, we use the `contextBridge` API to expose a custom API to the renderer process.
77
// This API allows the renderer process to invoke the `transformers:classify` event in the main process.
8-
contextBridge.exposeInMainWorld('electronAPI', {
9-
classify: (text) => ipcRenderer.invoke('transformers:classify', text)
8+
contextBridge.exposeInMainWorld("electronAPI", {
9+
classify: (text) => ipcRenderer.invoke("transformers:classify", text),
1010
});

next-vercel-ai-sdk/.gitignore

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.*
7+
.yarn/*
8+
!.yarn/patches
9+
!.yarn/plugins
10+
!.yarn/releases
11+
!.yarn/versions
12+
13+
# testing
14+
/coverage
15+
16+
# next.js
17+
/.next/
18+
/out/
19+
20+
# production
21+
/build
22+
23+
# misc
24+
.DS_Store
25+
*.pem
26+
27+
# debug
28+
npm-debug.log*
29+
yarn-debug.log*
30+
yarn-error.log*
31+
.pnpm-debug.log*
32+
33+
# env files (can opt-in for committing if needed)
34+
.env*
35+
36+
# vercel
37+
.vercel
38+
39+
# typescript
40+
*.tsbuildinfo
41+
next-env.d.ts

next-vercel-ai-sdk/README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Transformers.js and Vercel AI SDK example
2+
3+
A modern Transformers.js chat application powered by [@built-in-ai/transformers-js](https://github.com/jakobhoeg/built-in-ai) and [Vercel AI SDK](https://ai-sdk.dev/).
4+
This app demonstrates how to use Transformers.js models with Vercel AI SDK to quickly build a fully functional chat application.
5+
6+
Components to check out for the implementation:
7+
8+
- [page.tsx](./src/app/page.tsx)
9+
- [chat-transport.tsx](./src/app/chat-transport.ts)
10+
- [store.ts](./src/store/store.ts)
11+
- [models.ts](./src/app/models.ts)
12+
13+
## Features
14+
15+
- Run AI models directly in the browser
16+
- Stream and interrupt responses
17+
- Switch between different Transformers.js models
18+
- Upload and process images in conversations
19+
- Render reasoning for reasoning models (Qwen3)
20+
21+
## Tech Stack
22+
23+
- [Next.js 15](https://nextjs.org)
24+
- [Shadcn/ui](https://ui.shadcn.com) for modern, accessible components
25+
- [Zustand](https://github.com/pmndrs/zustand) for lightweight state management
26+
- **AI Integration**:
27+
- [Vercel AI SDK](https://ai-sdk.dev/) for chat interface and streaming
28+
- [@built-in-ai/transformers-js](https://github.com/jakobhoeg/built-in-ai) model provider that works as a model provider for Transformers.js to integreate with Vercel AI SDK.
29+
30+
## Getting Started
31+
32+
1. **Install dependencies**:
33+
34+
```bash
35+
npm install
36+
```
37+
38+
2. **Run the development server**:
39+
40+
```bash
41+
npm run dev
42+
```
43+
44+
3. **Open your browser**:
45+
Navigate to [http://localhost:3000](http://localhost:3000) to see the application.
46+
47+
## Deployment
48+
49+
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/huggingface/transformers.js-examples/tree/main/next-vercel-ai-sdk)

next-vercel-ai-sdk/components.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"$schema": "https://ui.shadcn.com/schema.json",
3+
"style": "new-york",
4+
"rsc": true,
5+
"tsx": true,
6+
"tailwind": {
7+
"config": "",
8+
"css": "src/app/globals.css",
9+
"baseColor": "zinc",
10+
"cssVariables": true,
11+
"prefix": ""
12+
},
13+
"aliases": {
14+
"components": "@/components",
15+
"utils": "@/lib/utils",
16+
"ui": "@/components/ui",
17+
"lib": "@/lib",
18+
"hooks": "@/hooks"
19+
},
20+
"iconLibrary": "lucide"
21+
}

0 commit comments

Comments
 (0)