Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
9 changes: 8 additions & 1 deletion app/components/evaluations/CategoryMetricsTable.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use client";

import { CategoryMetric } from "@/app/lib/types/evaluation";
import VerdictBadge from "./VerdictBadge";

interface CategoryMetricsTableProps {
categoryMetrics: CategoryMetric[];
Expand Down Expand Up @@ -60,7 +61,13 @@ export default function CategoryMetricsTable({
{formatScore(row.avg_cosine)}
</td>
<td className="px-5 py-2.5 text-sm text-right tabular-nums text-text-primary">
{formatScore(row.avg_correctness)}
<span className="inline-flex items-center gap-1.5">
{formatScore(row.avg_correctness)}
<VerdictBadge
value={row.avg_correctness}
dataType="NUMERIC"
/>
</span>
</td>
</tr>
))}
Expand Down
10 changes: 9 additions & 1 deletion app/components/evaluations/DetailedResultsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ import {
} from "@/app/lib/utils/evaluation";
import { formatScoreValue, getScoreByName } from "@/app/lib/utils";
import { InfoTooltip } from "@/app/components/ui";
import { GroupedResultsTable } from "@/app/components/evaluations";
import {
GroupedResultsTable,
VerdictBadge,
} from "@/app/components/evaluations";
import { MarkdownContent } from "@/app/components/chat";

interface DetailedResultsTableProps {
Expand Down Expand Up @@ -202,6 +205,11 @@ export default function DetailedResultsTable({
>
{value}
</div>
<VerdictBadge
name={score?.name}
value={score?.value}
dataType={score?.data_type}
/>
{score?.comment && (
<InfoTooltip text={score.comment} />
)}
Expand Down
6 changes: 6 additions & 0 deletions app/components/evaluations/GroupedResultsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Fragment } from "react";
import { TraceScore, GroupedTraceItem } from "@/app/lib/types/evaluation";
import { formatScoreValue } from "@/app/lib/utils";
import { InfoTooltip } from "@/app/components/ui";
import VerdictBadge from "./VerdictBadge";
export default function GroupedResultsTable({
traces,
}: {
Expand Down Expand Up @@ -206,6 +207,11 @@ export default function GroupedResultsTable({
>
{value}
</div>
<VerdictBadge
name={score.name}
value={score.value}
dataType={score.data_type}
/>
{score?.comment && (
<InfoTooltip text={score.comment} />
)}
Expand Down
12 changes: 10 additions & 2 deletions app/components/evaluations/MetricsOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import type { EvalJob, SummaryScore } from "@/app/lib/types/evaluation";
import { Button } from "@/app/components/ui";
import { RefreshIcon, WarningTriangleIcon } from "@/app/components/icons";
import VerdictBadge from "./VerdictBadge";

interface MetricsOverviewProps {
job: EvalJob;
Expand Down Expand Up @@ -57,8 +58,15 @@ export default function MetricsOverview({
key={summary.name}
className="rounded-lg px-6 py-5 text-center flex-1 min-w-[180px] relative bg-bg-primary shadow-sm"
>
<div className="text-xs font-medium mb-2 text-text-secondary">
{summary.name}
<div className="flex items-center justify-center gap-1.5 mb-2">
<span className="text-xs font-medium text-text-secondary">
{summary.name}
</span>
<VerdictBadge
name={summary.name}
value={summary.avg}
dataType={summary.data_type}
/>
</div>
<div className="text-2xl font-bold text-text-primary">
{summary.avg !== undefined ? summary.avg.toFixed(3) : "N/A"}
Expand Down
6 changes: 6 additions & 0 deletions app/components/evaluations/ScoreDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import type { ScoreObject } from "@/app/lib/types/evaluation";
import { hasSummaryScores } from "@/app/lib/utils/evaluation";
import VerdictBadge from "./VerdictBadge";

interface ScoreDisplayProps {
score: ScoreObject | null;
Expand Down Expand Up @@ -75,6 +76,11 @@ export default function ScoreDisplay({
<span>{summary.name}:</span>
<span className="font-semibold text-[#171717]">{value}</span>
{std !== null && <span>±{std}</span>}
<VerdictBadge
name={summary.name}
value={summary.avg}
dataType={summary.data_type}
/>
</span>
);
})}
Expand Down
41 changes: 41 additions & 0 deletions app/components/evaluations/VerdictBadge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"use client";

import {
getVerdictBand,
VERDICT_LABELS,
VerdictBand,
} from "@/app/lib/utils/evaluation";

interface VerdictBadgeProps {
value: number | string | null | undefined;
dataType?: "NUMERIC" | "CATEGORICAL";
name?: string;
size?: "sm" | "md";
}

const VERDICT_CLASSES: Record<VerdictBand, string> = {
good: "bg-status-success-bg text-status-success-text",
needs_refinement: "bg-status-warning-bg text-status-warning-text",
needs_improvement: "bg-status-error-bg text-status-error-text",
};

export default function VerdictBadge({
value,
dataType,
name,
size = "sm",
}: VerdictBadgeProps) {
const band = getVerdictBand(value, dataType, name);
if (!band) return null;

const padding =
size === "md" ? "px-2.5 py-1 text-xs" : "px-2 py-0.5 text-[10px]";

return (
<span
className={`inline-flex items-center shrink-0 rounded-full font-semibold uppercase tracking-wide ${padding} ${VERDICT_CLASSES[band]}`}
>
{VERDICT_LABELS[band]}
</span>
);
}
1 change: 1 addition & 0 deletions app/components/evaluations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ export { default as MetricsOverview } from "./MetricsOverview";
export { default as RunEvaluationForm } from "./RunEvaluationForm";
export { default as RunModeBadge } from "./RunModeBadge";
export { default as ScoreDisplay } from "./ScoreDisplay";
export { default as VerdictBadge } from "./VerdictBadge";
export { default as ViewDatasetModal } from "./ViewDatasetModal";
30 changes: 30 additions & 0 deletions app/lib/utils/evaluation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,36 @@ import type {
TraceItem,
} from "@/app/lib/types/evaluation";

export type VerdictBand = "good" | "needs_refinement" | "needs_improvement";

export const VERDICT_LABELS: Record<VerdictBand, string> = {
good: "Good",
needs_refinement: "Needs Refinement",
needs_improvement: "Needs Improvement",
};

/**
* Judge-metric scores are banded 0-5: Good (4-5), Needs Refinement (2-3),
* Needs Improvement (0-1). Cosine scores and categorical/N/A entries carry
* no verdict, so this returns null for them.
*/
export function getVerdictBand(
value: number | string | null | undefined,
dataType: "NUMERIC" | "CATEGORICAL" | undefined,
name?: string,
): VerdictBand | null {
if (dataType === "CATEGORICAL") return null;
if (name && /cosine/i.test(name)) return null;
if (value === null || value === undefined) return null;

const numValue = Number(value);
if (!Number.isFinite(numValue)) return null;

if (numValue >= 4) return "good";
if (numValue >= 2) return "needs_refinement";
return "needs_improvement";
}

export function hasSummaryScores(
score: ScoreObject | null | undefined,
): score is NewScoreObjectV2 | BasicScoreObject {
Expand Down
Loading