"""GLiDE-0.4B — a decision model: state in, typed questions out, calibrated probabilities.
Model: https://huggingface.co/fastino/GLiDE-0.4B
Author: Fastino — https://fastino.ai
Given a state (text or JSON) and one or more typed questions, GLiDE returns a probability
for every option of every question. The probabilities are read from a 255-way decision
readout — nothing is generated.
The `glide/` package is vendored verbatim from the model repository and the checkpoint
is streamed from the Hub at startup (~0.8 GB, bf16).
"""
import html as _html
import json
import time
import spaces # must come before torch
import torch
import gradio as gr
from glide import Glide, RequestError
MODEL_ID = "fastino/GLiDE-0.4B"
model = Glide.from_pretrained(MODEL_ID) # device="cuda", bf16, vision=True defaults
# --------------------------------------------------------------------------------------
# request building
# --------------------------------------------------------------------------------------
def _parse_state(text: str):
"""A JSON object/array is passed through structurally; anything else is plain text."""
s = (text or "").strip()
if s[:1] in "{[":
try:
v = json.loads(s)
if isinstance(v, (dict, list)):
return v
except json.JSONDecodeError:
pass
return text or ""
def _build_questions(questions_json: str) -> dict:
try:
questions = json.loads(questions_json)
except json.JSONDecodeError as e:
raise gr.Error(f"Questions are not valid JSON: {e}") from None
if not isinstance(questions, dict) or not questions:
raise gr.Error(
'Questions must be a non-empty JSON object, e.g. '
'{"intent": {"type": "choice", "instructions": "...", "criteria": {"a": "A", "b": "B"}}}'
)
return questions
def _score_legend(q: dict) -> dict:
"""Map the numeric level index strings GLiDE returns to the user's level descriptions."""
crit = q.get("criteria") if isinstance(q, dict) else None
if isinstance(crit, list):
return {str(i): str(d) for i, d in enumerate(crit)}
if isinstance(crit, dict):
try:
keys = sorted(crit, key=lambda x: float(x))
return {str(i): str(crit[k]) for i, k in enumerate(keys)}
except (TypeError, ValueError):
pass
return {}
# --------------------------------------------------------------------------------------
# rendering
# --------------------------------------------------------------------------------------
BADGE = {"noul": "#2563eb", "choice": "#7c3aed", "score": "#ea580c"}
def _bar(label: str, p: float, highlight: bool) -> str:
pct = max(0.0, min(1.0, float(p))) * 100
colour = "var(--color-accent)" if highlight else "var(--border-color-accent)"
weight = "600" if highlight else "400"
return (
'
'
f'
{_html.escape(label)}
'
'
'
f'
{p:.2f}
'
"
"
)
def _card(qid: str, ans: dict, question: dict) -> str:
t = ans["type"]
head = (
''
f'{_html.escape(qid)}'
f'{t}'
)
if t == "noul":
p = ans["noul"]
head += (
f'{p:.2f}'
f'conf {ans["confidence"]:.2f}
'
)
body = _bar("yes", p, p >= 0.5) + _bar("no", 1 - p, p < 0.5)
elif t == "choice":
head += (
f'{_html.escape(str(ans["choice"]))}'
f'conf {ans["confidence"]:.2f}'
)
best = ans["choice"]
body = "".join(_bar(k, v, k == best) for k, v in ans["probabilities"].items())
else: # score
legend = _score_legend(question)
head += (
f'level {ans["score"]}'
f'conf {ans["confidence"]:.2f}'
)
best = ans["score"]
body = "".join(
_bar(f"{k} · {legend[k]}" if k in legend else str(k), v, k == str(best))
for k, v in ans["probabilities"].items()
)
head += (
f''
f'expected level {ans["expected_level"]:.2f}
'
)
return (
'' + head + body + "
"
)
def _render(result: dict, questions: dict, latency_ms: float) -> str:
answers = result["answers"]
cards = "".join(_card(qid, a, questions.get(qid, {})) for qid, a in answers.items())
tokens = result.get("usage", {}).get("input_tokens", 0)
meta = (
''
f'{len(answers)} question(s) · {tokens} input tokens · {latency_ms:.0f} ms on GPU · '
'bf16 · nothing generated
'
)
return f'{meta}{cards}
'
# --------------------------------------------------------------------------------------
# inference
# --------------------------------------------------------------------------------------
@spaces.GPU(duration=15)
def decide(state: str, questions: str):
"""Answer typed questions about one state and return calibrated probabilities.
Args:
state: the situation to evaluate. Plain text, or a JSON object / array
(passed through structurally, e.g. {"ticket": "...", "customer_tier": "gold"}).
questions: a JSON object mapping your own question id to a question of type
"choice" (criteria = {option: description}, up to 255 options),
"noul" (yes/no, criteria = optional {"true": ..., "false": ...}) or
"score" (criteria = [ordered level descriptions, ...]).
Returns:
An HTML summary with a probability bar per option of every question, and the
raw System One response ({"model", "answers", "usage"}).
"""
q = _build_questions(questions)
t0 = time.perf_counter()
try:
result = model.decide(state=_parse_state(state), questions=q)
except RequestError as e:
raise gr.Error(f"GLiDE cannot serve this request: {e}") from None
if torch.cuda.is_available():
torch.cuda.synchronize()
latency_ms = (time.perf_counter() - t0) * 1000
return _render(result, q, latency_ms), result
# --------------------------------------------------------------------------------------
# examples — the two quickstart requests from the model card, verbatim
# --------------------------------------------------------------------------------------
EX1_STATE = json.dumps(
{"ticket": "I was charged twice for order #4821 and the second charge is still pending.", "customer_tier": "gold"},
indent=2,
)
EX1_QUESTIONS = json.dumps(
{
"intent": {"type": "choice", "instructions": "What does the customer want?",
"criteria": {"refund": "Get money back", "cancel": "Cancel the order",
"track": "Track a delivery", "other": "Something else"}},
"urgent": {"type": "noul", "instructions": "Should this ticket be escalated today?"},
"priority": {"type": "score", "instructions": "What support priority should this ticket get?",
"criteria": ["low: no impact on the customer", "medium: the customer is inconvenienced",
"high: the customer has lost money or cannot use the service"]},
},
indent=2,
)
EX2_STATE = "Order #4821 was delivered to the wrong address and the customer wants it re-sent today."
EX2_QUESTIONS = json.dumps(
{
"action": {"type": "choice", "instructions": "What should support do next?",
"criteria": {"resend": "Re-ship the order", "refund": "Refund the order",
"investigate": "Open a carrier investigation"}},
"urgent": {"type": "noul", "instructions": "Is the request time-sensitive?"},
},
indent=2,
)
EXAMPLES = [
[EX1_STATE, EX1_QUESTIONS],
[EX2_STATE, EX2_QUESTIONS],
]
EXAMPLE_LABELS = ["Support ticket — intent, urgency, priority (model-card quickstart)",
"Wrong address — next action + urgency (model-card HTTP example)"]
# --------------------------------------------------------------------------------------
# UI
# --------------------------------------------------------------------------------------
CSS = """
#col-container { max-width: 1180px; margin: 0 auto; }
.dark .gradio-container { color: var(--body-text-color); }
"""
INTRO = f"""# GLiDE-0.4B — state in, typed questions, calibrated probabilities out
[`{MODEL_ID}`](https://huggingface.co/{MODEL_ID}) is a **decision model** from
[Fastino](https://fastino.ai). Given a state (text or JSON) and one or more typed questions, it returns a
**probability for every option of every question** — read from a 255-way decision readout in a single forward
pass. Nothing is generated.
Three question types: **choice** (one of up to 255 named options), **noul** (yes / no → P(yes)) and
**score** (ordered levels). 0.40B params, bf16, 51.10 on the Decision Index 0.3.1 public suite. This model has
no vision encoder — images are rejected.
[Fastino](https://fastino.ai) · [model card](https://huggingface.co/{MODEL_ID}) ·
[Fastino API](https://docs.fastino.ai/inference/systemone)
"""
with gr.Blocks(title="GLiDE-0.4B decision model") as demo:
with gr.Column(elem_id="col-container"):
gr.Markdown(INTRO)
with gr.Row():
with gr.Column(scale=1):
state = gr.Textbox(
label="State — the situation to evaluate",
placeholder='e.g. {"ticket": "I was charged twice for order #4821…", "customer_tier": "gold"} (plain text or JSON)',
lines=10,
value=EX1_STATE,
)
with gr.Column(scale=1):
questions = gr.Code(
label="Questions (JSON)",
language="json",
lines=10,
value=EX1_QUESTIONS,
)
run = gr.Button("Decide", variant="primary")
answers_html = gr.HTML(label="Answers")
raw = gr.JSON(label="Raw System One response")
with gr.Accordion("Advanced — question schema & limits", open=False):
gr.Markdown(
'**Question schema** — `{"": {"type": …, "instructions": …, "criteria": …}}`\n\n'
"| type | `criteria` | answer |\n|---|---|---|\n"
"| `choice` | `{option: description or null}`, 1–255 options | `choice`, `probabilities`, `confidence` = top − second |\n"
"| `noul` | optional `{\"true\": …, \"false\": …}` | `noul` = P(yes), `confidence` = \\|2·P − 1\\| |\n"
"| `score` | `[level, level, …]` ordered, or `{numeric level: description}` | `score` = top level, `expected_level`, `probabilities` |\n\n"
"`state` and `instructions` may be any JSON value — objects are rendered as `key: value` lines. "
"Each question prompt holds up to **7,999 tokens** (state + question + options); longer prompts keep "
"their first 1,024 tokens and their end, so they are still answered. Answers are read from a "
"255-way decision readout — nothing is generated, so outputs are deterministic at a fixed temperature."
)
gr.Examples(
examples=EXAMPLES,
example_labels=EXAMPLE_LABELS,
inputs=[state, questions],
outputs=[answers_html, raw],
fn=decide,
cache_examples=True,
cache_mode="lazy",
label="Examples from the GLiDE-0.4B model card",
)
gr.on(
triggers=[run.click],
fn=decide,
inputs=[state, questions],
outputs=[answers_html, raw],
api_name="decide",
)
if __name__ == "__main__":
demo.launch(theme=gr.themes.Citrus(), css=CSS, mcp_server=True)