From 2124b3635945df2e749dd0a2a3adc278b21a7137 Mon Sep 17 00:00:00 2001 From: colin-sentry <161344340+colin-sentry@users.noreply.github.com> Date: Thu, 4 Apr 2024 16:32:49 -0400 Subject: [PATCH] Graph logic for AI analytics page (#68296) Adds time series graphs for prompt tokens and completion tokens --- static/app/routes.tsx | 4 +- .../{ai-analytics => aiAnalytics}/filters.tsx | 0 .../{ai-analytics => aiAnalytics}/index.tsx | 12 +++- .../{ai-analytics => aiAnalytics}/landing.tsx | 0 .../app/views/aiAnalytics/tokenUsageChart.tsx | 64 +++++++++++++++++++ 5 files changed, 77 insertions(+), 3 deletions(-) rename static/app/views/{ai-analytics => aiAnalytics}/filters.tsx (100%) rename static/app/views/{ai-analytics => aiAnalytics}/index.tsx (81%) rename static/app/views/{ai-analytics => aiAnalytics}/landing.tsx (100%) create mode 100644 static/app/views/aiAnalytics/tokenUsageChart.tsx diff --git a/static/app/routes.tsx b/static/app/routes.tsx index f3dd5dc4fc4b61..a5aa6ab2ef6b4d 100644 --- a/static/app/routes.tsx +++ b/static/app/routes.tsx @@ -1493,10 +1493,10 @@ function buildRoutes() { const aiAnalyticsRoutes = ( import('sentry/views/ai-analytics'))} + component={make(() => import('sentry/views/aiAnalytics'))} withOrgPath > - import('sentry/views/ai-analytics/landing'))} /> + import('sentry/views/aiAnalytics/landing'))} /> ); diff --git a/static/app/views/ai-analytics/filters.tsx b/static/app/views/aiAnalytics/filters.tsx similarity index 100% rename from static/app/views/ai-analytics/filters.tsx rename to static/app/views/aiAnalytics/filters.tsx diff --git a/static/app/views/ai-analytics/index.tsx b/static/app/views/aiAnalytics/index.tsx similarity index 81% rename from static/app/views/ai-analytics/index.tsx rename to static/app/views/aiAnalytics/index.tsx index 114d8259755336..dce6c51ad05921 100644 --- a/static/app/views/ai-analytics/index.tsx +++ b/static/app/views/aiAnalytics/index.tsx @@ -9,7 +9,8 @@ import PageFiltersContainer from 'sentry/components/organizations/pageFilters/co import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import useOrganization from 'sentry/utils/useOrganization'; -import AiAnalyticsFilters from 'sentry/views/ai-analytics/filters'; +import AiAnalyticsFilters from 'sentry/views/aiAnalytics/filters'; +import TokenUsageChart from 'sentry/views/aiAnalytics/tokenUsageChart'; function NoAccessComponent() { return ( @@ -35,6 +36,10 @@ function AiAnalyticsContainer() { setSearch(x)} query={search} /> + + + + @@ -56,6 +61,11 @@ const StyledBody = styled('div')` grid-template-areas: 'content saved-searches'; `; +const TwoColumns = styled('div')` + display: flex; + gap: ${space(2)}; +`; + const StyledMain = styled('section')` grid-area: content; padding: ${space(2)}; diff --git a/static/app/views/ai-analytics/landing.tsx b/static/app/views/aiAnalytics/landing.tsx similarity index 100% rename from static/app/views/ai-analytics/landing.tsx rename to static/app/views/aiAnalytics/landing.tsx diff --git a/static/app/views/aiAnalytics/tokenUsageChart.tsx b/static/app/views/aiAnalytics/tokenUsageChart.tsx new file mode 100644 index 00000000000000..13602ba78ea041 --- /dev/null +++ b/static/app/views/aiAnalytics/tokenUsageChart.tsx @@ -0,0 +1,64 @@ +import styled from '@emotion/styled'; + +import type {PageFilters} from 'sentry/types'; +import {MetricDisplayType} from 'sentry/utils/metrics/types'; +import {useMetricsQuery} from 'sentry/utils/metrics/useMetricsQuery'; +import withPageFilters from 'sentry/utils/withPageFilters'; +import {MetricChartContainer} from 'sentry/views/dashboards/metrics/chart'; + +interface TokenUsageChartProps { + metric: 'ai.total_tokens.used' | 'ai.prompt_tokens.used' | 'ai.completion_tokens.used'; + selection: PageFilters; + isGlobalSelectionReady?: boolean; +} + +function TokenUsageChart({selection, metric}: TokenUsageChartProps) { + const { + data: timeseriesData, + isLoading, + isError, + error, + } = useMetricsQuery( + [ + { + name: 'a', + mri: `c:custom/${metric}@tokens`, + op: 'sum', + }, + ], + selection, + { + intervalLadder: 'dashboard', + } + ); + + if (isError) { + return
{'' + error}
; + } + + return ( + + + + ); +} + +const TokenChartContainer = styled('div')` + overflow: hidden; + border: 1px solid ${p => p.theme.border}; + border-radius: ${p => p.theme.borderRadius}; + flex: 1 1 content; +`; + +export default withPageFilters(TokenUsageChart);