import { PrettyJsonView } from "@/src/components/ui/PrettyJsonView"; import { type APIScoreV2, type TraceDomain, AnnotationQueueObjectType, isGenerationLike, } from "@langfuse/shared"; import { AggUsageBadge } from "@/src/components/token-usage-badge"; import { Badge } from "@/src/components/ui/badge"; import { type ObservationReturnTypeWithMetadata } from "@/src/server/api/routers/traces"; import { IOPreview } from "@/src/components/trace/IOPreview"; import { formatIntervalSeconds } from "@/src/utils/dates"; import { withDefault, StringParam, useQueryParam } from "use-query-params"; import ScoresTable from "@/src/components/table/use-cases/scores"; import { AnnotateDrawer } from "@/src/features/scores/components/AnnotateDrawer"; import useLocalStorage from "@/src/components/useLocalStorage"; import { CommentDrawerButton } from "@/src/features/comments/CommentDrawerButton"; import { api } from "@/src/utils/api"; import { NewDatasetItemFromExistingObject } from "@/src/features/datasets/components/NewDatasetItemFromExistingObject"; import { CreateNewAnnotationQueueItem } from "@/src/features/annotation-queues/components/CreateNewAnnotationQueueItem"; import { useMemo, useState } from "react"; import { usdFormatter } from "@/src/utils/numbers"; import { calculateDisplayTotalCost } from "@/src/components/trace/lib/helpers"; import { useIsAuthenticatedAndProjectMember } from "@/src/features/auth/hooks"; import { TabsBar, TabsBarContent, TabsBarList, TabsBarTrigger, } from "@/src/components/ui/tabs-bar"; import { BreakdownTooltip } from "@/src/components/trace/BreakdownToolTip"; import { InfoIcon } from "lucide-react"; import { LocalIsoDate } from "@/src/components/LocalIsoDate"; import { ItemBadge } from "@/src/components/ItemBadge"; import Link from "next/link"; import { Tabs, TabsList, TabsTrigger } from "@/src/components/ui/tabs"; import { usePostHogClientCapture } from "@/src/features/posthog-analytics/usePostHogClientCapture"; import { useRouter } from "next/router"; import { CopyIdsPopover } from "@/src/components/trace/CopyIdsPopover"; import { useJsonExpansion } from "@/src/components/trace/JsonExpansionContext"; export const TracePreview = ({ trace, observations, scores, commentCounts, viewType = "detailed", }: { trace: Omit & { latency?: number; input: string | null; output: string | null; metadata: string | null; }; observations: ObservationReturnTypeWithMetadata[]; scores: APIScoreV2[]; commentCounts?: Map; viewType?: "detailed" | "focused"; }) => { const [selectedTab, setSelectedTab] = useQueryParam( "view", withDefault(StringParam, "preview"), ); const [currentView, setCurrentView] = useLocalStorage<"pretty" | "json">( "jsonViewPreference", "pretty", ); const [isPrettyViewAvailable, setIsPrettyViewAvailable] = useState(false); const [emptySelectedConfigIds, setEmptySelectedConfigIds] = useLocalStorage< string[] >("emptySelectedConfigIds", []); const isAuthenticatedAndProjectMember = useIsAuthenticatedAndProjectMember( trace.projectId, ); const capture = usePostHogClientCapture(); const router = useRouter(); const { peek } = router.query; const showScoresTab = isAuthenticatedAndProjectMember && peek === undefined; const { expansionState, setFieldExpansion } = useJsonExpansion(); const traceMedia = api.media.getByTraceOrObservationId.useQuery( { traceId: trace.id, projectId: trace.projectId, }, { enabled: isAuthenticatedAndProjectMember, refetchOnWindowFocus: false, refetchOnMount: false, refetchOnReconnect: false, staleTime: 50 * 60 * 1000, // 50 minutes }, ); const totalCost = useMemo( () => calculateDisplayTotalCost({ allObservations: observations, }), [observations], ); const usageDetails = useMemo( () => observations .filter((o) => isGenerationLike(o.type)) .map((o) => o.usageDetails), [observations], ); return (
{trace.name}
{viewType === "detailed" && ( <>
)}
{trace.sessionId ? ( Session: {trace.sessionId} ) : null} {trace.userId ? ( User ID: {trace.userId} ) : null} {trace.environment ? ( Env: {trace.environment} ) : null} {viewType === "detailed" && ( <> {!!trace.latency && ( Latency: {formatIntervalSeconds(trace.latency)} )} {totalCost && ( isGenerationLike(o.type)) .map((o) => o.costDetails)} isCost > Total Cost: {usdFormatter(totalCost.toNumber())} )} {usageDetails.length > 0 && ( } variant="tertiary" /> )} {!!trace.release && ( Release: {trace.release} )} {!!trace.version && ( Version: {trace.version} )} )}
setSelectedTab(value)} > {viewType === "detailed" && ( Preview {showScoresTab && ( Scores )} {selectedTab.includes("preview") && isPrettyViewAvailable && ( { capture("trace_detail:io_mode_switch", { view: value }); setCurrentView(value as "pretty" | "json"); }} > Formatted JSON )} )} {/* show preview always if not detailed view */}
setFieldExpansion("input", expansion) } onOutputExpansionChange={(expansion) => setFieldExpansion("output", expansion) } />
m.field === "metadata") ?? [] } currentView={currentView} externalExpansionState={expansionState.metadata} onExternalExpansionChange={(expansion) => setFieldExpansion("metadata", expansion) } />
{showScoresTab && (
)}
); };