diff --git a/backend/app/api/admin.py b/backend/app/api/admin.py index 2130e19..e20dc7c 100644 --- a/backend/app/api/admin.py +++ b/backend/app/api/admin.py @@ -4,7 +4,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from app.core.dependencies import get_current_admin from app.database import get_db -from app.models import Follow +from app.models import Bill, BillBrief, BillDocument, Follow from app.models.user import User from app.schemas.schemas import UserResponse @@ -79,6 +79,35 @@ async def toggle_admin( return user +# ── Analysis Stats ──────────────────────────────────────────────────────────── + +@router.get("/stats") +async def get_stats( + db: AsyncSession = Depends(get_db), + current_user: User = Depends(get_current_admin), +): + """Return analysis pipeline progress counters.""" + total_bills = (await db.execute(select(func.count()).select_from(Bill))).scalar() + docs_fetched = (await db.execute( + select(func.count()).select_from(BillDocument).where(BillDocument.raw_text.isnot(None)) + )).scalar() + total_briefs = (await db.execute(select(func.count()).select_from(BillBrief))).scalar() + full_briefs = (await db.execute( + select(func.count()).select_from(BillBrief).where(BillBrief.brief_type == "full") + )).scalar() + amendment_briefs = (await db.execute( + select(func.count()).select_from(BillBrief).where(BillBrief.brief_type == "amendment") + )).scalar() + return { + "total_bills": total_bills, + "docs_fetched": docs_fetched, + "briefs_generated": total_briefs, + "full_briefs": full_briefs, + "amendment_briefs": amendment_briefs, + "remaining": total_bills - total_briefs, + } + + # ── Celery Tasks ────────────────────────────────────────────────────────────── @router.post("/trigger-poll") diff --git a/frontend/app/settings/page.tsx b/frontend/app/settings/page.tsx index d4481c6..10ddbcd 100644 --- a/frontend/app/settings/page.tsx +++ b/frontend/app/settings/page.tsx @@ -13,6 +13,9 @@ import { Trash2, ShieldCheck, ShieldOff, + FileText, + Brain, + BarChart3, } from "lucide-react"; import { settingsAPI, adminAPI, type AdminUser } from "@/lib/api"; import { useAuthStore } from "@/stores/authStore"; @@ -33,6 +36,13 @@ export default function SettingsPage() { queryFn: () => settingsAPI.get(), }); + const { data: stats } = useQuery({ + queryKey: ["admin-stats"], + queryFn: () => adminAPI.getStats(), + enabled: !!currentUser?.is_admin, + refetchInterval: 30_000, + }); + const { data: users, isLoading: usersLoading } = useQuery({ queryKey: ["admin-users"], queryFn: () => adminAPI.listUsers(), @@ -85,13 +95,13 @@ export default function SettingsPage() { if (settingsLoading) return
Manage users, LLM provider, and system settings
Loading stats...
+ )} +