gist: on-device content topic tagging

Takes a piece of text β€” a title, a post, or a longer description β€” and returns the topics it is about, from a fixed 36-topic taxonomy, across 101 languages. A compact two-stream classifier (static embedding + hashed n-grams), with no transformer at inference. The deployable model is ~74 MB (int8 vocab-pruned multilingual embedding + a small fp16 head) and runs fully on device with zero per-call cost. Multi-label by design: most items carry two or three topics, and per-item scores can be aggregated across a collection (for example into channel- or feed-level topics).

"How to film a two-person podcast with two iPhones" β†’ technology, creator-economy Β· "CΓ³mo invertir en fondos indexados" β†’ finance Β· "Tips for adopting a rescue dog" β†’ pets-animals Β· "ζŠ•θ΅„ζŒ‡ζ•°εŸΊι‡‘ε…₯ι—¨" β†’ finance

Try it

Use

Drop-in SDKs run the model on device; each pins this repo's revision.

import { Gist } from "@desert-ant-labs/gist";           // browser (wasm + LiteRT.js)
// import { Gist } from "@desert-ant-labs/gist/native"; // Node (native)
const gist = await Gist.load();
await gist.classify("How to start a podcast with just your iPhone");
// [{ slug: "technology", name: "Technology & Software", score: 0.91 },
//  { slug: "creator-economy", name: "Creator Economy & Marketing", score: 0.44 }]
import Gist
let gist = Gist()
let topics = try await gist.classify("How to start a podcast with just your iPhone")

Files

File Format Size Contents
gist_embedding.i8 + .json int8 static embedding ~64 MB 101-language potion embedding (261,349 tokens Γ— 256 dims), the semantic feature extractor
gist.mlmodelc / gist.tflite Core ML / LiteRT ~6 MB The classifier head: fused features β†’ 36 topic probabilities
gist_tokenizer.bin Unigram ~4 MB The multilingual tokenizer
gist_config.json JSON tiny Slugs, feature dims, threshold
taxonomy.json JSON ~8 KB The 36 topics (slug, name, description, IAB + Apple category)

Architecture

A compact two-stream classifier β€” no large encoder:

  • Semantic stream: a frozen multilingual static embedding (Model2Vec potion-multilingual-128M, distilled from BAAI bge-m3), pruned per-script and int8-quantized. Tokenize (Unigram), gather the token rows, mean-pool, L2-normalize. Cross-lingual by construction across 101 languages.
  • Lexical stream: word and character n-grams hashed into a fixed vector, capturing proper nouns and exact tokens the semantic embedding smears (names, brands, gear).
  • Head: a small MLP fusing the two streams ([1, 8448]) into a sigmoid over the 36-topic taxonomy, trained with class balancing so it does not default to over-represented topics.

Distilled: open instruct LLMs (Apache/MIT) label the training text; a small student learns to reproduce it. Multi-label targets teach the co-occurrences (a tutorial is technology and creator-economy). Everything except the head is pure host-side code, so the same pipeline runs identically on Apple (Core ML), Android/Linux (LiteRT), and the web (WebAssembly + LiteRT.js).

Inputs and outputs

  • Input: a plain text string (title, or title + description). Best on short text like posts, titles, and descriptions.
  • Output: a probability over the 36 topics (features [1, 8448] β†’ topic_probs [1, 36]); take the top-k above the threshold in gist_config.json. Optimized for multi-label use β€” an item's 2–3 topics, optionally aggregated across a collection.

Languages

Cross-lingual by construction: the multilingual static embedding shares one representation space across 101 languages, so topic tagging transfers across all of them. A diverse 15-language spot check (across Latin, Cyrillic, Arabic, CJK, Devanagari, Hebrew, Thai, and Greek scripts) gives 88% top-3, with CJK, Arabic, and Cyrillic scripts matching or beating the Latin ones β€” topic classification is largely language-agnostic in the shared embedding.

Model variants

Two builds of the same 36-topic model live in this repo:

Variant Location Size Coverage
Multilingual (default) repo root ~74 MB 101 languages
English-only en/ ~15 MB English / Latin script only

The English build is a vocabulary prune of the same model β€” a smaller int8 embedding (32,251 tokens) and tokenizer, with the same classifier head, so it is topic-identical to the multilingual model on English input (no retraining). It does not cover non-Latin scripts (CJK, Arabic, Cyrillic, …); use it only when the input is reliably English/Latin. The SDKs select it with a flag β€” Gist.load({ variant: "english" }) (JS), Gist(variant: .english) (Swift), Gist(context, variant = GistVariant.ENGLISH) (Kotlin).

Evaluation

Recall on a held-out set of 572 human-labeled real posts (36 topics), zero-shot for the LLMs and zero-shot classifiers. Embedding classifiers get a light logistic head trained on the same corpus; recall@3 is the product metric (downstream aggregation consumes the top few topics).

Model Type Size recall@1 recall@3
Qwen2.5-7B (cloud) LLM zero-shot server 79% β€”
multilingual-e5-small + head transformer embed 110 MB 74% 92%
bge-small-en + head transformer embed 130 MB 71% 92%
gist static embed + n-grams + MLP ~74 MB 71% 91%
all-MiniLM-L6-v2 + head transformer embed 90 MB 68% 90%
potion + head static embed 30 MB 65% 89%
mDeBERTa-v3-mnli-xnli zero-shot NLI 560 MB 50% 73%
GLiClass-base zero-shot 400 MB 44% 65%

gist is tied on recall@3 with the best small models, at a fraction of the size and one on-device pass β€” and it beats every zero-shot classifier decisively (they never learned the taxonomy or the distribution). Only a 7B cloud LLM clearly leads on recall@1. An MTEB cross-check confirms the transformer edge is genuine static-embedding tradeoff, not a quirk of this gold.

Built on

License

Desert Ant Labs Source-Available License. Free for most apps; a commercial license is required at scale. Full terms are at the link. Licensing: licensing@desertant.com.

Citation

@software{gist_2026,
  title  = {gist: on-device content topic tagging},
  author = {Desert Ant Labs},
  year   = {2026},
  url    = {https://huggingface.co/desert-ant-labs/gist},
}

Β© 2026 Desert Ant Labs Β· https://desertant.com

Downloads last month
9
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Space using desert-ant-labs/gist 1