feat(nas): 模型调用统计镜像与界面 - sync_model_calls 表+拉取+聚合统计;fam-ui 新增'🤖 模型统计'页(按模型成功/失败/成功率/平均耗时 + 最近调用明细含失败原因)
This commit is contained in:
@@ -317,7 +317,7 @@ st.sidebar.markdown(
|
||||
# 顶部横向导航
|
||||
page = st.segmented_control(
|
||||
"功能页面",
|
||||
["🕒 事件时间轴", "💬 AI 对话", "📝 对话历史", "👤 人物管理", "📈 统计图表"],
|
||||
["🕒 事件时间轴", "💬 AI 对话", "📝 对话历史", "👤 人物管理", "📈 统计图表", "🤖 模型统计"],
|
||||
default="🕒 事件时间轴",
|
||||
label_visibility="collapsed"
|
||||
) or "🕒 事件时间轴"
|
||||
@@ -901,3 +901,83 @@ elif page == "📈 统计图表":
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
||||
# ============================================================
|
||||
# 模型统计页(云端模型识别成功/失败统计)
|
||||
# ============================================================
|
||||
elif page == "🤖 模型统计":
|
||||
page_header('🤖', '云端模型统计', '请求时间 · 耗时 · 成功/失败 · 失败原因')
|
||||
|
||||
conn = None
|
||||
try:
|
||||
conn = get_db_conn()
|
||||
cursor = conn.cursor()
|
||||
|
||||
# ---- 按模型聚合:成功/失败/成功率/平均耗时 ----
|
||||
st.markdown('<div style="font-size:15px;font-weight:700;color:#f1f5f9;'
|
||||
'margin:6px 0 14px 0;">按模型聚合</div>', unsafe_allow_html=True)
|
||||
cursor.execute(
|
||||
"""SELECT provider, model,
|
||||
SUM(CASE WHEN success=1 THEN 1 ELSE 0 END) AS ok_cnt,
|
||||
SUM(CASE WHEN success=0 THEN 1 ELSE 0 END) AS fail_cnt,
|
||||
ROUND(AVG(duration_sec),1) AS avg_dur,
|
||||
COUNT(*) AS total,
|
||||
MAX(created_at) AS last_call
|
||||
FROM sync_model_calls GROUP BY provider, model
|
||||
ORDER BY total DESC""")
|
||||
agg = cursor.fetchall()
|
||||
if agg:
|
||||
rows = []
|
||||
for r in agg:
|
||||
total = r['total'] or 0
|
||||
ok = r['ok_cnt'] or 0
|
||||
rate = (ok / total * 100) if total else 0
|
||||
rows.append({
|
||||
"模型": f"{r['provider']} / {r['model']}",
|
||||
"成功": ok,
|
||||
"失败": r['fail_cnt'] or 0,
|
||||
"成功率%": round(rate, 1),
|
||||
"平均耗时s": r['avg_dur'],
|
||||
"最后调用": str(r['last_call'] or '—')[:19],
|
||||
})
|
||||
st.dataframe(rows, use_container_width=True, hide_index=True)
|
||||
else:
|
||||
st.markdown('<div class="fam-empty">暂无模型调用记录(视频处理中或尚未同步)</div>',
|
||||
unsafe_allow_html=True)
|
||||
|
||||
# ---- 最近调用明细 ----
|
||||
st.markdown('<div style="font-size:15px;font-weight:700;color:#f1f5f9;'
|
||||
'margin:22px 0 14px 0;">最近调用明细</div>', unsafe_allow_html=True)
|
||||
cursor.execute(
|
||||
"""SELECT provider, model, started_at, duration_sec, success, error,
|
||||
filename, video_id
|
||||
FROM sync_model_calls ORDER BY id DESC LIMIT 100""")
|
||||
calls = cursor.fetchall()
|
||||
if calls:
|
||||
import pandas as pd
|
||||
rows = []
|
||||
for c in calls:
|
||||
rows.append({
|
||||
"请求时间": str(c['started_at'] or '—')[:19],
|
||||
"模型": f"{c['provider']} / {c['model']}",
|
||||
"耗时s": round(c['duration_sec'] or 0, 1),
|
||||
"状态": "✅ 成功" if c['success'] else "❌ 失败",
|
||||
"失败原因": (c['error'] or '')[:60],
|
||||
"视频": (c['filename'] or '')[:40],
|
||||
})
|
||||
st.dataframe(rows, use_container_width=True, hide_index=True)
|
||||
else:
|
||||
st.markdown('<div class="fam-empty">暂无调用明细</div>', unsafe_allow_html=True)
|
||||
|
||||
# ---- 说明 ----
|
||||
st.markdown(
|
||||
'<div style="font-size:11px;color:#64748b;margin-top:10px;">'
|
||||
'统计来自甲骨文端每次云端模型请求的记录(经 30 分钟同步拉取到本地镜像)。'
|
||||
'失败原因取值:429_quota(配额耗尽)/ timeout / 503_overload(过载重试)/ http_xxx / json_parse_failed 等。'
|
||||
'</div>', unsafe_allow_html=True)
|
||||
|
||||
except Exception as e:
|
||||
st.error(f"模型统计查询失败: {e}")
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
||||
Reference in New Issue
Block a user