diff --git a/dashboards/README.md b/dashboards/README.md index dbc00cb..6c8d5df 100644 --- a/dashboards/README.md +++ b/dashboards/README.md @@ -6,3 +6,6 @@ This directory contains the Grafana dashboards for the AI DIAL Realtime Analytic - [DIAL Analytics](dial_analytics.json) - This dashboard contains common metrics and visualizations - [DIAL Analytics Raw Data](dial_analytics_raw_data.json) - This dashboard contains simple time-series view +- [DIAL Analytics Aggregated Reports](dial_analytics_agg.json) - This dashboard is the aggregated version of DIAL Analytics. +- [DIAL Project Insights](dial_project_insights.json) - This dashboard provides detailed metrics and key performance indicators (KPIs) for individual projects, facilitating targeted analysis. +- [DIAL User Insights](dial_user_insights.json) - This dashboard offers user-specific insights, including usage patterns, cost breakdowns, and percentile rankings. \ No newline at end of file diff --git a/dashboards/dial_analytics_agg.json b/dashboards/dial_analytics_agg.json new file mode 100644 index 0000000..4273e99 --- /dev/null +++ b/dashboards/dial_analytics_agg.json @@ -0,0 +1,873 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 4, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 2, + "x": 0, + "y": 0 + }, + "id": 16, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "/.*/", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"experimental\"\r\n\r\n// Constants\r\nthreshold_duration_ns = ${threshold_duration_ns} // 1 day-1ns in nanoseconds\r\nsix_hours_ns = ${six_hours_ns} // 6 hours in nanoseconds\r\n\r\n// Calculate the time range duration\r\ntime_diff_ns = int(v: v.timeRangeStop) - int(v: v.timeRangeStart)\r\n\r\n// Calculate remainder for 6-hour alignment at start and end\r\nstart_remainder_ns = int(v: v.timeRangeStart) % six_hours_ns\r\nend_remainder_ns_pre = int(v: v.timeRangeStop) % six_hours_ns\r\n// Extract the hour from timeRangeStop in hours (convert nanoseconds to hours)\r\ntime_hour = int(v: int(v: v.timeRangeStop) % 86400000000000) / 3600000000000\r\n\r\n// Check if the end time is in xx:59:59 for the specified hours (05, 11, 17, 23)\r\nend_remainder_ns = ${end_reminder_calc}\r\n\r\n// Bucket selection logic based on total time range duration\r\nbucket_default_only = time_diff_ns <= threshold_duration_ns\r\n\r\n// Helper function to query bucket\r\ndefault_bucket_query = (start, stop) => from(bucket: \"${INFLUX_BUCKET}\")\r\n |> range(start: start, stop: stop)\r\n |> filter(fn: (r) => r._measurement == \"analytics\" and r._field == \"user_hash\")\r\n |> group()\r\n |> distinct()\r\n\r\nagg_bucket_query = (start, stop) => from(bucket: \"${INFLUX_BUCKET}_agg_stats\")\r\n |> range(start: start, stop: stop)\r\n |> filter(fn: (r) => r._measurement == \"analytics\" and r._field == \"user_hash\")\r\n |> group()\r\n |> distinct()\r\n\r\n// Query data for the start from the default bucket if the start time is not aligned\r\ndata_default_start = \r\n if start_remainder_ns > 0 and not bucket_default_only then ${data_default_start} \r\n else from(bucket: \"${INFLUX_BUCKET}\") |> limit(n: 0)\r\n\r\n// Query data for the aggregated bucket (middle part)\r\ndata_agg = \r\n if not bucket_default_only then ${data_agg}\r\n else from(bucket: \"${INFLUX_BUCKET}_agg_stats\") |> limit(n: 0)\r\n\r\n// Query data for the end from the default bucket if the end time is not aligned\r\ndata_default_end = \r\n if end_remainder_ns > 0 then ${data_default_end}\r\n else from(bucket: \"${INFLUX_BUCKET}\") |> limit(n: 0)\r\n\r\n// Combine data from all buckets (start, middle, end)\r\ncombined_data = ${combine_data}\r\n\r\n// Apply final grouping and counting to get the total unique user_hash count\r\nfinalData = combined_data\r\n |> group()\r\n |> distinct()\r\n |> count()\r\n\r\nfinalData\r\n", + "refId": "A" + } + ], + "title": "Unique Users", + "type": "stat" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "gridPos": { + "h": 10, + "w": 22, + "x": 2, + "y": 0 + }, + "id": 12, + "options": { + "datasource_count_field": "_value", + "datasource_tags_field": "topic", + "series_index": 0, + "wordCloudOptions": { + "deterministic": true, + "enableTooltip": true, + "fontFamily": "arial", + "fontSizes": [ + 15, + 80 + ], + "padding": 1, + "rotationAngles": [ + 0, + 0 + ], + "rotations": 2, + "scale": "sqrt", + "spiral": "archimedean", + "transitionDuration": 800 + } + }, + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"experimental\"\r\n\r\n// Constants\r\nthreshold_duration_ns = ${threshold_duration_ns} // 1 day-1ns in nanoseconds\r\nsix_hours_ns = ${six_hours_ns} // 6 hours in nanoseconds\r\n\r\n// Calculate the time range duration\r\ntime_diff_ns = int(v: v.timeRangeStop) - int(v: v.timeRangeStart)\r\n\r\n// Calculate remainder for 6-hour alignment at start and end\r\nstart_remainder_ns = int(v: v.timeRangeStart) % six_hours_ns\r\nend_remainder_ns_pre = int(v: v.timeRangeStop) % six_hours_ns\r\n// Extract the hour from timeRangeStop in hours (convert nanoseconds to hours)\r\ntime_hour = int(v: int(v: v.timeRangeStop) % 86400000000000) / 3600000000000\r\n\r\n// Check if the end time is in xx:59:59 for the specified hours (05, 11, 17, 23)\r\nend_remainder_ns = ${end_reminder_calc}\r\n\r\n// Bucket selection logic based on total time range duration\r\nbucket_default_only = time_diff_ns <= threshold_duration_ns\r\n\r\n// Helper function to query default bucket\r\ndefault_bucket_query = (start, stop) => from(bucket: \"${INFLUX_BUCKET}\")\r\n |> range(start: start, stop: stop)\r\n |> filter(fn: (r) => r._measurement == \"analytics\")\r\n |> filter(fn: (r) => r._field == \"number_request_messages\")\r\n |> map(fn: (r) => ({r with _field: \"topic_count\"})) // Map _field to \"topic_count\"\r\n |> group(columns: [\"topic\"])\r\n |> count()\r\n \r\n\r\n// Helper function to query aggregated bucket\r\nagg_bucket_query = (start, stop) => from(bucket: \"${INFLUX_BUCKET}_agg_topic\")\r\n |> range(start: start, stop: stop)\r\n |> filter(fn: (r) => r._measurement == \"analytics\" and r._field == \"topic_count\")\r\n |> group(columns: [\"topic\"])\r\n |> sum(column: \"_value\")\r\n\r\n// Query data for the start from the default bucket if the start time is not aligned\r\ndata_default_start = \r\n if start_remainder_ns > 0 and not bucket_default_only then ${data_default_start} \r\n else from(bucket: \"${INFLUX_BUCKET}\") |> limit(n: 0)\r\n\r\n// Query data for the aggregated bucket (middle part)\r\ndata_agg = \r\n if not bucket_default_only then ${data_agg}\r\n else from(bucket: \"${INFLUX_BUCKET}_agg_stats\") |> limit(n: 0)\r\n\r\n// Query data for the end from the default bucket if the end time is not aligned\r\ndata_default_end = \r\n if end_remainder_ns > 0 then ${data_default_end}\r\n else from(bucket: \"${INFLUX_BUCKET}\") |> limit(n: 0)\r\n\r\n// Combine data from all buckets (start, middle, end)\r\ncombined_data = ${combine_data}\r\n\r\n// Final aggregation over the entire dataset\r\nfinalData = combined_data\r\n\r\n |> map(fn: (r) => ({r with topic: r.topic})) // Explicitly preserve topic field\r\n |> map(fn: (r) => ({r with _start: v.timeRangeStart})) // Add static start time\r\n |> map(fn: (r) => ({r with _stop: v.timeRangeStop})) // Add static start time\r\n |> group(columns: [\"_start\",\"_stop\",\"topic\"]) // Ensure were grouping by topic\r\n |> sum(column: \"_value\") // Sum the values by topic\r\n |> group()\r\n\r\nfinalData\r\n\r\n\r\n", + "refId": "A" + } + ], + "title": "Popular Topics", + "type": "magnesium-wordcloud-panel" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "description": "", + "gridPos": { + "h": 15, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 14, + "options": { + "config": { + "displayModeBar": false + }, + "data": "", + "layout": { + "font": { + "color": "lightgrey" + }, + "margin": { + "t": 0 + }, + "paper_bgcolor": "rgba(0,0,0,0)", + "plot_bgcolor": "rgba(0,0,0,0)", + "xaxis": { + "automargin": true, + "autorange": true, + "categoryorder": "category ascending", + "range": [ + -0.5, + 461.5 + ], + "showgrid": false, + "showticklabels": true, + "type": "category" + }, + "yaxis": { + "automargin": true, + "autorange": true, + "range": [ + -0.5, + 403.5 + ], + "showgrid": false, + "type": "category" + } + }, + "onclick": "//console.log(data)\n//window.updateVariables({query:{'var-project':'test'}, partial: true})", + "script": "var title = data.series[0].fields.find(x => x.name === \"title\")?.values\nvar topic = data.series[0].fields.find(x => x.name === \"topic\")?.values\nvar count = data.series[0].fields.find(x => x.name === \"_value\")?.values\n\nvar trace = {\n x: title?.buffer || title || [\"No data\"],\n y: topic?.buffer || topic || [\"No data\"],\n z: count?.buffer || count || [NaN],\n type: 'heatmap',\n colorscale: \"YlOrRd\",\n};\n\nreturn {data:[trace]};" + }, + "pluginVersion": "9.2.4", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"experimental\"\r\nimport \"influxdata/influxdb/schema\"\r\n\r\n// Constants\r\nthreshold_duration_ns = ${threshold_duration_ns} // 1 day-1ns in nanoseconds\r\nsix_hours_ns = ${six_hours_ns} // 6 hours in nanoseconds\r\n\r\n// Calculate the time range duration\r\ntime_diff_ns = int(v: v.timeRangeStop) - int(v: v.timeRangeStart)\r\n\r\n// Calculate remainder for 6-hour alignment at start and end\r\nstart_remainder_ns = int(v: v.timeRangeStart) % six_hours_ns\r\nend_remainder_ns_pre = int(v: v.timeRangeStop) % six_hours_ns\r\n// Extract the hour from timeRangeStop in hours (convert nanoseconds to hours)\r\ntime_hour = int(v: int(v: v.timeRangeStop) % 86400000000000) / 3600000000000\r\n\r\n// Check if the end time is in xx:59:59 for the specified hours (05, 11, 17, 23)\r\nend_remainder_ns = ${end_reminder_calc}\r\n\r\n// Bucket selection logic based on total time range duration\r\nbucket_default_only = time_diff_ns <= threshold_duration_ns\r\n\r\n// Helper function to query the default bucket\r\ndefault_bucket_query = (start, stop) => from(bucket: \"${INFLUX_BUCKET}\")\r\n |> range(start: start, stop: stop)\r\n |> filter(fn: (r) => r._measurement == \"analytics\")\r\n |> filter(fn: (r) => r._field == \"number_request_messages\")\r\n |> group(columns: [\"topic\", \"title\"]) \r\n |> count() // Counting occurrences if non-aggregated\r\n\r\n// Helper function to query the aggregated bucket\r\nagg_bucket_query = (start, stop) => from(bucket: \"${INFLUX_BUCKET}_agg_topic\")\r\n |> range(start: start, stop: stop)\r\n |> filter(fn: (r) => r._measurement == \"analytics\")\r\n |> filter(fn: (r) => r._field == \"topic_count\")\r\n |> group(columns: [\"topic\", \"title\"]) \r\n |> sum(column: \"_value\") // Summing the values if aggregated\r\n\r\n// Query data for the start from the default bucket if the start time is not aligned\r\ndata_default_start = \r\n if start_remainder_ns > 0 and not bucket_default_only then ${data_default_start} \r\n else from(bucket: \"${INFLUX_BUCKET}\") |> limit(n: 0)\r\n\r\n// Query data for the aggregated bucket (middle part)\r\ndata_agg = \r\n if not bucket_default_only then ${data_agg}\r\n else from(bucket: \"${INFLUX_BUCKET}_agg_stats\") |> limit(n: 0)\r\n\r\n// Query data for the end from the default bucket if the end time is not aligned\r\ndata_default_end = \r\n if end_remainder_ns > 0 then ${data_default_end}\r\n else from(bucket: \"${INFLUX_BUCKET}\") |> limit(n: 0)\r\n\r\n// Combine data from all buckets (start, middle, end)\r\ncombined_data = ${combine_data}\r\n\r\n// Conditional logic to branch based on the time difference\r\nfinalData = \r\n combined_data\r\n // }))\r\n //|> map(fn: (r) => ({r with topic: r.topic})) // Explicitly preserve topic field\r\n |> map(fn: (r) => ({r with _start: v.timeRangeStart})) // Add static start time\r\n |> map(fn: (r) => ({r with _stop: v.timeRangeStop})) // Add static start time\r\n |> group(columns: [\"_start\",\"_stop\",\"topic\", \"title\"]) \r\n |> sum(column: \"_value\") // Summing the values if aggregated\r\n\r\n\r\nfinalData\r\n |> group()\r\n", + "refId": "A" + } + ], + "title": "Title-Topic Heatmap", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "topic": " " + } + } + } + ], + "type": "ae3e-plotly-panel" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "displayName": "Requests", + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Value" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 25 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"experimental\"\r\n\r\n\r\n// Constants\r\nthreshold_duration_ns = ${threshold_duration_ns} // 1 day-1ns in nanoseconds\r\nsix_hours_ns = ${six_hours_ns} // 6 hours in nanoseconds\r\n\r\n// Calculate the time range duration\r\ntime_diff_ns = int(v: v.timeRangeStop) - int(v: v.timeRangeStart)\r\n\r\n// Calculate remainder for 6-hour alignment at start and end\r\nstart_remainder_ns = int(v: v.timeRangeStart) % six_hours_ns\r\nend_remainder_ns_pre = int(v: v.timeRangeStop) % six_hours_ns\r\n\r\n// Extract the hour from timeRangeStop in hours (convert nanoseconds to hours)\r\ntime_hour = int(v: int(v: v.timeRangeStop) % 86400000000000) / 3600000000000\r\n\r\n// Check if the end time is in xx:59:59 for the specified hours (05, 11, 17, 23)\r\nend_remainder_ns = ${end_reminder_calc}\r\n\r\n// Bucket selection logic based on total time range duration\r\nbucket_default_only = time_diff_ns <= threshold_duration_ns\r\n\r\n// Helper function to query default bucket\r\ndefault_bucket_query = (start, stop) => from(bucket: \"${INFLUX_BUCKET}\")\r\n |> range(start: start, stop: stop)\r\n |> filter(fn: (r) => r._measurement == \"analytics\")\r\n |> filter(fn: (r) => r._field == \"number_request_messages\")\r\n |> group()\r\n |> aggregateWindow(every: v.windowPeriod, fn: count)\r\n |> keep(columns: [\"_time\", \"_value\"])\r\n\r\n// Helper function to query aggregated bucket\r\nagg_bucket_query = (start, stop) => from(bucket: \"${INFLUX_BUCKET}_agg_stats\")\r\n |> range(start: start, stop: stop)\r\n |> filter(fn: (r) => r._measurement == \"analytics\")\r\n |> filter(fn: (r) => r._field == \"request_count\")\r\n |> group()\r\n |> aggregateWindow(every: v.windowPeriod, fn: sum, column: \"_value\") // Sum the request_count column\r\n |> fill(value: 0) \r\n |> keep(columns: [\"_time\", \"_value\"]) \r\n\r\n// Query data for the start from the default bucket if the start time is not aligned\r\ndata_default_start = \r\n if start_remainder_ns > 0 and not bucket_default_only then ${data_default_start} \r\n else from(bucket: \"${INFLUX_BUCKET}\") |> limit(n: 0)\r\n\r\n// Query data for the aggregated bucket (middle part)\r\ndata_agg = \r\n if not bucket_default_only then ${data_agg}\r\n else from(bucket: \"${INFLUX_BUCKET}_agg_stats\") |> limit(n: 0)\r\n\r\n// Query data for the end from the default bucket if the end time is not aligned\r\ndata_default_end = \r\n if end_remainder_ns > 0 then ${data_default_end}\r\n else from(bucket: \"${INFLUX_BUCKET}\") |> limit(n: 0)\r\n\r\n// Combine data from all buckets (start, middle, end)\r\nfinalData = ${combine_data}\r\n\r\nfinalData\r\n", + "refId": "A" + } + ], + "title": "System Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "money" + }, + "properties": [ + { + "id": "unit", + "value": "currencyUSD" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "NaN": { + "index": 0, + "text": "Not configured" + } + }, + "type": "value" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 15, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 17, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": true, + "fields": [ + "request_count", + "prompt_tokens", + "completion_tokens", + "money" + ], + "reducer": [ + "sum" + ], + "show": true + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Money" + } + ] + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "hide": false, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"strings\"\r\nimport \"regexp\"\r\nimport \"array\"\r\nimport \"experimental\"\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Constants\r\nthreshold_duration_ns = ${threshold_duration_ns} // 1 day-1ns in nanoseconds\r\nsix_hours_ns = ${six_hours_ns} // 6 hours in nanoseconds\r\n\r\n// Calculate the time range duration\r\ntime_diff_ns = int(v: v.timeRangeStop) - int(v: v.timeRangeStart)\r\n\r\n// Calculate remainder for 6-hour alignment at start and end\r\nstart_remainder_ns = int(v: v.timeRangeStart) % six_hours_ns\r\nend_remainder_ns_pre = int(v: v.timeRangeStop) % six_hours_ns\r\n// Extract the hour from timeRangeStop in hours (convert nanoseconds to hours)\r\ntime_hour = int(v: int(v: v.timeRangeStop) % 86400000000000) / 3600000000000\r\n\r\n// Check if the end time is in xx:59:59 for the specified hours (05, 11, 17, 23)\r\nend_remainder_ns = ${end_reminder_calc}\r\n\r\n// Bucket selection logic based on total time range duration\r\nbucket_default_only = time_diff_ns <= threshold_duration_ns\r\n\r\n// Helper function to query default bucket\r\ndefault_bucket_query = (start, stop) => from(bucket: \"${INFLUX_BUCKET}\")\r\n |> range(start: start, stop: stop)\r\n |> filter(fn: (r) => r._measurement == \"analytics\")\r\n |> filter(fn: (r) => r._field == \"prompt_tokens\" or r._field == \"completion_tokens\" or r._field == \"number_request_messages\" or r._field == \"user_hash\" or r._field == \"price\"or r._field == \"request_count\")\r\n |> schema.fieldsAsCols()\r\n |> group(columns: [\"project_id\", \"deployment\", \"model\", \"user_hash\"])\r\n |> reduce(\r\n fn: (r, accumulator) => ({\r\n request_count: accumulator.request_count + 1,\r\n prompt_tokens: getOrDefault(f: r.prompt_tokens, d: 0) + accumulator.prompt_tokens,\r\n completion_tokens: getOrDefault(f: r.completion_tokens, d: 0) + accumulator.completion_tokens,\r\n money: getOrDefault(f: r.price, d: 0.0) + accumulator.money,\r\n user_count: 1\r\n }),\r\n identity: {request_count: 0, prompt_tokens: 0, completion_tokens: 0, money: 0.0, user_count: 0}\r\n )\r\n\r\n\r\n // Helper function to query aggregated bucket\r\n agg_bucket_query = (start, stop) => from(bucket: \"${INFLUX_BUCKET}_agg_stats\")\r\n |> range(start: start, stop: stop)\r\n |> filter(fn: (r) => r._field == \"prompt_tokens\" or r._field == \"completion_tokens\" or r._field == \"number_request_messages\" or r._field == \"user_hash\" or r._field == \"price\"or r._field == \"request_count\")\r\n |> schema.fieldsAsCols()\r\n |> group(columns: [\"project_id\", \"deployment\", \"model\", \"user_hash\"])\r\n |> reduce(\r\n fn: (r, accumulator) => ({\r\n request_count: getOrDefault(f: r.request_count, d: 0) + accumulator.request_count,\r\n prompt_tokens: getOrDefault(f: r.prompt_tokens, d: 0) + accumulator.prompt_tokens,\r\n completion_tokens: getOrDefault(f: r.completion_tokens, d: 0) + accumulator.completion_tokens,\r\n money: getOrDefault(f: r.price, d: 0.0) + accumulator.money,\r\n user_count: 1\r\n }),\r\n identity: {request_count: 0, prompt_tokens: 0, completion_tokens: 0, money: 0.0, user_count: 0}\r\n )\r\n\r\n\r\n// Query data for the start from the default bucket if the start time is not aligned\r\ndata_default_start = \r\n if start_remainder_ns > 0 and not bucket_default_only then ${data_default_start} \r\n else from(bucket: \"${INFLUX_BUCKET}\") |> limit(n: 0)\r\n\r\n// Query data for the aggregated bucket (middle part)\r\ndata_agg = \r\n if not bucket_default_only then ${data_agg}\r\n else from(bucket: \"${INFLUX_BUCKET}_agg_stats\") |> limit(n: 0)\r\n\r\n// Query data for the end from the default bucket if the end time is not aligned\r\ndata_default_end = \r\n if end_remainder_ns > 0 then ${data_default_end}\r\n else from(bucket: \"${INFLUX_BUCKET}\") |> limit(n: 0)\r\n\r\n// Combine data from all buckets (start, middle, end)\r\ncombined_data = ${combine_data}\r\n// User count is slightly differently calculated for the agg and for the start/end piece\r\nuser_count_value = if bucket_default_only then 0\r\n else -1\r\n// Combine default and agg buckets data \r\ncombined_data\r\n |> group(columns: [\"project_id\", \"deployment\", \"model\",\"user_hash\"])\r\n |> reduce(\r\n fn: (r, accumulator) => ({\r\n // user_count: accumulator.user_count + 1,\r\n request_count: r.request_count + accumulator.request_count,\r\n prompt_tokens: r.prompt_tokens + accumulator.prompt_tokens,\r\n completion_tokens: r.completion_tokens + accumulator.completion_tokens,\r\n money: r.money + accumulator.money\r\n }),\r\n identity: {request_count: 0, prompt_tokens: 0, completion_tokens: 0, money: 0.0}\r\n )\r\n |> group(columns: [\"project_id\", \"deployment\", \"model\"])\r\n |> reduce(\r\n fn: (r, accumulator) => ({\r\n user_count: accumulator.user_count + 1,\r\n request_count: r.request_count + accumulator.request_count,\r\n prompt_tokens: r.prompt_tokens + accumulator.prompt_tokens,\r\n completion_tokens: r.completion_tokens + accumulator.completion_tokens,\r\n money: r.money + accumulator.money\r\n }),\r\n identity: {user_count: user_count_value, request_count: 0, prompt_tokens: 0, completion_tokens: 0, money: 0.0}\r\n )\r\n |> group()\r\n", + "refId": "A" + } + ], + "title": "Stats Table", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "_time": true + }, + "indexByName": { + "completion_tokens": 6, + "deployment": 1, + "model": 2, + "money": 7, + "project_id": 0, + "prompt_tokens": 5, + "request_count": 4, + "user_count": 3 + }, + "renameByName": { + "completion_tokens": "Completion tokens", + "deployment": "Deployment", + "model": "Model", + "money": "Money", + "number_request_messages": "", + "project_id": "Project", + "prompt_tokens": "Prompt tokens", + "request_count": "Request count", + "user_count": "Users" + } + } + }, + { + "id": "sortBy", + "options": { + "fields": {}, + "sort": [ + { + "desc": true, + "field": "Money" + } + ] + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "money" + }, + "properties": [ + { + "id": "unit", + "value": "currencyUSD" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "NaN": { + "index": 0, + "text": "Not configured" + } + }, + "type": "value" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 15, + "w": 24, + "x": 0, + "y": 49 + }, + "id": 7, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": true, + "fields": "", + "reducer": [ + "sum" + ], + "show": true + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Money" + } + ] + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "hide": false, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"strings\"\r\nimport \"regexp\"\r\nimport \"array\"\r\nimport \"experimental\"\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Constants\r\nthreshold_duration_ns = ${threshold_duration_ns} // 1 day-1ns in nanoseconds\r\nsix_hours_ns = ${six_hours_ns} // 6 hours in nanoseconds\r\n\r\n// Calculate the time range duration\r\ntime_diff_ns = int(v: v.timeRangeStop) - int(v: v.timeRangeStart)\r\n\r\n// Calculate remainder for 6-hour alignment at start and end\r\nstart_remainder_ns = int(v: v.timeRangeStart) % six_hours_ns\r\nend_remainder_ns_pre = int(v: v.timeRangeStop) % six_hours_ns\r\n// Extract the hour from timeRangeStop in hours (convert nanoseconds to hours)\r\ntime_hour = int(v: int(v: v.timeRangeStop) % 86400000000000) / 3600000000000\r\n\r\n// Check if the end time is in xx:59:59 for the specified hours (05, 11, 17, 23)\r\nend_remainder_ns = ${end_reminder_calc}\r\n\r\n// Bucket selection logic based on total time range duration\r\nbucket_default_only = time_diff_ns <= threshold_duration_ns\r\n\r\n// Helper function to query default bucket\r\ndefault_bucket_query = (start, stop) => from(bucket: \"${INFLUX_BUCKET}\")\r\n |> range(start: start, stop: stop)\r\n |> filter(fn: (r) => r._measurement == \"analytics\")\r\n |> filter(fn: (r) => r._field == \"prompt_tokens\" or r._field == \"completion_tokens\" or r._field == \"number_request_messages\" or r._field == \"price\"or r._field == \"request_count\")\r\n |> schema.fieldsAsCols()\r\n |> group(columns: [\"project_id\"])\r\n |> reduce(\r\n fn: (r, accumulator) => ({\r\n request_count: accumulator.request_count + 1,\r\n prompt_tokens: getOrDefault(f: r.prompt_tokens, d: 0) + accumulator.prompt_tokens,\r\n completion_tokens: getOrDefault(f: r.completion_tokens, d: 0) + accumulator.completion_tokens,\r\n money: getOrDefault(f: r.price, d: 0.0) + accumulator.money\r\n }),\r\n identity: {request_count: 0, prompt_tokens: 0, completion_tokens: 0, money: 0.0}\r\n )\r\n\r\n\r\n // Helper function to query aggregated bucket\r\n agg_bucket_query = (start, stop) => from(bucket: \"${INFLUX_BUCKET}_agg_stats\")\r\n |> range(start: start, stop: stop)\r\n |> filter(fn: (r) => r._field == \"prompt_tokens\" or r._field == \"completion_tokens\" or r._field == \"number_request_messages\" or r._field == \"price\"or r._field == \"request_count\")\r\n |> schema.fieldsAsCols()\r\n |> group(columns: [\"project_id\"])\r\n |> reduce(\r\n fn: (r, accumulator) => ({\r\n request_count: getOrDefault(f: r.request_count, d: 0) + accumulator.request_count,\r\n prompt_tokens: getOrDefault(f: r.prompt_tokens, d: 0) + accumulator.prompt_tokens,\r\n completion_tokens: getOrDefault(f: r.completion_tokens, d: 0) + accumulator.completion_tokens,\r\n money: getOrDefault(f: r.price, d: 0.0) + accumulator.money\r\n }),\r\n identity: {request_count: 0, prompt_tokens: 0, completion_tokens: 0, money: 0.0}\r\n )\r\n\r\n\r\n// Query data for the start from the default bucket if the start time is not aligned\r\ndata_default_start = \r\n if start_remainder_ns > 0 and not bucket_default_only then ${data_default_start} \r\n else from(bucket: \"${INFLUX_BUCKET}\") |> limit(n: 0)\r\n\r\n// Query data for the aggregated bucket (middle part)\r\ndata_agg = \r\n if not bucket_default_only then ${data_agg}\r\n else from(bucket: \"${INFLUX_BUCKET}_agg_stats\") |> limit(n: 0)\r\n\r\n// Query data for the end from the default bucket if the end time is not aligned\r\ndata_default_end = \r\n if end_remainder_ns > 0 then ${data_default_end}\r\n else from(bucket: \"${INFLUX_BUCKET}\") |> limit(n: 0)\r\n\r\n// Combine data from all buckets (start, middle, end)\r\ncombined_data = ${combine_data}\r\n\r\ncombined_data\r\n |> group(columns: [\"project_id\"])\r\n |> reduce(\r\n fn: (r, accumulator) => ({\r\n request_count: r.request_count + accumulator.request_count,\r\n prompt_tokens: r.prompt_tokens + accumulator.prompt_tokens,\r\n completion_tokens: r.completion_tokens + accumulator.completion_tokens,\r\n money: r.money + accumulator.money\r\n }),\r\n identity: {request_count: 0, prompt_tokens: 0, completion_tokens: 0, money: 0.0}\r\n )\r\n |> group()\r\n", + "refId": "A" + } + ], + "title": "Project Stats Table", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "_time": true + }, + "indexByName": { + "completion_tokens": 3, + "money": 4, + "project_id": 0, + "prompt_tokens": 2, + "request_count": 1 + }, + "renameByName": { + "completion_tokens": "Completion tokens", + "model": "", + "money": "Money", + "number_request_messages": "", + "project_id": "Project", + "prompt_tokens": "Prompt tokens", + "request_count": "Request count" + } + } + }, + { + "id": "sortBy", + "options": { + "fields": {}, + "sort": [ + { + "desc": true, + "field": "Money" + } + ] + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "money" + }, + "properties": [ + { + "id": "unit", + "value": "currencyUSD" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "NaN": { + "index": 0, + "text": "Not configured" + } + }, + "type": "value" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 15, + "w": 24, + "x": 0, + "y": 64 + }, + "id": 8, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": true, + "fields": "", + "reducer": [ + "sum" + ], + "show": true + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Money" + } + ] + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "hide": false, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"strings\"\r\nimport \"regexp\"\r\nimport \"array\"\r\nimport \"experimental\"\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Constants\r\nthreshold_duration_ns = ${threshold_duration_ns} // 1 day-1ns in nanoseconds\r\nsix_hours_ns = ${six_hours_ns} // 6 hours in nanoseconds\r\n\r\n// Calculate the time range duration\r\ntime_diff_ns = int(v: v.timeRangeStop) - int(v: v.timeRangeStart)\r\n\r\n// Calculate remainder for 6-hour alignment at start and end\r\nstart_remainder_ns = int(v: v.timeRangeStart) % six_hours_ns\r\nend_remainder_ns_pre = int(v: v.timeRangeStop) % six_hours_ns\r\n// Extract the hour from timeRangeStop in hours (convert nanoseconds to hours)\r\ntime_hour = int(v: int(v: v.timeRangeStop) % 86400000000000) / 3600000000000\r\n\r\n// Check if the end time is in xx:59:59 for the specified hours (05, 11, 17, 23)\r\nend_remainder_ns = ${end_reminder_calc}\r\n\r\n// Bucket selection logic based on total time range duration\r\nbucket_default_only = time_diff_ns <= threshold_duration_ns\r\n\r\n// Helper function to query default bucket\r\ndefault_bucket_query = (start, stop) => from(bucket: \"${INFLUX_BUCKET}\")\r\n |> range(start: start, stop: stop)\r\n |> filter(fn: (r) => r._measurement == \"analytics\")\r\n |> filter(fn: (r) => r._field == \"prompt_tokens\" or r._field == \"completion_tokens\" or r._field == \"number_request_messages\" or r._field == \"price\"or r._field == \"request_count\")\r\n |> schema.fieldsAsCols()\r\n |> group(columns: [\"deployment\", \"model\"])\r\n |> reduce(\r\n fn: (r, accumulator) => ({\r\n request_count: accumulator.request_count + 1,\r\n prompt_tokens: getOrDefault(f: r.prompt_tokens, d: 0) + accumulator.prompt_tokens,\r\n completion_tokens: getOrDefault(f: r.completion_tokens, d: 0) + accumulator.completion_tokens,\r\n money: getOrDefault(f: r.price, d: 0.0) + accumulator.money\r\n }),\r\n identity: {request_count: 0, prompt_tokens: 0, completion_tokens: 0, money: 0.0}\r\n )\r\n\r\n // Helper function to query aggregated bucket\r\n agg_bucket_query = (start, stop) => from(bucket: \"${INFLUX_BUCKET}_agg_stats\")\r\n |> range(start: start, stop: stop)\r\n |> filter(fn: (r) => r._field == \"prompt_tokens\" or r._field == \"completion_tokens\" or r._field == \"number_request_messages\" or r._field == \"user_hash\" or r._field == \"price\"or r._field == \"request_count\")\r\n |> schema.fieldsAsCols()\r\n |> group(columns: [\"deployment\", \"model\"])\r\n |> reduce(\r\n fn: (r, accumulator) => ({\r\n request_count: getOrDefault(f: r.request_count, d: 0) + accumulator.request_count,\r\n prompt_tokens: getOrDefault(f: r.prompt_tokens, d: 0) + accumulator.prompt_tokens,\r\n completion_tokens: getOrDefault(f: r.completion_tokens, d: 0) + accumulator.completion_tokens,\r\n money: getOrDefault(f: r.price, d: 0.0) + accumulator.money\r\n }),\r\n identity: {request_count: 0, prompt_tokens: 0, completion_tokens: 0, money: 0.0}\r\n )\r\n\r\n\r\n// Query data for the start from the default bucket if the start time is not aligned\r\ndata_default_start = \r\n if start_remainder_ns > 0 and not bucket_default_only then ${data_default_start} \r\n else from(bucket: \"${INFLUX_BUCKET}\") |> limit(n: 0)\r\n\r\n// Query data for the aggregated bucket (middle part)\r\ndata_agg = \r\n if not bucket_default_only then ${data_agg}\r\n else from(bucket: \"${INFLUX_BUCKET}_agg_stats\") |> limit(n: 0)\r\n\r\n// Query data for the end from the default bucket if the end time is not aligned\r\ndata_default_end = \r\n if end_remainder_ns > 0 then ${data_default_end}\r\n else from(bucket: \"${INFLUX_BUCKET}\") |> limit(n: 0)\r\n\r\n// Combine data from all buckets (start, middle, end)\r\ncombined_data = ${combine_data}\r\n\r\ncombined_data\r\n |> group(columns: [\"deployment\", \"model\"])\r\n |> reduce(\r\n fn: (r, accumulator) => ({\r\n request_count: r.request_count + accumulator.request_count,\r\n prompt_tokens: r.prompt_tokens + accumulator.prompt_tokens,\r\n completion_tokens: r.completion_tokens + accumulator.completion_tokens,\r\n money: r.money + accumulator.money\r\n }),\r\n identity: {request_count: 0, prompt_tokens: 0, completion_tokens: 0, money: 0.0}\r\n )\r\n |> group()\r\n", + "refId": "A" + } + ], + "title": "Deployment/Model Stats Table", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "_time": true + }, + "indexByName": { + "completion_tokens": 4, + "deployment": 0, + "model": 1, + "money": 5, + "prompt_tokens": 3, + "request_count": 2 + }, + "renameByName": { + "completion_tokens": "Completion tokens", + "deployment": "Deployment", + "model": "Model", + "money": "Money", + "number_request_messages": "", + "project_id": "", + "prompt_tokens": "Prompt tokens", + "request_count": "Request count" + } + } + }, + { + "id": "sortBy", + "options": { + "fields": {}, + "sort": [ + { + "desc": true, + "field": "Money" + } + ] + } + } + ], + "type": "table" + } + ], + "refresh": "", + "schemaVersion": 39, + "tags": [ + "DIAL", + "ai-dial-analytics-realtime", + "Aggregated data" + ], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "InfluxDB_EPAM", + "value": "P3DF0C308D9792AAA" + }, + "description": "InfluxDB datasource", + "hide": 0, + "includeAll": false, + "label": "Data source", + "multi": false, + "name": "datasource", + "options": [], + "query": "influxdb", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": { + "selected": false, + "text": "default", + "value": "default" + }, + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "definition": "buckets()", + "description": "A InfluxDB bucket name", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "INFLUX_BUCKET", + "options": [], + "query": "buckets()", + "refresh": 1, + "regex": "/^(default)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "hide": 2, + "name": "combine_data", + "query": "if bucket_default_only then data_default_start else if start_remainder_ns > 0 and end_remainder_ns > 0 then union(tables: [data_default_start, data_agg, data_default_end]) else if start_remainder_ns > 0 then union(tables: [data_default_start, data_agg]) else if end_remainder_ns > 0 then union(tables: [data_agg, data_default_end]) else data_agg", + "skipUrlSync": false, + "type": "constant" + }, + { + "hide": 2, + "name": "data_default_end", + "query": "default_bucket_query(start: experimental.addDuration(d: -duration(v: end_remainder_ns), to: v.timeRangeStop), stop: v.timeRangeStop)", + "skipUrlSync": false, + "type": "constant" + }, + { + "hide": 2, + "name": "data_default_start", + "query": "default_bucket_query( start: v.timeRangeStart, stop: experimental.addDuration(d: duration(v: six_hours_ns - start_remainder_ns), to: v.timeRangeStart) ) else if bucket_default_only then default_bucket_query( start: v.timeRangeStart, stop: v.timeRangeStop )", + "skipUrlSync": false, + "type": "constant" + }, + { + "hide": 2, + "name": "data_agg", + "query": "agg_bucket_query( start: if start_remainder_ns > 0 then experimental.addDuration(d: duration(v: six_hours_ns - start_remainder_ns), to: v.timeRangeStart) else v.timeRangeStart, stop: if end_remainder_ns > 0 then experimental.addDuration(d: -duration(v: end_remainder_ns), to: v.timeRangeStop) else v.timeRangeStop )", + "skipUrlSync": false, + "type": "constant" + }, + { + "description": "1 day -1 nanoseconds: if query is above this, data is taken partially from aggregated buckets", + "hide": 2, + "name": "threshold_duration_ns", + "query": "86399999999999", + "skipUrlSync": false, + "type": "constant" + }, + { + "hide": 2, + "label": "", + "name": "six_hours_ns", + "query": "21600000000000", + "skipUrlSync": false, + "type": "constant" + }, + { + "hide": 2, + "name": "end_reminder_calc", + "query": "if int(v: v.timeRangeStop) % 3600000000000 == 3599000000000 and ( time_hour == 5 or time_hour == 11 or time_hour == 17 or time_hour == 23 ) then 0 else end_remainder_ns_pre", + "skipUrlSync": false, + "type": "constant" + } + ] + }, + "time": { + "from": "now-7d", + "to": "now" + }, + "timepicker": {}, + "timezone": "utc", + "title": "DIAL Analytics Agg", + "uid": "435858b2-4106-4d11-b6e8-9b0ff107b466fg", + "version": 3, + "weekStart": "" +} \ No newline at end of file diff --git a/dashboards/dial_project_insights.json b/dashboards/dial_project_insights.json new file mode 100644 index 0000000..abeab3c --- /dev/null +++ b/dashboards/dial_project_insights.json @@ -0,0 +1,1211 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 5, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "align": "left", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 48, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": true + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Request count" + } + ] + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Aggregate request counts per group\r\ndata_request = from(bucket: \"default_agg_stats\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => (r._field == \"prompt_tokens\" or r._field == \"request_count\" or r._field == \"price\" ) )\r\n |> filter(fn: (r) => exists r.project_id)\r\n |> schema.fieldsAsCols()\r\n |> group(columns: [\"project_id\", \"deployment\", \"model\"])\r\n |> reduce(\r\n fn: (r, accumulator) => ({\r\n request_count: getOrDefault(f: r.request_count, d: 0) + accumulator.request_count,\r\n prompt_tokens: getOrDefault(f: r.prompt_tokens, d: 0) + accumulator.prompt_tokens,\r\n price: getOrDefault(f: r.price, d: 0.0) + accumulator.price\r\n }),\r\n identity: {request_count: 0, prompt_tokens: 0, price:0.0}\r\n )\r\n\r\n data_request\r\n |> group()\r\n |> sort(columns: [\"request_count\"], desc: true)", + "refId": "A" + } + ], + "title": "Deployment/Model Stats Table", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "includeByName": {}, + "indexByName": { + "deployment": 2, + "model": 1, + "price": 5, + "project_id": 0, + "prompt_tokens": 4, + "request_count": 3 + }, + "renameByName": { + "deployment": "Deployment", + "model": "Model", + "price": "Cost ($)", + "project_id": "Project", + "prompt_tokens": "Prompt tokens", + "request_count": "Request count" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 10, + "x": 0, + "y": 13 + }, + "id": 43, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "none", + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Aggregate request counts per group\r\ndata_request = from(bucket: \"default_agg_kpi\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r._field == \"request_count\" and r.project_id !=\"\" )\r\n |> schema.fieldsAsCols()\r\n |> group(columns: [\"project_id\"])\r\n |> sum(column:\"request_count\")\r\n|>group()\r\n\r\n // Sort users by total_requests in descending order\r\nsorted_users = data_request\r\n |> sort(columns: [\"request_count\"], desc: true)\r\n |> map(fn: (r) => ({r with rowId: 1}))\r\n // Taking the cumulative sum gives sequential values 1,2,3,4 et...\r\n |> cumulativeSum(columns: [\"rowId\"])\r\n\r\n// Calculate percentile thresholds\r\npercentile_90_user = sorted_users |> quantile(column: \"rowId\", q: 0.9) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_80_user = sorted_users |> quantile(column: \"rowId\", q: 0.8) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_70_user = sorted_users |> quantile(column: \"rowId\", q: 0.7) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_60_user = sorted_users |> quantile(column: \"rowId\", q: 0.6) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_50_user = sorted_users |> quantile(column: \"rowId\", q: 0.5) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_40_user = sorted_users |> quantile(column: \"rowId\", q: 0.4) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_30_user = sorted_users |> quantile(column: \"rowId\", q: 0.3) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_20_user = sorted_users |> quantile(column: \"rowId\", q: 0.2) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_10_user = sorted_users |> quantile(column: \"rowId\", q: 0.1) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_01_user = sorted_users |> quantile(column: \"rowId\", q: 0.01) |> findRecord(fn: (key) => true, idx: 0)\r\n\r\n\r\n// Map percentiles to each user based on request count thresholds\r\ndeterminePercentiles = (sorted_users, topUsers) => \r\n if topUsers == \"No\" then\r\n sorted_users\r\n |> map(fn: (r) => ({\r\n request_count: r.request_count,\r\n rowId: r.rowId,\r\n percentile_user: if r.rowId >= percentile_90_user.rowId then \"0-10%\"\r\n else if r.rowId >= percentile_80_user.rowId then \"11-20%\"\r\n else if r.rowId >= percentile_70_user.rowId then \"21-30%\"\r\n else if r.rowId >= percentile_60_user.rowId then \"31-40%\"\r\n else if r.rowId >= percentile_50_user.rowId then \"41-50%\"\r\n else if r.rowId >= percentile_40_user.rowId then \"51-60%\"\r\n else if r.rowId >= percentile_30_user.rowId then \"61-70%\"\r\n else if r.rowId >= percentile_20_user.rowId then \"71-80%\"\r\n else if r.rowId >= percentile_10_user.rowId then \"81-90%\"\r\n else \"Top 10%\"\r\n }))\r\n else\r\n sorted_users\r\n |> map(fn: (r) => ({\r\n request_count: r.request_count,\r\n rowId: r.rowId,\r\n percentile_user: if r.rowId >= percentile_90_user.rowId then \"0-10%\"\r\n else if r.rowId >= percentile_80_user.rowId then \"11-20%\"\r\n else if r.rowId >= percentile_70_user.rowId then \"21-30%\"\r\n else if r.rowId >= percentile_60_user.rowId then \"31-40%\"\r\n else if r.rowId >= percentile_50_user.rowId then \"41-50%\"\r\n else if r.rowId >= percentile_40_user.rowId then \"51-60%\"\r\n else if r.rowId >= percentile_30_user.rowId then \"61-70%\"\r\n else if r.rowId >= percentile_20_user.rowId then \"71-80%\"\r\n else if r.rowId >= percentile_10_user.rowId then \"81-90%\"\r\n else if r.rowId >= percentile_01_user.rowId then \"91-99%\"\r\n else \"Top 1%\"\r\n }))\r\n\r\n// Define the bucket and call the function\r\ntopUsers = \"${Show_Top1_percent}\" // Replace with your actual bucket variable\r\npercentiles = determinePercentiles(sorted_users: sorted_users, topUsers: topUsers)\r\n\r\n// Count the number of users in each percentile\r\npercentile_data =\r\npercentiles\r\n |> group(columns: [\"percentile_user\"])\r\n |> sum(column: \"request_count\")\r\n |> map(fn: (r) => ({r with join_key: \"cross_join\"})) // Adding a dummy key for joining\r\n\r\n|> group()\r\ntotal_cost_data = percentiles\r\n\r\n |> sum(column: \"request_count\")\r\n |> map(fn: (r) => ({total_request_count: r.request_count, join_key: \"cross_join\"})) // Adding a dummy key for joining\r\n\r\n cross_joined_data = join(\r\n tables: {percentile: percentile_data, total: total_cost_data},\r\n on: [\"join_key\"]\r\n)\r\n |> map(fn: (r) => ({\r\n\r\n percent_of_request: float(v: r.request_count) / float(v: r.total_request_count)*100.0, \r\n percentile_user: r.percentile_user,\r\n sort: if r.percentile_user == \"0-10%\" then \"0\"\r\n else if r.percentile_user == \"11-20%\" then \"1\"\r\n else if r.percentile_user == \"21-30%\" then \"2\"\r\n else if r.percentile_user == \"31-40%\" then \"3\"\r\n else if r.percentile_user == \"41-50%\" then \"4\"\r\n else if r.percentile_user == \"51-60%\" then \"5\"\r\n else if r.percentile_user == \"61-70%\" then \"6\"\r\n else if r.percentile_user == \"71-80%\" then \"7\"\r\n else if r.percentile_user == \"81-90%\" then \"8\"\r\n else if r.percentile_user == \"91-99%\" then \"9\"\r\n else \"99\"\r\n }))\r\ncross_joined_data\r\n|>group()\r\n|> sort(columns: [\"sort\"], desc: true)\r\n ", + "refId": "A" + } + ], + "title": "Reqests share by deciles of Project in chat", + "type": "barchart" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "left", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percentile_user" + }, + "properties": [ + { + "id": "custom.width", + "value": 127 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Percent of request" + }, + "properties": [ + { + "id": "custom.width", + "value": 152 + } + ] + } + ] + }, + "gridPos": { + "h": 13, + "w": 6, + "x": 10, + "y": 13 + }, + "id": 39, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": true + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Aggregate request counts per group\r\ndata_request = from(bucket: \"default_agg_kpi\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r._field == \"request_count\" and r.project_id !=\"\" and r.project_id !=\"undefined\" )\r\n |> schema.fieldsAsCols()\r\n |> group(columns: [\"project_id\"])\r\n |> sum(column:\"request_count\")\r\n\r\n|>group()\r\n\r\n // Sort users by total_requests in descending order\r\nsorted_users = data_request\r\n |> sort(columns: [\"request_count\"], desc: true)\r\n |> map(fn: (r) => ({r with rowId: 1}))\r\n // Taking the cumulative sum gives sequential values 1,2,3,4 et...\r\n |> cumulativeSum(columns: [\"rowId\"])\r\n\r\n// Calculate percentile thresholds\r\npercentile_90_user = sorted_users |> quantile(column: \"rowId\", q: 0.9) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_80_user = sorted_users |> quantile(column: \"rowId\", q: 0.8) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_70_user = sorted_users |> quantile(column: \"rowId\", q: 0.7) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_60_user = sorted_users |> quantile(column: \"rowId\", q: 0.6) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_50_user = sorted_users |> quantile(column: \"rowId\", q: 0.5) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_40_user = sorted_users |> quantile(column: \"rowId\", q: 0.4) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_30_user = sorted_users |> quantile(column: \"rowId\", q: 0.3) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_20_user = sorted_users |> quantile(column: \"rowId\", q: 0.2) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_10_user = sorted_users |> quantile(column: \"rowId\", q: 0.1) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_01_user = sorted_users |> quantile(column: \"rowId\", q: 0.01) |> findRecord(fn: (key) => true, idx: 0)\r\n\r\n\r\n// Map percentiles to each user based on request count thresholds\r\ndeterminePercentiles = (sorted_users, topUsers) => \r\n if topUsers == \"No\" then\r\n sorted_users\r\n |> map(fn: (r) => ({\r\n request_count: r.request_count,\r\n rowId: r.rowId,\r\n percentile_user: if r.rowId >= percentile_90_user.rowId then \"0-10%\"\r\n else if r.rowId >= percentile_80_user.rowId then \"11-20%\"\r\n else if r.rowId >= percentile_70_user.rowId then \"21-30%\"\r\n else if r.rowId >= percentile_60_user.rowId then \"31-40%\"\r\n else if r.rowId >= percentile_50_user.rowId then \"41-50%\"\r\n else if r.rowId >= percentile_40_user.rowId then \"51-60%\"\r\n else if r.rowId >= percentile_30_user.rowId then \"61-70%\"\r\n else if r.rowId >= percentile_20_user.rowId then \"71-80%\"\r\n else if r.rowId >= percentile_10_user.rowId then \"81-90%\"\r\n else \"Top 10%\"\r\n }))\r\n else\r\n sorted_users\r\n |> map(fn: (r) => ({\r\n request_count: r.request_count,\r\n rowId: r.rowId,\r\n percentile_user: if r.rowId >= percentile_90_user.rowId then \"0-10%\"\r\n else if r.rowId >= percentile_80_user.rowId then \"11-20%\"\r\n else if r.rowId >= percentile_70_user.rowId then \"21-30%\"\r\n else if r.rowId >= percentile_60_user.rowId then \"31-40%\"\r\n else if r.rowId >= percentile_50_user.rowId then \"41-50%\"\r\n else if r.rowId >= percentile_40_user.rowId then \"51-60%\"\r\n else if r.rowId >= percentile_30_user.rowId then \"61-70%\"\r\n else if r.rowId >= percentile_20_user.rowId then \"71-80%\"\r\n else if r.rowId >= percentile_10_user.rowId then \"81-90%\"\r\n else if r.rowId >= percentile_01_user.rowId then \"91-99%\"\r\n else \"Top 1%\"\r\n }))\r\n// Define the bucket and call the function\r\ntopUsers = \"${Show_Top1_percent}\" // Replace with your actual bucket variable\r\npercentiles = determinePercentiles(sorted_users: sorted_users, topUsers: topUsers)\r\n// Count the number of users in each percentile\r\npercentile_data =\r\npercentiles\r\n |> group(columns: [\"percentile_user\"])\r\n |> sum(column: \"request_count\")\r\n |> map(fn: (r) => ({r with join_key: \"cross_join\"})) // Adding a dummy key for joining\r\n\r\n|> group()\r\ntotal_cost_data = percentiles\r\n\r\n |> sum(column: \"request_count\")\r\n |> map(fn: (r) => ({total_request_count: r.request_count, join_key: \"cross_join\"})) // Adding a dummy key for joining\r\n\r\n cross_joined_data = join(\r\n tables: {percentile: percentile_data, total: total_cost_data},\r\n on: [\"join_key\"]\r\n)\r\n |> map(fn: (r) => ({percent_of_request: float(v: r.request_count) / float(v: r.total_request_count)*100.0,\r\n \r\n request_count:r.request_count,\r\n Percentile_user: r.percentile_user,\r\n sort: if r.percentile_user == \"0-10%\" then \"0\"\r\n else if r.percentile_user == \"11-20%\" then \"1\"\r\n else if r.percentile_user == \"21-30%\" then \"2\"\r\n else if r.percentile_user == \"31-40%\" then \"3\"\r\n else if r.percentile_user == \"41-50%\" then \"4\"\r\n else if r.percentile_user == \"51-60%\" then \"5\"\r\n else if r.percentile_user == \"61-70%\" then \"6\"\r\n else if r.percentile_user == \"71-80%\" then \"7\"\r\n else if r.percentile_user == \"81-90%\" then \"8\"\r\n else if r.percentile_user == \"91-99%\" then \"9\"\r\n else \"99\"\r\n }))\r\ncross_joined_data\r\n|>group()\r\n |> rename(columns: {\"percent_of_request\": \"Percent of request\", \"request_count\": \"Request count\"})\r\n|> sort(columns: [\"sort\"], desc: true)\r\n|> drop(columns: [\"sort\"])", + "refId": "A" + } + ], + "title": "Reqests share by deciles of Project in chat", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "includeByName": {}, + "indexByName": {}, + "renameByName": { + "Percent of request": "Request(%)" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "left", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Project" + }, + "properties": [ + { + "id": "custom.width", + "value": 295 + } + ] + } + ] + }, + "gridPos": { + "h": 13, + "w": 8, + "x": 16, + "y": 13 + }, + "id": 44, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "10.4.0", + "repeat": "Show_by", + "repeatDirection": "v", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Aggregate request counts per group\r\ndata_request = from(bucket: \"default_agg_kpi\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r._field == \"request_count\" and r.project_id !=\"\" and r.project_id !=\"undefined\" )\r\n |> schema.fieldsAsCols()\r\n |> group(columns: [\"project_id\"])\r\n |> sum(column:\"request_count\")\r\n\r\n|>group()\r\n\r\n // Sort users by total_requests in descending order\r\ndata_request\r\n |> sort(columns: [\"request_count\"], desc: true)\r\n |> map(fn: (r) => ({r with rowId: 1}))\r\n // Taking the cumulative sum gives sequential values 1,2,3,4 et...\r\n |> cumulativeSum(columns: [\"rowId\"])\r\n |> filter(fn: (r) => r.rowId < 11)\r\n |> rename(columns: {\"request_count\": \"Request count\", \"project_id\": \"Project\"})\r\n |> drop(columns: [\"rowId\"])", + "refId": "A" + } + ], + "title": "Top 10 Projects by Request count", + "type": "table" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "orange", + "mode": "fixed" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 10, + "x": 0, + "y": 26 + }, + "id": 40, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "none", + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Aggregate request counts per group\r\ndata_request = from(bucket: \"default_agg_kpi\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r._field == \"cost\" and r.project_id !=\"\" )\r\n |> schema.fieldsAsCols()\r\n |> group(columns: [\"project_id\"])\r\n |> sum(column:\"cost\")\r\n\r\n|>group()\r\n\r\n // Sort users by total_requests in descending order\r\nsorted_users = data_request\r\n |> sort(columns: [\"cost\"], desc: true)\r\n |> map(fn: (r) => ({r with rowId: 1}))\r\n // Taking the cumulative sum gives sequential values 1,2,3,4 et...\r\n |> cumulativeSum(columns: [\"rowId\"])\r\n\r\n// Calculate percentile thresholds\r\npercentile_90_user = sorted_users |> quantile(column: \"rowId\", q: 0.9) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_80_user = sorted_users |> quantile(column: \"rowId\", q: 0.8) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_70_user = sorted_users |> quantile(column: \"rowId\", q: 0.7) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_60_user = sorted_users |> quantile(column: \"rowId\", q: 0.6) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_50_user = sorted_users |> quantile(column: \"rowId\", q: 0.5) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_40_user = sorted_users |> quantile(column: \"rowId\", q: 0.4) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_30_user = sorted_users |> quantile(column: \"rowId\", q: 0.3) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_20_user = sorted_users |> quantile(column: \"rowId\", q: 0.2) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_10_user = sorted_users |> quantile(column: \"rowId\", q: 0.1) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_01_user = sorted_users |> quantile(column: \"rowId\", q: 0.01) |> findRecord(fn: (key) => true, idx: 0)\r\n\r\n// Map percentiles to each user based on request count thresholds\r\ndeterminePercentiles = (sorted_users, topUsers) => \r\n if topUsers == \"No\" then\r\n sorted_users\r\n |> map(fn: (r) => ({\r\n cost: r.cost,\r\n rowId: r.rowId,\r\n percentile_user: if r.rowId >= percentile_90_user.rowId then \"0-10%\"\r\n else if r.rowId >= percentile_80_user.rowId then \"11-20%\"\r\n else if r.rowId >= percentile_70_user.rowId then \"21-30%\"\r\n else if r.rowId >= percentile_60_user.rowId then \"31-40%\"\r\n else if r.rowId >= percentile_50_user.rowId then \"41-50%\"\r\n else if r.rowId >= percentile_40_user.rowId then \"51-60%\"\r\n else if r.rowId >= percentile_30_user.rowId then \"61-70%\"\r\n else if r.rowId >= percentile_20_user.rowId then \"71-80%\"\r\n else if r.rowId >= percentile_10_user.rowId then \"81-90%\"\r\n else \"Top 10%\"\r\n }))\r\n else\r\n sorted_users\r\n |> map(fn: (r) => ({\r\n cost: r.cost,\r\n rowId: r.rowId,\r\n percentile_user: if r.rowId >= percentile_90_user.rowId then \"0-10%\"\r\n else if r.rowId >= percentile_80_user.rowId then \"11-20%\"\r\n else if r.rowId >= percentile_70_user.rowId then \"21-30%\"\r\n else if r.rowId >= percentile_60_user.rowId then \"31-40%\"\r\n else if r.rowId >= percentile_50_user.rowId then \"41-50%\"\r\n else if r.rowId >= percentile_40_user.rowId then \"51-60%\"\r\n else if r.rowId >= percentile_30_user.rowId then \"61-70%\"\r\n else if r.rowId >= percentile_20_user.rowId then \"71-80%\"\r\n else if r.rowId >= percentile_10_user.rowId then \"81-90%\"\r\n else if r.rowId >= percentile_01_user.rowId then \"91-99%\"\r\n else \"Top 1%\"\r\n }))\r\n\r\n// Define the bucket and call the function\r\ntopUsers = \"${Show_Top1_percent}\" // Replace with your actual bucket variable\r\npercentiles = determinePercentiles(sorted_users: sorted_users, topUsers: topUsers)\r\n\r\n// Count the number of users in each percentile\r\npercentile_data =\r\npercentiles\r\n |> group(columns: [\"percentile_user\"])\r\n |> sum(column: \"cost\")\r\n |> map(fn: (r) => ({r with join_key: \"cross_join\"})) // Adding a dummy key for joining\r\n\r\n|> group()\r\ntotal_cost_data = percentiles\r\n\r\n |> sum(column: \"cost\")\r\n |> map(fn: (r) => ({total_cost: r.cost, join_key: \"cross_join\"})) // Adding a dummy key for joining\r\n\r\n cross_joined_data = join(\r\n tables: {percentile: percentile_data, total: total_cost_data},\r\n on: [\"join_key\"]\r\n)\r\n |> map(fn: (r) => ({percent_of_request: r.cost / r.total_cost *100.0,\r\n \r\n percentile_user: r.percentile_user,\r\n\r\n sort: if r.percentile_user == \"0-10%\" then \"0\"\r\n else if r.percentile_user == \"11-20%\" then \"1\"\r\n else if r.percentile_user == \"21-30%\" then \"2\"\r\n else if r.percentile_user == \"31-40%\" then \"3\"\r\n else if r.percentile_user == \"41-50%\" then \"4\"\r\n else if r.percentile_user == \"51-60%\" then \"5\"\r\n else if r.percentile_user == \"61-70%\" then \"6\"\r\n else if r.percentile_user == \"71-80%\" then \"7\"\r\n else if r.percentile_user == \"81-90%\" then \"8\"\r\n else if r.percentile_user == \"91-99%\" then \"9\"\r\n else \"99\"\r\n }))\r\ncross_joined_data\r\n|>group()\r\n |> sort(columns: [\"sort\"], desc: true)\r\n ", + "refId": "A" + } + ], + "title": "Cost share by deciles of Project in chat", + "type": "barchart" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "left", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percentile_user" + }, + "properties": [ + { + "id": "custom.width", + "value": 127 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cost($)" + }, + "properties": [ + { + "id": "custom.width", + "value": 154 + } + ] + } + ] + }, + "gridPos": { + "h": 13, + "w": 6, + "x": 10, + "y": 26 + }, + "id": 42, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": true + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Aggregate request counts per group\r\ndata_request = from(bucket: \"default_agg_kpi\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r._field == \"cost\" and r.project_id !=\"\" and r.project_id !=\"undefined\" )\r\n |> schema.fieldsAsCols()\r\n |> group(columns: [\"project_id\"])\r\n |> sum(column: \"cost\")\r\n |>group()\r\n\r\n // Sort users by total_requests in descending order\r\nsorted_users = data_request\r\n |> sort(columns: [\"cost\"], desc: true)\r\n |> map(fn: (r) => ({r with rowId: 1}))\r\n // Taking the cumulative sum gives sequential values 1,2,3,4 et...\r\n |> cumulativeSum(columns: [\"rowId\"])\r\n\r\n// Calculate percentile thresholds\r\npercentile_90_user = sorted_users |> quantile(column: \"rowId\", q: 0.9) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_80_user = sorted_users |> quantile(column: \"rowId\", q: 0.8) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_70_user = sorted_users |> quantile(column: \"rowId\", q: 0.7) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_60_user = sorted_users |> quantile(column: \"rowId\", q: 0.6) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_50_user = sorted_users |> quantile(column: \"rowId\", q: 0.5) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_40_user = sorted_users |> quantile(column: \"rowId\", q: 0.4) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_30_user = sorted_users |> quantile(column: \"rowId\", q: 0.3) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_20_user = sorted_users |> quantile(column: \"rowId\", q: 0.2) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_10_user = sorted_users |> quantile(column: \"rowId\", q: 0.1) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_01_user = sorted_users |> quantile(column: \"rowId\", q: 0.01) |> findRecord(fn: (key) => true, idx: 0)\r\n\r\n\r\n// Map percentiles to each user based on request count thresholds\r\ndeterminePercentiles = (sorted_users, topUsers) => \r\n if topUsers == \"No\" then\r\n sorted_users\r\n |> map(fn: (r) => ({\r\n cost: r.cost,\r\n rowId: r.rowId,\r\n percentile_user: if r.rowId >= percentile_90_user.rowId then \"0-10%\"\r\n else if r.rowId >= percentile_80_user.rowId then \"11-20%\"\r\n else if r.rowId >= percentile_70_user.rowId then \"21-30%\"\r\n else if r.rowId >= percentile_60_user.rowId then \"31-40%\"\r\n else if r.rowId >= percentile_50_user.rowId then \"41-50%\"\r\n else if r.rowId >= percentile_40_user.rowId then \"51-60%\"\r\n else if r.rowId >= percentile_30_user.rowId then \"61-70%\"\r\n else if r.rowId >= percentile_20_user.rowId then \"71-80%\"\r\n else if r.rowId >= percentile_10_user.rowId then \"81-90%\"\r\n else \"Top 10%\"\r\n }))\r\n else\r\n sorted_users\r\n |> map(fn: (r) => ({\r\n cost: r.cost,\r\n rowId: r.rowId,\r\n percentile_user: if r.rowId >= percentile_90_user.rowId then \"0-10%\"\r\n else if r.rowId >= percentile_80_user.rowId then \"11-20%\"\r\n else if r.rowId >= percentile_70_user.rowId then \"21-30%\"\r\n else if r.rowId >= percentile_60_user.rowId then \"31-40%\"\r\n else if r.rowId >= percentile_50_user.rowId then \"41-50%\"\r\n else if r.rowId >= percentile_40_user.rowId then \"51-60%\"\r\n else if r.rowId >= percentile_30_user.rowId then \"61-70%\"\r\n else if r.rowId >= percentile_20_user.rowId then \"71-80%\"\r\n else if r.rowId >= percentile_10_user.rowId then \"81-90%\"\r\n else if r.rowId >= percentile_01_user.rowId then \"91-99%\"\r\n else \"Top 1%\"\r\n }))\r\n\r\n// Define the bucket and call the function\r\ntopUsers = \"${Show_Top1_percent}\" // Replace with your actual bucket variable\r\npercentiles = determinePercentiles(sorted_users: sorted_users, topUsers: topUsers)\r\n\r\n\r\n// Count the number of users in each percentile\r\npercentile_data =\r\npercentiles\r\n |> group(columns: [\"percentile_user\"])\r\n |> sum(column: \"cost\")\r\n |> map(fn: (r) => ({r with join_key: \"cross_join\"})) // Adding a dummy key for joining\r\n\r\n|> group()\r\ntotal_cost_data = percentiles\r\n\r\n |> sum(column: \"cost\")\r\n |> map(fn: (r) => ({total_cost: r.cost, join_key: \"cross_join\"})) // Adding a dummy key for joining\r\n\r\n cross_joined_data = join(\r\n tables: {percentile: percentile_data, total: total_cost_data},\r\n on: [\"join_key\"]\r\n)\r\n |> map(fn: (r) => ({percent_of_request: float(v: r.cost) / float(v: r.total_cost)*100.0,\r\n \r\n cost:r.cost,\r\n Percentile_user: r.percentile_user,\r\n sort: if r.percentile_user == \"0-10%\" then \"0\"\r\n else if r.percentile_user == \"11-20%\" then \"1\"\r\n else if r.percentile_user == \"21-30%\" then \"2\"\r\n else if r.percentile_user == \"31-40%\" then \"3\"\r\n else if r.percentile_user == \"41-50%\" then \"4\"\r\n else if r.percentile_user == \"51-60%\" then \"5\"\r\n else if r.percentile_user == \"61-70%\" then \"6\"\r\n else if r.percentile_user == \"71-80%\" then \"7\"\r\n else if r.percentile_user == \"81-90%\" then \"8\"\r\n else if r.percentile_user == \"91-99%\" then \"9\"\r\n else \"99\"\r\n }))\r\ncross_joined_data\r\n|>group()\r\n |> rename(columns: {\"percent_of_request\": \"Percent of Cost\", \"cost\": \"Cost($)\"})\r\n|> sort(columns: [\"sort\"], desc: true)\r\n|> drop(columns: [\"sort\"])", + "refId": "A" + } + ], + "title": "Cost share by deciles of Project in chat", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "includeByName": {}, + "indexByName": { + "Cost($)": 2, + "Percent of Cost": 1, + "Percentile_user": 0 + }, + "renameByName": { + "Percent of Cost": "Cost(%)" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "left", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Project" + }, + "properties": [ + { + "id": "custom.width", + "value": 326 + } + ] + } + ] + }, + "gridPos": { + "h": 13, + "w": 8, + "x": 16, + "y": 26 + }, + "id": 46, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "10.4.0", + "repeatDirection": "v", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Aggregate request counts per group\r\ndata_request = from(bucket: \"default_agg_kpi\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r._field == \"cost\" and r.project_id !=\"\" and r.project_id !=\"undefined\" )\r\n |> schema.fieldsAsCols()\r\n |> group(columns: [\"project_id\"])\r\n |> sum(column:\"cost\")\r\n\r\n|>group()\r\n\r\n // Sort users by total_requests in descending order\r\ndata_request\r\n |> sort(columns: [\"cost\"], desc: true)\r\n |> map(fn: (r) => ({r with rowId: 1}))\r\n // Taking the cumulative sum gives sequential values 1,2,3,4 et...\r\n |> cumulativeSum(columns: [\"rowId\"])\r\n |> filter(fn: (r) => r.rowId < 11)\r\n |> rename(columns: { \"project_id\": \"Project\",\"cost\": \"Cost($)\"})\r\n |> drop(columns: [\"rowId\"])", + "refId": "A" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "hide": false, + "refId": "B" + } + ], + "title": "Top 10 Projects by Cost", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "includeByName": {}, + "indexByName": { + "Cost($)": 1, + "Project": 0 + }, + "renameByName": {} + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 10, + "x": 0, + "y": 39 + }, + "id": 37, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "none", + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\ndata_request = from(bucket: \"default_agg_topic\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r.user_type == \"project\" and \r\n ( r._field == \"class_1\" or r._field == \"class_2\" or r._field == \"class_3\" or r._field == \"class_4\" or r._field == \"class_5\" or r._field == \"class_6\")\r\n )\r\n |> map(fn: (r) => ({\r\n _value: r._value,\r\n classification: if r._field == \"class_1\" then \"> 50000\"\r\n else if r._field == \"class_2\" then \"10001 - 50000\"\r\n else if r._field == \"class_3\" then \"5001 - 10000\"\r\n else if r._field == \"class_4\" then \"1001 - 5000\"\r\n else if r._field == \"class_5\" then \"101 - 1000\"\r\n else \"< 101\",\r\n sorting: if r._field == \"class_1\" then \"1\"\r\n else if r._field == \"class_2\" then \"2\"\r\n else if r._field == \"class_3\" then \"3\"\r\n else if r._field == \"class_4\" then \"4\"\r\n else if r._field == \"class_5\" then \"5\"\r\n else \"6\"\r\n }))\r\n |>group(columns: [\"classification\",\"sorting\"])\r\n |>sum(column: \"_value\")\r\n |> map(fn: (r) => ({join_col: \"key\",\r\n _value: r._value,\r\n sorting: r.sorting,\r\n classification: r.classification\r\n\r\n }))\r\n |>group()\r\n\r\n\r\nsum_tokens = data_request\r\n |>sum(column: \"_value\")\r\n |> map(fn: (r) => ({join_col: \"key\",\r\n total_tokens: r._value\r\n }))\r\n\r\ncross_joined_data = join(\r\n tables: {tokens: data_request, total: sum_tokens},\r\n on: [\"join_col\"]\r\n)\r\ncross_joined_data\r\n \r\n |> map(fn: (r) => ({\r\n percent_of_prompt_tokens: float(v: r._value)/float(v: r.total_tokens)*100.0, \r\n classification: r.classification,\r\n sorting: r.sorting\r\n \r\n })) \r\n |> sort(columns: [\"sorting\"], desc: true)", + "refId": "A" + } + ], + "title": "Distribution of messages length in tokens", + "type": "barchart" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "align": "left", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 14, + "x": 10, + "y": 39 + }, + "id": 38, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": true + }, + "showHeader": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Aggregate request counts per group\r\ndata_request = from(bucket: \"default_agg_topic\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r.user_type == \"project\" and \r\n ( r._field == \"class_1\" or r._field == \"class_2\" or r._field == \"class_3\" or r._field == \"class_4\" or r._field == \"class_5\" or r._field == \"class_6\")\r\n )\r\n |> map(fn: (r) => ({\r\n _value: r._value,\r\n classification: if r._field == \"class_1\" then \"> 50000\"\r\n else if r._field == \"class_2\" then \"10001 - 50000\"\r\n else if r._field == \"class_3\" then \"5001 - 10000\"\r\n else if r._field == \"class_4\" then \"1001 - 5000\"\r\n else if r._field == \"class_5\" then \"101 - 1000\"\r\n else \"< 101\",\r\n sorting: if r._field == \"class_1\" then \"1\"\r\n else if r._field == \"class_2\" then \"2\"\r\n else if r._field == \"class_3\" then \"3\"\r\n else if r._field == \"class_4\" then \"4\"\r\n else if r._field == \"class_5\" then \"5\"\r\n else \"6\"\r\n }))\r\n |>group(columns: [\"classification\",\"sorting\"])\r\n |>sum(column: \"_value\")\r\n |> map(fn: (r) => ({join_col: \"key\",\r\n prompt_tokens: r._value,\r\n sorting: r.sorting,\r\n classification: r.classification\r\n\r\n }))\r\n |>group()\r\n\r\n\r\nsum_tokens = data_request\r\n |>sum(column: \"prompt_tokens\")\r\n |> map(fn: (r) => ({join_col: \"key\",\r\n total_tokens: r.prompt_tokens\r\n }))\r\n\r\ncross_joined_data = join(\r\n tables: {tokens: data_request, total: sum_tokens},\r\n on: [\"join_col\"]\r\n)\r\ncross_joined_data\r\n \r\n |> map(fn: (r) => ({\r\n percent_of_prompt_tokens: float(v: r.prompt_tokens)/float(v: r.total_tokens)*100.0, \r\n classification: r.classification,\r\n sorting: r.sorting,\r\n prompt_tokens: r.prompt_tokens\r\n \r\n })) \r\n |> rename(columns: {\"percent_of_prompt_tokens\": \"Percent of messages\", \"prompt_tokens\": \"Number of messages\"})\r\n |> sort(columns: [\"sorting\"], desc: false)\r\n |> drop(columns: [\"sorting\"])", + "refId": "A" + } + ], + "title": "Distribution of messages length in tokens", + "type": "table" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "#73BF69", + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "fieldMinMax": false, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "user" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "project" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-purple", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 5, + "x": 0, + "y": 51 + }, + "id": 45, + "options": { + "displayLabels": [ + "percent" + ], + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "values": [ + "value" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "10.4.0", + "repeatDirection": "v", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Aggregate request counts per group\r\ndata_request = from(bucket: \"default_agg_kpi\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r._field == \"cost\")\r\n |> map(fn: (r) => ({ \r\n r with \r\n user_type: if r.user_hash == \"undefined\" then \"project\" else \"user\"\r\n })) \r\n |> group(columns: [\"user_type\"]) // Group by the new column\r\n |> sum(column: \"_value\") // Sum cost within the groups\r\n \r\n data_request\r\n |>group()", + "refId": "A" + } + ], + "title": "Distribution of Cost (user/project)", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "includeByName": {}, + "indexByName": { + "Project": 0, + "cost($)": 1 + }, + "renameByName": { + "cost($)": "Cost($)" + } + } + } + ], + "type": "piechart" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "fieldMinMax": false, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "user" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-blue", + "mode": "fixed" + } + } + ] + }, + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "_value" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "project" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-purple", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 5, + "x": 5, + "y": 51 + }, + "id": 47, + "options": { + "displayLabels": [ + "percent" + ], + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "values": [ + "value" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "10.4.0", + "repeatDirection": "v", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Aggregate request counts per group\r\ndata_request = from(bucket: \"default_agg_kpi\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r._field == \"request_count\")\r\n |> map(fn: (r) => ({ \r\n r with \r\n user_type: if r.user_hash == \"undefined\" then \"project\" else \"user\"\r\n })) \r\n |> group(columns: [\"user_type\"]) // Group by the new column\r\n |> sum(column: \"_value\") // Sum cost within the groups\r\n \r\n data_request\r\n |>group()", + "refId": "A" + } + ], + "title": "Distribution of Requests (user/project)", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "includeByName": {}, + "indexByName": { + "Project": 0, + "cost($)": 1 + }, + "renameByName": { + "cost($)": "Cost($)" + } + } + } + ], + "type": "piechart" + } + ], + "refresh": "", + "schemaVersion": 39, + "tags": [ + "DIAL", + "ai-dial-analytics-realtime", + "Aggregated data" + ], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "InfluxDB_EPAM", + "value": "P3DF0C308D9792AAA" + }, + "description": "InfluxDB datasource", + "hide": 0, + "includeAll": false, + "label": "Data source", + "multi": false, + "name": "datasource", + "options": [], + "query": "influxdb", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": { + "selected": false, + "text": "default", + "value": "default" + }, + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "definition": "buckets()", + "description": "A InfluxDB bucket name", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "INFLUX_BUCKET", + "options": [], + "query": "buckets()", + "refresh": 1, + "regex": "/^(default)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": { + "selected": false, + "text": "No", + "value": "No" + }, + "hide": 0, + "includeAll": false, + "multi": false, + "name": "Show_Top1_percent", + "options": [ + { + "selected": true, + "text": "No", + "value": "No" + }, + { + "selected": false, + "text": "Yes", + "value": "Yes" + } + ], + "query": "No, Yes", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timepicker": {}, + "timezone": "utc", + "title": "DIAL Project insights", + "uid": "fe37iatogssn4e", + "version": 53, + "weekStart": "" +} \ No newline at end of file diff --git a/dashboards/dial_user_insigths.json b/dashboards/dial_user_insigths.json new file mode 100644 index 0000000..0e22705 --- /dev/null +++ b/dashboards/dial_user_insigths.json @@ -0,0 +1,1132 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 6, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "orange", + "mode": "fixed" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 8, + "x": 0, + "y": 0 + }, + "id": 40, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "none", + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Aggregate request counts per group\r\ndata_request = from(bucket: \"default_agg_kpi\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r._field == \"cost\" and r.user_hash !=\"\" and r.user_hash !=\"undefined\" )\r\n |> schema.fieldsAsCols()\r\n |> group(columns: [\"user_hash\"])\r\n |> sum(column:\"cost\")\r\n\r\n|>group()\r\n\r\n // Sort users by total_requests in descending order\r\nsorted_users = data_request\r\n |> sort(columns: [\"cost\"], desc: true)\r\n |> map(fn: (r) => ({r with rowId: 1}))\r\n // Taking the cumulative sum gives sequential values 1,2,3,4 et...\r\n |> cumulativeSum(columns: [\"rowId\"])\r\n\r\n// Calculate percentile thresholds\r\npercentile_90_user = sorted_users |> quantile(column: \"rowId\", q: 0.9) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_80_user = sorted_users |> quantile(column: \"rowId\", q: 0.8) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_70_user = sorted_users |> quantile(column: \"rowId\", q: 0.7) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_60_user = sorted_users |> quantile(column: \"rowId\", q: 0.6) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_50_user = sorted_users |> quantile(column: \"rowId\", q: 0.5) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_40_user = sorted_users |> quantile(column: \"rowId\", q: 0.4) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_30_user = sorted_users |> quantile(column: \"rowId\", q: 0.3) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_20_user = sorted_users |> quantile(column: \"rowId\", q: 0.2) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_10_user = sorted_users |> quantile(column: \"rowId\", q: 0.1) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_01_user = sorted_users |> quantile(column: \"rowId\", q: 0.01) |> findRecord(fn: (key) => true, idx: 0)\r\n\r\n// Map percentiles to each user based on request count thresholds\r\ndeterminePercentiles = (sorted_users, topUsers) => \r\n if topUsers == \"No\" then\r\n sorted_users\r\n |> map(fn: (r) => ({\r\n cost: r.cost,\r\n rowId: r.rowId,\r\n percentile_user: if r.rowId >= percentile_90_user.rowId then \"0-10%\"\r\n else if r.rowId >= percentile_80_user.rowId then \"11-20%\"\r\n else if r.rowId >= percentile_70_user.rowId then \"21-30%\"\r\n else if r.rowId >= percentile_60_user.rowId then \"31-40%\"\r\n else if r.rowId >= percentile_50_user.rowId then \"41-50%\"\r\n else if r.rowId >= percentile_40_user.rowId then \"51-60%\"\r\n else if r.rowId >= percentile_30_user.rowId then \"61-70%\"\r\n else if r.rowId >= percentile_20_user.rowId then \"71-80%\"\r\n else if r.rowId >= percentile_10_user.rowId then \"81-90%\"\r\n else \"Top 10%\"\r\n }))\r\n else\r\n sorted_users\r\n |> map(fn: (r) => ({\r\n cost: r.cost,\r\n rowId: r.rowId,\r\n percentile_user: if r.rowId >= percentile_90_user.rowId then \"0-10%\"\r\n else if r.rowId >= percentile_80_user.rowId then \"11-20%\"\r\n else if r.rowId >= percentile_70_user.rowId then \"21-30%\"\r\n else if r.rowId >= percentile_60_user.rowId then \"31-40%\"\r\n else if r.rowId >= percentile_50_user.rowId then \"41-50%\"\r\n else if r.rowId >= percentile_40_user.rowId then \"51-60%\"\r\n else if r.rowId >= percentile_30_user.rowId then \"61-70%\"\r\n else if r.rowId >= percentile_20_user.rowId then \"71-80%\"\r\n else if r.rowId >= percentile_10_user.rowId then \"81-90%\"\r\n else if r.rowId >= percentile_01_user.rowId then \"91-99%\"\r\n else \"Top 1%\"\r\n }))\r\n\r\n// Define the bucket and call the function\r\ntopUsers = \"${Show_Top1_percent}\" // Replace with your actual bucket variable\r\npercentiles = determinePercentiles(sorted_users: sorted_users, topUsers: topUsers)\r\n\r\n// Count the number of users in each percentile\r\npercentile_data =\r\npercentiles\r\n |> group(columns: [\"percentile_user\"])\r\n |> sum(column: \"cost\")\r\n |> map(fn: (r) => ({r with join_key: \"cross_join\"})) // Adding a dummy key for joining\r\n\r\n|> group()\r\ntotal_cost_data = percentiles\r\n\r\n |> sum(column: \"cost\")\r\n |> map(fn: (r) => ({total_cost: r.cost, join_key: \"cross_join\"})) // Adding a dummy key for joining\r\n\r\n cross_joined_data = join(\r\n tables: {percentile: percentile_data, total: total_cost_data},\r\n on: [\"join_key\"]\r\n)\r\n |> map(fn: (r) => ({percent_of_request: r.cost / r.total_cost *100.0,\r\n \r\n percentile_user: r.percentile_user,\r\n\r\n sort: if r.percentile_user == \"0-10%\" then \"0\"\r\n else if r.percentile_user == \"11-20%\" then \"1\"\r\n else if r.percentile_user == \"21-30%\" then \"2\"\r\n else if r.percentile_user == \"31-40%\" then \"3\"\r\n else if r.percentile_user == \"41-50%\" then \"4\"\r\n else if r.percentile_user == \"51-60%\" then \"5\"\r\n else if r.percentile_user == \"61-70%\" then \"6\"\r\n else if r.percentile_user == \"71-80%\" then \"7\"\r\n else if r.percentile_user == \"81-90%\" then \"8\"\r\n else if r.percentile_user == \"91-99%\" then \"9\"\r\n else \"99\"\r\n }))\r\ncross_joined_data\r\n|>group()\r\n |> sort(columns: [\"sort\"], desc: true)\r\n ", + "refId": "A" + } + ], + "title": "Cost share by deciles of Users in chat", + "type": "barchart" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "left", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percentile_user" + }, + "properties": [ + { + "id": "custom.width", + "value": 127 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cost($)" + }, + "properties": [ + { + "id": "custom.width", + "value": 71 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Percent of Cost" + }, + "properties": [ + { + "id": "custom.width", + "value": 128 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cost(%)" + }, + "properties": [ + { + "id": "custom.width", + "value": 118 + } + ] + } + ] + }, + "gridPos": { + "h": 13, + "w": 5, + "x": 8, + "y": 0 + }, + "id": 42, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": true + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Aggregate request counts per group\r\ndata_request = from(bucket: \"default_agg_kpi\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r._field == \"cost\" and r.user_hash !=\"\" and r.user_hash !=\"undefined\" )\r\n |> schema.fieldsAsCols()\r\n |> group(columns: [\"user_hash\"])\r\n |> sum(column: \"cost\")\r\n |>group()\r\n\r\n // Sort users by total_requests in descending order\r\nsorted_users = data_request\r\n |> sort(columns: [\"cost\"], desc: true)\r\n |> map(fn: (r) => ({r with rowId: 1}))\r\n // Taking the cumulative sum gives sequential values 1,2,3,4 et...\r\n |> cumulativeSum(columns: [\"rowId\"])\r\n\r\n// Calculate percentile thresholds\r\npercentile_90_user = sorted_users |> quantile(column: \"rowId\", q: 0.9) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_80_user = sorted_users |> quantile(column: \"rowId\", q: 0.8) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_70_user = sorted_users |> quantile(column: \"rowId\", q: 0.7) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_60_user = sorted_users |> quantile(column: \"rowId\", q: 0.6) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_50_user = sorted_users |> quantile(column: \"rowId\", q: 0.5) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_40_user = sorted_users |> quantile(column: \"rowId\", q: 0.4) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_30_user = sorted_users |> quantile(column: \"rowId\", q: 0.3) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_20_user = sorted_users |> quantile(column: \"rowId\", q: 0.2) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_10_user = sorted_users |> quantile(column: \"rowId\", q: 0.1) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_01_user = sorted_users |> quantile(column: \"rowId\", q: 0.01) |> findRecord(fn: (key) => true, idx: 0)\r\n\r\n\r\n// Map percentiles to each user based on request count thresholds\r\ndeterminePercentiles = (sorted_users, topUsers) => \r\n if topUsers == \"No\" then\r\n sorted_users\r\n |> map(fn: (r) => ({\r\n cost: r.cost,\r\n rowId: r.rowId,\r\n percentile_user: if r.rowId >= percentile_90_user.rowId then \"0-10%\"\r\n else if r.rowId >= percentile_80_user.rowId then \"11-20%\"\r\n else if r.rowId >= percentile_70_user.rowId then \"21-30%\"\r\n else if r.rowId >= percentile_60_user.rowId then \"31-40%\"\r\n else if r.rowId >= percentile_50_user.rowId then \"41-50%\"\r\n else if r.rowId >= percentile_40_user.rowId then \"51-60%\"\r\n else if r.rowId >= percentile_30_user.rowId then \"61-70%\"\r\n else if r.rowId >= percentile_20_user.rowId then \"71-80%\"\r\n else if r.rowId >= percentile_10_user.rowId then \"81-90%\"\r\n else \"Top 10%\"\r\n }))\r\n else\r\n sorted_users\r\n |> map(fn: (r) => ({\r\n cost: r.cost,\r\n rowId: r.rowId,\r\n percentile_user: if r.rowId >= percentile_90_user.rowId then \"0-10%\"\r\n else if r.rowId >= percentile_80_user.rowId then \"11-20%\"\r\n else if r.rowId >= percentile_70_user.rowId then \"21-30%\"\r\n else if r.rowId >= percentile_60_user.rowId then \"31-40%\"\r\n else if r.rowId >= percentile_50_user.rowId then \"41-50%\"\r\n else if r.rowId >= percentile_40_user.rowId then \"51-60%\"\r\n else if r.rowId >= percentile_30_user.rowId then \"61-70%\"\r\n else if r.rowId >= percentile_20_user.rowId then \"71-80%\"\r\n else if r.rowId >= percentile_10_user.rowId then \"81-90%\"\r\n else if r.rowId >= percentile_01_user.rowId then \"91-99%\"\r\n else \"Top 1%\"\r\n }))\r\n\r\n// Define the bucket and call the function\r\ntopUsers = \"${Show_Top1_percent}\" // Replace with your actual bucket variable\r\npercentiles = determinePercentiles(sorted_users: sorted_users, topUsers: topUsers)\r\n\r\n\r\n// Count the number of users in each percentile\r\npercentile_data =\r\npercentiles\r\n |> group(columns: [\"percentile_user\"])\r\n |> sum(column: \"cost\")\r\n |> map(fn: (r) => ({r with join_key: \"cross_join\"})) // Adding a dummy key for joining\r\n\r\n|> group()\r\ntotal_cost_data = percentiles\r\n\r\n |> sum(column: \"cost\")\r\n |> map(fn: (r) => ({total_cost: r.cost, join_key: \"cross_join\"})) // Adding a dummy key for joining\r\n\r\n cross_joined_data = join(\r\n tables: {percentile: percentile_data, total: total_cost_data},\r\n on: [\"join_key\"]\r\n)\r\n |> map(fn: (r) => ({percent_of_request: float(v: r.cost) / float(v: r.total_cost)*100.0,\r\n \r\n cost:r.cost,\r\n Percentile_user: r.percentile_user,\r\n sort: if r.percentile_user == \"0-10%\" then \"0\"\r\n else if r.percentile_user == \"11-20%\" then \"1\"\r\n else if r.percentile_user == \"21-30%\" then \"2\"\r\n else if r.percentile_user == \"31-40%\" then \"3\"\r\n else if r.percentile_user == \"41-50%\" then \"4\"\r\n else if r.percentile_user == \"51-60%\" then \"5\"\r\n else if r.percentile_user == \"61-70%\" then \"6\"\r\n else if r.percentile_user == \"71-80%\" then \"7\"\r\n else if r.percentile_user == \"81-90%\" then \"8\"\r\n else if r.percentile_user == \"91-99%\" then \"9\"\r\n else \"99\"\r\n }))\r\ncross_joined_data\r\n|>group()\r\n |> rename(columns: {\"percent_of_request\": \"Percent of Cost\", \"cost\": \"Cost($)\"})\r\n|> sort(columns: [\"sort\"], desc: true)\r\n|> drop(columns: [\"sort\"])", + "refId": "A" + } + ], + "title": "Cost share by deciles of Users in chat", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "includeByName": {}, + "indexByName": { + "Cost($)": 2, + "Percent of Cost": 1, + "Percentile_user": 0 + }, + "renameByName": { + "Percent of Cost": "Cost(%)" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "left", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Prompt tokens" + }, + "properties": [ + { + "id": "custom.width", + "value": 141 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Deployment" + }, + "properties": [ + { + "id": "custom.width", + "value": 235 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Request count" + }, + "properties": [ + { + "id": "custom.width", + "value": 131 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cost ($)" + }, + "properties": [ + { + "id": "custom.width", + "value": 108 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Model" + }, + "properties": [ + { + "id": "custom.width", + "value": 218 + } + ] + } + ] + }, + "gridPos": { + "h": 19, + "w": 11, + "x": 13, + "y": 0 + }, + "id": 48, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": true + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Aggregate request counts per group\r\ndata_request = from(bucket: \"default_agg_stats\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => (r._field == \"prompt_tokens\" or r._field == \"request_count\" or r._field == \"price\" ))\r\n |> filter(fn: (r) => not exists r.project_id)\r\n |> schema.fieldsAsCols()\r\n |> group(columns: [\"deployment\", \"model\"])\r\n |> reduce(\r\n fn: (r, accumulator) => ({\r\n request_count: getOrDefault(f: r.request_count, d: 0) + accumulator.request_count,\r\n prompt_tokens: getOrDefault(f: r.prompt_tokens, d: 0) + accumulator.prompt_tokens,\r\n price: getOrDefault(f: r.price, d: 0.0) + accumulator.price\r\n }),\r\n identity: {request_count: 0, prompt_tokens: 0, price:0.0}\r\n )\r\n\r\n data_request\r\n |> group()\r\n |> sort(columns: [\"request_count\"], desc: true)", + "refId": "A" + } + ], + "title": "Deployment/Model Stats Table", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "includeByName": {}, + "indexByName": { + "deployment": 1, + "model": 0, + "price": 4, + "prompt_tokens": 3, + "request_count": 2 + }, + "renameByName": { + "deployment": "Deployment", + "model": "Model", + "price": "Cost ($)", + "project_id": "", + "prompt_tokens": "Prompt tokens", + "request_count": "Request count" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 14, + "w": 8, + "x": 0, + "y": 13 + }, + "id": 43, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "none", + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Aggregate request counts per group\r\ndata_request = from(bucket: \"default_agg_kpi\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r._field == \"request_count\" and r.user_hash !=\"\" and r.user_hash !=\"undefined\" )\r\n |> schema.fieldsAsCols()\r\n |> group(columns: [\"user_hash\"])\r\n |> sum(column:\"request_count\")\r\n|>group()\r\n\r\n // Sort users by total_requests in descending order\r\nsorted_users = data_request\r\n |> sort(columns: [\"request_count\"], desc: true)\r\n |> map(fn: (r) => ({r with rowId: 1}))\r\n // Taking the cumulative sum gives sequential values 1,2,3,4 et...\r\n |> cumulativeSum(columns: [\"rowId\"])\r\n\r\n// Calculate percentile thresholds\r\npercentile_90_user = sorted_users |> quantile(column: \"rowId\", q: 0.9) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_80_user = sorted_users |> quantile(column: \"rowId\", q: 0.8) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_70_user = sorted_users |> quantile(column: \"rowId\", q: 0.7) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_60_user = sorted_users |> quantile(column: \"rowId\", q: 0.6) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_50_user = sorted_users |> quantile(column: \"rowId\", q: 0.5) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_40_user = sorted_users |> quantile(column: \"rowId\", q: 0.4) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_30_user = sorted_users |> quantile(column: \"rowId\", q: 0.3) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_20_user = sorted_users |> quantile(column: \"rowId\", q: 0.2) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_10_user = sorted_users |> quantile(column: \"rowId\", q: 0.1) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_01_user = sorted_users |> quantile(column: \"rowId\", q: 0.01) |> findRecord(fn: (key) => true, idx: 0)\r\n\r\n\r\n// Map percentiles to each user based on request count thresholds\r\ndeterminePercentiles = (sorted_users, topUsers) => \r\n if topUsers == \"No\" then\r\n sorted_users\r\n |> map(fn: (r) => ({\r\n request_count: r.request_count,\r\n rowId: r.rowId,\r\n percentile_user: if r.rowId >= percentile_90_user.rowId then \"0-10%\"\r\n else if r.rowId >= percentile_80_user.rowId then \"11-20%\"\r\n else if r.rowId >= percentile_70_user.rowId then \"21-30%\"\r\n else if r.rowId >= percentile_60_user.rowId then \"31-40%\"\r\n else if r.rowId >= percentile_50_user.rowId then \"41-50%\"\r\n else if r.rowId >= percentile_40_user.rowId then \"51-60%\"\r\n else if r.rowId >= percentile_30_user.rowId then \"61-70%\"\r\n else if r.rowId >= percentile_20_user.rowId then \"71-80%\"\r\n else if r.rowId >= percentile_10_user.rowId then \"81-90%\"\r\n else \"Top 10%\"\r\n }))\r\n else\r\n sorted_users\r\n |> map(fn: (r) => ({\r\n request_count: r.request_count,\r\n rowId: r.rowId,\r\n percentile_user: if r.rowId >= percentile_90_user.rowId then \"0-10%\"\r\n else if r.rowId >= percentile_80_user.rowId then \"11-20%\"\r\n else if r.rowId >= percentile_70_user.rowId then \"21-30%\"\r\n else if r.rowId >= percentile_60_user.rowId then \"31-40%\"\r\n else if r.rowId >= percentile_50_user.rowId then \"41-50%\"\r\n else if r.rowId >= percentile_40_user.rowId then \"51-60%\"\r\n else if r.rowId >= percentile_30_user.rowId then \"61-70%\"\r\n else if r.rowId >= percentile_20_user.rowId then \"71-80%\"\r\n else if r.rowId >= percentile_10_user.rowId then \"81-90%\"\r\n else if r.rowId >= percentile_01_user.rowId then \"91-99%\"\r\n else \"Top 1%\"\r\n }))\r\n\r\n// Define the bucket and call the function\r\ntopUsers = \"${Show_Top1_percent}\" // Replace with your actual bucket variable\r\npercentiles = determinePercentiles(sorted_users: sorted_users, topUsers: topUsers)\r\n\r\n// Count the number of users in each percentile\r\npercentile_data =\r\npercentiles\r\n |> group(columns: [\"percentile_user\"])\r\n |> sum(column: \"request_count\")\r\n |> map(fn: (r) => ({r with join_key: \"cross_join\"})) // Adding a dummy key for joining\r\n\r\n|> group()\r\ntotal_cost_data = percentiles\r\n\r\n |> sum(column: \"request_count\")\r\n |> map(fn: (r) => ({total_request_count: r.request_count, join_key: \"cross_join\"})) // Adding a dummy key for joining\r\n\r\n cross_joined_data = join(\r\n tables: {percentile: percentile_data, total: total_cost_data},\r\n on: [\"join_key\"]\r\n)\r\n |> map(fn: (r) => ({\r\n\r\n percent_of_request: float(v: r.request_count) / float(v: r.total_request_count)*100.0, \r\n percentile_user: r.percentile_user,\r\n sort: if r.percentile_user == \"0-10%\" then \"0\"\r\n else if r.percentile_user == \"11-20%\" then \"1\"\r\n else if r.percentile_user == \"21-30%\" then \"2\"\r\n else if r.percentile_user == \"31-40%\" then \"3\"\r\n else if r.percentile_user == \"41-50%\" then \"4\"\r\n else if r.percentile_user == \"51-60%\" then \"5\"\r\n else if r.percentile_user == \"61-70%\" then \"6\"\r\n else if r.percentile_user == \"71-80%\" then \"7\"\r\n else if r.percentile_user == \"81-90%\" then \"8\"\r\n else if r.percentile_user == \"91-99%\" then \"9\"\r\n else \"99\"\r\n }))\r\ncross_joined_data\r\n|>group()\r\n|> sort(columns: [\"sort\"], desc: true)\r\n ", + "refId": "A" + } + ], + "title": "Reqests share by deciles of Users in chat", + "type": "barchart" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "left", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percentile_user" + }, + "properties": [ + { + "id": "custom.width", + "value": 121 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Percent of request" + }, + "properties": [ + { + "id": "custom.width", + "value": 105 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Request count" + }, + "properties": [ + { + "id": "custom.width", + "value": 119 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Request(%)" + }, + "properties": [ + { + "id": "custom.width", + "value": 123 + } + ] + } + ] + }, + "gridPos": { + "h": 14, + "w": 5, + "x": 8, + "y": 13 + }, + "id": 39, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": true + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Aggregate request counts per group\r\ndata_request = from(bucket: \"default_agg_kpi\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r._field == \"request_count\" and r.user_hash !=\"\" and r.user_hash !=\"undefined\" )\r\n |> schema.fieldsAsCols()\r\n |> group(columns: [\"user_hash\"])\r\n |> sum(column:\"request_count\")\r\n\r\n|>group()\r\n\r\n // Sort users by total_requests in descending order\r\nsorted_users = data_request\r\n |> sort(columns: [\"request_count\"], desc: true)\r\n |> map(fn: (r) => ({r with rowId: 1}))\r\n // Taking the cumulative sum gives sequential values 1,2,3,4 et...\r\n |> cumulativeSum(columns: [\"rowId\"])\r\n\r\n// Calculate percentile thresholds\r\npercentile_90_user = sorted_users |> quantile(column: \"rowId\", q: 0.9) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_80_user = sorted_users |> quantile(column: \"rowId\", q: 0.8) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_70_user = sorted_users |> quantile(column: \"rowId\", q: 0.7) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_60_user = sorted_users |> quantile(column: \"rowId\", q: 0.6) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_50_user = sorted_users |> quantile(column: \"rowId\", q: 0.5) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_40_user = sorted_users |> quantile(column: \"rowId\", q: 0.4) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_30_user = sorted_users |> quantile(column: \"rowId\", q: 0.3) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_20_user = sorted_users |> quantile(column: \"rowId\", q: 0.2) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_10_user = sorted_users |> quantile(column: \"rowId\", q: 0.1) |> findRecord(fn: (key) => true, idx: 0)\r\npercentile_01_user = sorted_users |> quantile(column: \"rowId\", q: 0.01) |> findRecord(fn: (key) => true, idx: 0)\r\n\r\n\r\n// Map percentiles to each user based on request count thresholds\r\ndeterminePercentiles = (sorted_users, topUsers) => \r\n if topUsers == \"No\" then\r\n sorted_users\r\n |> map(fn: (r) => ({\r\n request_count: r.request_count,\r\n rowId: r.rowId,\r\n percentile_user: if r.rowId >= percentile_90_user.rowId then \"0-10%\"\r\n else if r.rowId >= percentile_80_user.rowId then \"11-20%\"\r\n else if r.rowId >= percentile_70_user.rowId then \"21-30%\"\r\n else if r.rowId >= percentile_60_user.rowId then \"31-40%\"\r\n else if r.rowId >= percentile_50_user.rowId then \"41-50%\"\r\n else if r.rowId >= percentile_40_user.rowId then \"51-60%\"\r\n else if r.rowId >= percentile_30_user.rowId then \"61-70%\"\r\n else if r.rowId >= percentile_20_user.rowId then \"71-80%\"\r\n else if r.rowId >= percentile_10_user.rowId then \"81-90%\"\r\n else \"Top 10%\"\r\n }))\r\n else\r\n sorted_users\r\n |> map(fn: (r) => ({\r\n request_count: r.request_count,\r\n rowId: r.rowId,\r\n percentile_user: if r.rowId >= percentile_90_user.rowId then \"0-10%\"\r\n else if r.rowId >= percentile_80_user.rowId then \"11-20%\"\r\n else if r.rowId >= percentile_70_user.rowId then \"21-30%\"\r\n else if r.rowId >= percentile_60_user.rowId then \"31-40%\"\r\n else if r.rowId >= percentile_50_user.rowId then \"41-50%\"\r\n else if r.rowId >= percentile_40_user.rowId then \"51-60%\"\r\n else if r.rowId >= percentile_30_user.rowId then \"61-70%\"\r\n else if r.rowId >= percentile_20_user.rowId then \"71-80%\"\r\n else if r.rowId >= percentile_10_user.rowId then \"81-90%\"\r\n else if r.rowId >= percentile_01_user.rowId then \"91-99%\"\r\n else \"Top 1%\"\r\n }))\r\n// Define the bucket and call the function\r\ntopUsers = \"${Show_Top1_percent}\" // Replace with your actual bucket variable\r\npercentiles = determinePercentiles(sorted_users: sorted_users, topUsers: topUsers)\r\n// Count the number of users in each percentile\r\npercentile_data =\r\npercentiles\r\n |> group(columns: [\"percentile_user\"])\r\n |> sum(column: \"request_count\")\r\n |> map(fn: (r) => ({r with join_key: \"cross_join\"})) // Adding a dummy key for joining\r\n\r\n|> group()\r\ntotal_cost_data = percentiles\r\n\r\n |> sum(column: \"request_count\")\r\n |> map(fn: (r) => ({total_request_count: r.request_count, join_key: \"cross_join\"})) // Adding a dummy key for joining\r\n\r\n cross_joined_data = join(\r\n tables: {percentile: percentile_data, total: total_cost_data},\r\n on: [\"join_key\"]\r\n)\r\n |> map(fn: (r) => ({percent_of_request: float(v: r.request_count) / float(v: r.total_request_count)*100.0,\r\n \r\n request_count:r.request_count,\r\n Percentile_user: r.percentile_user,\r\n sort: if r.percentile_user == \"0-10%\" then \"0\"\r\n else if r.percentile_user == \"11-20%\" then \"1\"\r\n else if r.percentile_user == \"21-30%\" then \"2\"\r\n else if r.percentile_user == \"31-40%\" then \"3\"\r\n else if r.percentile_user == \"41-50%\" then \"4\"\r\n else if r.percentile_user == \"51-60%\" then \"5\"\r\n else if r.percentile_user == \"61-70%\" then \"6\"\r\n else if r.percentile_user == \"71-80%\" then \"7\"\r\n else if r.percentile_user == \"81-90%\" then \"8\"\r\n else if r.percentile_user == \"91-99%\" then \"9\"\r\n else \"99\"\r\n }))\r\ncross_joined_data\r\n|>group()\r\n |> rename(columns: {\"percent_of_request\": \"Percent of request\", \"request_count\": \"Request count\"})\r\n|> sort(columns: [\"sort\"], desc: true)\r\n|> drop(columns: [\"sort\"])", + "refId": "A" + } + ], + "title": "Reqests share by deciles of Users in chat", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "includeByName": {}, + "indexByName": {}, + "renameByName": { + "Percent of request": "Request(%)" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "fieldMinMax": false, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "user" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-blue", + "mode": "fixed" + } + } + ] + }, + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "_value" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "project" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-purple", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 5, + "x": 13, + "y": 19 + }, + "id": 47, + "options": { + "displayLabels": [ + "percent" + ], + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "values": [ + "value" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "10.4.0", + "repeatDirection": "v", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Aggregate request counts per group\r\ndata_request = from(bucket: \"default_agg_kpi\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r._field == \"request_count\")\r\n |> map(fn: (r) => ({ \r\n r with \r\n user_type: if r.user_hash == \"undefined\" then \"project\" else \"user\"\r\n })) \r\n |> group(columns: [\"user_type\"]) // Group by the new column\r\n |> sum(column: \"_value\") // Sum cost within the groups\r\n \r\n data_request\r\n |>group()", + "refId": "A" + } + ], + "title": "Distribution of Requests (user/project)", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "includeByName": {}, + "indexByName": { + "Project": 0, + "cost($)": 1 + }, + "renameByName": { + "cost($)": "Cost($)" + } + } + } + ], + "type": "piechart" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "#73BF69", + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "fieldMinMax": false, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "user" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "project" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-purple", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 19 + }, + "id": 45, + "options": { + "displayLabels": [ + "percent" + ], + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "values": [ + "value" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "10.4.0", + "repeatDirection": "v", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Aggregate request counts per group\r\ndata_request = from(bucket: \"default_agg_kpi\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r._field == \"cost\")\r\n |> map(fn: (r) => ({ \r\n r with \r\n user_type: if r.user_hash == \"undefined\" then \"project\" else \"user\"\r\n })) \r\n |> group(columns: [\"user_type\"]) // Group by the new column\r\n |> sum(column: \"_value\") // Sum cost within the groups\r\n \r\n data_request\r\n |>group()", + "refId": "A" + } + ], + "title": "Distribution of Cost (user/project)", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "includeByName": {}, + "indexByName": { + "Project": 0, + "cost($)": 1 + }, + "renameByName": { + "cost($)": "Cost($)" + } + } + } + ], + "type": "piechart" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 13, + "x": 0, + "y": 27 + }, + "id": 37, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "none", + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\ndata_request = from(bucket: \"default_agg_topic\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r.user_type != \"project\" and \r\n ( r._field == \"class_1\" or r._field == \"class_2\" or r._field == \"class_3\" or r._field == \"class_4\" or r._field == \"class_5\" or r._field == \"class_6\")\r\n )\r\n |> map(fn: (r) => ({\r\n _value: r._value,\r\n classification: if r._field == \"class_1\" then \"> 50000\"\r\n else if r._field == \"class_2\" then \"10001 - 50000\"\r\n else if r._field == \"class_3\" then \"5001 - 10000\"\r\n else if r._field == \"class_4\" then \"1001 - 5000\"\r\n else if r._field == \"class_5\" then \"101 - 1000\"\r\n else \"< 101\",\r\n sorting: if r._field == \"class_1\" then \"1\"\r\n else if r._field == \"class_2\" then \"2\"\r\n else if r._field == \"class_3\" then \"3\"\r\n else if r._field == \"class_4\" then \"4\"\r\n else if r._field == \"class_5\" then \"5\"\r\n else \"6\"\r\n }))\r\n |>group(columns: [\"classification\",\"sorting\"])\r\n |>sum(column: \"_value\")\r\n |> map(fn: (r) => ({join_col: \"key\",\r\n _value: r._value,\r\n sorting: r.sorting,\r\n classification: r.classification\r\n\r\n }))\r\n |>group()\r\n\r\n\r\nsum_tokens = data_request\r\n |>sum(column: \"_value\")\r\n |> map(fn: (r) => ({join_col: \"key\",\r\n total_tokens: r._value\r\n }))\r\n\r\ncross_joined_data = join(\r\n tables: {tokens: data_request, total: sum_tokens},\r\n on: [\"join_col\"]\r\n)\r\ncross_joined_data\r\n \r\n |> map(fn: (r) => ({\r\n percent_of_prompt_tokens: float(v: r._value)/float(v: r.total_tokens)*100.0, \r\n classification: r.classification,\r\n sorting: r.sorting\r\n \r\n })) \r\n |> sort(columns: [\"sorting\"], desc: true)", + "refId": "A" + } + ], + "title": "Distribution of messages length in tokens", + "type": "barchart" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "align": "left", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 11, + "x": 13, + "y": 27 + }, + "id": 38, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": true + }, + "showHeader": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "query": "import \"influxdata/influxdb/schema\"\r\nimport \"experimental\"\r\nimport \"array\"\r\n\r\ngetOrDefault = (f, d) => if exists f then f else d\r\n\r\n// Aggregate request counts per group\r\ndata_request = from(bucket: \"default_agg_topic\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r.user_type == \"project\" and \r\n (r._field == \"class_1\" or r._field == \"class_2\" or r._field == \"class_3\" or r._field == \"class_4\" or r._field == \"class_5\" or r._field == \"class_6\")\r\n )\r\n |> map(fn: (r) => ({\r\n _value: r._value,\r\n classification: if r._field == \"class_1\" then \"> 50000\"\r\n else if r._field == \"class_2\" then \"10001 - 50000\"\r\n else if r._field == \"class_3\" then \"5001 - 10000\"\r\n else if r._field == \"class_4\" then \"1001 - 5000\"\r\n else if r._field == \"class_5\" then \"101 - 1000\"\r\n else \"< 101\",\r\n sorting: if r._field == \"class_1\" then \"1\"\r\n else if r._field == \"class_2\" then \"2\"\r\n else if r._field == \"class_3\" then \"3\"\r\n else if r._field == \"class_4\" then \"4\"\r\n else if r._field == \"class_5\" then \"5\"\r\n else \"6\"\r\n }))\r\n |>group(columns: [\"classification\",\"sorting\"])\r\n |>sum(column: \"_value\")\r\n |> map(fn: (r) => ({join_col: \"key\",\r\n prompt_tokens: r._value,\r\n sorting: r.sorting,\r\n classification: r.classification\r\n\r\n }))\r\n |>group()\r\n\r\n\r\nsum_tokens = data_request\r\n |>sum(column: \"prompt_tokens\")\r\n |> map(fn: (r) => ({join_col: \"key\",\r\n total_tokens: r.prompt_tokens\r\n }))\r\n\r\ncross_joined_data = join(\r\n tables: {tokens: data_request, total: sum_tokens},\r\n on: [\"join_col\"]\r\n)\r\ncross_joined_data\r\n \r\n |> map(fn: (r) => ({\r\n percent_of_prompt_tokens: float(v: r.prompt_tokens)/float(v: r.total_tokens)*100.0, \r\n classification: r.classification,\r\n sorting: r.sorting,\r\n prompt_tokens: r.prompt_tokens\r\n \r\n })) \r\n |> rename(columns: {\"percent_of_prompt_tokens\": \"Percent of messages\", \"prompt_tokens\": \"Number of messages\"})\r\n |> sort(columns: [\"sorting\"], desc: false)\r\n |> drop(columns: [\"sorting\"])", + "refId": "A" + } + ], + "title": "Distribution of messages length in tokens", + "type": "table" + } + ], + "refresh": "", + "schemaVersion": 39, + "tags": [ + "DIAL", + "Aggregated data", + "ai-dial-analytics-realtime" + ], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "InfluxDB_EPAM", + "value": "P3DF0C308D9792AAA" + }, + "description": "InfluxDB datasource", + "hide": 0, + "includeAll": false, + "label": "Data source", + "multi": false, + "name": "datasource", + "options": [], + "query": "influxdb", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": { + "selected": false, + "text": "default", + "value": "default" + }, + "datasource": { + "type": "influxdb", + "uid": "P3DF0C308D9792AAA" + }, + "definition": "buckets()", + "description": "A InfluxDB bucket name", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "INFLUX_BUCKET", + "options": [], + "query": "buckets()", + "refresh": 1, + "regex": "/^(default)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": { + "selected": false, + "text": "No", + "value": "No" + }, + "hide": 0, + "includeAll": false, + "multi": false, + "name": "Show_Top1_percent", + "options": [ + { + "selected": true, + "text": "No", + "value": "No" + }, + { + "selected": false, + "text": "Yes", + "value": "Yes" + } + ], + "query": "No, Yes", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timepicker": {}, + "timezone": "utc", + "title": "DIAL User insights", + "uid": "fe37iatogssdfd", + "version": 11, + "weekStart": "" +} \ No newline at end of file