From fb0da9bd3910b2179674a04fb4823e3581293a22 Mon Sep 17 00:00:00 2001 From: Saurav Panda Date: Thu, 16 Apr 2026 10:41:19 -0700 Subject: [PATCH] chore: upgrade jest to v30, document Demucs and Flare engines in README - Upgrade jest, jest-environment-jsdom, and @types/jest from v29 to v30, clearing all 4 low-severity npm audit vulnerabilities (0 remaining) - Add Demucs (audio source separation) and Flare (GGUF via WASM) usage examples, model lists, and acknowledgments to README - Fix duplicate example package names causing jest haste collision warning - Auto-fix 9 lint warnings (template literals, unused eslint-disable comments) Co-Authored-By: Claude Opus 4.6 (1M context) --- README.md | 45 +++++++++++++++++++++++- examples/audio-demo/package.json | 2 +- examples/chat-demo/package.json | 2 +- package.json | 6 ++-- src/core/database/index.ts | 2 +- src/core/llm/browserai.test.ts | 12 +++---- src/engines/flare-engine-wrapper.test.ts | 4 +-- 7 files changed, 58 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 6a51af9..82d1ad7 100644 --- a/README.md +++ b/README.md @@ -48,12 +48,13 @@ - 🎯 Run AI models directly in the browser - no server required! - ⚑ WebGPU acceleration for blazing fast inference -- πŸ”„ Seamless switching between MLC and Transformers engines +- πŸ”„ Seamless switching between MLC, Transformers, Flare, and Demucs engines - πŸ“¦ Pre-configured popular models ready to use - πŸ› οΈ Easy-to-use API for text generation and more - πŸ”§ Web Worker support for non-blocking UI performance - πŸ“Š Structured output generation with JSON schemas - πŸŽ™οΈ Speech recognition and text-to-speech capabilities +- 🎡 Audio source separation (Demucs) - isolate vocals, drums, bass, and other stems - πŸ’Ύ Built-in database support for storing conversations and embeddings @@ -163,6 +164,37 @@ audioContext.decodeAudioData(audioBuffer, (buffer) => { }); ``` +### Audio Source Separation (Demucs) +```javascript +import { DemucsEngine } from '@browserai/browserai/demucs'; + +const engine = new DemucsEngine(); +await engine.loadModel({ /* htdemucs config */ }); + +// Separate an AudioBuffer into stems +const result = await engine.separate(audioBuffer, { + shifts: 1, // Time-shift augmentation passes (higher = better quality, slower) + overlap: 0.25, // Segment overlap ratio +}); + +// result.sources contains: drums, bass, other, vocals (each as AudioBuffer) +const vocals = result.sources['vocals']; +``` + +### Flare Engine (GGUF Models via WASM) +```javascript +const ai = new BrowserAI(); + +// Load a GGUF model via the Flare engine +await ai.loadModel('llama-3.2-1b-flare'); + +// Generate text β€” same API as MLC/Transformers +const response = await ai.generateText('Explain quantum computing briefly'); + +// Optional: Load a LoRA adapter +await ai.loadAdapter({ url: 'https://example.com/adapter.safetensors' }); +``` + ## πŸ”§ Supported Models More models will be added soon. Request a model by creating an issue. @@ -197,6 +229,15 @@ More models will be added soon. Request a model by creating an issue. - Whisper-small-all (Speech Recognition) - Kokoro-TTS (Text-to-Speech) +### Flare Models (GGUF via WASM) +- SmolLM2-135M-Instruct (Q8_0, Q4_K_M) +- SmolLM2-360M-Instruct (Q8_0) +- Qwen2.5-0.5B-Instruct (Q4_K_M) +- Llama-3.2-1B-Instruct (Q8_0, Q4_K_M) + +### Demucs Models (Audio Source Separation) +- HTDemucs (4-stem: drums, bass, other, vocals) + ## πŸ—ΊοΈ Enhanced Roadmap ### Phase 1: Foundation @@ -238,6 +279,8 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file - [MLC AI](https://github.com/mlc-ai/mlc-llm) for their incredible mode compilation library and support for webgpu runtime and xgrammar - [Hugging Face](https://huggingface.co/) and [Xenova](https://github.com/xenova) for their Transformers.js library, licensed under Apache License 2.0. The original code has been modified to work in a browser environment and converted to TypeScript. +- [Facebook Research](https://github.com/facebookresearch/demucs) for Demucs, the state-of-the-art music source separation model. +- [Aspect](https://github.com/aspect-build/flare) for the Flare WASM inference engine enabling GGUF model support in the browser. - All our contributors and supporters! --- diff --git a/examples/audio-demo/package.json b/examples/audio-demo/package.json index c3507d2..8799c45 100644 --- a/examples/audio-demo/package.json +++ b/examples/audio-demo/package.json @@ -1,5 +1,5 @@ { - "name": "browser-ai-demo", + "name": "browser-ai-audio-demo", "private": true, "version": "0.0.0", "type": "module", diff --git a/examples/chat-demo/package.json b/examples/chat-demo/package.json index 5d24f06..d6f5087 100644 --- a/examples/chat-demo/package.json +++ b/examples/chat-demo/package.json @@ -1,5 +1,5 @@ { - "name": "browser-ai-demo", + "name": "browser-ai-chat-demo", "private": true, "version": "0.0.0", "type": "module", diff --git a/package.json b/package.json index 5e487bd..dd08018 100644 --- a/package.json +++ b/package.json @@ -65,13 +65,13 @@ }, "type": "module", "devDependencies": { - "@types/jest": "^29.5.14", + "@types/jest": "^30.0.0", "@typescript-eslint/eslint-plugin": "^8.20.0", "@typescript-eslint/parser": "^8.20.0", "@webgpu/types": "^0.1.53", "eslint": "^9.18.0", - "jest": "^29.7.0", - "jest-environment-jsdom": "^29.7.0", + "jest": "^30.3.0", + "jest-environment-jsdom": "^30.3.0", "prettier": "^3.4.2", "ts-jest": "^29.2.5", "tsup": "^8.3.5", diff --git a/src/core/database/index.ts b/src/core/database/index.ts index 989c860..053bedf 100644 --- a/src/core/database/index.ts +++ b/src/core/database/index.ts @@ -60,7 +60,7 @@ export class DatabaseImpl implements Database { const available = Object.keys(vectorStoreFactories); throw new Error( available.length === 0 - ? `Vector store support is not yet implemented. No vector store backends are available.` + ? 'Vector store support is not yet implemented. No vector store backends are available.' : `Vector store type "${type}" not supported. Available types: ${available.join(', ')}`, ); } diff --git a/src/core/llm/browserai.test.ts b/src/core/llm/browserai.test.ts index bdb7bfc..87f2b5b 100644 --- a/src/core/llm/browserai.test.ts +++ b/src/core/llm/browserai.test.ts @@ -185,14 +185,14 @@ describe('BrowserAI β€” engine registry sanity', () => { // This is a smoke test that no two registries have collided and broken // the spread order β€” if, say, demucs-models.json has a key that shadows // an mlc-models.json key, loading the older entry would silently break. - // eslint-disable-next-line @typescript-eslint/no-require-imports + const mlc = require('../../config/models/mlc-models.json') as Record; - // eslint-disable-next-line @typescript-eslint/no-require-imports + const transformers = require('../../config/models/transformers-models.json') as Record; - // eslint-disable-next-line @typescript-eslint/no-require-imports + const demucs = require('../../config/models/demucs-models.json') as Record; - // eslint-disable-next-line @typescript-eslint/no-require-imports + const flare = require('../../config/models/flare-models.json') as Record; const mlcKeys = new Set(Object.keys(mlc)); @@ -215,7 +215,7 @@ describe('BrowserAI β€” engine registry sanity', () => { }); test('every Flare model config has engine: "flare"', () => { - // eslint-disable-next-line @typescript-eslint/no-require-imports + const flare = require('../../config/models/flare-models.json') as Record; for (const cfg of Object.values(flare)) { expect(cfg.engine).toBe('flare'); @@ -223,7 +223,7 @@ describe('BrowserAI β€” engine registry sanity', () => { }); test('every Demucs model config has engine: "demucs"', () => { - // eslint-disable-next-line @typescript-eslint/no-require-imports + const demucs = require('../../config/models/demucs-models.json') as Record; for (const cfg of Object.values(demucs)) { diff --git a/src/engines/flare-engine-wrapper.test.ts b/src/engines/flare-engine-wrapper.test.ts index 512fc13..fb50533 100644 --- a/src/engines/flare-engine-wrapper.test.ts +++ b/src/engines/flare-engine-wrapper.test.ts @@ -101,9 +101,9 @@ describe('flare-models.json', () => { const flareKeys = new Set(Object.keys(flareModels)); // Intentionally import lazily to avoid the cross-engine tests depending // on a specific MLC registry shape. - // eslint-disable-next-line @typescript-eslint/no-require-imports + const mlcModels = require('../config/models/mlc-models.json') as Record; - // eslint-disable-next-line @typescript-eslint/no-require-imports + const demucsModels = require('../config/models/demucs-models.json') as Record; for (const k of flareKeys) { expect(mlcModels[k]).toBeUndefined();