← All ivy-nodes
IVYXSTUDIO · IVY NODE
J

Jev · Score

ivy.node.jev-score · v0.1.0

ivyx✓

Asks TypeSafe Jev where a text or JSON state sits on an ordered scale of 2 to 10 described levels and returns a score from 0 to the top level with the nearest level, its description and the confidence. Use it to rate or grade urgency, severity, sentiment, quality or correctness. Levels go from low to high; the score is probability-weighted, so it can land between two levels. When the state is a JSON object its fields come back beside the answer, so a for-each over rows keeps each row.

#jev#typesafe#score#rate#grade#severity#sentiment#decision

Inputs

FieldTypeDescription
staterequiredNot declaredThe text, or a JSON object or array, that Jev judges.
instructionsrequiredstringWhat to rate, in words; the model never sees anything else about it.
levelsrequiredarrayTwo to ten level descriptions, from the low end of the scale to the high end.
jev_api_keyrequiredstringThe TypeSafe API key; reference the stored secret jev-api-key, never the key itself.
base_urlstringThe System One server.
modelstringThe Jev model; pin a version such as jev-1.13.0 before tuning a threshold.

Outputs

FieldTypeDescription
scorerequirednumber0 to the top level number; can fall between levels.
levelrequiredintegerThe nearest level number, 0 for the first.
level_textrequiredstringThe nearest level's description.
isobjectFor each level, as lowercase words joined by _, whether it is the nearest one; a branch reads is.<level>.
normalizedrequirednumberThe score scaled to 0–1.
confidencerequirednumber0–1, how peaked the probabilities are.
probabilitiesobjectEach level's probability, keyed by level number.
modelstringThe model version that answered.

Source

python

inp = __ivy_ctx__["nodes"][__ivy_node_id__]["input"]

import json
import re
import requests

def slug(text):
    """The key a branch reads: "Needs action today" → "needs_action_today"."""
    return re.sub(r"[^a-z0-9]+", "_", str(text).lower()).strip("_")

def ask(question):
    state = inp.get("state")
    if state is None or (isinstance(state, str) and not state.strip()) or state == {} or state == []:
        raise ValueError("state is empty; give Jev the text or JSON to judge.")
    instructions = str(inp.get("instructions") or "").strip()
    if not instructions:
        raise ValueError("instructions is empty; say what Jev should decide.")
    key = inp.get("jev_api_key")
    if not key:
        raise ValueError("jev_api_key is missing; reference the stored secret jev-api-key.")
    question["instructions"] = instructions
    base = str(inp.get("base_url") or "https://api.typesafe.ai").rstrip("/")
    response = requests.post(
        base + "/v1/systemone",
        headers={"Authorization": "Bearer " + str(key), "Content-Type": "application/json"},
        json={"state": state, "model": inp.get("model") or "jev-latest", "questions": {"q": question}},
        timeout=60,
    )
    if response.status_code in (401, 403):
        raise PermissionError(f"Jev refused the API key (HTTP {response.status_code}).")
    if response.status_code != 200:
        raise RuntimeError(f"Jev answered HTTP {response.status_code}: {response.text[:300]}")
    body = response.json()
    answer = (body.get("answers") or {}).get("q")
    if not isinstance(answer, dict):
        raise RuntimeError("Jev's answer has no entry for the question.")
    return answer, body.get("model")

levels = [str(l) for l in (inp.get("levels") or []) if str(l).strip()]
if not 2 <= len(levels) <= 10:
    raise ValueError("levels needs between 2 and 10 descriptions, lowest first.")
answer, model = ask({"type": "score", "criteria": levels})
score = float(answer.get("score"))
level = max(0, min(len(levels) - 1, int(round(score))))

out = __ivy_ctx__["nodes"][__ivy_node_id__]["output"]
out["score"] = score
out["level"] = level
out["level_text"] = levels[level]
out["is"] = {slug(t): i == level for i, t in enumerate(levels)}
out["normalized"] = round(score / (len(levels) - 1), 4)
out["confidence"] = answer.get("confidence")
out["probabilities"] = answer.get("probabilities") or {}
out["model"] = model
# An object state's fields come back beside the answer, so a for-each over
# rows keeps each row (its date, its question) next to its score.
if isinstance(inp.get("state"), dict):
    for _k, _v in inp["state"].items():
        out.setdefault(_k, _v)

Tests

Requires: python:3.9, requests

  • severe

    Two exclamation marks land on the top of a three-level scale.

  • calm

    A calm message is level 0 on a five-level scale.

  • row

    A row as the state comes back beside its score, and the node's own fields win.

  • one-level

    A single level is refused before any call.

  • empty-state

    An empty state is refused before any call.