From 40b2a5fa92efae17c2e1e8387ad1c8717c8c9115 Mon Sep 17 00:00:00 2001 From: kantan-kanto Date: Sat, 26 Sep 2026 18:17:30 +0900 Subject: [PATCH] Add jev.probabilities and an eight-way aspect ratio default Jev script --- README.md | 6 ++++++ __init__.py | 29 +++++++++++++++++++++++++---- jev_backend.py | 8 +++++--- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b6a04c0..3101f15 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,7 @@ Functions (`state` is a string, dict, or list; text only): - `jev.yes(state, question[, threshold])` → `bool` (yes-probability ≥ `threshold`, default `0.5`) - `jev.noul(state, question)` → yes-probability (`0.0`–`1.0`). Compare it with a threshold; using it directly as a condition raises an error. - `jev.choice(state, question, options)` → the most likely option (`str`). `options` is a list of 2–16 labels, or a dict of labels to descriptions. +- `jev.probabilities(state, question, options)` → `dict` of each option to its probability (sums to `1.0`). Same `options` as `jev.choice`; asking both with the same arguments runs the model once. - `jev.score(state, question, levels)` → expected level (`float`, `0` to `len(levels) - 1`) for 2–16 ordered level descriptions ```python @@ -103,8 +104,13 @@ else: kind = jev.choice(it1, "Which orientation suits this prompt?", ["portrait", "landscape"]) ov2, ov3 = (384, 512) if kind == "portrait" else (512, 384) + +probs = jev.probabilities(it1, "Which orientation suits this prompt?", ["portrait", "landscape"]) +ot1 = f"{kind} (portrait: {probs['portrait']:.3f}, landscape: {probs['landscape']:.3f})" ``` +The node's default script picks one of eight aspect ratios for the prompt in `it1`, outputs its width and height to `out_value_1` / `out_value_2`, and lists every ratio's probability in `out_text_1`. + Notes: - Each question takes one forward pass (about 1–1.5 s with a 4B–9B model on GPU); the first question also loads the model. - Probabilities are uncalibrated and depend on the model; test thresholds on your own inputs. diff --git a/__init__.py b/__init__.py index ed6fdc9..5ec0927 100644 --- a/__init__.py +++ b/__init__.py @@ -517,6 +517,10 @@ class _SafeScriptInterpreter: if len(args) != 3: raise ValueError("jev.choice() expects 3 arguments") return self.jev.choice(*args) + if name == "probabilities": + if len(args) != 3: + raise ValueError("jev.probabilities() expects 3 arguments") + return self.jev.probabilities(*args) if name == "score": if len(args) != 3: raise ValueError("jev.score() expects 3 arguments") @@ -868,11 +872,28 @@ class MultiOutputScriptJev(MultiOutputScript): "# Jev: jev.yes(state, question[, threshold]) -> bool\n" "# jev.noul(state, question) -> probability\n" "# jev.choice(state, question, options) -> str\n" + "# jev.probabilities(state, question, options) -> {option: probability}\n" "# jev.score(state, question, levels) -> float\n" - "# Example:\n" - "kind = jev.choice(it1, \"What orientation suits this prompt?\", [\"portrait\", \"landscape\"])\n" - "ov1, ov2 = (384, 512) if kind == \"portrait\" else (512, 384)\n" - "ot1 = kind\n" + "# Example: pick an aspect ratio for the prompt in it1\n" + "sizes = {\n" + " \"1:1 (Square)\": (1024, 1024),\n" + " \"2:3 (Portrait Photo)\": (832, 1216),\n" + " \"3:2 (Photo)\": (1216, 832),\n" + " \"3:4 (Portrait Standard)\": (896, 1152),\n" + " \"4:3 (Standard)\": (1152, 896),\n" + " \"9:16 (Portrait Widescreen)\": (768, 1344),\n" + " \"16:9 (Widescreen)\": (1344, 768),\n" + " \"21:9 (Ultrawide)\": (1536, 640),\n" + "}\n" + "question = \"Which image aspect ratio best suits this prompt?\"\n" + "ratios = list(sizes)\n" + "best = jev.choice(it1, question, ratios)\n" + "probs = jev.probabilities(it1, question, ratios)\n" + "ov1, ov2 = sizes[best]\n" + "lines = [best]\n" + "for ratio in ratios:\n" + " lines.append(f\"{ratio}: {probs[ratio]:.3f}\")\n" + "ot1 = \"\\n\".join(lines)\n" ) types["required"]["model"] = (list(list_local_models()),) types["required"]["max_jev_calls"] = ("INT", {"default": 8, "min": 1, "max": 64}) diff --git a/jev_backend.py b/jev_backend.py index ae7d0a1..f228b53 100644 --- a/jev_backend.py +++ b/jev_backend.py @@ -49,12 +49,14 @@ class JevBackend: return self._ask(state, question, ["Yes", "No"])[0] def choice(self, state: Any, question: Any, options: list | dict) -> str: + probabilities = self.probabilities(state, question, options) + return max(probabilities, key=probabilities.get) + + def probabilities(self, state: Any, question: Any, options: list | dict) -> dict[str, float]: if isinstance(options, list): options = {str(option): None for option in options} - labels = list(options) descriptions = [label if description is None else f"{label}: {description}" for label, description in options.items()] - probabilities = self._ask(state, question, descriptions) - return labels[probabilities.index(max(probabilities))] + return dict(zip(options, self._ask(state, question, descriptions))) def score(self, state: Any, question: Any, levels: list) -> float: probabilities = self._ask(state, question, list(levels))