"""Decision Models Comparison: a minimal gr.Workflow. Prompt + "question + options" -> one format step -> 4 decision-model Space nodes in parallel (vllm-sr/d3, Cloudflare/clef, autotrust/JEV-27B-VL, Mapika/decider-2b) -> one compare step -> one comparison output (table + probability bars). Graph: workflow.json (see build_graph.py).""" import json import re import gradio as gr MODELS = [("d3", "vllm-sr/d3"), ("clef", "Cloudflare/clef"), ("jev", "autotrust/JEV-27B-VL"), ("decider", "Mapika/decider-2b")] def _key(o: str) -> str: return re.sub(r"[^a-z0-9_]+", "_", o.lower()).strip("_") or "opt" def format_question(question_block: str): """First line = question, following lines (or commas) = options. Returns the question in each model family's input format.""" lines = [x.strip() for x in (question_block or "").splitlines() if x.strip()] question = lines[0] if lines else "Which option fits best?" opts = [_key(o) for line in lines[1:] for o in line.split(",") if o.strip()] or ["yes", "no"] questions_json = json.dumps({"decision": {"type": "choice", "instructions": question, "criteria": {o: o for o in opts}}}) decider = f"choice decision: {question}\n" + "\n".join(f"- {o}" for o in opts) return questions_json, question, "\n".join(opts), decider def _probs(raw) -> dict: if isinstance(raw, str): try: raw = json.loads(raw) except Exception: return {} if not isinstance(raw, dict): return {} if "answers" in raw: raw = raw["answers"].get("decision", {}) return {_key(k): float(v) for k, v in (raw.get("probabilities") or {}).items()} def _bar(p: float, width: int = 20) -> str: n = round(p * width) return "█" * n + "░" * (width - n) def compare_decisions(d3: dict, clef: dict, jev: str, decider: str) -> str: """Merge the four models' outputs into one markdown view: table + probability bars.""" res = {name: _probs(r) for (_, name), r in zip(MODELS, (d3, clef, jev, decider))} opts = sorted({o for p in res.values() for o in p}) table = ["| Model | Decision | Confidence | Margin vs 2nd | " + " | ".join(opts) + " |", "|---" * (4 + len(opts)) + "|"] bars, votes = [], {} for name, p in res.items(): if not p: table.append(f"| {name} | ⚠️ no result |" + " |" * (2 + len(opts))) continue ranked = sorted(p.items(), key=lambda kv: -kv[1]) top, conf = ranked[0] margin = conf - (ranked[1][1] if len(ranked) > 1 else 0) votes[top] = votes.get(top, 0) + 1 cells = " | ".join(f"**{p.get(o, 0):.1%}**" if o == top else f"{p.get(o, 0):.1%}" for o in opts) table.append(f"| {name} | **{top}** | {conf:.1%} | {margin:.1%} | {cells} |") bars.append(f"{name:<22} " + " ".join(f"{o}:{_bar(p.get(o, 0), 10)}" for o in opts)) verdict = ", ".join(f"{k}: {v}/{len(res)}" for k, v in sorted(votes.items(), key=lambda kv: -kv[1])) agree = "✅ all models agree" if len(votes) == 1 else "⚠️ models disagree" return ("### Decision comparison\n\n" + "\n".join(table) + f"\n\n**Votes:** {verdict} ({agree})" + "\n\n#### Probabilities\n```\n" + "\n".join(bars) + "\n```") demo = gr.Workflow(graph="workflow.json", bind=[format_question, compare_decisions]) if __name__ == "__main__": demo.launch()