import styled from '@emotion/styled'; import {Breadcrumbs} from 'sentry/components/breadcrumbs'; import * as Layout from 'sentry/components/layouts/thirds'; import NoProjectMessage from 'sentry/components/noProjectMessage'; import {DatePageFilter} from 'sentry/components/organizations/datePageFilter'; import {EnvironmentPageFilter} from 'sentry/components/organizations/environmentPageFilter'; import PageFilterBar from 'sentry/components/organizations/pageFilterBar'; import {ProjectPageFilter} from 'sentry/components/organizations/projectPageFilter'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import {CurrencyUnit, DurationUnit, RateUnit} from 'sentry/utils/discover/fields'; import {decodeScalar} from 'sentry/utils/queryString'; import {MutableSearch} from 'sentry/utils/tokenizeSearch'; import {useLocation} from 'sentry/utils/useLocation'; import useOrganization from 'sentry/utils/useOrganization'; import { NumberOfPipelinesChart, PipelineDurationChart, TotalTokensUsedChart, } from 'sentry/views/llmMonitoring/llmMonitoringCharts'; import {PipelineSpansTable} from 'sentry/views/llmMonitoring/pipelineSpansTable'; import {MODULE_TITLE} from 'sentry/views/llmMonitoring/settings'; import {MetricReadout} from 'sentry/views/performance/metricReadout'; import * as ModuleLayout from 'sentry/views/performance/moduleLayout'; import {ModulePageProviders} from 'sentry/views/performance/modulePageProviders'; import {useModuleBreadcrumbs} from 'sentry/views/performance/utils/useModuleBreadcrumbs'; import {useSpanMetrics} from 'sentry/views/starfish/queries/useDiscover'; import { SpanFunction, SpanMetricsField, type SpanMetricsQueryFilters, } from 'sentry/views/starfish/types'; interface Props { params: { groupId: string; }; } type Query = { 'span.description'?: string; }; export function LLMMonitoringPage({params}: Props) { const location = useLocation(); const organization = useOrganization(); const {groupId} = params; const spanDescription = decodeScalar(location.query?.['span.description']); const filters: SpanMetricsQueryFilters = { 'span.group': groupId, 'span.category': 'ai.pipeline', }; const {data, isLoading: areSpanMetricsLoading} = useSpanMetrics( { search: MutableSearch.fromQueryObject(filters), fields: [ SpanMetricsField.SPAN_OP, 'count()', `${SpanFunction.SPM}()`, `avg(${SpanMetricsField.SPAN_DURATION})`, ], enabled: Boolean(groupId), }, 'api.ai-pipelines.view' ); const spanMetrics = data[0] ?? {}; const {data: totalTokenData, isLoading: isTotalTokenDataLoading} = useSpanMetrics( { search: MutableSearch.fromQueryObject({ 'span.category': 'ai', 'span.ai.pipeline.group': groupId, }), fields: [ 'ai_total_tokens_used()', 'ai_total_tokens_used(c:spans/ai.total_cost@usd)', ], enabled: Boolean(groupId), }, 'api.ai-pipelines.view' ); const tokenUsedMetric = totalTokenData[0] ?? {}; const crumbs = useModuleBreadcrumbs('ai'); return ( {MODULE_TITLE} ); } function PageWithProviders({params}: Props) { const location = useLocation(); const {'span.description': spanDescription} = location.query; return ( ); } export default PageWithProviders; const SpaceBetweenWrap = styled('div')` display: flex; justify-content: space-between; flex-wrap: wrap; gap: ${space(2)}; `; const MetricsRibbon = styled('div')` display: flex; flex-wrap: wrap; gap: ${space(4)}; `;