Skip to main content

systemprompt_cli/commands/analytics/content/
mod.rs

1mod 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::CliConfig;
12use crate::shared::render_result;
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 = "Top performing content", hide = true)]
23    Popular(top::TopArgs),
24
25    #[command(about = "Content trends over time")]
26    Trends(trends::TrendsArgs),
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
30pub struct ContentStatsOutput {
31    pub period: String,
32    pub total_views: i64,
33    pub unique_visitors: i64,
34    pub avg_time_on_page_seconds: i64,
35    pub avg_scroll_depth: f64,
36    pub total_clicks: i64,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
40pub struct TopContentRow {
41    #[serde(rename = "content_id")]
42    pub content: String,
43    pub slug: String,
44    pub title: String,
45    pub source: String,
46    pub views: i64,
47    pub unique_visitors: i64,
48    pub avg_time_seconds: i64,
49    pub trend: String,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
53pub struct TopContentOutput {
54    pub period: String,
55    pub content: Vec<TopContentRow>,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
59pub struct ContentTrendPoint {
60    pub timestamp: String,
61    pub views: i64,
62    pub unique_visitors: i64,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
66pub struct ContentTrendsOutput {
67    pub period: String,
68    pub group_by: String,
69    pub points: Vec<ContentTrendPoint>,
70}
71
72pub async fn execute(command: ContentCommands, config: &CliConfig) -> Result<()> {
73    match command {
74        ContentCommands::Stats(args) => {
75            let result = stats::execute(args, config).await?;
76            render_result(&result);
77            Ok(())
78        },
79        ContentCommands::Top(args) | ContentCommands::Popular(args) => {
80            let result = top::execute(args, config).await?;
81            render_result(&result);
82            Ok(())
83        },
84        ContentCommands::Trends(args) => {
85            let result = trends::execute(args, config).await?;
86            render_result(&result);
87            Ok(())
88        },
89    }
90}
91
92pub async fn execute_with_pool(
93    command: ContentCommands,
94    db_ctx: &DatabaseContext,
95    config: &CliConfig,
96) -> Result<()> {
97    match command {
98        ContentCommands::Stats(args) => {
99            let result = stats::execute_with_pool(args, db_ctx, config).await?;
100            render_result(&result);
101            Ok(())
102        },
103        ContentCommands::Top(args) | ContentCommands::Popular(args) => {
104            let result = top::execute_with_pool(args, db_ctx, config).await?;
105            render_result(&result);
106            Ok(())
107        },
108        ContentCommands::Trends(args) => {
109            let result = trends::execute_with_pool(args, db_ctx, config).await?;
110            render_result(&result);
111            Ok(())
112        },
113    }
114}