Skip to main content
Glama

@arizeai/phoenix-mcp

Official
by Arize-ai
ProjectMetricsPage.tsx7.97 kB
import { forwardRef, Suspense, useMemo } from "react"; import { useParams } from "react-router"; import { css } from "@emotion/react"; import { Alert, Flex, Heading, Loading, Text, useTimeRange, View, } from "@phoenix/components"; import { ErrorBoundary } from "@phoenix/components/exception"; import { ONE_MONTH_MS } from "@phoenix/constants/timeConstants"; import { TopModelsByCost } from "@phoenix/pages/project/metrics/TopModelsByCost"; import { TopModelsByToken } from "@phoenix/pages/project/metrics/TopModelsByToken"; import { TraceErrorsTimeSeries } from "@phoenix/pages/project/metrics/TraceErrorsTimeSeries"; import { fullTimeFormatter } from "@phoenix/utils/timeFormatUtils"; import { LLMSpanCountTimeSeries } from "./LLMSpanCountTimeSeries"; import { LLMSpanErrorsTimeSeries } from "./LLMSpanErrorsTimeSeries"; import { SpanAnnotationScoreTimeSeries } from "./SpanAnnotationScoreTimeSeries"; import { ToolSpanCountTimeSeries } from "./ToolSpanCountTimeSeries"; import { ToolSpanErrorsTimeSeries } from "./ToolSpanErrorsTimeSeries"; import { TraceCountTimeSeries } from "./TraceCountTimeSeries"; import { TraceLatencyPercentilesTimeSeries } from "./TraceLatencyPercentilesTimeSeries"; import { TraceTokenCostTimeSeries } from "./TraceTokenCostTimeSeries"; import { TraceTokenCountTimeSeries } from "./TraceTokenCountTimeSeries"; interface MetricPanelHeaderProps { title: string; subtitle?: string; } function MetricPanelHeader({ title, subtitle }: MetricPanelHeaderProps) { return ( <div css={css` padding: var(--ac-global-dimension-size-100) var(--ac-global-dimension-size-200) 0 var(--ac-global-dimension-size-200); display: flex; flex-direction: row; gap: var(--ac-global-dimension-size-100); `} className="dashboard-panel-header" > <Flex direction="column"> <Heading>{title}</Heading> {subtitle && ( <Text size="XS" color="grey-600"> {subtitle} </Text> )} </Flex> </div> ); } interface MetricPanelProps extends MetricPanelHeaderProps { children: React.ReactNode; } export const MetricPanel = forwardRef(function MetricPanel( { title, subtitle, children }: MetricPanelProps, ref: React.Ref<HTMLDivElement> ) { return ( <View borderWidth="thin" borderColor="grey-200" borderRadius="medium" height="100%" width="100%" data-testid={`dashboard-panel`} backgroundColor="grey-75" ref={ref} > <div css={css` display: flex; flex-direction: column; height: 100%; `} > <MetricPanelHeader title={title} subtitle={subtitle} /> <div css={css` flex: 1 1 auto; padding: var(--ac-global-dimension-size-200); height: 190px; overflow: auto; `} > <ErrorBoundary> <Suspense fallback={<Loading />}>{children}</Suspense> </ErrorBoundary> </div> </div> </View> ); }); export function ProjectMetricsPage() { const { projectId } = useParams(); if (!projectId) { throw new Error("projectId is required"); } const { timeRange: contextTimeRange } = useTimeRange(); const isOpenTimeRange = contextTimeRange.start === null || contextTimeRange.end === null; const timeRange = useMemo<TimeRange>(() => { const start = contextTimeRange.start; const end = contextTimeRange.end; if (start && end) { return { start, end }; } else if (!start && end) { return { start: new Date(end.getTime() - ONE_MONTH_MS), end }; } else if (start && !end) { return { start, end: new Date(start.getTime() + ONE_MONTH_MS) }; } else if (!start && !end) { return { start: new Date(Date.now() - ONE_MONTH_MS), end: new Date() }; } else { throw new Error( `Invalid time range: ${JSON.stringify(contextTimeRange)}` ); } }, [contextTimeRange]); return ( <main css={css` width: 100%; height: 100%; box-sizing: border-box; overflow-y: auto; `} > {isOpenTimeRange && ( <Alert variant="info" banner title="Time Range Adjusted"> {`This view does not support open-ended time ranges. Your time range has been set to ${fullTimeFormatter(timeRange.start)} to ${fullTimeFormatter(timeRange.end)}`} </Alert> )} <div css={css` display: flex; flex-direction: column; gap: var(--ac-global-dimension-size-200); padding: var(--ac-global-dimension-size-200); `} > <Flex direction="row" gap="size-200"> <MetricPanel title="Traces over time" subtitle="Overall volume of traces" > <TraceCountTimeSeries projectId={projectId} timeRange={timeRange} /> </MetricPanel> <MetricPanel title="Traces with errors" subtitle="Overall volume of traces with errors" > <TraceErrorsTimeSeries projectId={projectId} timeRange={timeRange} /> </MetricPanel> </Flex> <Flex direction="row" gap="size-200"> <MetricPanel title="Trace Latency" subtitle="Latency percentiles"> <TraceLatencyPercentilesTimeSeries projectId={projectId} timeRange={timeRange} /> </MetricPanel> <MetricPanel title="Annotation scores" subtitle="Average annotation scores" > <SpanAnnotationScoreTimeSeries projectId={projectId} timeRange={timeRange} /> </MetricPanel> </Flex> <Flex direction="row" gap="size-200"> <MetricPanel title="Cost" subtitle="Estimated cost in USD"> <TraceTokenCostTimeSeries projectId={projectId} timeRange={timeRange} /> </MetricPanel> <MetricPanel title="Top models by cost"> <TopModelsByCost projectId={projectId} timeRange={timeRange} /> </MetricPanel> </Flex> <Flex direction="row" gap="size-200"> <MetricPanel title="Token usage" subtitle="Token usage by prompt and completion" > <TraceTokenCountTimeSeries projectId={projectId} timeRange={timeRange} /> </MetricPanel> <MetricPanel title="Top models by tokens"> <TopModelsByToken projectId={projectId} timeRange={timeRange} /> </MetricPanel> </Flex> <Flex direction="row" gap="size-200"> <MetricPanel title="LLM spans" subtitle="LLM span count over time"> <LLMSpanCountTimeSeries projectId={projectId} timeRange={timeRange} /> </MetricPanel> <MetricPanel title="LLM spans with errors" subtitle="LLM spans with errors over time" > <LLMSpanErrorsTimeSeries projectId={projectId} timeRange={timeRange} /> </MetricPanel> </Flex> <Flex direction="row" gap="size-200"> <MetricPanel title="Tool spans" subtitle="Tool span count over time"> <ToolSpanCountTimeSeries projectId={projectId} timeRange={timeRange} /> </MetricPanel> <MetricPanel title="Tool spans with errors" subtitle="Tool spans with errors over time" > <ToolSpanErrorsTimeSeries projectId={projectId} timeRange={timeRange} /> </MetricPanel> </Flex> </div> </main> ); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Arize-ai/phoenix'

If you have feedback or need assistance with the MCP directory API, please join our Discord server