refactor: consolidate rankings into combined charts
- Change top models from Top 3 to Top 5 - Simplify titles: remove 'Top X' and parenthetical details - Replace separate user tables (by amount/by count) with single ChartBar - Replace separate provider tables with single ChartBar - Add get_top_users_combined and get_top_providers_combined functions
This commit is contained in:
parent
c9e860c691
commit
855f376671
@ -70,7 +70,7 @@ async def get_top_models(request):
|
||||
WHERE a.use_date = ${today}$
|
||||
GROUP BY a.llmid, b.name
|
||||
ORDER BY cnt DESC
|
||||
LIMIT 3
|
||||
LIMIT 5
|
||||
"""
|
||||
recs = await sor.sqlExe(sql, {'today': today})
|
||||
result = []
|
||||
@ -200,6 +200,59 @@ async def get_top_providers_by_count(request):
|
||||
return result
|
||||
|
||||
|
||||
async def get_top_users_combined(request):
|
||||
"""Top 5 users by amount with count - for combined ChartBar"""
|
||||
env = request._run_ns
|
||||
async with get_sor_context(env, 'sage') as sor:
|
||||
sql = """
|
||||
SELECT
|
||||
COALESCE(b.nick_name, b.username) as user_name,
|
||||
COUNT(*) as cnt,
|
||||
COALESCE(SUM(a.amount), 0) as total_amount
|
||||
FROM llmusage a
|
||||
LEFT JOIN users b ON a.userid = b.id
|
||||
GROUP BY a.userid, b.nick_name, b.username
|
||||
ORDER BY total_amount DESC
|
||||
LIMIT 5
|
||||
"""
|
||||
recs = await sor.sqlExe(sql, {})
|
||||
result = []
|
||||
for r in recs:
|
||||
result.append({
|
||||
'user_name': r.get('user_name', 'Unknown'),
|
||||
'cnt': int(r.get('cnt', 0)),
|
||||
'total_amount': round(float(r.get('total_amount', 0)), 2)
|
||||
})
|
||||
return result
|
||||
|
||||
|
||||
async def get_top_providers_combined(request):
|
||||
"""Top 5 providers by amount with count - for combined ChartBar"""
|
||||
env = request._run_ns
|
||||
async with get_sor_context(env, 'sage') as sor:
|
||||
sql = """
|
||||
SELECT
|
||||
COALESCE(c.orgname, 'Unknown') as provider_name,
|
||||
COUNT(*) as cnt,
|
||||
COALESCE(SUM(a.amount), 0) as total_amount
|
||||
FROM llmusage a
|
||||
LEFT JOIN llm b ON a.llmid = b.id
|
||||
LEFT JOIN organization c ON b.providerid = c.id
|
||||
GROUP BY b.providerid, c.orgname
|
||||
ORDER BY total_amount DESC
|
||||
LIMIT 5
|
||||
"""
|
||||
recs = await sor.sqlExe(sql, {})
|
||||
result = []
|
||||
for r in recs:
|
||||
result.append({
|
||||
'provider_name': r.get('provider_name', 'Unknown'),
|
||||
'cnt': int(r.get('cnt', 0)),
|
||||
'total_amount': round(float(r.get('total_amount', 0)), 2)
|
||||
})
|
||||
return result
|
||||
|
||||
|
||||
async def get_active_users_today(request):
|
||||
"""获取今日活跃用户数(今日有llmusage记录的去重用户)"""
|
||||
env = request._run_ns
|
||||
@ -481,6 +534,8 @@ def load_dashboard():
|
||||
g.get_top_users_by_count = get_top_users_by_count
|
||||
g.get_top_providers_by_amount = get_top_providers_by_amount
|
||||
g.get_top_providers_by_count = get_top_providers_by_count
|
||||
g.get_top_users_combined = get_top_users_combined
|
||||
g.get_top_providers_combined = get_top_providers_combined
|
||||
g.get_active_users_today = get_active_users_today
|
||||
g.get_new_users_month = get_new_users_month
|
||||
g.get_total_orgs = get_total_orgs
|
||||
|
||||
6
wwwroot/api/top_providers.dspy
Normal file
6
wwwroot/api/top_providers.dspy
Normal file
@ -0,0 +1,6 @@
|
||||
# coding=utf-8
|
||||
"""Top providers data API for ChartBar"""
|
||||
import json
|
||||
|
||||
providers = await get_top_providers_combined(request)
|
||||
return json.dumps(providers, ensure_ascii=False, default=str)
|
||||
6
wwwroot/api/top_users.dspy
Normal file
6
wwwroot/api/top_users.dspy
Normal file
@ -0,0 +1,6 @@
|
||||
# coding=utf-8
|
||||
"""Top users data API for ChartBar"""
|
||||
import json
|
||||
|
||||
users = await get_top_users_combined(request)
|
||||
return json.dumps(users, ensure_ascii=False, default=str)
|
||||
9
wwwroot/chart_top_providers.ui
Normal file
9
wwwroot/chart_top_providers.ui
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"widgettype": "ChartBar",
|
||||
"options": {
|
||||
"height": "300px",
|
||||
"data_url": "api/top_providers.dspy",
|
||||
"nameField": "provider_name",
|
||||
"valueFields": ["total_amount", "cnt"]
|
||||
}
|
||||
}
|
||||
9
wwwroot/chart_top_users.ui
Normal file
9
wwwroot/chart_top_users.ui
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"widgettype": "ChartBar",
|
||||
"options": {
|
||||
"height": "300px",
|
||||
"data_url": "api/top_users.dspy",
|
||||
"nameField": "user_name",
|
||||
"valueFields": ["total_amount", "cnt"]
|
||||
}
|
||||
}
|
||||
@ -175,7 +175,7 @@
|
||||
"widgettype": "Title4",
|
||||
"options": {
|
||||
"fontWeight": "600",
|
||||
"otext": "Top 3 模型(今日调用)",
|
||||
"otext": "热门模型",
|
||||
"i18n": true
|
||||
}
|
||||
},
|
||||
@ -372,16 +372,16 @@
|
||||
"options": {
|
||||
"fontWeight": "600",
|
||||
"marginBottom": "16px",
|
||||
"otext": "用户消费排行(Top 5)",
|
||||
"otext": "用户排行",
|
||||
"i18n": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "RefreshWidget",
|
||||
"id": "table_top_users",
|
||||
"id": "chart_top_users",
|
||||
"options": {
|
||||
"period_seconds": 30,
|
||||
"url": "{{entire_url('table_top_users.ui')}}"
|
||||
"period_seconds": 60,
|
||||
"url": "{{entire_url('chart_top_users.ui')}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -401,85 +401,19 @@
|
||||
"options": {
|
||||
"fontWeight": "600",
|
||||
"marginBottom": "16px",
|
||||
"otext": "用户调用排行(Top 5)",
|
||||
"otext": "供应商排行",
|
||||
"i18n": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "RefreshWidget",
|
||||
"id": "table_top_users_count",
|
||||
"id": "chart_top_providers",
|
||||
"options": {
|
||||
"period_seconds": 30,
|
||||
"url": "{{entire_url('table_top_users_count.ui')}}"
|
||||
"period_seconds": 60,
|
||||
"url": "{{entire_url('chart_top_providers.ui')}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"gap": "20px",
|
||||
"marginTop": "20px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"css": "card",
|
||||
"width": "50%",
|
||||
"borderRadius": "12px",
|
||||
"padding": "20px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Title4",
|
||||
"options": {
|
||||
"fontWeight": "600",
|
||||
"marginBottom": "16px",
|
||||
"otext": "供应商交易排行(金额 Top 5)",
|
||||
"i18n": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "RefreshWidget",
|
||||
"id": "table_top_providers_amount",
|
||||
"options": {
|
||||
"period_seconds": 30,
|
||||
"url": "{{entire_url('table_top_providers_amount.ui')}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"css": "card",
|
||||
"width": "50%",
|
||||
"borderRadius": "12px",
|
||||
"padding": "20px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Title4",
|
||||
"options": {
|
||||
"fontWeight": "600",
|
||||
"marginBottom": "16px",
|
||||
"otext": "供应商调用排行(数量 Top 5)",
|
||||
"i18n": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "RefreshWidget",
|
||||
"id": "table_top_providers_count",
|
||||
"options": {
|
||||
"period_seconds": 30,
|
||||
"url": "{{entire_url('table_top_providers_count.ui')}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
{% endif %}
|
||||
]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user