import {
HoverCard,
HoverCardContent,
HoverCardTrigger,
} from "@/src/components/ui/hover-card";
import {
type CategoricalAggregate,
type AggregatedScoreData,
} from "@langfuse/shared";
import { numberFormatter } from "@/src/utils/numbers";
import { cn } from "@/src/utils/tailwind";
import { BracesIcon, MessageCircleMore, Copy, Check } from "lucide-react";
import { JSONView } from "@/src/components/ui/CodeJsonViewer";
import { api } from "@/src/utils/api";
import useProjectIdFromURL from "@/src/hooks/useProjectIdFromURL";
import { Skeleton } from "@/src/components/ui/skeleton";
import React from "react";
import { copyTextToClipboard } from "@/src/utils/clipboard";
import { Button } from "@/src/components/ui/button";
const COLOR_MAP = new Map([
["True", "bg-light-green p-0.5 text-dark-green"],
["False", "bg-light-red p-0.5 text-dark-red"],
]);
const COLLAPSE_CATEGORICAL_SCORES_AFTER = 2;
const ScoreValueCounts = ({
valueCounts,
wrap,
}: {
valueCounts: CategoricalAggregate["valueCounts"];
wrap: boolean;
}) => {
return valueCounts.map(({ value, count }, index) => (
{value}
{`: ${numberFormatter(count, 0)}`}
{!wrap && index < valueCounts.length - 1 && (
{";"}
)}
));
};
export const ScoresTableCell = ({
aggregate,
displayFormat,
wrap = true,
hasMetadata,
}: {
aggregate: AggregatedScoreData;
displayFormat: "smart" | "aggregate";
wrap?: boolean;
hasMetadata?: boolean;
}) => {
const projectId = useProjectIdFromURL();
const [copied, setCopied] = React.useState(false);
const handleCopy = async (e: React.MouseEvent) => {
e.stopPropagation();
if (aggregate.comment) {
await copyTextToClipboard(aggregate.comment);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}
};
if (displayFormat === "smart" && aggregate.values.length === 1 && projectId) {
const value =
aggregate.type === "NUMERIC"
? aggregate.average.toFixed(4)
: aggregate.values[0];
return (
{value}
{aggregate.comment && (
)}
{hasMetadata && !!aggregate.id && (
)}
);
}
if (aggregate.type === "NUMERIC") {
return (
{`Ø ${aggregate.average.toFixed(4)}`}
);
}
return (
{aggregate.valueCounts.length > COLLAPSE_CATEGORICAL_SCORES_AFTER ? (
) : (
)}
);
};
function AggregateScoreMetadataPeek({
scoreId,
projectId,
}: {
scoreId: string;
projectId: string;
}) {
const [isOpen, setIsOpen] = React.useState(false);
const { data: metadata } = api.scores.getScoreMetadataById.useQuery(
{
projectId,
id: scoreId,
},
{
enabled: !!projectId && !!scoreId && isOpen,
trpc: {
context: {
skipBatch: true,
},
},
refetchOnMount: false,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
staleTime: Infinity,
},
);
const metadataLoaded = metadata && Object.keys(metadata).length > 0;
return (
{metadataLoaded ? (
) : (
)}
);
}