Skip to main content

systemprompt_cli/commands/analytics/requests/
mod.rs

1mod list;
2mod models;
3mod stats;
4mod trends;
5
6use anyhow::Result;
7use clap::Subcommand;
8use schemars::JsonSchema;
9use serde::{Deserialize, Serialize};
10use systemprompt_runtime::DatabaseContext;
11
12use crate::shared::render_result;
13use crate::CliConfig;
14
15#[derive(Debug, Subcommand)]
16pub enum RequestsCommands {
17    #[command(about = "Aggregate AI request statistics")]
18    Stats(stats::StatsArgs),
19
20    #[command(about = "List individual AI requests")]
21    List(list::ListArgs),
22
23    #[command(about = "AI request trends over time")]
24    Trends(trends::TrendsArgs),
25
26    #[command(about = "Model usage breakdown")]
27    Models(models::ModelsArgs),
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
31pub struct RequestStatsOutput {
32    pub period: String,
33    pub total_requests: i64,
34    pub total_tokens: i64,
35    pub input_tokens: i64,
36    pub output_tokens: i64,
37    pub total_cost_microdollars: i64,
38    pub avg_latency_ms: i64,
39    pub cache_hit_rate: f64,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
43pub struct RequestTrendPoint {
44    pub timestamp: String,
45    pub request_count: i64,
46    pub total_tokens: i64,
47    pub cost_microdollars: i64,
48    pub avg_latency_ms: i64,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
52pub struct RequestTrendsOutput {
53    pub period: String,
54    pub group_by: String,
55    pub points: Vec<RequestTrendPoint>,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
59pub struct ModelUsageRow {
60    pub provider: String,
61    pub model: String,
62    pub request_count: i64,
63    pub total_tokens: i64,
64    pub total_cost_microdollars: i64,
65    pub avg_latency_ms: i64,
66    pub percentage: f64,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
70pub struct ModelsOutput {
71    pub period: String,
72    pub models: Vec<ModelUsageRow>,
73    pub total_requests: i64,
74}
75
76pub async fn execute(command: RequestsCommands, config: &CliConfig) -> Result<()> {
77    match command {
78        RequestsCommands::Stats(args) => {
79            let result = stats::execute(args, config).await?;
80            render_result(&result);
81            Ok(())
82        },
83        RequestsCommands::List(args) => {
84            let result = list::execute(args, config).await?;
85            render_result(&result);
86            Ok(())
87        },
88        RequestsCommands::Trends(args) => {
89            let result = trends::execute(args, config).await?;
90            render_result(&result);
91            Ok(())
92        },
93        RequestsCommands::Models(args) => {
94            let result = models::execute(args, config).await?;
95            render_result(&result);
96            Ok(())
97        },
98    }
99}
100
101pub async fn execute_with_pool(
102    command: RequestsCommands,
103    db_ctx: &DatabaseContext,
104    config: &CliConfig,
105) -> Result<()> {
106    match command {
107        RequestsCommands::Stats(args) => {
108            let result = stats::execute_with_pool(args, db_ctx, config).await?;
109            render_result(&result);
110            Ok(())
111        },
112        RequestsCommands::List(args) => {
113            let result = list::execute_with_pool(args, db_ctx, config).await?;
114            render_result(&result);
115            Ok(())
116        },
117        RequestsCommands::Trends(args) => {
118            let result = trends::execute_with_pool(args, db_ctx, config).await?;
119            render_result(&result);
120            Ok(())
121        },
122        RequestsCommands::Models(args) => {
123            let result = models::execute_with_pool(args, db_ctx, config).await?;
124            render_result(&result);
125            Ok(())
126        },
127    }
128}