Skip to content

Commit 8ced4dd

Browse files
authored
Create Moonshine Web demo (huggingface#21)
* Create basic audio visualizer demo app * Working demo * Move constants to separate folder * Fix sphere render on page load * Improve UI on mobile * Better error-handling and UI notifications * Formatting * Refactoring * Minor UI improvements * Better logging * Track transcript times + add buttons * UI improvements * Device auto-detection * UI fixes * Fix bloom filter memory leak * Formatting * Remove settings (for now) * Rename -> `moonshine-web` * Improve notification system * Finalize demo * Update moonshine-web/src/App.jsx
1 parent 5392c16 commit 8ced4dd

File tree

18 files changed

+7013
-0
lines changed

18 files changed

+7013
-0
lines changed

moonshine-web/.gitignore

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?

moonshine-web/README.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
---
2+
title: Moonshine Web
3+
emoji: 🌙
4+
colorFrom: blue
5+
colorTo: pink
6+
sdk: static
7+
pinned: false
8+
license: apache-2.0
9+
models:
10+
- onnx-community/moonshine-base-ONNX
11+
short_description: Real-time in-browser speech recognition
12+
thumbnail: https://huggingface.co/spaces/webml-community/moonshine-web/resolve/main/banner.png
13+
---
14+
15+
# Moonshine Web
16+
17+
A simple React + Vite application for running [Moonshine Base](https://huggingface.co/onnx-community/moonshine-base-ONNX), a powerful speech-to-text model optimized for fast and accurate automatic speech recognition (ASR) on resource-constrained devices. It runs locally in the browser using Transformers.js and WebGPU-acceleration (or WASM as a fallback).
18+
19+
## Getting Started
20+
21+
Follow the steps below to set up and run the application.
22+
23+
### 1. Clone the Repository
24+
25+
Clone the examples repository from GitHub:
26+
27+
```sh
28+
git clone https://github.com/huggingface/transformers.js-examples.git
29+
```
30+
31+
### 2. Navigate to the Project Directory
32+
33+
Change your working directory to the `moonshine-web` folder:
34+
35+
```sh
36+
cd transformers.js-examples/moonshine-web
37+
```
38+
39+
### 3. Install Dependencies
40+
41+
Install the necessary dependencies using npm:
42+
43+
```sh
44+
npm i
45+
```
46+
47+
### 4. Run the Development Server
48+
49+
Start the development server:
50+
51+
```sh
52+
npm run dev
53+
```
54+
55+
The application should now be running locally. Open your browser and go to `http://localhost:5173` to see it in action.
56+
57+
## Acknowledgements
58+
59+
The audio visualizer was adapted from Wael Yasmina's [amazing tutorial](https://waelyasmina.net/articles/how-to-create-a-3d-audio-visualizer-using-three-js/).

moonshine-web/eslint.config.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import js from "@eslint/js";
2+
import globals from "globals";
3+
import react from "eslint-plugin-react";
4+
import reactHooks from "eslint-plugin-react-hooks";
5+
import reactRefresh from "eslint-plugin-react-refresh";
6+
7+
export default [
8+
{ ignores: ["dist"] },
9+
{
10+
files: ["**/*.{js,jsx}"],
11+
languageOptions: {
12+
ecmaVersion: 2020,
13+
globals: globals.browser,
14+
parserOptions: {
15+
ecmaVersion: "latest",
16+
ecmaFeatures: { jsx: true },
17+
sourceType: "module",
18+
},
19+
},
20+
settings: { react: { version: "18.3" } },
21+
plugins: {
22+
react,
23+
"react-hooks": reactHooks,
24+
"react-refresh": reactRefresh,
25+
},
26+
rules: {
27+
...js.configs.recommended.rules,
28+
...react.configs.recommended.rules,
29+
...react.configs["jsx-runtime"].rules,
30+
...reactHooks.configs.recommended.rules,
31+
"react/jsx-no-target-blank": "off",
32+
"react-refresh/only-export-components": [
33+
"warn",
34+
{ allowConstantExport: true },
35+
],
36+
},
37+
},
38+
];

moonshine-web/index.html

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/png" href="/logo.png" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Moonshine Web</title>
8+
</head>
9+
<body>
10+
<div id="root"></div>
11+
<script id="vertexshader" type="vertex">
12+
uniform float u_time;
13+
14+
vec3 mod289(vec3 x)
15+
{
16+
return x - floor(x * (1.0 / 289.0)) * 289.0;
17+
}
18+
19+
vec4 mod289(vec4 x)
20+
{
21+
return x - floor(x * (1.0 / 289.0)) * 289.0;
22+
}
23+
24+
vec4 permute(vec4 x)
25+
{
26+
return mod289(((x*34.0)+10.0)*x);
27+
}
28+
29+
vec4 taylorInvSqrt(vec4 r)
30+
{
31+
return 1.79284291400159 - 0.85373472095314 * r;
32+
}
33+
34+
vec3 fade(vec3 t) {
35+
return t*t*t*(t*(t*6.0-15.0)+10.0);
36+
}
37+
38+
// Classic Perlin noise, periodic variant
39+
float pnoise(vec3 P, vec3 rep)
40+
{
41+
vec3 Pi0 = mod(floor(P), rep); // Integer part, modulo period
42+
vec3 Pi1 = mod(Pi0 + vec3(1.0), rep); // Integer part + 1, mod period
43+
Pi0 = mod289(Pi0);
44+
Pi1 = mod289(Pi1);
45+
vec3 Pf0 = fract(P); // Fractional part for interpolation
46+
vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0
47+
vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
48+
vec4 iy = vec4(Pi0.yy, Pi1.yy);
49+
vec4 iz0 = Pi0.zzzz;
50+
vec4 iz1 = Pi1.zzzz;
51+
52+
vec4 ixy = permute(permute(ix) + iy);
53+
vec4 ixy0 = permute(ixy + iz0);
54+
vec4 ixy1 = permute(ixy + iz1);
55+
56+
vec4 gx0 = ixy0 * (1.0 / 7.0);
57+
vec4 gy0 = fract(floor(gx0) * (1.0 / 7.0)) - 0.5;
58+
gx0 = fract(gx0);
59+
vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0);
60+
vec4 sz0 = step(gz0, vec4(0.0));
61+
gx0 -= sz0 * (step(0.0, gx0) - 0.5);
62+
gy0 -= sz0 * (step(0.0, gy0) - 0.5);
63+
64+
vec4 gx1 = ixy1 * (1.0 / 7.0);
65+
vec4 gy1 = fract(floor(gx1) * (1.0 / 7.0)) - 0.5;
66+
gx1 = fract(gx1);
67+
vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1);
68+
vec4 sz1 = step(gz1, vec4(0.0));
69+
gx1 -= sz1 * (step(0.0, gx1) - 0.5);
70+
gy1 -= sz1 * (step(0.0, gy1) - 0.5);
71+
72+
vec3 g000 = vec3(gx0.x,gy0.x,gz0.x);
73+
vec3 g100 = vec3(gx0.y,gy0.y,gz0.y);
74+
vec3 g010 = vec3(gx0.z,gy0.z,gz0.z);
75+
vec3 g110 = vec3(gx0.w,gy0.w,gz0.w);
76+
vec3 g001 = vec3(gx1.x,gy1.x,gz1.x);
77+
vec3 g101 = vec3(gx1.y,gy1.y,gz1.y);
78+
vec3 g011 = vec3(gx1.z,gy1.z,gz1.z);
79+
vec3 g111 = vec3(gx1.w,gy1.w,gz1.w);
80+
81+
vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));
82+
g000 *= norm0.x;
83+
g010 *= norm0.y;
84+
g100 *= norm0.z;
85+
g110 *= norm0.w;
86+
vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));
87+
g001 *= norm1.x;
88+
g011 *= norm1.y;
89+
g101 *= norm1.z;
90+
g111 *= norm1.w;
91+
92+
float n000 = dot(g000, Pf0);
93+
float n100 = dot(g100, vec3(Pf1.x, Pf0.yz));
94+
float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z));
95+
float n110 = dot(g110, vec3(Pf1.xy, Pf0.z));
96+
float n001 = dot(g001, vec3(Pf0.xy, Pf1.z));
97+
float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z));
98+
float n011 = dot(g011, vec3(Pf0.x, Pf1.yz));
99+
float n111 = dot(g111, Pf1);
100+
101+
vec3 fade_xyz = fade(Pf0);
102+
vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z);
103+
vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y);
104+
float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x);
105+
return 2.2 * n_xyz;
106+
}
107+
108+
uniform float u_frequency;
109+
110+
void main() {
111+
float noise = 3.0 * pnoise(position + u_time, vec3(10.0));
112+
float displacement = (u_frequency / 30.) * (noise / 10.);
113+
vec3 newPosition = position + normal * displacement;
114+
gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);
115+
}
116+
</script>
117+
<script id="fragmentshader" type="fragment">
118+
uniform float u_red;
119+
uniform float u_blue;
120+
uniform float u_green;
121+
void main() {
122+
gl_FragColor = vec4(vec3(u_red, u_green, u_blue), 1. );
123+
}
124+
</script>
125+
<script type="module" src="/src/main.jsx"></script>
126+
</body>
127+
</html>

0 commit comments

Comments
 (0)