systemprompt_cli/commands/analytics/content/
mod.rs1mod stats;
2mod top;
3mod trends;
4
5use anyhow::Result;
6use clap::Subcommand;
7use schemars::JsonSchema;
8use serde::{Deserialize, Serialize};
9use systemprompt_runtime::DatabaseContext;
10
11use crate::shared::render_result;
12use crate::CliConfig;
13
14#[derive(Debug, Subcommand)]
15pub enum ContentCommands {
16 #[command(about = "Content engagement statistics")]
17 Stats(stats::StatsArgs),
18
19 #[command(about = "Top performing content")]
20 Top(top::TopArgs),
21
22 #[command(about = "Content trends over time")]
23 Trends(trends::TrendsArgs),
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
27pub struct ContentStatsOutput {
28 pub period: String,
29 pub total_views: i64,
30 pub unique_visitors: i64,
31 pub avg_time_on_page_seconds: i64,
32 pub avg_scroll_depth: f64,
33 pub total_clicks: i64,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
37pub struct TopContentRow {
38 pub content_id: String,
39 pub views: i64,
40 pub unique_visitors: i64,
41 pub avg_time_seconds: i64,
42 pub trend: String,
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
46pub struct TopContentOutput {
47 pub period: String,
48 pub content: Vec<TopContentRow>,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
52pub struct ContentTrendPoint {
53 pub timestamp: String,
54 pub views: i64,
55 pub unique_visitors: i64,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
59pub struct ContentTrendsOutput {
60 pub period: String,
61 pub group_by: String,
62 pub points: Vec<ContentTrendPoint>,
63}
64
65pub async fn execute(command: ContentCommands, config: &CliConfig) -> Result<()> {
66 match command {
67 ContentCommands::Stats(args) => {
68 let result = stats::execute(args, config).await?;
69 render_result(&result);
70 Ok(())
71 },
72 ContentCommands::Top(args) => {
73 let result = top::execute(args, config).await?;
74 render_result(&result);
75 Ok(())
76 },
77 ContentCommands::Trends(args) => {
78 let result = trends::execute(args, config).await?;
79 render_result(&result);
80 Ok(())
81 },
82 }
83}
84
85pub async fn execute_with_pool(
86 command: ContentCommands,
87 db_ctx: &DatabaseContext,
88 config: &CliConfig,
89) -> Result<()> {
90 match command {
91 ContentCommands::Stats(args) => {
92 let result = stats::execute_with_pool(args, db_ctx, config).await?;
93 render_result(&result);
94 Ok(())
95 },
96 ContentCommands::Top(args) => {
97 let result = top::execute_with_pool(args, db_ctx, config).await?;
98 render_result(&result);
99 Ok(())
100 },
101 ContentCommands::Trends(args) => {
102 let result = trends::execute_with_pool(args, db_ctx, config).await?;
103 render_result(&result);
104 Ok(())
105 },
106 }
107}