Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
208 changes: 203 additions & 5 deletions site/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,192 @@ function jsonBlock(value, emptyMessage) {
return pre;
}

function safeMarkdownLink(rawHref) {
try {
const url = new URL(rawHref, window.location.href);
return ["http:", "https:", "mailto:"].includes(url.protocol) ? url.href : null;
} catch {
return null;
}
}

function appendInlineMarkdown(parent, text) {
const tokenPattern = /(?:\\\*|`[^`\n]+`|\*\*[^*\n]+?\*\*|__[^_\n]+?__|(?<![\\*])\*(?![\s*])(?:\\.|[^*\\\n])*(?<![\s\\])\*(?!\*)|\[[^\]\n]+\]\([^\s)]+\))/g;
let cursor = 0;

for (const match of text.matchAll(tokenPattern)) {
const token = match[0];
const offset = match.index;
parent.append(text.slice(cursor, offset));
if (token === "\\*") {
parent.append("*");
} else if (token.startsWith("`")) {
parent.append(element("code", "", token.slice(1, -1)));
} else if (token.startsWith("**") || token.startsWith("__")) {
parent.append(element("strong", "", token.slice(2, -2)));
} else if (token.startsWith("*")) {
parent.append(element("em", "", token.slice(1, -1)));
} else {
const separator = token.lastIndexOf("](");
const label = token.slice(1, separator);
const href = safeMarkdownLink(token.slice(separator + 2, -1));
if (href) {
const link = element("a", "", label);
link.href = href;
link.rel = "noopener noreferrer";
parent.append(link);
} else {
parent.append(token);
}
}
cursor = offset + token.length;
}
parent.append(text.slice(cursor));
}

function markdownTableCells(line) {
const trimmed = line.trim().replace(/^\|/, "").replace(/\|$/, "");
return trimmed.split("|").map((cell) => cell.trim());
}

function isMarkdownTableDivider(line) {
return markdownTableCells(line).every((cell) => /^:?-{3,}:?$/.test(cell));
}

function isMarkdownBlockStart(lines, index) {
const line = lines[index];
return (
/^\s*```/.test(line)
|| /^#{1,6}\s+/.test(line)
|| /^\s*(?:[-+*]|\d+[.)])\s+/.test(line)
|| /^>\s?/.test(line)
|| /^\s*(?:-{3,}|\*{3,}|_{3,})\s*$/.test(line)
|| (line.includes("|") && index + 1 < lines.length && isMarkdownTableDivider(lines[index + 1]))
);
}

function appendMarkdownLines(parent, lines) {
for (let index = 0; index < lines.length;) {
const line = lines[index];
if (!line.trim()) {
index += 1;
continue;
}

const fence = line.match(/^\s*```([^\s`]*)\s*$/);
if (fence) {
const codeLines = [];
index += 1;
while (index < lines.length && !/^\s*```\s*$/.test(lines[index])) {
codeLines.push(lines[index]);
index += 1;
}
if (index < lines.length) index += 1;
const code = element("code", fence[1] ? `language-${fence[1]}` : "", codeLines.join("\n"));
const pre = element("pre", "markdown-code-block");
pre.append(code);
parent.append(pre);
continue;
}

const heading = line.match(/^(#{1,6})\s+(.+)$/);
if (heading) {
const headingNode = element("h5", `markdown-heading markdown-heading-${heading[1].length}`);
appendInlineMarkdown(headingNode, heading[2]);
parent.append(headingNode);
index += 1;
continue;
}

if (/^\s*(?:-{3,}|\*{3,}|_{3,})\s*$/.test(line)) {
parent.append(element("hr"));
index += 1;
continue;
}

if (line.includes("|") && index + 1 < lines.length && isMarkdownTableDivider(lines[index + 1])) {
const table = element("table", "markdown-table");
const head = element("thead");
const headRow = element("tr");
markdownTableCells(line).forEach((cell) => {
const header = element("th");
appendInlineMarkdown(header, cell);
headRow.append(header);
});
head.append(headRow);
table.append(head);
index += 2;
const body = element("tbody");
while (index < lines.length && lines[index].includes("|") && lines[index].trim()) {
const row = element("tr");
markdownTableCells(lines[index]).forEach((cell) => {
const data = element("td");
appendInlineMarkdown(data, cell);
row.append(data);
});
body.append(row);
index += 1;
}
table.append(body);
const tableWrap = element("div", "markdown-table-wrap");
tableWrap.append(table);
parent.append(tableWrap);
continue;
}

const listItem = line.match(/^\s*([-+*]|\d+[.)])\s+(.+)$/);
if (listItem) {
const ordered = /^\d/.test(listItem[1]);
const list = element(ordered ? "ol" : "ul");
if (ordered) {
const start = Number.parseInt(listItem[1], 10);
if (start !== 1) list.start = start;
}
while (index < lines.length) {
const item = lines[index].match(/^\s*([-+*]|\d+[.)])\s+(.+)$/);
if (!item || /^\d/.test(item[1]) !== ordered) break;
const listNode = element("li");
appendInlineMarkdown(listNode, item[2]);
list.append(listNode);
index += 1;
}
parent.append(list);
continue;
}

if (/^>\s?/.test(line)) {
const quoteLines = [];
while (index < lines.length && /^>\s?/.test(lines[index])) {
quoteLines.push(lines[index].replace(/^>\s?/, ""));
index += 1;
}
const quote = element("blockquote");
appendMarkdownLines(quote, quoteLines);
parent.append(quote);
continue;
}

const paragraphLines = [line];
index += 1;
while (index < lines.length && lines[index].trim() && !isMarkdownBlockStart(lines, index)) {
paragraphLines.push(lines[index]);
index += 1;
}
const paragraph = element("p");
paragraphLines.forEach((paragraphLine, lineIndex) => {
if (lineIndex) paragraph.append(element("br"));
appendInlineMarkdown(paragraph, paragraphLine);
});
parent.append(paragraph);
}
}

function renderMarkdown(markdown) {
const fragment = document.createDocumentFragment();
appendMarkdownLines(fragment, markdown.replace(/\r\n?/g, "\n").split("\n"));
return fragment;
}

function renderAnswerCard(answer, modelById) {
const card = element("article", "model-answer");
const header = element("div", "model-answer-header");
Expand All @@ -221,12 +407,24 @@ function renderAnswerCard(answer, modelById) {
card.append(element("p", "answer-reason", answer.reason || answer.status || "No score detail"));

const hasContent = Boolean(answer.content.trim());
const response = element(
"pre",
`answer-copy${hasContent ? "" : " answer-copy-empty"}`,
hasContent ? answer.content : "No text response.",
);
const response = element("div", `answer-copy markdown-body${hasContent ? "" : " answer-copy-empty"}`);
if (hasContent) {
response.append(renderMarkdown(answer.content));
} else {
response.append(element("p", "", "No text response."));
}
card.append(response);
if (hasContent) {
const raw = element("details", "answer-details answer-raw");
raw.append(element("summary", "", "Raw Markdown"));
const renderRawMarkdown = () => {
if (!raw.open) return;
raw.append(element("pre", "answer-json", answer.content));
raw.removeEventListener("toggle", renderRawMarkdown);
};
raw.addEventListener("toggle", renderRawMarkdown);
card.append(raw);
}
if (answer.tool_calls.length) {
const details = element("details", "answer-details");
details.append(element("summary", "", `Tool calls (${answer.tool_calls.length})`));
Expand Down
2 changes: 1 addition & 1 deletion site/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ <h2>Read every response</h2>

<div class="answer-browser-meta">
<p id="answer-count">Loading all model answers…</p>
<p>Answers are shown verbatim; spelling and language choices are not corrected.</p>
<p>Answers are rendered from the original Markdown; open Raw Markdown to inspect the exact output.</p>
</div>
<div id="answer-cases" class="answer-cases" aria-live="polite">
<p class="loading-state">Loading model answers…</p>
Expand Down
119 changes: 113 additions & 6 deletions site/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -849,7 +849,7 @@ tbody tr:first-child .rank-badge {

.model-answer h4 {
margin: 0;
font-size: 13px;
font-size: 15px;
}

.answer-status {
Expand All @@ -873,26 +873,133 @@ tbody tr:first-child .rank-badge {
}

.answer-reason {
margin: 8px 0 16px;
margin: 8px 0 18px;
color: var(--faint);
font-size: 10px;
font-size: 11px;
}

.answer-copy {
max-height: 430px;
max-height: 560px;
overflow: auto;
margin: 0;
color: #dce4df;
white-space: pre-wrap;
overflow-wrap: anywhere;
font: 12px/1.7 ui-monospace, SFMono-Regular, Menlo, monospace;
font: 16px/1.72 Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

.answer-copy-empty {
color: var(--faint);
font-style: italic;
}

.markdown-body > :first-child { margin-top: 0; }
.markdown-body > :last-child { margin-bottom: 0; }

.markdown-body p,
.markdown-body ul,
.markdown-body ol,
.markdown-body blockquote,
.markdown-body .markdown-table-wrap,
.markdown-body .markdown-code-block {
margin: 0 0 1em;
}

.markdown-body ul,
.markdown-body ol {
padding-left: 1.45em;
}

.markdown-body li + li {
margin-top: 0.32em;
}

.markdown-body strong {
color: #f2f7f4;
font-weight: 760;
}

.markdown-heading {
margin: 1.25em 0 0.55em;
color: var(--ink);
font-size: 20px;
line-height: 1.3;
}

.markdown-heading-1,
.markdown-heading-2 {
font-size: 22px;
}

.markdown-body code {
padding: 0.15em 0.35em;
border: 1px solid var(--line);
border-radius: 5px;
background: rgba(0, 0, 0, 0.24);
font: 0.9em/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
}

.markdown-code-block {
overflow: auto;
padding: 16px;
border: 1px solid var(--line);
border-radius: 10px;
background: rgba(0, 0, 0, 0.28);
white-space: pre;
}

.markdown-code-block code {
padding: 0;
border: 0;
background: transparent;
}

.markdown-body blockquote {
padding: 0.15em 0 0.15em 1em;
color: var(--muted);
border-left: 3px solid var(--mint);
}

.markdown-body hr {
margin: 1.4em 0;
border: 0;
border-top: 1px solid var(--line);
}

.markdown-body a {
color: var(--mint);
}

.markdown-table-wrap {
overflow-x: auto;
}

.markdown-table {
min-width: 360px;
font-size: 13px;
}

.markdown-table th,
.markdown-table td {
padding: 9px 10px;
border: 1px solid var(--line);
text-align: left;
vertical-align: top;
}

.markdown-table th {
color: var(--ink);
background: rgba(255, 255, 255, 0.045);
}

.model-answer .answer-details.answer-raw {
margin-top: 20px;
}

.answer-raw .answer-json {
max-height: 300px;
font-size: 12px;
}

.model-answer .answer-details {
margin-top: 16px;
}
Expand Down
Loading
Loading