Files
LockInBroAPI/app/routers/analytics.py
2026-03-29 06:57:34 -04:00

95 lines
3.3 KiB
Python

from fastapi import APIRouter, Depends, HTTPException
from app.middleware.auth import get_current_user_id
from app.models import AnalyticsSummary
from app.services.db import get_pool
from app.services.hex_service import run_notebook
router = APIRouter(prefix="/analytics", tags=["analytics"])
@router.get("/distractions")
async def distraction_analytics(user_id: str = Depends(get_current_user_id)):
try:
return await run_notebook("distraction_patterns", user_id)
except Exception as e:
raise HTTPException(status_code=502, detail=f"Hex error: {e}")
@router.get("/focus-trends")
async def focus_trends(user_id: str = Depends(get_current_user_id)):
try:
return await run_notebook("focus_trends", user_id)
except Exception as e:
raise HTTPException(status_code=502, detail=f"Hex error: {e}")
@router.get("/weekly-report")
async def weekly_report(user_id: str = Depends(get_current_user_id)):
try:
return await run_notebook("weekly_report", user_id)
except Exception as e:
raise HTTPException(status_code=502, detail=f"Hex error: {e}")
@router.post("/refresh")
async def refresh_analytics(user_id: str = Depends(get_current_user_id)):
results = {}
for key in ("distraction_patterns", "focus_trends", "weekly_report"):
try:
results[key] = await run_notebook(key, user_id)
except Exception as e:
results[key] = {"error": str(e)}
return results
@router.get("/summary", response_model=AnalyticsSummary)
async def analytics_summary(user_id: str = Depends(get_current_user_id)):
pool = await get_pool()
# Direct Postgres queries — no Hex needed
focus_minutes = await pool.fetchval(
"""SELECT COALESCE(SUM(EXTRACT(EPOCH FROM (ended_at - started_at)) / 60), 0)
FROM sessions WHERE user_id = $1::uuid AND ended_at IS NOT NULL
AND started_at > now() - interval '7 days'""",
user_id,
)
sessions_completed = await pool.fetchval(
"""SELECT COUNT(*) FROM sessions
WHERE user_id = $1::uuid AND status = 'completed'
AND started_at > now() - interval '7 days'""",
user_id,
)
tasks_completed = await pool.fetchval(
"""SELECT COUNT(*) FROM tasks
WHERE user_id = $1::uuid AND status = 'done'
AND updated_at > now() - interval '7 days'""",
user_id,
)
top_distractors = await pool.fetch(
"""SELECT app_name, COUNT(*) as count
FROM distractions
WHERE user_id = $1::uuid AND detected_at > now() - interval '7 days'
GROUP BY app_name ORDER BY count DESC LIMIT 5""",
user_id,
)
avg_attention = await pool.fetchval(
"""SELECT AVG((checkpoint->>'attention_score')::float)
FROM sessions
WHERE user_id = $1::uuid AND checkpoint->>'attention_score' IS NOT NULL
AND started_at > now() - interval '7 days'""",
user_id,
)
return AnalyticsSummary(
total_focus_minutes=float(focus_minutes or 0),
sessions_completed=sessions_completed or 0,
tasks_completed=tasks_completed or 0,
top_distractors=[{"app_name": r["app_name"], "count": r["count"]} for r in top_distractors],
avg_attention_score=float(avg_attention) if avg_attention else None,
)