From 69beb9c00295689ca4355e1e6306f78281d2553d Mon Sep 17 00:00:00 2001 From: inference-bot Date: Thu, 1 Oct 2026 15:35:57 -0600 Subject: [PATCH] Broker: co-op-wide model leaderboard endpoint for member dashboard (aggregate, anonymized) --- app/main.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/app/main.py b/app/main.py index 317a086..3b07d3f 100644 --- a/app/main.py +++ b/app/main.py @@ -2245,6 +2245,35 @@ async def broker_usage(request: Request, days: int = 0): return await broker_get_usage(email, days=days) +@app.get("/broker/model-leaderboard") +@limiter.limit("30/minute") +async def broker_model_leaderboard(request: Request, days: int = 0): + """Co-op-wide model popularity for the member dashboard. + + Same aggregation as the admin model-usage view (spend/tokens/requests per + model, across all members) but served through the broker so members can + see which models the co-op uses most — social guidance for model choice. + No per-member data; aggregate totals only. + """ + _verify_broker_secret(request) + if litellm_db_ready(): + try: + usage = aggregate_model_usage(days=days) + except Exception as e: + logger.warning("broker leaderboard: DB path failed (%s)", e) + usage = None + if usage: + return { + "models": [ + {"model": m["model"], "spend": m["spend"], + "tokens": m["tokens"], "requests": m["requests"]} + for m in usage["models"][:10] + ] + } + # Fallback: empty (rare; the DB path is the norm) + return {"models": []} + + async def reconcile_memberships() -> dict: """Reconcile the portal against the live Open Collective member list.