Update index.html
Browse files- index.html +63 -14
index.html
CHANGED
|
@@ -413,6 +413,11 @@
|
|
| 413 |
margin-bottom: 1.5rem;
|
| 414 |
border-bottom: 1px solid #e5e7eb;
|
| 415 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 416 |
.disclaimer-heading {
|
| 417 |
font-size: 0.7rem;
|
| 418 |
font-weight: 700;
|
|
@@ -508,7 +513,7 @@
|
|
| 508 |
}
|
| 509 |
|
| 510 |
// ββ Edit this disclaimer to update what's shown on the language selection screen ββ
|
| 511 |
-
|
| 512 |
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 513 |
|
| 514 |
// ββ HuggingFace dataset configuration βββββββββββββββββββββββββββββββββββββββββββ
|
|
@@ -692,6 +697,27 @@
|
|
| 692 |
let selectedLanguage = null;
|
| 693 |
let audioSamples = [];
|
| 694 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 695 |
// Fetch metadata CSV and filter by language, then randomly sample 10 files
|
| 696 |
async function fetchAudioSamples(language) {
|
| 697 |
const langCode = LANGUAGE_CODE_MAP[language];
|
|
@@ -713,15 +739,15 @@
|
|
| 713 |
const line = lines[i].trim();
|
| 714 |
if (!line) continue;
|
| 715 |
|
| 716 |
-
|
| 717 |
-
|
| 718 |
-
if (firstComma === -1) continue;
|
| 719 |
|
| 720 |
-
const file =
|
| 721 |
-
const lang =
|
|
|
|
| 722 |
|
| 723 |
if (lang === langCode) {
|
| 724 |
-
files.push(file);
|
| 725 |
}
|
| 726 |
}
|
| 727 |
|
|
@@ -735,11 +761,18 @@
|
|
| 735 |
}
|
| 736 |
|
| 737 |
// Generate HuggingFace URL for an audio file
|
| 738 |
-
function getAudioUrl(
|
|
|
|
| 739 |
const fileName = filePath.split("/").pop();
|
| 740 |
return `https://huggingface.co/datasets/${HF_DATASET}/resolve/main/${filePath}`;
|
| 741 |
}
|
| 742 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 743 |
function updateProgress() {
|
| 744 |
document.getElementById("progress-label").textContent =
|
| 745 |
`${submitted} / ${TOTAL} responses submitted`;
|
|
@@ -761,7 +794,7 @@
|
|
| 761 |
});
|
| 762 |
}
|
| 763 |
|
| 764 |
-
function renderGridField(fieldId, raw) {
|
| 765 |
const { label, options: g } = raw;
|
| 766 |
// Format: { columns: [[id, label, configStr], ...], rows: [[id, label, configStr], ...] }
|
| 767 |
const rowsRaw = g.rows ?? [];
|
|
@@ -785,11 +818,18 @@
|
|
| 785 |
const headerCells = cols.map((c) => `<th>${c.label}</th>`).join("");
|
| 786 |
const bodyRows = rows
|
| 787 |
.map(
|
| 788 |
-
(r) =>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 789 |
<tr>
|
| 790 |
-
<td class="grid-row-label">${
|
| 791 |
${cols.map((c, i) => `<td><input type="radio" name="${fieldId}__${r.id}" value="${i + 1}"></td>`).join("")}
|
| 792 |
-
</tr>`
|
|
|
|
| 793 |
)
|
| 794 |
.join("");
|
| 795 |
|
|
@@ -897,7 +937,8 @@
|
|
| 897 |
`#form-${formDef.id} .form-body`,
|
| 898 |
);
|
| 899 |
if (!formBody) return;
|
| 900 |
-
const
|
|
|
|
| 901 |
formBody.insertAdjacentHTML("beforeend", gridHtml);
|
| 902 |
});
|
| 903 |
|
|
@@ -933,13 +974,21 @@
|
|
| 933 |
});
|
| 934 |
}
|
| 935 |
|
|
|
|
|
|
|
| 936 |
function showLanguagePicker() {
|
| 937 |
-
const languages = ["French", "German", "
|
| 938 |
card.innerHTML = `
|
| 939 |
<div class="disclaimer-section">
|
| 940 |
<div class="disclaimer-heading">Before you begin</div>
|
| 941 |
<div class="disclaimer">${DISCLAIMER}</div>
|
| 942 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 943 |
<div class="lang-picker-title">Choose a language</div>
|
| 944 |
<div class="lang-picker-sub">Select the language for this survey session.</div>
|
| 945 |
<div class="lang-grid">
|
|
|
|
| 413 |
margin-bottom: 1.5rem;
|
| 414 |
border-bottom: 1px solid #e5e7eb;
|
| 415 |
}
|
| 416 |
+
.survey-description {
|
| 417 |
+
margin-bottom: 0.25rem;
|
| 418 |
+
padding-bottom: 0.75rem;
|
| 419 |
+
border-bottom: 1px solid #e5e7eb;
|
| 420 |
+
}
|
| 421 |
.disclaimer-heading {
|
| 422 |
font-size: 0.7rem;
|
| 423 |
font-weight: 700;
|
|
|
|
| 513 |
}
|
| 514 |
|
| 515 |
// ββ Edit this disclaimer to update what's shown on the language selection screen ββ
|
| 516 |
+
const DISCLAIMER = `By participating in this survey, you agree that your anonymized responses may be used for academic research as part of a master's thesis. No personally identifiable information will be collected.\n\nPlease select only one language that you are a native speaker of or fluent in at a bilingual level. <strong style="color:#dc2626;">β οΈ Do not proceed if you are not proficient in any of the listed languages, as inaccurate responses may affect the validity of the survey results.</strong>\n\nEach audio clip you hear may not exceed 30 seconds.\n\nIf you speak multiple languages, please complete the survey for one language first. You will have the option to select another language and complete a new survey afterward.`;
|
| 517 |
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 518 |
|
| 519 |
// ββ HuggingFace dataset configuration βββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
| 697 |
let selectedLanguage = null;
|
| 698 |
let audioSamples = [];
|
| 699 |
|
| 700 |
+
// Parse CSV line handling quoted values
|
| 701 |
+
function parseCSVLine(line) {
|
| 702 |
+
const result = [];
|
| 703 |
+
let current = '';
|
| 704 |
+
let inQuotes = false;
|
| 705 |
+
|
| 706 |
+
for (let i = 0; i < line.length; i++) {
|
| 707 |
+
const char = line[i];
|
| 708 |
+
if (char === '"') {
|
| 709 |
+
inQuotes = !inQuotes;
|
| 710 |
+
} else if (char === ',' && !inQuotes) {
|
| 711 |
+
result.push(current.trim());
|
| 712 |
+
current = '';
|
| 713 |
+
} else {
|
| 714 |
+
current += char;
|
| 715 |
+
}
|
| 716 |
+
}
|
| 717 |
+
result.push(current.trim());
|
| 718 |
+
return result;
|
| 719 |
+
}
|
| 720 |
+
|
| 721 |
// Fetch metadata CSV and filter by language, then randomly sample 10 files
|
| 722 |
async function fetchAudioSamples(language) {
|
| 723 |
const langCode = LANGUAGE_CODE_MAP[language];
|
|
|
|
| 739 |
const line = lines[i].trim();
|
| 740 |
if (!line) continue;
|
| 741 |
|
| 742 |
+
const parts = parseCSVLine(line);
|
| 743 |
+
if (parts.length < 3) continue;
|
|
|
|
| 744 |
|
| 745 |
+
const file = parts[0];
|
| 746 |
+
const lang = parts[1];
|
| 747 |
+
const namedEntity = parts[2];
|
| 748 |
|
| 749 |
if (lang === langCode) {
|
| 750 |
+
files.push({ file, namedEntity });
|
| 751 |
}
|
| 752 |
}
|
| 753 |
|
|
|
|
| 761 |
}
|
| 762 |
|
| 763 |
// Generate HuggingFace URL for an audio file
|
| 764 |
+
function getAudioUrl(audioSample) {
|
| 765 |
+
const filePath = audioSample.file;
|
| 766 |
const fileName = filePath.split("/").pop();
|
| 767 |
return `https://huggingface.co/datasets/${HF_DATASET}/resolve/main/${filePath}`;
|
| 768 |
}
|
| 769 |
|
| 770 |
+
// Get named entity for current audio sample
|
| 771 |
+
function getNamedEntity() {
|
| 772 |
+
const audioSample = audioSamples[submitted];
|
| 773 |
+
return audioSample?.namedEntity || '';
|
| 774 |
+
}
|
| 775 |
+
|
| 776 |
function updateProgress() {
|
| 777 |
document.getElementById("progress-label").textContent =
|
| 778 |
`${submitted} / ${TOTAL} responses submitted`;
|
|
|
|
| 794 |
});
|
| 795 |
}
|
| 796 |
|
| 797 |
+
function renderGridField(fieldId, raw, namedEntity = '') {
|
| 798 |
const { label, options: g } = raw;
|
| 799 |
// Format: { columns: [[id, label, configStr], ...], rows: [[id, label, configStr], ...] }
|
| 800 |
const rowsRaw = g.rows ?? [];
|
|
|
|
| 818 |
const headerCells = cols.map((c) => `<th>${c.label}</th>`).join("");
|
| 819 |
const bodyRows = rows
|
| 820 |
.map(
|
| 821 |
+
(r, index) => {
|
| 822 |
+
let rowLabel = r.label;
|
| 823 |
+
// Add named entity to the 4th row (index 3)
|
| 824 |
+
if (index === 3 && namedEntity) {
|
| 825 |
+
rowLabel += ` <em>"<strong style="color:#6b7280;">${namedEntity}</strong>"</em>?`;
|
| 826 |
+
}
|
| 827 |
+
return `
|
| 828 |
<tr>
|
| 829 |
+
<td class="grid-row-label">${rowLabel}</td>
|
| 830 |
${cols.map((c, i) => `<td><input type="radio" name="${fieldId}__${r.id}" value="${i + 1}"></td>`).join("")}
|
| 831 |
+
</tr>`;
|
| 832 |
+
},
|
| 833 |
)
|
| 834 |
.join("");
|
| 835 |
|
|
|
|
| 937 |
`#form-${formDef.id} .form-body`,
|
| 938 |
);
|
| 939 |
if (!formBody) return;
|
| 940 |
+
const namedEntity = getNamedEntity();
|
| 941 |
+
const gridHtml = renderGridField(fieldId, raw, namedEntity);
|
| 942 |
formBody.insertAdjacentHTML("beforeend", gridHtml);
|
| 943 |
});
|
| 944 |
|
|
|
|
| 974 |
});
|
| 975 |
}
|
| 976 |
|
| 977 |
+
const SURVEY_DES = "In this survey, you will evaluate <strong>10 audio samples</strong>. For each audio, you need to answer <strong>4 questions</strong> related to:\n\n<strong>Pronunciation</strong> β How clearly and correctly the words are pronounced\n<strong>Grammar</strong> β How grammatically correct the speech sounds\n<strong>Naturalness</strong> β How natural the overall speech sounds\n\n<strong>Rating Scale:</strong> 1 (Poor) to 5 (Excellent)\n\nPlease listen to each audio carefully before providing your ratings.";
|
| 978 |
+
|
| 979 |
function showLanguagePicker() {
|
| 980 |
+
const languages = ["French", "German", "Italian", "Spanish"];
|
| 981 |
card.innerHTML = `
|
| 982 |
<div class="disclaimer-section">
|
| 983 |
<div class="disclaimer-heading">Before you begin</div>
|
| 984 |
<div class="disclaimer">${DISCLAIMER}</div>
|
| 985 |
</div>
|
| 986 |
+
<div class="survey-description">
|
| 987 |
+
<div class="disclaimer-heading">About this Survey</div>
|
| 988 |
+
<div class="disclaimer">
|
| 989 |
+
${SURVEY_DES}
|
| 990 |
+
</div>
|
| 991 |
+
</div>
|
| 992 |
<div class="lang-picker-title">Choose a language</div>
|
| 993 |
<div class="lang-picker-sub">Select the language for this survey session.</div>
|
| 994 |
<div class="lang-grid">
|