math-annotation-demo / config.yaml
aops02's picture
Restore Kseniia-style single-column layout
ff159de verified
Raw
History Blame Contribute Delete
18 kB
annotation_task_name: "Evaluation of Math Tutor Responses"
task_dir: "."
data_files:
- "my-annotation-task/data/math_annotator_demo_all_with_id_text2show.csv"
item_properties:
id_key: id
text_key: text2show
instance_display:
fields:
- key: text2show_html
type: html
layout:
direction: vertical
gap: "16px"
resizable: false
output_annotation_dir: "annotation_output/"
export_annotation_format: "json"
require_password: false
annotation_schemes:
- annotation_type: radio
required: true
name: Content Correctness
description: "Content Correctness: Are the facts, explanations, code, fixes, or judgments technically and factually correct?"
labels: ["Yes", "To some extent", "No"]
- annotation_type: radio
required: true
name: Learner-State Assessment
description: "Learner-State Assessment: Does the tutor correctly assess whether the learner's work is correct, incorrect, incomplete, or uncertain?"
labels: ["Yes", "To some extent", "No"]
- annotation_type: radio
required: true
name: Issue Localization
description: "Issue Localization: Does the tutor identify the relevant step, line, concept, or reasoning gap?"
labels: ["Yes", "To some extent", "No"]
- annotation_type: radio
required: true
name: Disclosure Appropriateness
description: "Disclosure Appropriateness: Does the tutor reveal an appropriate amount of solution detail given the task type and learner state?"
labels: ["Yes", "To some extent", "No"]
- annotation_type: radio
required: true
name: Providing Guidance
description: "Providing Guidance: Does the response provide useful help, such as a hint, explanation, validation, diagnostic feedback, worked step, or repair advice?"
labels: ["Yes", "To some extent", "No"]
- annotation_type: radio
required: true
name: Coherence
description: "Coherence: Is the response logically consistent and generally relevant to the task?"
labels: ["Yes", "To some extent", "No"]
- annotation_type: radio
required: true
name: Actionability
description: "Actionability: After reading the response, is it clear what the learner should do, think about, or check next?"
labels: ["Yes", "To some extent", "No"]
- annotation_type: radio
required: true
name: Clarity
description: "Clarity: Is the response easy to understand in terms of context, structure, and references?"
labels: ["Yes", "To some extent", "No"]
- annotation_type: radio
required: true
name: Conciseness
description: "Conciseness: Is the response appropriately scoped in length and detail for the context?"
labels: ["Yes", "To some extent", "No"]
- annotation_type: radio
required: true
name: Humanness
description: "Humanness: Does this look or sound like what a human tutor would do or say in this context?"
labels: ["Yes", "To some extent", "No"]
# Generated but intentionally not enabled for the first demo:
# phases:
# training:
# enabled: true
# data_file: "my-annotation-task/data/training_questions.json"
# passing_criteria:
# min_correct: 8
# total_questions: 14
# retries:
# enabled: true
# max_retries: 2
# show_explanations: true
# randomize: true
#
# gold_standards:
# enabled: true
# items_file: "my-annotation-task/data/gold_standards.json"
# mode: "separate"
# accuracy:
# min_threshold: 0.7
# evaluation_count: 14
custom_footer_html: |
<style>
:root {
--math-demo-accent: #6d55d8;
--math-demo-ink: #111827;
--math-demo-muted: #5b6472;
--math-demo-border: #d0d7de;
--math-demo-soft: #f6f8fa;
}
body {
background: #f3f5f9;
}
.container-fluid {
padding-left: clamp(10px, 2vw, 24px);
padding-right: clamp(10px, 2vw, 24px);
}
#task_layout.text-annotation {
margin-left: auto;
margin-right: auto;
max-width: min(92vw, 960px);
width: 100%;
}
#task_layout.text-annotation .shadcn-card-content {
padding: clamp(10px, 1.4vw, 18px);
}
.potato-instance-meta {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin: 0 0 10px;
}
.potato-instance-meta span {
border: 1px solid #d7dcef;
border-radius: 999px;
background: #f8fafc;
color: #475569;
font-size: 12px;
font-weight: 700;
padding: 4px 9px;
}
.potato-text-section {
margin-bottom: 14px;
}
.potato-text-section h3 {
color: var(--math-demo-ink);
font-size: 1.18rem;
line-height: 1.2;
margin: 0 0 6px;
}
.potato-text-section p {
color: var(--math-demo-ink);
font-size: 0.96rem;
line-height: 1.5;
margin: 0 0 10px;
}
.potato-text-section code {
background: #f1f5f9;
border-radius: 4px;
color: #b83280;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
padding: 1px 4px;
}
.potato-code-block {
background: var(--math-demo-soft);
border: 1px solid var(--math-demo-border);
border-radius: 6px;
color: #24292f;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
font-size: 14px;
line-height: 1.45;
margin: 8px 0 12px;
overflow-x: auto;
padding: 12px;
white-space: pre-wrap;
}
.annotation-stepper-workspace {
align-items: stretch;
display: flex;
flex-direction: column;
gap: 18px;
}
.annotation-stepper-workspace > .mb-4 {
margin-bottom: 0 !important;
min-width: 0;
}
.annotation-stepper-workspace .instance-display-container {
background: #fff;
border: 1px solid var(--math-demo-border);
border-radius: 8px;
box-shadow: inset -8px 0 0 rgba(148, 163, 184, 0.08);
padding: clamp(14px, 1.6vw, 22px);
}
.annotation-stepper-workspace .display-field,
.annotation-stepper-workspace .display-field-resizable,
.annotation-stepper-workspace .text-display-content {
max-height: none !important;
min-height: 0 !important;
}
#annotation-forms.annotation-stepper {
background: #fff;
border: 1px solid var(--math-demo-border);
border-radius: 8px;
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.08);
margin-top: 4px;
padding: 13px;
width: 100%;
}
#annotation-forms.annotation-stepper .annotation-stepper-hidden {
display: none !important;
}
#annotation-forms.annotation-stepper .annotation-form {
border: 0;
box-shadow: none;
margin-bottom: 0;
padding: 0;
}
#annotation-forms.annotation-stepper .shadcn-radio-options {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
#annotation-forms.annotation-stepper .shadcn-radio-option {
min-width: 150px;
}
#annotation-forms.annotation-stepper .shadcn-radio-input[value="Yes"] + .shadcn-radio-label {
background: #e8f5ee;
border: 1px solid #8fc9a8;
border-radius: 999px;
color: #17603a;
font-weight: 700;
padding: 6px 10px;
}
#annotation-forms.annotation-stepper .shadcn-radio-input[value="To some extent"] + .shadcn-radio-label {
background: #fff7d6;
border: 1px solid #e6c75a;
border-radius: 999px;
color: #7a5a00;
font-weight: 700;
padding: 6px 10px;
}
#annotation-forms.annotation-stepper .shadcn-radio-input[value="No"] + .shadcn-radio-label {
background: #fde8e8;
border: 1px solid #f2a6a6;
border-radius: 999px;
color: #9b1c1c;
font-weight: 700;
padding: 6px 10px;
}
#annotation-forms.annotation-stepper .shadcn-radio-input:checked + .shadcn-radio-label {
box-shadow: 0 0 0 3px rgba(31, 111, 235, 0.18);
}
.annotation-stepper-controls {
border-bottom: 1px solid #e5e7eb;
margin-bottom: 12px;
padding-bottom: 10px;
}
.annotation-stepper-row {
align-items: center;
display: flex;
gap: 12px;
justify-content: space-between;
margin-bottom: 8px;
}
.annotation-stepper-kicker {
color: var(--math-demo-muted);
font-size: 0.82rem;
font-weight: 700;
text-transform: uppercase;
}
.annotation-stepper-title {
color: var(--math-demo-ink);
font-size: 1rem;
font-weight: 750;
line-height: 1.3;
}
.annotation-stepper-help {
color: var(--math-demo-muted);
font-size: 0.9rem;
margin-top: 4px;
}
.annotation-stepper-actions {
display: flex;
flex-wrap: wrap;
gap: 8px;
justify-content: flex-end;
}
.annotation-stepper-button {
background: #fff;
border: 1px solid #cbd5e1;
border-radius: 6px;
color: #1f2937;
cursor: pointer;
font-weight: 650;
min-height: 36px;
padding: 7px 10px;
}
.annotation-stepper-button:hover:not(:disabled) {
background: #f8fafc;
border-color: #94a3b8;
}
.annotation-stepper-button:disabled {
color: #9ca3af;
cursor: not-allowed;
opacity: 0.7;
}
.annotation-stepper-progress {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 6px;
}
.annotation-stepper-dot {
align-items: center;
background: #f8fafc;
border: 1px solid #d1d5db;
border-radius: 999px;
color: #4b5563;
cursor: pointer;
display: inline-flex;
font-size: 0.8rem;
font-weight: 700;
height: 28px;
justify-content: center;
min-width: 28px;
padding: 0 8px;
}
.annotation-stepper-dot.is-active {
background: #1f6feb;
border-color: #1f6feb;
color: #fff;
}
.annotation-stepper-dot.is-answered:not(.is-active) {
background: #e8f5ee;
border-color: #8fc9a8;
color: #17603a;
}
@media (max-width: 720px) {
.container-fluid {
padding-left: 8px;
padding-right: 8px;
}
.annotation-stepper-row {
align-items: flex-start;
flex-direction: column;
}
.annotation-stepper-workspace {
gap: 12px;
}
.annotation-stepper-workspace .instance-display-container {
padding: 12px;
}
#annotation-forms.annotation-stepper .shadcn-radio-option {
min-width: 100%;
}
}
</style>
<script>
window.MathJax = {
tex: {
inlineMath: [["\\(", "\\)"]],
displayMath: [["\\[", "\\]"]]
},
options: { skipHtmlTags: ["script", "noscript", "style", "textarea", "pre", "code"] }
};
</script>
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js" async></script>
<script>
(function () {
function onReady(fn) {
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", fn);
} else {
fn();
}
}
function textOf(element) {
return element ? (element.textContent || "").trim() : "";
}
function dimensionTitle(form) {
var legend = textOf(form.querySelector("legend"));
var colon = legend.indexOf(":");
return colon > 0 ? legend.slice(0, colon) : (legend || form.id || "Dimension");
}
function isAnswered(form) {
if (form.querySelector("input[type='radio']:checked")) return true;
if (form.querySelector("input[type='checkbox']:checked")) return true;
var fields = form.querySelectorAll("input[type='text'], input[type='number'], textarea, select");
for (var i = 0; i < fields.length; i += 1) {
if ((fields[i].value || "").trim()) return true;
}
return false;
}
function firstUnansweredIndex(forms) {
for (var i = 0; i < forms.length; i += 1) {
if (!isAnswered(forms[i])) return i;
}
return forms.length - 1;
}
function initDimensionStepper() {
var container = document.getElementById("annotation-forms");
if (!container || container.getAttribute("data-stepper-ready") === "true") return;
var forms = Array.prototype.slice.call(container.querySelectorAll("form.annotation-form.radio"));
if (forms.length < 2) return;
container.setAttribute("data-stepper-ready", "true");
container.classList.add("annotation-stepper");
var main = document.getElementById("main-content");
var displayPane = main ? main.querySelector(".mb-4") : null;
if (main && displayPane) {
var workspace = document.createElement("div");
workspace.className = "annotation-stepper-workspace";
main.insertBefore(workspace, displayPane);
workspace.appendChild(displayPane);
workspace.appendChild(container);
}
var currentIndex = firstUnansweredIndex(forms);
var showAll = false;
var controls = document.createElement("div");
controls.className = "annotation-stepper-controls";
controls.innerHTML = [
'<div class="annotation-stepper-row">',
' <div>',
' <div class="annotation-stepper-kicker"></div>',
' <div class="annotation-stepper-title"></div>',
' <div class="annotation-stepper-help"></div>',
' </div>',
' <div class="annotation-stepper-actions">',
' <button type="button" class="annotation-stepper-button" data-stepper-prev>Prev</button>',
' <button type="button" class="annotation-stepper-button" data-stepper-next>Next</button>',
' <button type="button" class="annotation-stepper-button" data-stepper-toggle>Show all</button>',
' </div>',
'</div>',
'<div class="annotation-stepper-progress" aria-label="Dimension progress"></div>'
].join("");
container.insertBefore(controls, container.firstChild);
var kicker = controls.querySelector(".annotation-stepper-kicker");
var title = controls.querySelector(".annotation-stepper-title");
var help = controls.querySelector(".annotation-stepper-help");
var progress = controls.querySelector(".annotation-stepper-progress");
var prev = controls.querySelector("[data-stepper-prev]");
var next = controls.querySelector("[data-stepper-next]");
var toggle = controls.querySelector("[data-stepper-toggle]");
var dots = forms.map(function (form, index) {
var dot = document.createElement("button");
dot.type = "button";
dot.className = "annotation-stepper-dot";
dot.textContent = String(index + 1);
dot.title = dimensionTitle(form);
dot.addEventListener("click", function () {
showAll = false;
currentIndex = index;
render(true);
});
progress.appendChild(dot);
return dot;
});
function render(shouldScroll) {
for (var i = 0; i < forms.length; i += 1) {
var active = showAll || i === currentIndex;
forms[i].classList.toggle("annotation-stepper-hidden", !active);
forms[i].setAttribute("aria-hidden", active ? "false" : "true");
dots[i].classList.toggle("is-active", !showAll && i === currentIndex);
dots[i].classList.toggle("is-answered", isAnswered(forms[i]));
}
var answeredCount = forms.filter(isAnswered).length;
if (showAll) {
kicker.textContent = answeredCount + " / " + forms.length + " answered";
title.textContent = "All dimensions";
help.textContent = "Showing every annotation box.";
} else {
kicker.textContent = "Dimension " + (currentIndex + 1) + " / " + forms.length;
title.textContent = dimensionTitle(forms[currentIndex]);
help.textContent = isAnswered(forms[currentIndex])
? "Answered. You can adjust it or move to another dimension."
: "Choose a label, or use Next to skip ahead.";
}
prev.disabled = showAll || currentIndex === 0;
next.disabled = showAll || currentIndex === forms.length - 1;
toggle.textContent = showAll ? "One at a time" : "Show all";
if (shouldScroll && window.matchMedia("(max-width: 1099px)").matches) {
container.scrollIntoView({ behavior: "smooth", block: "start" });
}
}
prev.addEventListener("click", function () {
if (currentIndex > 0) {
currentIndex -= 1;
showAll = false;
render(true);
}
});
next.addEventListener("click", function () {
if (currentIndex < forms.length - 1) {
currentIndex += 1;
showAll = false;
render(true);
}
});
toggle.addEventListener("click", function () {
showAll = !showAll;
render(false);
});
container.addEventListener("change", function (event) {
var form = event.target.closest ? event.target.closest("form.annotation-form") : null;
var index = forms.indexOf(form);
if (index === -1) return;
currentIndex = index;
render(false);
if (!showAll && event.target.type === "radio" && event.target.checked && index < forms.length - 1) {
window.setTimeout(function () {
if (currentIndex === index && isAnswered(forms[index])) {
currentIndex = index + 1;
render(false);
}
}, 350);
}
});
render(false);
}
onReady(function () {
window.setTimeout(initDimensionStepper, 250);
});
}());
</script>