whk-sjtu's picture
chore: refresh curated demo assets
65335ce verified
Raw
History Blame Contribute Delete
3.67 kB
const BENCHMARK_COPY = {
text: {
title: "Text Editing",
description:
"Localized substitution, insertion, deletion, and longer text edits in English and Mandarin.",
},
emotion: {
title: "Emotion Editing",
description:
"Phrase-level, multi-span, and whole-utterance emotion control.",
},
prosody: {
title: "Prosody Editing",
description:
"Pitch and speaking-rate control over one or more selected regions.",
},
pause: {
title: "Pause Editing",
description:
"Insertion and reduction of natural pauses at one or more boundaries.",
},
multi: {
title: "Compositional Editing",
description:
"Up to three text and acoustic operations in one instruction.",
},
noise: {
title: "Noise Preservation & Denoising",
description:
"Editing speech while preserving background sound, plus enhancement for denoising.",
},
multi_speaker: {
title: "Multi-speaker Preservation",
description:
"Editing a bilingual, two-speaker source without speaker labels in the instruction.",
},
};
const escapeHtml = (value) =>
String(value)
.replaceAll("&", "&")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll('"', "&quot;");
function audioCell(label, path, kind = "source") {
const isOurs = kind === "ours";
return `
<div class="audio-cell ${isOurs ? "ours" : ""}">
<div class="audio-label">
<span>${escapeHtml(label)}</span>
${isOurs ? '<span class="model-badge">Ours</span>' : ""}
</div>
<audio controls preload="none" src="${encodeURI(path)}"></audio>
</div>`;
}
function sampleRow(sample, index) {
const players = [
audioCell("Source", sample.source_audio),
...sample.systems.map((system) =>
audioCell(system.label, system.audio, system.kind),
),
].join("");
const tags = sample.tags
.map((tag) => `<span class="tag">${escapeHtml(tag)}</span>`)
.join("");
return `
<article class="sample-row">
<div class="sample-meta">
<span class="sample-index">Example ${index + 1}</span>
<span class="sample-focus">${escapeHtml(sample.focus)}</span>
<span class="tag-row">${tags}</span>
</div>
<div class="instruction-panel">
<div class="instruction-label">Instruction</div>
${sample.instruction_html}
</div>
<div class="audio-grid">${players}</div>
</article>`;
}
function renderSection(section) {
const copy = BENCHMARK_COPY[section.benchmark] || {
title: section.title,
description: "",
};
const pending = section.status === "pending_manual_samples";
const body = pending
? `<div class="pending-row">${escapeHtml(copy.description)}</div>`
: `<div class="sample-list">${section.samples.map(sampleRow).join("")}</div>`;
return `
<section class="card benchmark-section" id="${escapeHtml(section.benchmark)}">
<div class="card-heading benchmark-heading">
<h2>${escapeHtml(copy.title)}</h2>
<p>${escapeHtml(copy.description)}</p>
</div>
${body}
</section>`;
}
async function loadSamples() {
const container = document.querySelector("#sample-sections");
try {
const response = await fetch("data/samples.json", { cache: "no-store" });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
container.innerHTML = data.sections.map(renderSection).join("");
} catch (error) {
container.innerHTML = `
<section class="card error-card">
Could not load the audio examples: ${escapeHtml(error.message)}
</section>`;
}
}
loadSamples();