Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

small redesign of labeling queue #167

Merged
merged 3 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,22 @@ import { eq, and } from 'drizzle-orm';
import { isFeatureEnabled } from '@/lib/features/features';
import { Feature } from '@/lib/features/features';
import { clickhouseClient } from '@/lib/clickhouse/client';
import { z } from 'zod';

const removeQueueItemSchema = z.object({
id: z.string(),
spanId: z.string(),
addedLabels: z.array(z.object({
value: z.number(),
labelClass: z.object({
name: z.string(),
id: z.string()
})
})),
action: z.object({
resultId: z.string().optional()
})
});

// remove an item from the queue
export async function POST(request: Request, { params }: { params: { projectId: string; queueId: string } }) {
Expand All @@ -14,32 +29,41 @@ export async function POST(request: Request, { params }: { params: { projectId:
}

const body = await request.json();
const { id, spanId, action } = body;
const result = removeQueueItemSchema.safeParse(body);

if (!result.success) {
return Response.json({ error: 'Invalid request body', details: result.error }, { status: 400 });
}

const { id, spanId, addedLabels, action } = result.data;

if (action.resultId) {
const labelingQueue = await db.query.labelingQueues.findFirst({
where: eq(labelingQueues.id, params.queueId)
});

// get all labels of the span
// FIXME: this takes values from previous labels,
// potentially from a different queue
const labelsOfSpan = await db.query.labels.findMany({
where: eq(labels.spanId, spanId),
with: {
labelClass: true
}
});
// adding new labels to the span
const newLabels = addedLabels.map(({ value, labelClass }) => ({
value: value,
classId: labelClass.id,
spanId,
labelSource: "MANUAL" as const,
}));

await db.insert(labels).values(newLabels);


const resultId = action.resultId;

// create new results in batch
const evaluationValues = labelsOfSpan.map(label => ({
score: label.value ?? 0,
name: `${label.labelClass.name}_${labelingQueue?.name}`,
const evaluationValues = addedLabels.map(({ value, labelClass }) => ({
score: value ?? 0,
name: `${labelClass.name}_${labelingQueue?.name}`,
resultId,
}));

await db.insert(evaluationScores).values(evaluationValues);

if (isFeatureEnabled(Feature.FULL_BUILD)) {
const evaluation = await db.query.evaluations.findFirst({
with: {
Expand All @@ -63,8 +87,6 @@ export async function POST(request: Request, { params }: { params: { projectId:
});
}
}

await db.insert(evaluationScores).values(evaluationValues);
}

const deletedQueueData = await db
Expand Down
5 changes: 0 additions & 5 deletions frontend/components/dataset/dataset.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,6 @@ export default function Dataset({ dataset }: DatasetProps) {
</div>
<AddDatapointsDialog datasetId={dataset.id} onUpdate={mutate} />
<ManualAddDatapoint datasetId={dataset.id} onUpdate={mutate} />
{/* <IndexDatasetDialog
datasetId={dataset.id}
defaultDataset={dataset}
onUpdate={mutate}
/> */}
</div>
<div className="flex-grow">
<DataTable
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/evaluation/evaluation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ export default function Evaluation({
</Select>
</div>
</div>
<div className="flex flex-grow">
<div className="flex flex-grow flex-col">
<div className="flex flex-col flex-grow">
{selectedScoreName && (
<div className="flex flex-row space-x-4 p-4 mr-4">
Expand Down
147 changes: 32 additions & 115 deletions frontend/components/queue/labels.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import {
LabelClass,
LabelSource,
RegisteredLabelClassForPath,
Span,
} from '@/lib/traces/types';
import { cn, swrFetcher } from '@/lib/utils';
Expand All @@ -12,8 +10,6 @@ import {
Loader2,
MoreVertical,
Plus,
Tag,
X
} from 'lucide-react';
import { Button } from '../ui/button';
import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';
Expand All @@ -26,21 +22,14 @@ import {
TableHeader,
TableRow
} from '../ui/table';
import { v4 } from 'uuid';
import { renderNodeInput } from '@/lib/flow/utils';
import { PopoverClose } from '@radix-ui/react-popover';
import { toast, useToast } from '@/lib/hooks/use-toast';
import { toast } from '@/lib/hooks/use-toast';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger
} from '../ui/dropdown-menu';
import { EvaluatorEditorDialog } from '../evaluator/evaluator-editor-dialog';
import { Graph } from '@/lib/flow/graph';
import { CodeNode, LLMNode, NodeType } from '@/lib/flow/types';
import { Switch } from '../ui/switch';
import { eventEmitter } from '@/lib/event-emitter';
import {
Dialog,
DialogContent,
Expand All @@ -55,9 +44,10 @@ import { AddLabel } from '../traces/add-label';
interface LabelsProps {
span: Span | undefined;
className?: string;
onAddLabel: (value: number, labelClass: LabelClass) => void;
}

export function Labels({ span }: LabelsProps) {
export function Labels({ span, onAddLabel }: LabelsProps) {
const { projectId } = useProjectContext();
const { data: labelClasses, mutate: mutateLabelClasses } = useSWR<LabelClass[]>(`/api/projects/${projectId}/label-classes`, swrFetcher);
const [open, setOpen] = useState(false);
Expand All @@ -75,7 +65,6 @@ export function Labels({ span }: LabelsProps) {
setIsDeletingLabelClass(false);
if (res.ok) {
mutateLabelClasses();
eventEmitter.emit('mutateSpanLabels');

toast({
title: "Label class deleted",
Expand All @@ -92,8 +81,8 @@ export function Labels({ span }: LabelsProps) {

return (
<>
<div className="flex-col items-center space-y-2">
<div className="flex justify-between">
<div className="flex flex-col w-full">
<div className="flex justify-between flex-none">
<h2 className="text-lg font-medium">Labels</h2>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
Expand All @@ -115,37 +104,46 @@ export function Labels({ span }: LabelsProps) {
</div>
<div className="flex-col space-y-1">
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Add label</TableHead>
<TableHead></TableHead>
</TableRow>
</TableHeader>
<TableBody className="text-base">
{labelClasses?.map((labelClass) => (
<TableRow key={labelClass.id} className="px-0 mx-0">
<TableCell className="p-0 py-2">
<div className={cn('flex')}>
<p className="border rounded-lg bg-secondary p-1 px-2 text-sm overflow-hidden truncate max-w-[150px]">
<div className={cn('flex pr-1')}>
<p className="border rounded-lg bg-secondary p-1 px-2 text-sm overflow-hidden truncate max-w-[100px]">
{labelClass.name}
</p>
</div>
</TableCell>
<TableCell className="px-0">
<AddLabelInstance
span={span}
projectId={projectId}
labelClass={labelClass}
onAddLabel={(value) => {
mutateLabelClasses();
}}
/>
<Popover>
<PopoverTrigger asChild>
<Button variant="outline" className="px-1.5">
Add
<ChevronDown size={14} className="ml-1" />
</Button>
</PopoverTrigger>
<PopoverContent side="bottom" align="end">
<div className="flex flex-col space-y-2">
{Object.entries(labelClass.valueMap).map(([key, value], index) => (
<PopoverClose key={index}>
<div
onClick={() => {
onAddLabel(value, labelClass);
}}
className="cursor-pointer hover:bg-secondary-foreground/10 p-1 rounded border px-2"
>
{key}
</div>
</PopoverClose>
))}
</div>
</PopoverContent>
</Popover>
</TableCell>
<TableCell className="w-12">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button className="w-12" variant="ghost">
<Button variant="ghost">
<MoreVertical size={14} />
</Button>
</DropdownMenuTrigger>
Expand Down Expand Up @@ -200,84 +198,3 @@ export function Labels({ span }: LabelsProps) {
</>
);
}

function AddLabelInstance({
span,
projectId,
labelClass,
onAddLabel
}: {
span: Span | undefined;
projectId: string;
labelClass: LabelClass;
onAddLabel: (value: string) => void;
}) {
const [isLoading, setIsLoading] = useState(false);

const addLabel = async (
value: string,
labelClass: LabelClass,
source: LabelSource,
reasoning?: string
) => {
const response = await fetch(
`/api/projects/${projectId}/spans/${span?.spanId}/labels`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
classId: labelClass.id,
value: labelClass.valueMap[value],
source: source,
reasoning: reasoning
})
}
);

setIsLoading(false);

if (response.ok) {
onAddLabel(value);
eventEmitter.emit('mutateSpanLabels');
toast({
title: 'Label added',
description: `${labelClass.name} label with value ${value} was successfully added.`
});
} else {
toast({
title: 'Error',
description: 'Failed to add label',
variant: 'destructive'
});
}
};

return (
<Popover>
<PopoverTrigger asChild>
<Button variant="outline">
Add
<ChevronDown size={14} className="ml-1" />
</Button>
</PopoverTrigger>
<PopoverContent side="bottom" align="end">
<div className="flex flex-col space-y-2">
{Object.entries(labelClass.valueMap).map(([key, value], index) => (
<PopoverClose key={index}>
<div
onClick={() => {
addLabel(key, labelClass, LabelSource.MANUAL);
}}
className="cursor-pointer hover:bg-secondary-foreground/10 p-1 rounded border px-2"
>
{key}
</div>
</PopoverClose>
))}
</div>
</PopoverContent>
</Popover>
);
}
Loading