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::CliConfig;
13
14#[derive(Debug, Subcommand)]
15pub enum RequestsCommands {
16    #[command(about = "Aggregate AI request statistics")]
17    Stats(stats::StatsArgs),
18
19    #[command(about = "List individual AI requests")]
20    List(list::ListArgs),
21
22    #[command(about = "AI request trends over time")]
23    Trends(trends::TrendsArgs),
24
25    #[command(about = "Model usage breakdown")]
26    Models(models::ModelsArgs),
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
30pub struct RequestStatsOutput {
31    pub period: String,
32    pub total_requests: i64,
33    pub total_tokens: i64,
34    pub input_tokens: i64,
35    pub output_tokens: i64,
36    pub total_cost_cents: i64,
37    pub avg_latency_ms: i64,
38    pub cache_hit_rate: f64,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
42pub struct RequestTrendPoint {
43    pub timestamp: String,
44    pub request_count: i64,
45    pub total_tokens: i64,
46    pub cost_cents: i64,
47    pub avg_latency_ms: i64,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
51pub struct RequestTrendsOutput {
52    pub period: String,
53    pub group_by: String,
54    pub points: Vec<RequestTrendPoint>,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
58pub struct ModelUsageRow {
59    pub provider: String,
60    pub model: String,
61    pub request_count: i64,
62    pub total_tokens: i64,
63    pub total_cost_cents: i64,
64    pub avg_latency_ms: i64,
65    pub percentage: f64,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
69pub struct ModelsOutput {
70    pub period: String,
71    pub models: Vec<ModelUsageRow>,
72    pub total_requests: i64,
73}
74
75pub async fn execute(command: RequestsCommands, config: &CliConfig) -> Result<()> {
76    match command {
77        RequestsCommands::Stats(args) => stats::execute(args, config).await,
78        RequestsCommands::List(args) => list::execute(args, config).await,
79        RequestsCommands::Trends(args) => trends::execute(args, config).await,
80        RequestsCommands::Models(args) => models::execute(args, config).await,
81    }
82}
83
84pub async fn execute_with_pool(
85    command: RequestsCommands,
86    db_ctx: &DatabaseContext,
87    config: &CliConfig,
88) -> Result<()> {
89    match command {
90        RequestsCommands::Stats(args) => stats::execute_with_pool(args, db_ctx, config).await,
91        RequestsCommands::List(args) => list::execute_with_pool(args, db_ctx, config).await,
92        RequestsCommands::Trends(args) => trends::execute_with_pool(args, db_ctx, config).await,
93        RequestsCommands::Models(args) => models::execute_with_pool(args, db_ctx, config).await,
94    }
95}