cp500/infon-coref-pointer
027
1# @cp500/infon-coref2 3Multilingual coreference resolution in the browser or Node, via ONNX.4 5The trained model is a pointer-network coref resolver fine-tuned on6top of a multilingual MiniLM-L12 distilled from XLM-R. It handles7**English, Japanese, Korean, Thai, and Chinese** — replaces8English-only [fastcoref](https://github.com/shon-otmazgin/fastcoref)9for use cases that need multilingual coverage.10 11The model artefacts live at12[**cp500/infon-coref-pointer**](https://huggingface.co/cp500/infon-coref-pointer)13on the Hugging Face Hub. This package is the JavaScript client that14loads them.15 16## Install17 18```bash19npm install @cp500/infon-coref onnxruntime-web20# or for Node:21npm install @cp500/infon-coref onnxruntime-node22```23 24The ONNX runtime is a **peer dependency** so you only install the one25your environment needs. ``@huggingface/tokenizers`` is **optional**;26if installed, we use its WASM SentencePiece tokenizer (faster and27fully spec-compliant). Otherwise the package falls back to a minimal28pure-JS tokenizer that handles the XLM-R vocabulary.29 30## Quick start (browser)31 32```ts33import { InfonCorefModel } from '@cp500/infon-coref';34 35const model = await InfonCorefModel.fromHub('cp500/infon-coref-pointer', {36 precision: 'fp16', // 'fp16' (default, ~235 MB) or 'fp32' (~470 MB)37 device: 'auto', // tries WebGPU, falls back to WASM38});39 40const result = await model.resolve(41 'Toyota announced a partnership with Panasonic on battery technology. ' +42 'The Japanese automaker said the deal is worth $250 million.'43);44 45for (const cluster of result.clusters) {46 const surfaces = cluster.map(i => result.mentions[i].text);47 console.log(surfaces.join(' ↔ '));48 // Toyota ↔ The Japanese automaker49}50```51 52## Quick start (Node)53 54```ts55import { InfonCorefModel } from '@cp500/infon-coref';56 57// Same API as fromHub, but reads from local files (e.g. after a58// huggingface-cli download).59const model = await InfonCorefModel.fromLocal('./models/infon-coref/');60const result = await model.resolve('Toyota e Panasonic anunciaram...');61```62 63## What you get back64 65```ts66interface CorefResult {67 text: string; // original input, unchanged68 tokens: Token[]; // wordpieces with char offsets69 mentions: Mention[]; // detected mentions in document order70 clusters: number[][]; // clusters[c] = list of mention indices71 timing: {72 tokenize: number;73 backbone: number;74 bioDecode: number;75 scorer: number;76 total: number; // ms77 };78}79 80interface Mention {81 start: number; // wordpiece index, inclusive82 end: number; // wordpiece index, inclusive83 charStart: number; // char offset in source text84 charEnd: number;85 text: string; // literal substring of source text86 cluster: number; // -1 for singleton87 antecedent: number; // 0-based mention index, -1 = no antecedent88}89```90 91## Languages92 93Trained on synthetic Bedrock/Claude-generated data balanced across:94 95| Code | Language |96|------|----------------|97| `en` | English |98| `ja` | Japanese |99| `ko` | Korean |100| `th` | Thai |101| `zh` | Chinese (Simplified) |102 103The XLM-R backbone covers ~100 languages but mention detection +104pointer-net heads were only trained on these 5. Other languages may105work via zero-shot transfer; verify on your domain before shipping.106 107## API108 109### `InfonCorefModel.fromHub(repo, options?)`110 111Load model artefacts from a Hugging Face repo. Downloads (and caches112in the browser Cache API) ``meta.json``, the chosen ONNX backbone,113the mention scorer, and ``tokenizer.json``.114 115| Option | Type | Default | Notes |116|----------------|-----------------------------------------|-----------|-------|117| `precision` | `'fp32' \| 'fp16'` | `'fp16'` | FP16 halves the download. Falls back to FP32 if FP16 is missing in the repo. |118| `device` | `'auto' \| 'webgpu' \| 'wasm' \| 'cpu' \| 'cuda'` | `'auto'` | Browser auto-prefers WebGPU. |119| `maxLength` | `number` | `256` | Truncates inputs longer than N wordpieces. |120| `bioThreshold` | `number` | none | If set, suppresses low-confidence span detections. `0.7` is a common stricter setting. |121| `revision` | `string` | `'main'` | HF branch/tag/commit-SHA pin. |122| `debug` | `boolean` | `false` | Logs per-stage timings to `console.debug`. |123 124### `InfonCorefModel.fromLocal(baseUrl, options?)`125 126Same as `fromHub` but loads files relative to a base URL or127filesystem path. Browser: `baseUrl` is a URL prefix128(`/models/coref/`). Node: a directory path (`./models/coref/`).129 130The directory must contain:131 132```133meta.json134tokenizer.json135onnx/backbone_bio.onnx (and .onnx.data sidecar if present)136onnx/backbone_bio_fp16.onnx137onnx/mention_scorer.onnx138onnx/mention_scorer_fp16.onnx139```140 141### `model.resolve(text, options?)`142 143Run end-to-end coref on a single document. Returns144[`CorefResult`](#what-you-get-back).145 146`options` accepts the same per-call overrides as `fromHub`'s147`maxLength`, `bioThreshold`, `debug`.148 149## Power-user exports150 151If you want to swap one stage of the pipeline (e.g. a custom152tokenizer or a different ORT runtime), the helpers are exported153individually:154 155```ts156import {157 buildPairs, // mention M → flat (pair_i, pair_j) tensors158 decodeBio, // BIO logits → wordpiece spans159 groupClusters, // antecedent decisions → union-find clusters160 loadTokenizer, // SentencePiece JSON → Tokenizer161 fetchHubFile, // HF Hub fetch + browser-cache162} from '@cp500/infon-coref';163```164 165These match the Python reference implementation in166[`scripts/coref_onnx_experiment.py`](https://github.com/cp500/overlord/blob/main/infon/scripts/coref_onnx_experiment.py)167exactly — useful when comparing a Python/TS pipeline at the168intermediate-tensor level.169 170## Architecture171 172```173┌─────────────────────────┐174│ text │175└────────────┬────────────┘176 ▼177┌─────────────────────────┐178│ SentencePiece tokenize │ tokenizer.json (XLM-R vocab)179└────────────┬────────────┘180 ▼ input_ids, attention_mask181┌─────────────────────────┐182│ backbone_bio.onnx │ MiniLM-L12 (12 layers, H=384)183│ • XLM-R encoder │ + 3-class BIO head184│ • bio_logits (T,3) │185└────────┬────────┬───────┘186 │ │187 │ ▼ bio_logits → run-length decode → spans188 │ ┌──────────────────────┐189 │ │ decodeBio (TS) │190 │ └──────────┬───────────┘191 │ ▼ span_starts, span_ends192 │ ┌──────────────────────┐193 │ │ buildPairs (TS) │194 │ └──────────┬───────────┘195 │ ▼ pair_i, pair_j (triangular)196 ▼ ▼197┌─────────────────────────┐198│ mention_scorer.onnx │ gather + segment-mean pool +199│ • pair_scores (P,) │ 3-vector pair MLP200└────────────┬────────────┘201 ▼202┌─────────────────────────┐203│ pickAntecedents (TS) │204│ + groupClusters (TS) │205└────────────┬────────────┘206 ▼207 CorefResult208```209 210The split between the two ONNX graphs exists so the BIO head can211share computation with the backbone (one forward pass), while the212mention scorer can be re-run with different `(pair_i, pair_j)`213batches without recomputing hidden states. It also keeps each ONNX214file's input signature simple enough to trace cleanly.215 216## Performance ballpark217 218Numbers from a 2024 M1 Pro Macbook on a 110-token English document:219 220| Stage | WASM (FP16) | WebGPU (FP16) | Node CPU (FP16) |221|-----------|-------------|---------------|-----------------|222| Tokenize | 4 ms | 4 ms | 2 ms |223| Backbone | 220 ms | 70 ms | 90 ms |224| BIO | <1 ms | <1 ms | <1 ms |225| Scorer | 5 ms | 4 ms | 2 ms |226| **Total** | **~230 ms** | **~80 ms** | **~95 ms** |227 228First call adds ~2-4 s for ONNX session warmup. The Cache API in229browsers persists the downloaded model so warmup-after-reload is230limited to session creation.231 232## License233 234Apache 2.0. The trained weights at `cp500/infon-coref-pointer` carry235the same license; the underlying MiniLM-L12 backbone is also Apache2362.0.237 238## Status239 240Alpha. The API is stable enough to integrate behind your own241abstraction; expect minor breaking changes on the public class242shape until 1.0.243 244Issue tracker: https://github.com/cp500/infon-coref-js/issues245 