npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

transliteration-bangla

v0.1.4

Published

Banglish-to-Bangla transliteration in the browser with ONNX Runtime Web

Readme

NOTE: IT IS AN INTERNAL TOOL PUBLISHED PUBLICLY.

transliteration-bangla

Run Banglish-to-Bangla transliteration entirely in the browser with ONNX Runtime Web. Inference runs inside a dedicated Web Worker and supports WebGPU with an automatic WASM/CPU fallback.

ami tomake bhalobashi → আমি তোমাকে ভালোবাসি
vai kemon acho         → ভাই কেমন আছো

Install

pnpm add transliteration-bangla

Inside this monorepo, add the workspace package instead:

pnpm --filter <your-app> add transliteration-bangla@workspace:*

The package is browser-only and uses ESM, Web Workers, and ONNX Runtime Web.

Model assets

The npm package does not contain model weights. Host these files together in a public, CORS-enabled directory:

encoder.onnx
decoder.onnx
src_vocab.json
tgt_vocab.json
config.json

Pass that directory as modelBaseUrl. After the model successfully initializes, newly downloaded assets are saved in IndexedDB. Later runtimes using the same resolved asset URLs read them from IndexedDB instead of downloading them again.

Use an immutable or versioned directory URL, such as /bangla-model/v1/. To deploy a new model, change the URL so it receives a separate cache entry.

The worker supports both the original full-prefix decoder and the faster self-kv-cache-v1 decoder produced by this repository's export tool. Put each precision variant in its own immutable directory and select it with modelBaseUrl:

| Variant | ONNX graphs | Recommended backend | Notes | | ------- | ----------- | ------------------- | ---------------------------------------------------------------- | | FP32 | 26.7 MB | WASM or WebGPU | Highest precision and the default | | INT8 | 8.7 MB | WASM | Smallest download; benchmark quality and latency for your inputs | | FP16 | 13.7 MB | WebGPU | Smaller GPU-oriented variant; not usually faster on WASM |

These variants are post-training conversions. They do not retrain or otherwise change the learned model weights, although reduced precision must still be validated against representative inputs.

Basic usage

import { createTransliterator } from "transliteration-bangla";

const transliterator = await createTransliterator({
  modelBaseUrl: "https://your-domain.com/transliteration-model/v2/",
});

const bangla = await transliterator.transliterate("ami tomake bhalobashi");

console.log(bangla);
// আমি তোমাকে ভালোবাসি

console.log(transliterator.device);
// "webgpu" or "wasm"

// Terminate the worker when it is no longer needed.
transliterator.dispose();

The default auto mode tries WebGPU first and automatically uses WASM/CPU when WebGPU is unavailable or cannot initialize the model.

React example with debouncing

Create the runtime once, reuse it for every request, and dispose it when the component unmounts:

import { useEffect, useRef, useState } from "react";
import {
  createTransliterator,
  SupersededRequestError,
  type Transliterator,
} from "transliteration-bangla";

export function TransliterationInput() {
  const runtime = useRef<Transliterator | undefined>(undefined);
  const [input, setInput] = useState("");
  const [output, setOutput] = useState("");
  const [ready, setReady] = useState(false);

  useEffect(() => {
    let cancelled = false;

    void createTransliterator({
      modelBaseUrl: "https://your-domain.com/transliteration-model/v2/",
      device: "auto",
    }).then((instance) => {
      if (cancelled) {
        instance.dispose();
        return;
      }

      runtime.current = instance;
      setReady(true);
    });

    return () => {
      cancelled = true;
      runtime.current?.dispose();
      runtime.current = undefined;
    };
  }, []);

  useEffect(() => {
    if (!ready || !runtime.current) return;

    const timeout = window.setTimeout(async () => {
      try {
        const result = await runtime.current?.transliterate(input);
        setOutput(result ?? "");
      } catch (error) {
        if (!(error instanceof SupersededRequestError)) throw error;
      }
    }, 350);

    return () => window.clearTimeout(timeout);
  }, [input, ready]);

  return (
    <div>
      <textarea
        value={input}
        onChange={(event) => setInput(event.target.value)}
        placeholder="Type Banglish"
      />
      <p>{ready ? output : "Loading model…"}</p>
    </div>
  );
}

Production code may also want to catch initialization and inference errors and ignore stale results when the input changes during an active request.

Choose WebGPU or WASM

const webgpuRuntime = await createTransliterator({
  modelBaseUrl: "https://your-domain.com/transliteration-model/v2/",
  device: "webgpu",
});

const cpuRuntime = await createTransliterator({
  modelBaseUrl: "https://your-domain.com/transliteration-model/v2/",
  device: "wasm",
});

Supported device values:

| Value | Behavior | | ---------- | ---------------------------------------------------------------- | | "auto" | Prefer WebGPU and fall back to WASM/CPU | | "webgpu" | Request WebGPU and fall back to WASM/CPU if initialization fails | | "wasm" | Always use WASM/CPU |

Always inspect transliterator.device after initialization to determine which backend is actually active.

WebGPU generally requires a supported browser and a secure context such as HTTPS or localhost. The WASM backend works on a wider range of browsers.

Multithreaded WASM

Browsers only allow ONNX Runtime's WASM threads when the application is cross-origin isolated. Configure these response headers on the application:

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

Cross-origin model responses must continue to satisfy CORS under this policy. The package requests up to four threads by default, capped by available hardware. Without isolation it safely uses one thread. Inspect transliterator.wasmThreads and transliterator.crossOriginIsolated to see the actual runtime configuration, or pass wasmThreads to request a different cap.

Loading progress

Use onProgress to update a loading indicator while the model is downloaded and initialized:

const transliterator = await createTransliterator({
  modelBaseUrl: "https://your-domain.com/transliteration-model/v2/",
  requestTimeoutMs: 120_000,
  onProgress({ progress, message }) {
    console.log(`${Math.round(progress * 100)}%`, message);
  },
  onFatalError(error) {
    console.error(error);
  },
});

Detailed inference result

transliterateDetailed() includes the worker-side inference duration:

const result = await transliterator.transliterateDetailed("Bangladesh amader desh");

console.log(result.text);
// বাংলাদেশ আমাদের দেশ

console.log(result.durationMs);
// Inference duration in milliseconds

API

createTransliterator(options)

Creates the Web Worker, downloads the model files, initializes ONNX Runtime, and resolves when the model is ready.

| Option | Type | Required | Description | | ------------------- | ------------------------------ | -------- | ---------------------------------------------------------------------------- | | modelBaseUrl | string | Yes | CORS-enabled directory containing the five model files | | device | "auto" \| "webgpu" \| "wasm" | No | Backend preference; defaults to "auto" | | wasmBaseUrl | string | No | Custom base URL for ONNX Runtime WASM files | | wasmThreads | number | No | Requested WASM thread cap; defaults to 4 and requires cross-origin isolation | | maxOutputLength | number | No | Positive output-token limit, capped by the model context | | requestScheduling | "latest" \| "fifo" | No | Concurrent request policy; defaults to "latest" | | requestTimeoutMs | number | No | Per-request timeout; defaults to 120 seconds; use 0 to disable | | onProgress | (event) => void | No | Receives initialization progress and messages | | onFatalError | (error) => void | No | Reports terminal worker or WebGPU device failures |

With the default "latest" scheduling, a newer call rejects older outstanding calls with SupersededRequestError, and the worker discards obsolete queued work. Use "fifo" when every concurrent request must complete.

Inputs longer than the model context are handled automatically inside the worker. Each chunk fills as much of the context as possible, splits at whitespace, and preserves the boundary whitespace in the combined result. Text is split inside a word only when that individual word exceeds the model context. maxOutputLength applies independently to each generated chunk.

Only ASCII English letters (A-Z and a-z) are sent to the model. ASCII digits (0-9) bypass inference and are mapped directly to Bangla digits (০-৯). Ordinary English phrases remain grouped across single spaces for contextual accuracy. Bangla text, other scripts, punctuation, symbols, emoji, and unusual whitespace bypass the model and are copied to the result exactly. Periods between numeric digits remain decimal points, while sentence-ending periods become Bangla dari (). Leading decimals such as .5 are supported, and repeated dots are preserved. URLs, email addresses, domains, IP addresses, and explicit version strings bypass all conversion so identifiers remain valid.

The returned Transliterator provides:

| Member | Description | | ----------------------------- | ------------------------------------------------------ | | device | The active backend: "webgpu" or "wasm" | | wasmThreads | Actual configured WASM thread count | | crossOriginIsolated | Whether the worker is cross-origin isolated | | decoder | "kv-cache" or legacy "full-prefix" | | transliterate(text) | Resolves to the Bangla output string | | transliterateDetailed(text) | Resolves to { text, durationMs } | | dispose() | Terminates the worker and rejects outstanding requests |

Generate optimized assets

From the source repository, generate and validate every variant with:

python tools/export_model.py \
  --source /path/to/model/checkpoint-directory \
  --output /path/to/deployment-directory \
  --variants all

The source directory must contain best_model.pt, both vocabulary files, config.json, and the adjacent infer.py model definition expected by the exporter. Output validation runs real CPU inference for FP32, INT8, and FP16 and fails if any known transliteration changes.

Notes

  • The first initialization downloads and compiles the model, so it is slower than subsequent inference calls.
  • Initialize during application startup or idle time and reuse one runtime. Recreating it avoids downloads after the first load but still rebuilds the ONNX sessions.
  • Model assets are cached in IndexedDB by their complete resolved URLs after a successful initialization.
  • Always call dispose() when the runtime is no longer needed. It owns a dedicated worker and two ONNX sessions that intentionally remain alive for reuse until the worker is terminated.
  • A request timeout or fatal worker/WebGPU error terminates that runtime. Create a new runtime to continue.
  • Inputs longer than the model's 256-token context are truncated.
  • User text stays on the device; the runtime does not call a translation API.
  • The model host must allow cross-origin requests when it is on a different origin from the application.
  • Confirm that you have permission to host and redistribute whichever model weights you provide.