diff --git a/docs/generate_benchmark_svg.py b/docs/generate_benchmark_svg.py
index 354fa78..3c0725d 100644
--- a/docs/generate_benchmark_svg.py
+++ b/docs/generate_benchmark_svg.py
@@ -22,73 +22,97 @@
# Values normalized to 0-100 scale (0-1 metrics × 100).
ADAPTERS = {
"qr": {
- "label": "Query Rewrite", "lib": "raglib", "type": "alora",
+ "label": "Query Rewrite",
+ "lib": "raglib",
+ "type": "alora",
"snippet": "rag.rewrite_question(query, ctx, backend)",
"base": {"3b": 61, "8b": 67, "30b": 64},
"improved": {"3b": 86, "8b": 84, "30b": 87},
},
"qc": {
- "label": "Query Clarification", "lib": "raglib", "type": "alora",
+ "label": "Query Clarification",
+ "lib": "raglib",
+ "type": "alora",
"snippet": "rag.clarify_query(query, docs, ctx, backend)",
"base": {"3b": 65, "8b": 48, "30b": 76},
"improved": {"3b": 95, "8b": 96, "30b": 95},
},
"an": {
- "label": "Answerability", "lib": "raglib", "type": "alora",
+ "label": "Answerability",
+ "lib": "raglib",
+ "type": "alora",
"snippet": "rag.check_answerability(query, docs, ctx, backend)",
"base": {"3b": 59, "8b": 66, "30b": 65},
"improved": {"3b": 91, "8b": 91, "30b": 92},
},
"hd": {
- "label": "Hallucination Det.", "lib": "raglib", "type": "lora",
+ "label": "Hallucination Det.",
+ "lib": "raglib",
+ "type": "lora",
"snippet": "rag.flag_hallucinated_content(response, docs, ctx, backend)",
"base": {"3b": 42, "8b": 45, "30b": 54},
"improved": {"3b": 71, "8b": 74, "30b": 83},
},
"ci": {
- "label": "Citations", "lib": "raglib", "type": "lora",
+ "label": "Citations",
+ "lib": "raglib",
+ "type": "lora",
"snippet": "rag.find_citations(answer, docs, ctx, backend)",
"base": {"3b": 10, "8b": 18, "30b": 55},
"improved": {"3b": 64, "8b": 66, "30b": 71},
},
"ca": {
- "label": "Context Attr.", "lib": "corelib", "type": "lora",
+ "label": "Context Attr.",
+ "lib": "corelib",
+ "type": "lora",
"snippet": "core.find_context_attributions(answer, docs, ctx, backend)",
"base": {"3b": 34, "8b": 27, "30b": 65},
"improved": {"3b": 92, "8b": 96, "30b": 90},
},
"rc": {
- "label": "Req. Check", "lib": "corelib", "type": "alora",
+ "label": "Req. Check",
+ "lib": "corelib",
+ "type": "alora",
"snippet": "core.requirement_check(ctx, backend, requirements)",
"base": {"3b": 51, "8b": 54, "30b": 57},
"improved": {"3b": 77, "8b": 77, "30b": 78},
},
"un": {
- "label": "Uncertainty", "lib": "corelib", "type": "alora",
+ "label": "Uncertainty",
+ "lib": "corelib",
+ "type": "alora",
"snippet": "core.check_certainty(ctx, backend)",
"base": {"3b": 63, "8b": 64, "30b": 65},
"improved": {"3b": 77, "8b": 78, "30b": 80},
},
"gc": {
- "label": "Guardian Core", "lib": "guardianlib", "type": "alora",
+ "label": "Guardian Core",
+ "lib": "guardianlib",
+ "type": "alora",
"snippet": 'guardian.check(ctx, backend, "harm")',
"base": {"3b": 1, "8b": 67, "30b": 69},
"improved": {"3b": 78, "8b": 80, "30b": 81},
},
"fd": {
- "label": "Factuality Det.", "lib": "guardianlib", "type": "alora",
+ "label": "Factuality Det.",
+ "lib": "guardianlib",
+ "type": "alora",
"snippet": "guardian.factuality_detection(ctx, backend)",
"base": {"3b": 8, "8b": 25, "30b": 51},
"improved": {"3b": 81, "8b": 83, "30b": 83},
},
"fc": {
- "label": "Factuality Corr.", "lib": "guardianlib", "type": "alora",
+ "label": "Factuality Corr.",
+ "lib": "guardianlib",
+ "type": "alora",
"snippet": "guardian.factuality_correction(ctx, backend)",
"base": {"3b": 0, "8b": 19, "30b": 13},
"improved": {"3b": 19, "8b": 23, "30b": 26},
},
"pg": {
- "label": "Policy Guardrails", "lib": "guardianlib", "type": "alora",
+ "label": "Policy Guardrails",
+ "lib": "guardianlib",
+ "type": "alora",
"snippet": "guardian.policy_guardrails(ctx, backend, policy)",
"base": {"3b": 82, "8b": 80, "30b": 88},
"improved": {"3b": 95, "8b": 95, "30b": 96},
@@ -96,12 +120,33 @@
}
LIBS = {
- "corelib": {"fill": "#8A3FFC", "text": "white", "sub": "#d4bbff",
- "pill_bg": "#EDE7FF", "pill_text": "#8A3FFC", "bar": "#8A3FFC", "pct": "#8A3FFC"},
- "raglib": {"fill": "#009D9A", "text": "white", "sub": "#9ef0f0",
- "pill_bg": "#E0F7F6", "pill_text": "#009D9A", "bar": "#009D9A", "pct": "#009D9A"},
- "guardianlib": {"fill": "#F1C21B", "text": "#161616", "sub": "#7a5f00",
- "pill_bg": "#FEF3C7", "pill_text": "#B45309", "bar": "#F1C21B", "pct": "#B45309"},
+ "corelib": {
+ "fill": "#8A3FFC",
+ "text": "white",
+ "sub": "#d4bbff",
+ "pill_bg": "#EDE7FF",
+ "pill_text": "#8A3FFC",
+ "bar": "#8A3FFC",
+ "pct": "#8A3FFC",
+ },
+ "raglib": {
+ "fill": "#009D9A",
+ "text": "white",
+ "sub": "#9ef0f0",
+ "pill_bg": "#E0F7F6",
+ "pill_text": "#009D9A",
+ "bar": "#009D9A",
+ "pct": "#009D9A",
+ },
+ "guardianlib": {
+ "fill": "#F1C21B",
+ "text": "#161616",
+ "sub": "#7a5f00",
+ "pill_bg": "#FEF3C7",
+ "pill_text": "#B45309",
+ "bar": "#F1C21B",
+ "pct": "#B45309",
+ },
}
# 9 slots: Latin square rotation — 3 adapter groups × 3 models.
@@ -117,16 +162,16 @@
# Rotation: 3b→A 8b→B 30b→C | 3b→B 8b→C 30b→A | 3b→C 8b→A 30b→B
SLOTS = [
# ── Cycle 1 ──
- {"model": "3b", "adapters": ["qr", "an", "ca", "gc"]},
- {"model": "8b", "adapters": ["qc", "hd", "rc", "fd"]},
+ {"model": "3b", "adapters": ["qr", "an", "ca", "gc"]},
+ {"model": "8b", "adapters": ["qc", "hd", "rc", "fd"]},
{"model": "30b", "adapters": ["ci", "un", "fc", "pg"]},
# ── Cycle 2 ──
- {"model": "3b", "adapters": ["qc", "hd", "rc", "fd"]},
- {"model": "8b", "adapters": ["ci", "un", "fc", "pg"]},
+ {"model": "3b", "adapters": ["qc", "hd", "rc", "fd"]},
+ {"model": "8b", "adapters": ["ci", "un", "fc", "pg"]},
{"model": "30b", "adapters": ["qr", "an", "ca", "gc"]},
# ── Cycle 3 ──
- {"model": "3b", "adapters": ["ci", "un", "fc", "pg"]},
- {"model": "8b", "adapters": ["qr", "an", "ca", "gc"]},
+ {"model": "3b", "adapters": ["ci", "un", "fc", "pg"]},
+ {"model": "8b", "adapters": ["qr", "an", "ca", "gc"]},
{"model": "30b", "adapters": ["qc", "hd", "rc", "fd"]},
]
@@ -134,7 +179,9 @@
_seen = set()
for _s in SLOTS:
_seen.update(_s["adapters"])
-assert len(_seen) == 12, f"Only {len(_seen)} adapters covered: missing {set(ADAPTERS.keys()) - _seen}"
+assert len(_seen) == 12, (
+ f"Only {len(_seen)} adapters covered: missing {set(ADAPTERS.keys()) - _seen}"
+)
# ── LAYOUT CONSTANTS ──────────────────────────────────────────────────────────
@@ -152,12 +199,12 @@
PCT_X = 750
# Row positions (bottom to top: row 0 = bottom)
-ROW_Y = [274, 200, 126, 52] # baseline bar y
-IMP_ROW_Y = [294, 220, 146, 72] # improved bar y (baseline + 20)
-BASE_TEXT_Y = [286, 212, 138, 64] # baseline pct text y (ROW_Y + 12)
-IMP_TEXT_Y = [306, 232, 158, 84] # improved pct text y (IMP_ROW_Y + 12)
+ROW_Y = [274, 200, 126, 52] # baseline bar y
+IMP_ROW_Y = [294, 220, 146, 72] # improved bar y (baseline + 20)
+BASE_TEXT_Y = [286, 212, 138, 64] # baseline pct text y (ROW_Y + 12)
+IMP_TEXT_Y = [306, 232, 158, 84] # improved pct text y (IMP_ROW_Y + 12)
-ADAPTER_Y = [196, 144, 92, 40] # adapter box y
+ADAPTER_Y = [196, 144, 92, 40] # adapter box y
ADAPTER_TEXT1_Y = [216, 164, 112, 60]
ADAPTER_TEXT2_Y = [234, 182, 130, 78]
@@ -169,14 +216,20 @@
GROW_SECONDS = 1.0 # duration of bar grow animation
# Code panel (below main content)
-CODE_PANEL_Y = 390 # top of code block background rect
-CODE_PANEL_H = 92 # height of code block rect
-CODE_HEADER_Y = 404 # y for "MELLEA INVOCATION" label
-CODE_LINE_Y = [421, 438, 455, 472] # y per adapter row (row 0 first = top); 17px spacing
+CODE_PANEL_Y = 390 # top of code block background rect
+CODE_PANEL_H = 92 # height of code block rect
+CODE_HEADER_Y = 404 # y for "MELLEA INVOCATION" label
+CODE_LINE_Y = [
+ 421,
+ 438,
+ 455,
+ 472,
+] # y per adapter row (row 0 first = top); 17px spacing
# ── HELPERS ───────────────────────────────────────────────────────────────────
+
def bar_width(pct_val):
"""Convert percentage (0-100) to bar pixel width (430px track)."""
return round(pct_val / 100 * BAR_TRACK_W)
@@ -187,7 +240,7 @@ def smil_visibility(active_slot, stagger_s=0):
n = len(SLOTS)
if stagger_s == 0:
values = ";".join("visible" if i == active_slot else "hidden" for i in range(n))
- key_times = ";".join(f"{i/n:.6f}" for i in range(n))
+ key_times = ";".join(f"{i / n:.6f}" for i in range(n))
else:
points = []
for i in range(n):
@@ -202,20 +255,24 @@ def smil_visibility(active_slot, stagger_s=0):
key_times = ";".join(f"{t:.6f}" for t, _ in points)
key_times = key_times.replace("0.000000", "0")
- return (f'')
+ return (
+ f''
+ )
def smil_animate_fill(values):
"""Return an element for fill color with discrete calcMode."""
n = len(values)
vals = ";".join(values)
- key_times = ";".join(f"{i/n:.6f}" for i in range(n))
+ key_times = ";".join(f"{i / n:.6f}" for i in range(n))
key_times = key_times.replace("0.000000", "0")
- return (f'')
+ return (
+ f''
+ )
def smil_animate_width_grow(values, delay_s=0):
@@ -244,53 +301,73 @@ def smil_animate_width_grow(values, delay_s=0):
vals = ";".join(str(v) for _, v in points)
key_times = ";".join(f"{t:.6f}" for t, _ in points)
key_times = key_times.replace("0.000000", "0").replace("1.000000", "1")
- return (f'')
+ return (
+ f''
+ )
# ── SCHEDULE COMMENT ──────────────────────────────────────────────────────────
+
def generate_schedule_comment():
"""Generate the schedule comment block."""
lines = []
lines.append("")
return "\n".join(lines)
# ── LEFT PANEL ────────────────────────────────────────────────────────────────
+
def generate_left_panel():
"""Generate left panel: base model box + adapter boxes with SMIL animations."""
lines = []
lines.append("")
lines.append("")
- lines.append('CUSTOM GRANITE SWITCH MODEL')
+ lines.append(
+ 'CUSTOM GRANITE SWITCH MODEL'
+ )
lines.append("")
# ── Base model box (static rect, text toggled per slot) ──
lines.append("")
- lines.append('')
+ lines.append(
+ ''
+ )
for si, slot in enumerate(SLOTS):
model = slot["model"]
minfo = MODELS[model]
- lines.append(f'')
- lines.append(f' {smil_visibility(si)}')
- lines.append(f' {minfo["label"]}')
- lines.append(f' base model')
- lines.append(f' {minfo["params"]}')
- lines.append(f' ibm-granite \u00b7 HuggingFace')
- lines.append(f'')
+ lines.append('')
+ lines.append(f" {smil_visibility(si)}")
+ lines.append(
+ f' {minfo["label"]}'
+ )
+ lines.append(
+ ' base model'
+ )
+ lines.append(
+ f' {minfo["params"]}'
+ )
+ lines.append(
+ ' ibm-granite \u00b7 HuggingFace'
+ )
+ lines.append("")
lines.append("")
# ── Adapter boxes (4 rows, staggered appearance) ──
@@ -303,8 +380,10 @@ def generate_left_panel():
adapter_ids = [slot["adapters"][row_idx] for slot in SLOTS]
fills = [LIBS[ADAPTERS[aid]["lib"]]["fill"] for aid in adapter_ids]
- lines.append(f"")
- lines.append(f'')
+ lines.append(
+ f""
+ )
+ lines.append('')
# Visibility with stagger
vis_points = []
for i in range(len(SLOTS)):
@@ -314,21 +393,29 @@ def generate_left_panel():
vis_points.append((appear_at, "visible"))
vis_values = ";".join(v for _, v in vis_points)
vis_kt = ";".join(f"{t:.6f}" for t, _ in vis_points).replace("0.000000", "0")
- lines.append(f' ')
- lines.append(f' ')
- lines.append(f' {smil_animate_fill(fills)}')
- lines.append(f' ')
+ lines.append(
+ f' '
+ )
+ lines.append(
+ f' '
+ )
+ lines.append(f" {smil_animate_fill(fills)}")
+ lines.append(" ")
# Text variants
for si, aid in enumerate(adapter_ids):
info = ADAPTERS[aid]
lib = LIBS[info["lib"]]
- lines.append(f' ')
- lines.append(f' {smil_visibility(si, stagger)}')
- lines.append(f' {info["label"]}')
- lines.append(f' {info["lib"]}')
- lines.append(f' ')
- lines.append(f'')
+ lines.append(' ')
+ lines.append(f" {smil_visibility(si, stagger)}")
+ lines.append(
+ f' {info["label"]}'
+ )
+ lines.append(
+ f' {info["lib"]}'
+ )
+ lines.append(" ")
+ lines.append("")
lines.append("")
return "\n".join(lines)
@@ -336,11 +423,14 @@ def generate_left_panel():
# ── RIGHT PANEL ───────────────────────────────────────────────────────────────
+
def generate_right_panel():
"""Generate right panel: headers, bars, labels, percentages with SMIL."""
lines = []
lines.append("")
- lines.append('')
+ lines.append(
+ ''
+ )
lines.append("")
lines.append("")
@@ -348,10 +438,12 @@ def generate_right_panel():
for si, slot in enumerate(SLOTS):
model = slot["model"]
minfo = MODELS[model]
- lines.append(f'')
- lines.append(f' {smil_visibility(si)}')
- lines.append(f' PERFORMANCE \u00b7 {minfo["label"].upper()}')
- lines.append(f'')
+ lines.append('')
+ lines.append(f" {smil_visibility(si)}")
+ lines.append(
+ f' PERFORMANCE \u00b7 {minfo["label"].upper()}'
+ )
+ lines.append("")
lines.append("")
# ── Bars and labels for each row ──
@@ -364,36 +456,54 @@ def generate_right_panel():
adapter_ids = [slot["adapters"][row_idx] for slot in SLOTS]
model_ids = [slot["model"] for slot in SLOTS]
- base_widths = [bar_width(ADAPTERS[adapter_ids[si]]["base"][model_ids[si]]) for si in range(len(SLOTS))]
- imp_widths = [bar_width(ADAPTERS[adapter_ids[si]]["improved"][model_ids[si]]) for si in range(len(SLOTS))]
- imp_fills = [LIBS[ADAPTERS[adapter_ids[si]]["lib"]]["bar"] for si in range(len(SLOTS))]
+ base_widths = [
+ bar_width(ADAPTERS[adapter_ids[si]]["base"][model_ids[si]])
+ for si in range(len(SLOTS))
+ ]
+ imp_widths = [
+ bar_width(ADAPTERS[adapter_ids[si]]["improved"][model_ids[si]])
+ for si in range(len(SLOTS))
+ ]
+ imp_fills = [
+ LIBS[ADAPTERS[adapter_ids[si]]["lib"]]["bar"] for si in range(len(SLOTS))
+ ]
lines.append(f"")
# Track backgrounds (static)
- lines.append(f'')
- lines.append(f'')
+ lines.append(
+ f''
+ )
+ lines.append(
+ f''
+ )
# Baseline bar — grows from 0
- lines.append(f'')
- lines.append(f' {smil_animate_width_grow(base_widths, delay_s=0.5)}')
- lines.append(f'')
+ lines.append(
+ f''
+ )
+ lines.append(f" {smil_animate_width_grow(base_widths, delay_s=0.5)}")
+ lines.append("")
# Improved bar — grows when adapter tile appears
- lines.append(f'')
- lines.append(f' {smil_animate_width_grow(imp_widths, delay_s=stagger)}')
- lines.append(f' {smil_animate_fill(imp_fills)}')
- lines.append(f'')
+ lines.append(
+ f''
+ )
+ lines.append(f" {smil_animate_width_grow(imp_widths, delay_s=stagger)}")
+ lines.append(f" {smil_animate_fill(imp_fills)}")
+ lines.append("")
# Baseline percentage — appears immediately
for si in range(len(SLOTS)):
aid = adapter_ids[si]
model = model_ids[si]
base_val = ADAPTERS[aid]["base"][model]
- lines.append(f'')
- lines.append(f' {smil_visibility(si)}')
- lines.append(f' {base_val}%')
- lines.append(f'')
+ lines.append('')
+ lines.append(f" {smil_visibility(si)}")
+ lines.append(
+ f' {base_val}%'
+ )
+ lines.append("")
# Improved percentage — appears when bar finishes growing
for si in range(len(SLOTS)):
@@ -402,10 +512,12 @@ def generate_right_panel():
info = ADAPTERS[aid]
lib = LIBS[info["lib"]]
imp_val = info["improved"][model]
- lines.append(f'')
- lines.append(f' {smil_visibility(si, stagger + GROW_SECONDS)}')
- lines.append(f' {imp_val}%')
- lines.append(f'')
+ lines.append('')
+ lines.append(f" {smil_visibility(si, stagger + GROW_SECONDS)}")
+ lines.append(
+ f' {imp_val}%'
+ )
+ lines.append("")
# Row labels + badges
for si in range(len(SLOTS)):
@@ -417,41 +529,59 @@ def generate_right_panel():
type_x = BAR_X + len(info["label"]) * 7 + 10
type_w = 34 if info["type"] == "alora" else 28
pill_x = type_x + type_w + 6
- pill_w = 64 if info["lib"] == "guardianlib" else (46 if info["lib"] == "corelib" else 40)
-
- lines.append(f'')
- lines.append(f' {smil_visibility(si)}')
- lines.append(f' {info["label"]}')
- lines.append(f' ')
- lines.append(f' {type_label}')
- lines.append(f' ')
- lines.append(f' {info["lib"]}')
- lines.append(f'')
+ pill_w = (
+ 64
+ if info["lib"] == "guardianlib"
+ else (46 if info["lib"] == "corelib" else 40)
+ )
+
+ lines.append('')
+ lines.append(f" {smil_visibility(si)}")
+ lines.append(
+ f' {info["label"]}'
+ )
+ lines.append(
+ f' '
+ )
+ lines.append(
+ f' {type_label}'
+ )
+ lines.append(
+ f' '
+ )
+ lines.append(
+ f' {info["lib"]}'
+ )
+ lines.append("")
lines.append("")
# Legend at bottom (static)
- lines.append('prompted baseline \u2192 with aLoRA/LoRA adapter')
+ lines.append(
+ 'prompted baseline \u2192 with aLoRA/LoRA adapter'
+ )
return "\n".join(lines)
# ── CODE PANEL ────────────────────────────────────────────────────────────────
_CODE_FONT_SIZE = 12
-_CODE_FONT = "'JetBrains Mono','Fira Code','SF Mono',Consolas,Menlo,'Courier New',monospace"
+_CODE_FONT = (
+ "'JetBrains Mono','Fira Code','SF Mono',Consolas,Menlo,'Courier New',monospace"
+)
# Syntax-highlight palette (light background)
-_C_MODULE = "#6f6f6f" # module prefix: rag., core., guardian.
-_C_PAREN = "#8d8d8d" # parentheses and commas
-_C_ARG = "#393939" # positional argument names
-_C_STRING = "#198038" # string literals e.g. "harm"
+_C_MODULE = "#6f6f6f" # module prefix: rag., core., guardian.
+_C_PAREN = "#8d8d8d" # parentheses and commas
+_C_ARG = "#393939" # positional argument names
+_C_STRING = "#198038" # string literals e.g. "harm"
def _tokenize(snippet):
"""Split snippet into (text, role) tokens where role drives color selection."""
paren = snippet.index("(")
call_site = snippet[:paren]
- args_raw = snippet[paren + 1:-1]
+ args_raw = snippet[paren + 1 : -1]
tokens = []
if "." in call_site:
@@ -477,12 +607,22 @@ def _render_snippet(snippet, base_x, y, func_color):
tspan elements have no explicit x — the browser handles glyph advance widths
correctly for whichever monospace font it resolves.
"""
- color_map = {"module": _C_MODULE, "func": func_color,
- "paren": _C_PAREN, "arg": _C_ARG, "str": _C_STRING}
- spans = [f'{text}'
- for text, role in _tokenize(snippet)]
- return (f''
- + "".join(spans) + "")
+ color_map = {
+ "module": _C_MODULE,
+ "func": func_color,
+ "paren": _C_PAREN,
+ "arg": _C_ARG,
+ "str": _C_STRING,
+ }
+ spans = [
+ f'{text}'
+ for text, role in _tokenize(snippet)
+ ]
+ return (
+ f''
+ + "".join(spans)
+ + ""
+ )
def generate_code_panel():
@@ -494,9 +634,15 @@ def generate_code_panel():
lines = []
lines.append("")
lines.append("")
- lines.append(f'')
- lines.append(f'')
- lines.append(f'MELLEA INVOCATION')
+ lines.append(
+ f''
+ )
+ lines.append(
+ f''
+ )
+ lines.append(
+ f'MELLEA INVOCATION'
+ )
for row_idx in range(4):
stagger = ADAPTER_STAGGER[row_idx]
@@ -506,10 +652,10 @@ def generate_code_panel():
for si, aid in enumerate(adapter_ids):
info = ADAPTERS[aid]
lib = LIBS[info["lib"]]
- lines.append(f'')
- lines.append(f' {smil_visibility(si, stagger)}')
- lines.append(f' {_render_snippet(info["snippet"], 52, cy, lib["pct"])}')
- lines.append(f'')
+ lines.append('')
+ lines.append(f" {smil_visibility(si, stagger)}")
+ lines.append(f" {_render_snippet(info['snippet'], 52, cy, lib['pct'])}")
+ lines.append("")
lines.append("")
return "\n".join(lines)
@@ -517,19 +663,26 @@ def generate_code_panel():
# ── MAIN SVG GENERATION ───────────────────────────────────────────────────────
+
def generate_svg():
"""Generate the complete SVG with SMIL animations."""
parts = []
- parts.append(f'