tuieval 0.2.0.dev43__py3-none-any.whl → 0.2.0.dev50__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tuieval/_version.py +2 -2
- tuieval/cli.py +1 -1
- tuieval/pta.py +103 -112
- tuieval/run_evals.py +9 -4
- tuieval/tui.py +32 -33
- {tuieval-0.2.0.dev43.dist-info → tuieval-0.2.0.dev50.dist-info}/METADATA +1 -1
- {tuieval-0.2.0.dev43.dist-info → tuieval-0.2.0.dev50.dist-info}/RECORD +10 -10
- {tuieval-0.2.0.dev43.dist-info → tuieval-0.2.0.dev50.dist-info}/WHEEL +0 -0
- {tuieval-0.2.0.dev43.dist-info → tuieval-0.2.0.dev50.dist-info}/entry_points.txt +0 -0
- {tuieval-0.2.0.dev43.dist-info → tuieval-0.2.0.dev50.dist-info}/licenses/LICENSE +0 -0
tuieval/_version.py
CHANGED
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.2.0.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 2, 0, '
|
|
21
|
+
__version__ = version = '0.2.0.dev50'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 2, 0, 'dev50')
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
tuieval/cli.py
CHANGED
|
@@ -14,7 +14,7 @@ Start here
|
|
|
14
14
|
|
|
15
15
|
Day to day
|
|
16
16
|
tuieval compare [...] scorecards (--speed, --pairwise, --failures)
|
|
17
|
-
tuieval pta the PTA index:
|
|
17
|
+
tuieval pta the PTA index: parsimony, speed and accuracy per model, as bars
|
|
18
18
|
tuieval report the verdicts with their evidence, as a markdown file
|
|
19
19
|
tuieval history every verdict change, newest first
|
|
20
20
|
tuieval items tests that don't separate models or look broken
|
tuieval/pta.py
CHANGED
|
@@ -1,145 +1,133 @@
|
|
|
1
|
-
"""PTA index:
|
|
1
|
+
"""PTA index: parsimony, speed (time) and accuracy per model, 0-100 each and higher is better, shown
|
|
2
|
+
as a bar per score for each model.
|
|
2
3
|
|
|
3
|
-
P
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
P parsimony a score out of 100, from the tokens (reasoning and answer) used on every question
|
|
5
|
+
compared (each question at its median over repeats): 100 for the model that used the
|
|
6
|
+
fewest, POINTS_PER_DOUBLING points less for every doubling (0 at about 100 times more).
|
|
7
|
+
Unlike T it doesn't depend on the machine: it's how much a model says to get there.
|
|
8
|
+
T speed a score out of 100, the same from the total time to answer those questions: 100 for
|
|
9
|
+
the fastest model. Log scales, so models that are all far behind the best still differ.
|
|
10
|
+
A accuracy a percentage: the share of answers to those questions that passed.
|
|
9
11
|
|
|
10
12
|
Models are compared on the questions all of them answered, so one that skipped some never looks
|
|
11
|
-
faster.
|
|
12
|
-
|
|
13
|
+
faster. Server and connection errors aren't answers. By default a model with fewer than half as many
|
|
14
|
+
answers as the most-answered model is left out (listed, so it can be picked), or it would shrink the
|
|
15
|
+
shared questions for everyone. There's no combined number: the three stay side by side, and verdicts
|
|
16
|
+
and critical failures stay where they are (verdict.py).
|
|
13
17
|
"""
|
|
14
|
-
import
|
|
18
|
+
import math
|
|
19
|
+
|
|
20
|
+
from rich.markup import escape as rich_escape
|
|
15
21
|
|
|
16
22
|
from . import compare
|
|
17
23
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
COLORS = ["cyan", "magenta", "yellow", "green", "red", "blue", "bright_white", "bright_cyan"]
|
|
24
|
+
MIN_SHARE = 0.5 # fewer answers than this share of the most-answered model's: left out by default
|
|
25
|
+
POINTS_PER_DOUBLING = 15
|
|
21
26
|
|
|
22
27
|
|
|
23
|
-
def
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
m = next((m for m in cfg["models"] if m["label"] == label), None)
|
|
27
|
-
server = cfg["servers"].get(m["server"], {}) if m else {}
|
|
28
|
-
if not server:
|
|
28
|
+
def score(total, best):
|
|
29
|
+
"""P and T: 100 for the best (lowest) total, POINTS_PER_DOUBLING less for every doubling, never below 0."""
|
|
30
|
+
if not total or not best:
|
|
29
31
|
return None
|
|
30
|
-
|
|
31
|
-
return 100
|
|
32
|
-
host = urllib.parse.urlparse(server.get("url", "")).hostname or ""
|
|
33
|
-
return 100 if host.lower() in LOCAL_HOSTS else 0
|
|
32
|
+
return max(0.0, 100 - POINTS_PER_DOUBLING * math.log2(total / best))
|
|
34
33
|
|
|
35
34
|
|
|
36
|
-
def index(rows,
|
|
37
|
-
"""{"questions": n shared, "models": [{model, P, T, A, total_s, passed, answers, alongside
|
|
38
|
-
|
|
35
|
+
def index(rows, models=None):
|
|
36
|
+
"""{"questions": n shared, "models": [{model, P, T, A, tokens, total_s, passed, answers, alongside,
|
|
37
|
+
fewest, fastest}],
|
|
38
|
+
"left_out": [(model, questions answered)], "no_answers": [model], "most": questions answered by the
|
|
39
|
+
most-answered model}, best accuracy first. models: the ones to compare (default: every model in rows
|
|
40
|
+
with enough answers; models named here are compared whatever their count)."""
|
|
41
|
+
no_answers = sorted({r["model"] for r in rows} - {r["model"] for r in rows if not r.get("error")})
|
|
42
|
+
rows = [r for r in rows if not r.get("error")] # a server or connection error isn't an answer
|
|
39
43
|
tests = compare.per_question(rows)
|
|
40
|
-
|
|
44
|
+
counts = {}
|
|
45
|
+
for t in tests:
|
|
46
|
+
for m in t["cells"]:
|
|
47
|
+
counts[m] = counts.get(m, 0) + 1
|
|
48
|
+
most = max(counts.values(), default=0)
|
|
49
|
+
if models:
|
|
50
|
+
no_answers = [m for m in no_answers if m in models]
|
|
51
|
+
models, left_out = sorted(m for m in models if m in counts), []
|
|
52
|
+
else:
|
|
53
|
+
models = sorted(m for m in counts if counts[m] >= MIN_SHARE * most)
|
|
54
|
+
left_out = sorted(((m, n) for m, n in counts.items() if m not in models), key=lambda x: (-x[1], x[0]))
|
|
41
55
|
shared = [t for t in tests if models and all(m in t["cells"] for m in models)]
|
|
42
56
|
out = []
|
|
43
57
|
for m in models:
|
|
44
58
|
cells = [t["cells"][m] for t in shared]
|
|
45
59
|
answers = sum(c["n"] for c in cells)
|
|
46
|
-
out.append({"model": m, "
|
|
60
|
+
out.append({"model": m, "tokens": sum(c["tokens"] or 0 for c in cells),
|
|
61
|
+
"total_s": sum(c["secs"] or 0 for c in cells),
|
|
47
62
|
"passed": sum(c["passed"] for c in cells), "answers": answers,
|
|
48
63
|
"A": 100 * sum(c["passed"] for c in cells) / answers if answers else None,
|
|
49
64
|
# answers that ran while other models were served shared the machine's speed
|
|
50
65
|
"alongside": any(r.get("alongside") for c in cells for r in c["rows"])})
|
|
51
66
|
fastest = min((x["total_s"] for x in out if x["total_s"] > 0), default=None)
|
|
67
|
+
fewest = min((x["tokens"] for x in out if x["tokens"] > 0), default=None)
|
|
52
68
|
for x in out:
|
|
53
|
-
x["T"] =
|
|
69
|
+
x["P"], x["T"] = score(x["tokens"], fewest), score(x["total_s"], fastest)
|
|
70
|
+
x["fewest"] = bool(fewest) and x["tokens"] == fewest
|
|
71
|
+
x["fastest"] = bool(fastest) and x["total_s"] == fastest
|
|
54
72
|
out.sort(key=lambda x: (-(x["A"] or 0), -(x["T"] or 0), x["model"]))
|
|
55
|
-
return {"questions": len(shared), "models": out
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"""
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
lines = []
|
|
84
|
-
for bits, colors in zip(self.bits, self.color):
|
|
85
|
-
out = []
|
|
86
|
-
for b, c in zip(bits, colors):
|
|
87
|
-
ch = chr(0x2800 + b) if b else " "
|
|
88
|
-
out.append(f"[{c}]{ch}[/]" if b and c else ch)
|
|
89
|
-
lines.append("".join(out).rstrip())
|
|
90
|
-
return lines
|
|
73
|
+
return {"questions": len(shared), "models": out, "left_out": left_out, "no_answers": no_answers,
|
|
74
|
+
"most": most}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
LETTERS = (("P", "parsimony", "/100", "cyan"), ("T", "speed", "/100", "magenta"), ("A", "accuracy", "%", "green"))
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def bars(result, width=20, markup=True):
|
|
81
|
+
"""Lines with a row per model and a bar per score (P, T, A), longer = better, each with its number:
|
|
82
|
+
the at-a-glance view. markup=False gives plain text (the report)."""
|
|
83
|
+
if not result["models"]:
|
|
84
|
+
return []
|
|
85
|
+
name_w = max(len(x["model"]) for x in result["models"])
|
|
86
|
+
cell_w = width + 6 # the bar, a space and "100%" or " 100"
|
|
87
|
+
head = " " * (name_w + 2) + "".join(f"{f'{k} {name}':<{cell_w}}" for k, name, _, _ in LETTERS)
|
|
88
|
+
lines = [f"[b]{head.rstrip()}[/b]" if markup else head.rstrip()]
|
|
89
|
+
for x in result["models"]:
|
|
90
|
+
cells = []
|
|
91
|
+
for k, _, unit, color in LETTERS:
|
|
92
|
+
v = x[k]
|
|
93
|
+
full = 0 if v is None else round(width * max(0, min(100, v)) / 100)
|
|
94
|
+
bar, rest = "█" * full, "░" * (width - full)
|
|
95
|
+
num = "-" if v is None else f"{v:.0f}{'%' if unit == '%' else ''}"
|
|
96
|
+
bar = f"[{color}]{bar}[/][grey37]{rest}[/]" if markup else bar + rest
|
|
97
|
+
cells.append(f"{bar} {num:>4}")
|
|
98
|
+
name = f"{x['model']:<{name_w}}"
|
|
99
|
+
lines.append(f"{rich_escape(name) if markup else name} " + " ".join(cells))
|
|
100
|
+
return lines
|
|
91
101
|
|
|
92
102
|
|
|
93
|
-
def
|
|
94
|
-
"""
|
|
95
|
-
|
|
96
|
-
cols = max(20, width)
|
|
97
|
-
w = cols * 2 - 2 # dots across
|
|
98
|
-
h = int(w * 0.866) # an equilateral triangle (braille dots are about square)
|
|
99
|
-
rows = h // 4 + 1
|
|
100
|
-
top, left, right = (w / 2, 0), (0, h), (w, h)
|
|
101
|
-
center = (w / 2, h * 2 / 3)
|
|
102
|
-
c = _Canvas(cols, rows)
|
|
103
|
-
|
|
104
|
-
def at(corner, score):
|
|
105
|
-
return (center[0] + (corner[0] - center[0]) * score / 100, center[1] + (corner[1] - center[1]) * score / 100)
|
|
106
|
-
|
|
107
|
-
for corner in (top, left, right): # axes, the 50% ring, then the frame
|
|
108
|
-
c.line(center, corner, "grey37", dotted=True)
|
|
109
|
-
half = [at(k, 50) for k in (top, left, right)]
|
|
110
|
-
for a, b in zip(half, half[1:] + half[:1]):
|
|
111
|
-
c.line(a, b, "grey37", dotted=True)
|
|
112
|
-
for a, b in ((top, left), (left, right), (right, top)):
|
|
113
|
-
c.line(a, b, "grey70")
|
|
114
|
-
for i, x in enumerate(result["models"][:len(COLORS)][::-1]): # the best ends on top
|
|
115
|
-
color = COLORS[len(result["models"][:len(COLORS)]) - 1 - i]
|
|
116
|
-
pts = [at(k, s or 0) for k, s in ((top, x["P"]), (left, x["T"]), (right, x["A"]))]
|
|
117
|
-
for a, b in zip(pts, pts[1:] + pts[:1]):
|
|
118
|
-
c.line(a, b, color)
|
|
119
|
-
lines = c.text()
|
|
120
|
-
pad = " " * max(0, cols // 2 - 5)
|
|
121
|
-
return ([f"{pad}[b]P[/b] privacy"] + lines
|
|
122
|
-
+ [f"[b]T[/b] time{' ' * max(1, cols - 15)}[b]A[/b] accuracy"])
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def legend(result):
|
|
126
|
-
"""One Rich markup line per model: its colour on the triangle and its three scores."""
|
|
103
|
+
def left_out_lines(result):
|
|
104
|
+
"""Plain sentences on the models not compared (too few answers, or only server errors) and on
|
|
105
|
+
answers that shared the machine with other models."""
|
|
127
106
|
out = []
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
+ ("
|
|
107
|
+
if result["left_out"]:
|
|
108
|
+
out.append("Left out (fewer than half as many answers as the most-answered model; pick them under "
|
|
109
|
+
"Models or --only to include them): "
|
|
110
|
+
+ ", ".join(f"{m} ({n} of {result['most']})" for m, n in result["left_out"]))
|
|
111
|
+
if result["no_answers"]:
|
|
112
|
+
out.append("No answers, only server errors: " + ", ".join(result["no_answers"]))
|
|
113
|
+
shared = [x["model"] for x in result["models"] if x["alongside"]]
|
|
114
|
+
if shared:
|
|
115
|
+
out.append("Some answers ran alongside other models, which shared the machine's speed: " + ", ".join(shared))
|
|
132
116
|
return out
|
|
133
117
|
|
|
134
118
|
|
|
135
|
-
def _score(v):
|
|
136
|
-
|
|
119
|
+
def _score(v, unit=""):
|
|
120
|
+
"""A is a percentage (%), P and T scores out of 100 (/100: on a log scale, not percentages)."""
|
|
121
|
+
return "-" if v is None else f"{v:.0f}{unit}"
|
|
137
122
|
|
|
138
123
|
|
|
139
124
|
def table(result):
|
|
140
125
|
"""(header, rows) for a plain table of the index."""
|
|
141
|
-
header = ["model", "P
|
|
142
|
-
|
|
126
|
+
header = ["model", "P parsimony /100", "T speed /100", "A accuracy %", "tokens", "total time",
|
|
127
|
+
"answers right"]
|
|
128
|
+
rows = [[x["model"], _score(x["P"]), _score(x["T"]), _score(x["A"], "%"),
|
|
129
|
+
f"{round(x['tokens']):,}" + (" ★" if x.get("fewest") else ""),
|
|
130
|
+
fmt_total(x["total_s"]) + (" ★" if x.get("fastest") else ""),
|
|
143
131
|
f"{x['passed']}/{x['answers']}"] for x in result["models"]]
|
|
144
132
|
return header, rows
|
|
145
133
|
|
|
@@ -158,8 +146,10 @@ def scope_note(result, models):
|
|
|
158
146
|
"""What the scores compare, in a sentence."""
|
|
159
147
|
if not result["questions"]:
|
|
160
148
|
return "These models have no question in common yet, so there's nothing to compare."
|
|
161
|
-
return (f"Compared on the {result['questions']} questions all {len(models)} model(s) answered. "
|
|
162
|
-
"
|
|
149
|
+
return (f"Compared on the {result['questions']} questions all {len(result['models'])} model(s) answered. "
|
|
150
|
+
f"A is a percentage. P parsimony and T speed are scores out of 100, not percentages: 100 = the fewest "
|
|
151
|
+
f"tokens / the fastest total time (★), {POINTS_PER_DOUBLING} points less for each doubling; a better "
|
|
152
|
+
"model added lowers the others.")
|
|
163
153
|
|
|
164
154
|
|
|
165
155
|
def for_engine(e, labels=None, packs=None, results_dir=None):
|
|
@@ -169,7 +159,7 @@ def for_engine(e, labels=None, packs=None, results_dir=None):
|
|
|
169
159
|
if packs:
|
|
170
160
|
rows = [r for r in rows if r["suite"] in packs]
|
|
171
161
|
models = sorted({r["model"] for r in rows} & set(labels) if labels else {r["model"] for r in rows})
|
|
172
|
-
return index(rows,
|
|
162
|
+
return index(rows, models if labels else None), models
|
|
173
163
|
|
|
174
164
|
|
|
175
165
|
def markdown(result, models):
|
|
@@ -177,9 +167,10 @@ def markdown(result, models):
|
|
|
177
167
|
lines = ["## PTA index", "", scope_note(result, models), ""]
|
|
178
168
|
if not result["questions"]:
|
|
179
169
|
return lines
|
|
170
|
+
lines += ["```"] + bars(result, markup=False) + ["```", ""]
|
|
180
171
|
header, rows = table(result)
|
|
181
172
|
lines += ["| " + " | ".join(header) + " |", "|" + "---|" * len(header)]
|
|
182
173
|
lines += ["| " + " | ".join(r) + " |" for r in rows]
|
|
183
|
-
|
|
184
|
-
lines += ["",
|
|
174
|
+
for line in left_out_lines(result):
|
|
175
|
+
lines += ["", line]
|
|
185
176
|
return lines
|
tuieval/run_evals.py
CHANGED
|
@@ -389,11 +389,11 @@ def report_markdown(e, labels=None):
|
|
|
389
389
|
|
|
390
390
|
def cmd_pta(argv):
|
|
391
391
|
p = argparse.ArgumentParser(prog="tuieval pta",
|
|
392
|
-
description="The PTA index:
|
|
393
|
-
"
|
|
392
|
+
description="The PTA index: parsimony (tokens), speed and accuracy per model (0-100, higher is better), as a "
|
|
393
|
+
"bar per score for each model and a table, over the questions all the models answered.")
|
|
394
394
|
p.add_argument("--only", help="comma-separated model labels (default: every model with results)")
|
|
395
395
|
p.add_argument("--packs", help="comma-separated packs (default: all)")
|
|
396
|
-
p.add_argument("--width", type=int, default=
|
|
396
|
+
p.add_argument("--width", type=int, default=20, help="bar width in characters (default 20)")
|
|
397
397
|
p.add_argument("--models")
|
|
398
398
|
p.add_argument("--results-dir")
|
|
399
399
|
a = p.parse_args(argv)
|
|
@@ -408,15 +408,20 @@ def cmd_pta(argv):
|
|
|
408
408
|
sys.exit("no finished results to compare" + (" for those models or packs" if labels or packs else ""))
|
|
409
409
|
out.print(pta.scope_note(result, models))
|
|
410
410
|
if not result["questions"]:
|
|
411
|
+
for line in pta.left_out_lines(result):
|
|
412
|
+
out.print(line, markup=False)
|
|
411
413
|
return
|
|
412
414
|
out.print()
|
|
413
|
-
for line in pta.
|
|
415
|
+
for line in pta.bars(result, a.width):
|
|
414
416
|
out.print(line)
|
|
415
417
|
header, rows = pta.table(result)
|
|
416
418
|
widths = [max(len(h), *(len(r[i]) for r in rows)) for i, h in enumerate(header)]
|
|
417
419
|
out.print()
|
|
418
420
|
for line in [header] + rows:
|
|
419
421
|
out.print(" ".join(c.ljust(w) for c, w in zip(line, widths)).rstrip(), markup=False)
|
|
422
|
+
for line in pta.left_out_lines(result):
|
|
423
|
+
out.print()
|
|
424
|
+
out.print(line, markup=False)
|
|
420
425
|
|
|
421
426
|
|
|
422
427
|
def cmd_report(argv):
|
tuieval/tui.py
CHANGED
|
@@ -10,10 +10,10 @@ Run screen: live reasoning and answer, per-test ✓/✗, TTFT and tokens/s, p
|
|
|
10
10
|
k skips the current model, c cancels everything, f pauses auto-scroll.
|
|
11
11
|
r shows results at any time (also mid-run); n starts a new run when it ends.
|
|
12
12
|
Enter on a Recent results row shows that answer in full.
|
|
13
|
-
Results: opens on
|
|
14
|
-
question
|
|
15
|
-
|
|
16
|
-
answer, question.
|
|
13
|
+
Results: opens on the PTA index (parsimony, speed and accuracy per model, as bars). Per
|
|
14
|
+
question compares each model's tokens and seconds on the same question. ctrl+r
|
|
15
|
+
reloads (it also reloads when a run's pack finishes). Enter on a Failures row or a
|
|
16
|
+
Per question cell shows the answer: grading and checks, reasoning, answer, question.
|
|
17
17
|
Answer detail: [ and ] step to the previous/next answer; esc/q close.
|
|
18
18
|
Anywhere: esc/q go back (q quits only on Setup), ctrl+q quits, w lists this session's runs and
|
|
19
19
|
tunes. Leaving a live run or tune keeps it going; the header shows its progress.
|
|
@@ -331,11 +331,11 @@ with the model's reasoning and answer as they stream, then recent results with t
|
|
|
331
331
|
v with several models at a time: stream the next one (k skips the one streaming)""",
|
|
332
332
|
"ResultsScreen": """[b]Results[/b]
|
|
333
333
|
|
|
334
|
-
Opens on [b]
|
|
335
|
-
|
|
334
|
+
Opens on the [b]PTA index[/b]: parsimony (tokens), speed and accuracy per model, a bar each (0-100,
|
|
335
|
+
longer = better). [b]Production readiness[/b] gives one verdict per model and use case, and what's
|
|
336
|
+
missing when it's INCONCLUSIVE. The other tabs are the evidence:
|
|
336
337
|
Scorecard accuracy, critical failures and truncation per model and pack
|
|
337
338
|
Speed & tokens time and tokens per answer (★ = nothing beats it on both accuracy and time)
|
|
338
|
-
PTA index privacy, total time and accuracy per model (0-100 each), as a triangle
|
|
339
339
|
Per question every question, model by model
|
|
340
340
|
Is the difference real? whether one model is really better than another, or it's noise
|
|
341
341
|
Tests that separate the questions that tell models apart
|
|
@@ -2341,7 +2341,18 @@ class ResultsScreen(Screen):
|
|
|
2341
2341
|
yield Static(id="results-info")
|
|
2342
2342
|
if self.smoke_dir:
|
|
2343
2343
|
yield Button("Show this Smoke run's results", id="toggle-smoke")
|
|
2344
|
-
with TabbedContent(initial="tab-
|
|
2344
|
+
with TabbedContent(initial="tab-pta"):
|
|
2345
|
+
with TabPane("PTA index", id="tab-pta"):
|
|
2346
|
+
with Horizontal(id="pta-controls"):
|
|
2347
|
+
yield Select([("All packs", "")], id="pta-pack", allow_blank=False, value="")
|
|
2348
|
+
yield Button("Models: all", id="pta-models")
|
|
2349
|
+
yield Static("[dim]P parsimony: tokens used (reasoning and answer). T speed: total time. A accuracy: "
|
|
2350
|
+
"answers right. Longer bars are better for all three. Verdicts and critical failures "
|
|
2351
|
+
"are in Production readiness.[/dim]")
|
|
2352
|
+
yield Static(id="pta-note")
|
|
2353
|
+
yield Static(id="pta-bars")
|
|
2354
|
+
yield DataTable(id="pta", zebra_stripes=True, cursor_type="none")
|
|
2355
|
+
yield Static(id="pta-left-out")
|
|
2345
2356
|
with TabPane("Production readiness"):
|
|
2346
2357
|
yield Static(id="readiness-short")
|
|
2347
2358
|
yield Static(self.READINESS_HELP, id="readiness-help")
|
|
@@ -2366,19 +2377,6 @@ class ResultsScreen(Screen):
|
|
|
2366
2377
|
"On another machine, times are measured there if the model ran there, otherwise "
|
|
2367
2378
|
"projected from each answer's token counts and that machine's tuned speeds.[/dim]")
|
|
2368
2379
|
yield DataTable(id="speed", zebra_stripes=True)
|
|
2369
|
-
with TabPane("PTA index", id="tab-pta"):
|
|
2370
|
-
with Horizontal(id="pta-controls"):
|
|
2371
|
-
yield Select([("All packs", "")], id="pta-pack", allow_blank=False, value="")
|
|
2372
|
-
yield Button("Models: all", id="pta-models")
|
|
2373
|
-
yield Static("[dim]P privacy: 100 when prompts stay on machines you control (local, or a server "
|
|
2374
|
-
"marked private = true), 0 for a hosted API. T time: total time for every question "
|
|
2375
|
-
"compared, relative to the fastest model (100). A accuracy: answers right. Bigger "
|
|
2376
|
-
"triangle = better all round; verdicts and critical failures are in Production "
|
|
2377
|
-
"readiness.[/dim]")
|
|
2378
|
-
yield Static(id="pta-note")
|
|
2379
|
-
with Horizontal(id="pta-body"):
|
|
2380
|
-
yield Static(id="pta-triangle")
|
|
2381
|
-
yield DataTable(id="pta", zebra_stripes=True, cursor_type="none")
|
|
2382
2380
|
with TabPane("Per question", id="tab-per-question"):
|
|
2383
2381
|
with Horizontal(id="pq-controls"):
|
|
2384
2382
|
yield Select([("All packs", "")], id="pq-pack", allow_blank=False, value="")
|
|
@@ -2586,21 +2584,22 @@ class ResultsScreen(Screen):
|
|
|
2586
2584
|
present = {r["model"] for r in rows}
|
|
2587
2585
|
chosen = {m for m in self.app.pq_models if m in present}
|
|
2588
2586
|
self.query_one("#pta-models", Button).label = f"Models: {len(chosen)} picked" if chosen else "Models: all"
|
|
2589
|
-
models = sorted(chosen or present)
|
|
2590
2587
|
t = self.query_one("#pta", DataTable)
|
|
2591
2588
|
t.clear(columns=True)
|
|
2592
|
-
if not
|
|
2589
|
+
if not present:
|
|
2593
2590
|
self.query_one("#pta-note", Static).update("No finished results to compare yet.")
|
|
2594
|
-
self.query_one("#pta-
|
|
2591
|
+
self.query_one("#pta-bars", Static).update("")
|
|
2592
|
+
self.query_one("#pta-left-out", Static).update("")
|
|
2595
2593
|
return
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
self.query_one("#pta-
|
|
2600
|
-
self.query_one("#pta-
|
|
2601
|
-
"\n".join(
|
|
2594
|
+
# none picked: every model with enough answers (pta.index leaves out the rest, and says so)
|
|
2595
|
+
result = pta.index(rows, sorted(chosen) or None)
|
|
2596
|
+
self.query_one("#pta-note", Static).update(pta.scope_note(result, sorted(present)))
|
|
2597
|
+
self.query_one("#pta-bars", Static).update("\n".join(pta.bars(result)) if result["questions"] else "")
|
|
2598
|
+
self.query_one("#pta-left-out", Static).update(
|
|
2599
|
+
"\n".join(f"[dim]{rich_escape(line)}[/dim]" for line in pta.left_out_lines(result)))
|
|
2602
2600
|
header, table = pta.table(result)
|
|
2603
|
-
|
|
2601
|
+
for i, h in enumerate(header): # sized to the contents: added before the rows, a column keeps its header's width
|
|
2602
|
+
t.add_column(h, width=max(len(h), *(len(r[i]) for r in table)) if table else None)
|
|
2604
2603
|
t.add_rows(table)
|
|
2605
2604
|
|
|
2606
2605
|
def fill_per_question(self):
|
|
@@ -2908,9 +2907,9 @@ class EvalsApp(App):
|
|
|
2908
2907
|
#pq-controls { height: 3; }
|
|
2909
2908
|
#pta-controls { height: 3; }
|
|
2910
2909
|
#pta-controls Select { width: 28; margin-right: 1; }
|
|
2911
|
-
#pta-
|
|
2912
|
-
#pta-triangle { width: auto; padding: 1 2 0 0; }
|
|
2910
|
+
#pta-bars { height: auto; padding: 1 0 0 0; }
|
|
2913
2911
|
#pta { width: 1fr; height: auto; margin-top: 1; }
|
|
2912
|
+
#pta-left-out { height: auto; padding: 1 0 0 0; }
|
|
2914
2913
|
#pq-controls Checkbox { width: auto; }
|
|
2915
2914
|
#pq-controls Select { width: 28; margin-right: 1; }
|
|
2916
2915
|
#pq-models { margin-right: 1; min-width: 20; }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: tuieval
|
|
3
|
-
Version: 0.2.0.
|
|
3
|
+
Version: 0.2.0.dev50
|
|
4
4
|
Summary: Evaluate local and frontier LLMs on your own questions: accuracy, speed, tokens and PASS/FAIL verdicts, in the terminal.
|
|
5
5
|
Project-URL: Homepage, https://github.com/ashe-wb/tuieval
|
|
6
6
|
Project-URL: Issues, https://github.com/ashe-wb/tuieval/issues
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
tuieval/__init__.py,sha256=myVXVX7htbwezW6k3x_FuKgn1RSZ2WcTaDEMByGn6Wg,312
|
|
2
2
|
tuieval/__main__.py,sha256=E6Gls0DNz8GQK2K-kOUIx8cYhgANW_CH54VKrfCfs14,52
|
|
3
|
-
tuieval/_version.py,sha256=
|
|
3
|
+
tuieval/_version.py,sha256=cUlv5rRBNcBZ7a8L_s4uRBMTmFx7dza4nVKsHqXS0Pg,535
|
|
4
4
|
tuieval/builtin.toml,sha256=Kxw22RZCJhURUyu5Wz8tj5Y1nM85A8hFVRbA4ocoPUg,4293
|
|
5
|
-
tuieval/cli.py,sha256=
|
|
5
|
+
tuieval/cli.py,sha256=gzGBzhqvR0WKJQQNHB8CudpgViIeIyawrNWa54whmoI,4502
|
|
6
6
|
tuieval/client.py,sha256=kpsyLEZKfxCsvIGBHBbBy83TpI97CvnGCDq-4AbJS4Y,9986
|
|
7
7
|
tuieval/compare.py,sha256=SHN_o_nlppFcHMBqBZRITIkeQDPaR_JxhUZItQLMBwo,26270
|
|
8
8
|
tuieval/doctor.py,sha256=y1C_ggjd8oikXTrovgTBf26wjThP8EoVkfTVeO_n5dQ,6070
|
|
@@ -12,12 +12,12 @@ tuieval/machines.py,sha256=ImEihNj8QlBRdCHLED4QIdjJUvjVtZgo6DiVU5h6Zzs,13415
|
|
|
12
12
|
tuieval/onboard.py,sha256=IYETVDWCCo9vF0Dtj4_rr9VanYeCky8PwP3-2g5A_l0,6215
|
|
13
13
|
tuieval/packs.py,sha256=tiLmxsrX_M5EUMuR4Yvb7pLBLEI15wamHSjflD6wjoY,11299
|
|
14
14
|
tuieval/profiles.py,sha256=soeLxjdB-l-OxSY8jZ4yjwfdSnsBV-QICcwKxRJS7nQ,3663
|
|
15
|
-
tuieval/pta.py,sha256=
|
|
15
|
+
tuieval/pta.py,sha256=KkrOxE1hTDwu1435IrzMzIysrgVUvFuKVo786VlRyK4,9056
|
|
16
16
|
tuieval/remove.py,sha256=Vwh43nm9lVb9U9aN-h6CMYbkTwdR3UWfZObwweF72n0,5157
|
|
17
|
-
tuieval/run_evals.py,sha256=
|
|
17
|
+
tuieval/run_evals.py,sha256=5bQEqU533XYiLze9dYcl72c5GSIpohMj1eqJrePRwnc,46450
|
|
18
18
|
tuieval/scaffold.py,sha256=YBOqniJpf_GtKKAFF3_OHxxMGbmTWdFjcClGcOnrrKE,12130
|
|
19
19
|
tuieval/selftest.py,sha256=nExkrOidgymlmvkxImEBfrQG5iTUN5WuRMIKtqusCCs,9835
|
|
20
|
-
tuieval/tui.py,sha256=
|
|
20
|
+
tuieval/tui.py,sha256=21Re8fM5rf3zbHIKvK9laMV-mL2HjcGfMReoRg0DRLw,164268
|
|
21
21
|
tuieval/tune.py,sha256=jXwYuSjfdqbLCE3WonP2xaUHwk_FnhI67twB1BaHggI,38992
|
|
22
22
|
tuieval/verdict.py,sha256=Muo1a05mCv781MlEJsXwDsGaKbRi0JS4Lv8HdvK_Aco,19054
|
|
23
23
|
tuieval/watch_proxy.py,sha256=z916NRhEur04a9RnLm6ZpIEY1SnnUGPiHYbmlD9ktQ0,11035
|
|
@@ -46,8 +46,8 @@ tuieval/templates/packs/tool_call/pack.toml,sha256=n4bx0lGJHSmW41uVqhfIXJ2BWZpmT
|
|
|
46
46
|
tuieval/templates/packs/tool_call/system.txt,sha256=mKxu-lB-0YjLHXdgeFJa8x2C180OvcNz5cHv2N5Bg3U,254
|
|
47
47
|
tuieval/templates/packs/tool_call/tests.yaml,sha256=Nv7c4syrzJ9cU8EBKSK_1ZSFx9V02aCjW4-2TBCPT7s,1859
|
|
48
48
|
tuieval/templates/packs/tool_call/tools.yaml,sha256=HgxCkh0On2VwbHSsjAGM8tNCK7ZtKLGrs7lMCn3Fprs,1048
|
|
49
|
-
tuieval-0.2.0.
|
|
50
|
-
tuieval-0.2.0.
|
|
51
|
-
tuieval-0.2.0.
|
|
52
|
-
tuieval-0.2.0.
|
|
53
|
-
tuieval-0.2.0.
|
|
49
|
+
tuieval-0.2.0.dev50.dist-info/METADATA,sha256=VW1tuB9QtgVUt9irfVVzrDhkF907wql1_WpM7PasfPU,13881
|
|
50
|
+
tuieval-0.2.0.dev50.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
51
|
+
tuieval-0.2.0.dev50.dist-info/entry_points.txt,sha256=7eIhi1GpFxBP2OLJV02Nn8LwsNuO512eKOGt1IBbj04,45
|
|
52
|
+
tuieval-0.2.0.dev50.dist-info/licenses/LICENSE,sha256=7wfRgGtBGH1aXhZkIn47oUznqKC18kEPMvUVgol7Ffc,1077
|
|
53
|
+
tuieval-0.2.0.dev50.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|