Spaces:
Running
Running
| """admin/routers/analytics.py β Analytics and reporting routes. | |
| Routes: | |
| GET /{slug}/analytics β Daily session counts | |
| GET /{slug}/analytics/funnel β Conversion funnel | |
| GET /{slug}/analytics/intents β Intent label distribution | |
| GET /{slug}/analytics/unanswered β Phase 10A: Unanswered/boundary questions | |
| GET /{slug}/analytics/books β Phase 10B: Per-book engagement breakdown | |
| GET /{slug}/analytics/heatmap β Phase 10C: Hourly Γ weekday activity heatmap | |
| GET /{slug}/analytics/visitors β Unique visitor counts (new vs returning) | |
| GET /{slug}/analytics/geo β Country and city distribution | |
| GET /{slug}/analytics/devices β Device, browser, OS breakdown | |
| GET /{slug}/analytics/sessions/stats β Avg turns, avg rating, session stats | |
| """ | |
| from fastapi import APIRouter, Depends, Query | |
| from sqlalchemy.ext.asyncio import AsyncSession | |
| from app.dependencies import get_db, get_current_author_scoped | |
| from app.services.admin_analytics_service import AdminAnalyticsService | |
| router = APIRouter() | |
| async def get_analytics( | |
| author_slug: str, | |
| days: int = Query(30, ge=1, le=365), | |
| current_user=Depends(get_current_author_scoped), | |
| db: AsyncSession = Depends(get_db), | |
| ): | |
| """Return daily session counts for dashboard charts.""" | |
| return await AdminAnalyticsService(db).daily_sessions(current_user.id, days) | |
| async def get_conversion_funnel( | |
| author_slug: str, | |
| days: int = Query(30, ge=1, le=365), | |
| current_user=Depends(get_current_author_scoped), | |
| db: AsyncSession = Depends(get_db), | |
| ): | |
| """Return conversion funnel data (sessions β chat β book β link β click).""" | |
| return await AdminAnalyticsService(db).conversion_funnel(current_user.id, days) | |
| async def get_intent_distribution( | |
| author_slug: str, | |
| days: int = Query(30, ge=1, le=365), | |
| current_user=Depends(get_current_author_scoped), | |
| db: AsyncSession = Depends(get_db), | |
| ): | |
| """Return distribution of detected intent labels.""" | |
| return await AdminAnalyticsService(db).intent_distribution(current_user.id, days) | |
| async def get_unanswered_questions( | |
| author_slug: str, | |
| days: int = Query(30, ge=1, le=365), | |
| current_user=Depends(get_current_author_scoped), | |
| db: AsyncSession = Depends(get_db), | |
| ): | |
| """Return sessions where boundary/fallback was triggered.""" | |
| return await AdminAnalyticsService(db).unanswered_questions(current_user.id, days) | |
| async def get_book_analytics( | |
| author_slug: str, | |
| days: int = Query(30, ge=1, le=365), | |
| current_user=Depends(get_current_author_scoped), | |
| db: AsyncSession = Depends(get_db), | |
| ): | |
| """Return per-book engagement breakdown.""" | |
| return await AdminAnalyticsService(db).book_engagement(current_user.id, days) | |
| async def get_activity_heatmap( | |
| author_slug: str, | |
| days: int = Query(90, ge=7, le=365), | |
| current_user=Depends(get_current_author_scoped), | |
| db: AsyncSession = Depends(get_db), | |
| ): | |
| """Return hourly Γ weekday activity heatmap.""" | |
| return await AdminAnalyticsService(db).activity_heatmap(current_user.id, days) | |
| async def get_visitor_stats( | |
| author_slug: str, | |
| days: int = Query(30, ge=1, le=365), | |
| current_user=Depends(get_current_author_scoped), | |
| db: AsyncSession = Depends(get_db), | |
| ): | |
| """Return unique visitor counts with new vs returning breakdown.""" | |
| return await AdminAnalyticsService(db).visitor_stats(current_user.id, days) | |
| async def get_geo_breakdown( | |
| author_slug: str, | |
| days: int = Query(30, ge=1, le=365), | |
| current_user=Depends(get_current_author_scoped), | |
| db: AsyncSession = Depends(get_db), | |
| ): | |
| """Return geographic distribution of visitors.""" | |
| return await AdminAnalyticsService(db).geo_breakdown(current_user.id, days) | |
| async def get_device_breakdown( | |
| author_slug: str, | |
| days: int = Query(30, ge=1, le=365), | |
| current_user=Depends(get_current_author_scoped), | |
| db: AsyncSession = Depends(get_db), | |
| ): | |
| """Return device, browser, and OS distribution of visitors.""" | |
| return await AdminAnalyticsService(db).device_breakdown(current_user.id, days) | |
| async def get_session_stats( | |
| author_slug: str, | |
| days: int = Query(30, ge=1, le=365), | |
| current_user=Depends(get_current_author_scoped), | |
| db: AsyncSession = Depends(get_db), | |
| ): | |
| """Return session-level aggregate statistics.""" | |
| return await AdminAnalyticsService(db).session_stats(current_user.id, days) | |