GitHub - ngxson/wllama: WebAssembly binding for llama.cpp - Enabling on-browser LLM inference (original) (raw)

WebAssembly binding for llama.cpp

👉 Try the demo app

👉 See the blog post introducing WebGPU support in llama.cpp and wllama

📄 Documentation

For changelog, please visit releases page

Features

Limitations:

Code demo and documentation

Demo:

How to use

Use Wllama inside React Typescript project

Install it:

Then, import the module:

import { Wllama } from '@wllama/wllama'; let wllamaInstance = new Wllama(WLLAMA_CONFIG_PATHS, ...); // (the rest is the same with earlier example)

For complete code example, see examples/main/src/utils/wllama.context.tsx

NOTE: this example only covers completions usage. For embeddings, please see examples/embeddings/index.html

WebGPU support

WebGPU support is introduced via PR #215.

Upon updating to V3.1, WebGPU will be enabled automatically. By default, all layers will be offloaded to GPU. If the model is too big to fit into VRAM, you can manually adjust the number of layers via the n_gpu_layers parameter of LoadModelParams. Example:

// (optionally) will allow running WebGPU on Firefox via compat mode; performance will be significantly degraded wllama.setCompat('default', 'firefox_safari');

await wllama.loadModel(files, { n_gpu_layers: 4, // meaning 4 layers are offloaded to GPU; set to 0 to disable GPU inference });

Prepare your model

Simple usage with ES6 module

For complete code, see examples/basic/index.html

import { Wllama } from './esm/index.js';

(async () => { const CONFIG_PATHS = { default: './esm/wasm/wllama.wasm', }; // Automatically switch between single-thread and multi-thread version based on browser support // If you want to enforce single-thread, add { "n_threads": 1 } to LoadModelConfig const wllama = new Wllama(CONFIG_PATHS); // Define a function for tracking the model download progress const progressCallback = ({ loaded, total }) => { // Calculate the progress as a percentage const progressPercentage = Math.round((loaded / total) * 100); // Log the progress in a user-friendly format console.log(Downloading... ${progressPercentage}%); }; // Load GGUF from Hugging Face hub // (alternatively, you can use loadModelFromUrl if the model is not from HF hub) await wllama.loadModelFromHF( { repo: 'ggml-org/models', file: 'tinyllamas/stories260K.gguf' }, { progressCallback } ); const response = await wllama.createChatCompletion({ messages: [{ role: 'user', content: elemInput.value }], max_tokens: 50, temperature: 0.5, top_k: 40, top_p: 0.9, }); console.log(response.choices[0].message.content); })();

Alternatively, you can use the *.wasm files from CDN:

import WasmFromCDN from '@wllama/wllama/esm/wasm-from-cdn.js'; const wllama = new Wllama(WasmFromCDN); // NOTE: this is not recommended, only use when you can't embed wasm files in your project

Split model

Cases where we want to split the model:

We use llama-gguf-split to split a big gguf file into smaller files. You can download the pre-built binary via llama.cpp release page:

Split the model into chunks of 512 Megabytes

./llama-gguf-split --split-max-size 512M ./my_model.gguf ./my_model

This will output files ending with -00001-of-00003.gguf, -00002-of-00003.gguf, and so on.

You can then pass to loadModelFromUrl or loadModelFromHF the URL of the first file and it will automatically load all the chunks:

const wllama = new Wllama(CONFIG_PATHS, { parallelDownloads: 5, // optional: maximum files to download in parallel (default: 3) }); await wllama.loadModelFromHF({ repo: 'ngxson/tinyllama_split_test', file: 'stories15M-q8_0-00001-of-00003.gguf', });

Custom logger (suppress debug messages)

When initializing Wllama, you can pass a custom logger to Wllama.

Example 1: Suppress debug message

import { Wllama, LoggerWithoutDebug } from '@wllama/wllama';

const wllama = new Wllama(pathConfig, { // LoggerWithoutDebug is predefined inside wllama logger: LoggerWithoutDebug, });

Example 2: Add emoji prefix to log messages

const wllama = new Wllama(pathConfig, { logger: { debug: (...args) => console.debug('🔧', ...args), log: (...args) => console.log('â„šī¸', ...args), warn: (...args) => console.warn('âš ī¸', ...args), error: (...args) => console.error('â˜ ī¸', ...args), }, });

How to compile the binary yourself

This repository already come with pre-built binary from llama.cpp source code. However, in some cases you may want to compile it yourself:

You can use the commands below to compile it yourself:

/!\ IMPORTANT: Require having docker compose installed

Clone the repository with submodule

git clone --recurse-submodules https://github.com/ngxson/wllama.git cd wllama

Optionally, you can run this command to update llama.cpp to latest upstream version (bleeding-edge, use with your own risk!)

git submodule update --remote --merge

Install the required modules

npm i

Firstly, build llama.cpp into wasm

npm run build:wasm

Then, build ES module

npm run build

TODO

Acknowledgments

Wllama was created and is maintained by Xuan-Son Nguyen. The WebGPU backend for llama.cpp is maintained by Reese Levine. We thank all other contributors to both wllama and llama.cpp, whose work made this project possible.