annotation-studio / frontend /src /AnnotationExamples.tsx
pepijn223's picture
pepijn223 HF Staff
Add per-annotation prompt editors and illustrated annotation timelines
53a2e9c verified
Raw History Blame Contribute Delete
6.36 kB
import { useState } from "react";
import { Clock3, Layers3 } from "lucide-react";
const types = [
"Subtasks",
"Plans",
"Memory",
"Task rephrasings",
"Interjections & speech",
"Visual questions",
];
const phases = [
{
title: "Pick up a cup and place it on a tray",
duration: "8.0 s",
rows: [
["0.0–1.4 s", "Reach the right gripper toward the cup", 1.4],
["1.4–2.5 s", "Grasp the cup with the right gripper", 1.1],
["2.5–5.6 s", "Move the cup over the tray", 3.1],
["5.6–8.0 s", "Place the cup on the tray and release it", 2.4],
] as [string, string, number][],
},
{
title: "Wipe a section of the counter",
duration: "18.0 s",
rows: [
["0.0–2.0 s", "Pick up the sponge", 2],
["2.0–15.5 s", "Wipe the counter with the sponge", 13.5],
["15.5–18.0 s", "Place the sponge beside the sink", 2.5],
] as [string, string, number][],
},
];
const examples: Record<string, { label: string; text: string }[]> = {
Plans: [
{
label: "At 2.5 s · after grasping the cup",
text: "1. Move the cup over the tray.\n2. Place the cup on the tray and release it.",
},
{
label: "At 5.6 s · after moving the cup",
text: "1. Place the cup on the tray and release it.",
},
],
Memory: [
{ label: "At 2.5 s · completed action", text: "I picked up the cup." },
{
label: "At 15.5 s · after the wiping phase",
text: "I picked up the sponge and wiped the counter.",
},
],
"Task rephrasings": [
{
label: "Original task · place the cup on the tray",
text: "Move the cup onto the tray.",
},
{
label: "Same objects, action and destination",
text: "Could you put the cup on the tray, please?",
},
],
"Interjections & speech": [
{
label: "At 2.5 s · before transporting the cup",
text: "User: “Now move the cup over the tray, please.”\nRobot: “On it.”",
},
{
label: "At 15.5 s · before putting down the sponge",
text: "User: “Place the sponge beside the sink.”\nRobot: “Okay.”",
},
],
"Visual questions": [
{
label: "At 2.5 s · object state",
text: 'Q: What is the state of the cup?\nA: {"label":"cup","attribute":"state","value":"held by the right gripper"}',
},
{
label: "At 8.0 s · spatial relation",
text: 'Q: Where is the cup relative to the tray?\nA: {"subject":"cup","relation":"on","object":"tray"}',
},
],
};
const explanations: Record<string, string> = {
Subtasks:
"One meaningful action phase per segment. Reach, grasp, move and release can have separate boundaries; a sustained action stays together while its purpose is unchanged.",
Plans:
"A plan lists the remaining subtasks at each boundary. Completed actions disappear as the episode progresses.",
Memory:
"Short first-person summaries of completed work, updated at subtask boundaries. Keep useful outcomes rather than replaying every motion.",
"Task rephrasings":
"Different wording for the same episode-level instruction. These do not create new temporal segments or change the task.",
"Interjections & speech":
"A short user cue and paired robot acknowledgement at a subtask transition. The request matches what the recorded robot does next.",
"Visual questions":
"A question and a structured answer grounded in a sampled frame. These are point-in-time annotations, not action spans.",
};
export default function AnnotationExamples({ custom }: { custom: boolean }) {
const [type, setType] = useState("Subtasks");
return (
<section className="annotation-examples" aria-labelledby="examples-title">
<div className="examples-heading">
<Layers3 size={16} />
<h3 id="examples-title">What will the annotations look like?</h3>
<span>Illustrative examples</span>
</div>
<div className="example-tabs" aria-label="Example annotation type">
{types.map((t) => (
<button
key={t}
className={t === type ? "active" : ""}
aria-pressed={t === type}
onClick={() => setType(t)}
>
{t}
</button>
))}
</div>
<p className="examples-explanation">{explanations[type]}</p>
<div className="example-pair">
{type === "Subtasks"
? phases.map((example, index) => (
<article className="example-card" key={example.title}>
<div className="example-kicker">
EXAMPLE {index + 1}
<span>
<Clock3 size={11} />
{example.duration}
</span>
</div>
<h4>{example.title}</h4>
<div
className="example-timeline"
aria-label={`Illustrated timeline: ${example.rows.length} action phases`}
>
{example.rows.map(([time, text, seconds], i) => (
<span
key={time}
style={{ flex: seconds }}
className={`phase-${i}`}
title={`${time}: ${text}`}
/>
))}
</div>
<div className="example-rows">
{example.rows.map(([time, text], i) => (
<div key={time}>
<span className={`phase-dot phase-${i}`} />
<code>{time}</code>
<span>{text}</span>
</div>
))}
</div>
</article>
))
: examples[type].map((example, index) => (
<article className="example-card" key={example.label}>
<div className="example-kicker">EXAMPLE {index + 1}</div>
<h4>{example.label}</h4>
<p className="example-output">{example.text}</p>
</article>
))}
</div>
<p className="example-footnote">
Illustrations of the default style, not predictions for your dataset.
Boundaries depend on the visible action.
{custom
? " Your custom prompts may change the wording and granularity."
: ""}
</p>
</section>
);
}