aiAnalyticsCharts.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. import styled from '@emotion/styled';
  2. import {t} from 'sentry/locale';
  3. import {space} from 'sentry/styles/space';
  4. import type {MetricsQueryApiResponseLastMeta} from 'sentry/types';
  5. import {MetricDisplayType} from 'sentry/utils/metrics/types';
  6. import {useMetricsQuery} from 'sentry/utils/metrics/useMetricsQuery';
  7. import usePageFilters from 'sentry/utils/usePageFilters';
  8. import {MetricChartContainer} from 'sentry/views/dashboards/metrics/chart';
  9. export function TotalTokensUsedChart() {
  10. const {selection, isReady: isGlobalSelectionReady} = usePageFilters();
  11. const {
  12. data: timeseriesData,
  13. isLoading,
  14. isError,
  15. error,
  16. } = useMetricsQuery(
  17. [
  18. {
  19. name: 'total',
  20. mri: `c:spans/ai.total_tokens.used@none`,
  21. op: 'sum',
  22. // TODO this double counts the (e.g.) langchain and openai token usage
  23. },
  24. ],
  25. selection,
  26. {
  27. intervalLadder: 'dashboard',
  28. }
  29. );
  30. if (!isGlobalSelectionReady) {
  31. return null;
  32. }
  33. if (isError) {
  34. return <div>{'' + error}</div>;
  35. }
  36. return (
  37. <TokenChartContainer>
  38. <PanelTitle>{t('Total tokens used')}</PanelTitle>
  39. <MetricChartContainer
  40. timeseriesData={timeseriesData}
  41. isLoading={isLoading}
  42. metricQueries={[
  43. {
  44. name: 'mql',
  45. formula: '$total',
  46. },
  47. ]}
  48. displayType={MetricDisplayType.AREA}
  49. chartHeight={200}
  50. />
  51. </TokenChartContainer>
  52. );
  53. }
  54. interface NumberOfPipelinesChartProps {
  55. groupId?: string;
  56. }
  57. export function NumberOfPipelinesChart({groupId}: NumberOfPipelinesChartProps) {
  58. const {selection, isReady: isGlobalSelectionReady} = usePageFilters();
  59. let query = 'span.category:"ai.pipeline"';
  60. if (groupId) {
  61. query = `${query} span.group:"${groupId}"`;
  62. }
  63. const {
  64. data: timeseriesData,
  65. isLoading,
  66. isError,
  67. error,
  68. } = useMetricsQuery(
  69. [
  70. {
  71. name: 'number',
  72. mri: `d:spans/exclusive_time@millisecond`,
  73. op: 'count',
  74. query,
  75. },
  76. ],
  77. selection,
  78. {
  79. intervalLadder: 'dashboard',
  80. }
  81. );
  82. if (!isGlobalSelectionReady) {
  83. return null;
  84. }
  85. if (isError) {
  86. return <div>{'' + error}</div>;
  87. }
  88. return (
  89. <TokenChartContainer>
  90. <PanelTitle>{t('Number of AI pipelines')}</PanelTitle>
  91. <MetricChartContainer
  92. timeseriesData={timeseriesData}
  93. isLoading={isLoading}
  94. metricQueries={[
  95. {
  96. name: 'mql',
  97. formula: '$number',
  98. },
  99. ]}
  100. displayType={MetricDisplayType.AREA}
  101. chartHeight={200}
  102. />
  103. </TokenChartContainer>
  104. );
  105. }
  106. interface PipelineDurationChartProps {
  107. groupId?: string;
  108. }
  109. export function PipelineDurationChart({groupId}: PipelineDurationChartProps) {
  110. const {selection, isReady: isGlobalSelectionReady} = usePageFilters();
  111. let query = 'span.category:"ai.pipeline"';
  112. if (groupId) {
  113. query = `${query} span.group:"${groupId}"`;
  114. }
  115. const {
  116. data: timeseriesData,
  117. isLoading,
  118. isError,
  119. error,
  120. } = useMetricsQuery(
  121. [
  122. {
  123. name: 'a',
  124. mri: `d:spans/duration@millisecond`,
  125. op: 'avg',
  126. query,
  127. },
  128. ],
  129. selection,
  130. {
  131. intervalLadder: 'dashboard',
  132. }
  133. );
  134. const lastMeta = timeseriesData?.meta?.findLast(_ => true);
  135. if (lastMeta && lastMeta.length >= 2) {
  136. // TODO hack: there is a bug somewhere that is dropping the unit
  137. (lastMeta[1] as MetricsQueryApiResponseLastMeta).unit = 'millisecond';
  138. }
  139. if (!isGlobalSelectionReady) {
  140. return null;
  141. }
  142. if (isError) {
  143. return <div>{'' + error}</div>;
  144. }
  145. return (
  146. <TokenChartContainer>
  147. <PanelTitle>{t('AI pipeline duration')}</PanelTitle>
  148. <MetricChartContainer
  149. timeseriesData={timeseriesData}
  150. isLoading={isLoading}
  151. metricQueries={[
  152. {
  153. name: 'mql',
  154. formula: '$a',
  155. },
  156. ]}
  157. displayType={MetricDisplayType.AREA}
  158. chartHeight={200}
  159. />
  160. </TokenChartContainer>
  161. );
  162. }
  163. const PanelTitle = styled('h5')`
  164. padding: ${space(3)} ${space(3)} 0;
  165. margin: 0;
  166. `;
  167. const TokenChartContainer = styled('div')`
  168. border: 1px solid ${p => p.theme.border};
  169. border-radius: ${p => p.theme.borderRadius};
  170. height: 100%;
  171. display: flex;
  172. flex-direction: column;
  173. `;