sundial-encoder-full

Time expressions (en / es / fr / de) → a portable IR → SQL / JS date ranges. A tiny (~14 MB) multi-head classifier that runs in the browser or on the server in a single forward pass.

What it does

Given a phrase like "last 7 days", "último miércoles de 2027", "first day of the month" or "a fortnight ago", the model emits an IR skeleton — the structure only, no digits (last_n(N, day), nth_weekday(last, wed, YEAR), nth_day(1, month, this), offset(-N, week), …). A small deterministic layer (in the repo) then extracts the exact numbers, months and dates from the input and materializes the full IR, which renders to a bound SQLite / Postgres predicate or a JS {start, end} range.

The model never generates a digit. Because the output space is a finite set of skeletons, this is classification, not generation — so a 14 M-parameter encoder with a few heads is enough, and it generalizes to years and phrasings it barely saw.

Model

  • Base: google/electra-small-discriminator (~14 M params), fine-tuned as a multi-head classifier with one head per IR slot: op / unit / which / dow / ord / scope / sign / has_at.
  • Format: int8 ONNX, ~14 MB. Runtime: onnxruntime (WASM in the browser, single pass, ~1 ms/inf CPU).
  • Trained on en + es + fr + de, basic + complex expressions, plus LLM-distilled paraphrases for phrasing robustness.

Files: model_int8.onnx, the tokenizer, heads.json (the per-head label vocabulary).

Highlights

  • Matches a T5 seq2seq (98.6% gold) at 14 MB and ~30× faster per inference.
  • One 14 MB English-vocab base handles en/es/fr/de at ~99% (a 135 MB multilingual base adds ~1%).
  • vs rule engines: a tie with Duckling on the constructs it supports, but wins on out-of-distribution phrasing (91.7% vs 38.9% on paraphrases) — the distilled model generalizes the long tail.

Usage

The model outputs the 8 head logits; you argmax them, compose the skeleton, then run the deterministic materialize + renderers from the repo. The repo ships a ready-to-run script:

git clone https://github.com/ceritium/sundial && cd sundial
uv run --project train python train/predict_onnx.py \
    --hf ceritium/sundial-encoder-full \
    --inputs data/gold/gold_complex_en.jsonl --out models/pred.jsonl
node eval/run_eval.mjs --gold data/gold/gold_complex_en.jsonl --predictions models/pred.jsonl --skeleton
# -> 26 examples · 100.0%  (skeleton -> materialize -> execute vs gold)

Minimal inference (Python + onnxruntime):

import json, numpy as np, onnxruntime as ort
from huggingface_hub import hf_hub_download
from transformers import AutoTokenizer

repo = "ceritium/sundial-encoder-full"
tok = AutoTokenizer.from_pretrained(repo)
heads = json.load(open(hf_hub_download(repo, "heads.json")))
sess = ort.InferenceSession(hf_hub_download(repo, "model_int8.onnx"))

enc = tok("last wednesday of 2027".lower(), return_tensors="np", truncation=True, max_length=32)
logits = sess.run(heads["head_names"], {"input_ids": enc["input_ids"].astype(np.int64),
                                        "attention_mask": enc["attention_mask"].astype(np.int64)})
slots = {n: heads["heads"][n][int(np.argmax(logits[i][0]))] for i, n in enumerate(heads["head_names"])}
print(slots)  # -> {op: nth_weekday, ord: last, dow: wed, scope: year, ...}  (compose + materialize in the repo)

License

MIT. Experimental research model — see the repo for the full IR grammar, renderers (validated by execution), training/distillation pipeline, and benchmarks.

Downloads last month
38
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support