From df2311d4f044b408b68c272136ca855c3eee4ca9 Mon Sep 17 00:00:00 2001 From: OoO Date: Tue, 5 May 2026 01:15:58 +0800 Subject: [PATCH] =?UTF-8?q?feat(p55):=203=20=E5=80=8B=E5=9C=93=E9=A4=85?= =?UTF-8?q?=E5=9C=96=E8=A3=9C=E9=BD=8A=20=E2=80=94=20promotion=5Freview/pp?= =?UTF-8?q?t=5Faudit/budget?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit S-1: promotion_review 蒸餾池 30d doughnut - 取代原 col-md-2 卡片網格 - 8 種狀態各自分色: pending(灰) / awaiting_review(黃) / approved(綠) / rejected_quality(紅) / rejected_hallucination(深紅) / rejected_duplicate(橘) / rejected_human(暗紅) / expired(灰) - 左圓餅 + 右表格雙視角 S-2: ppt_audit 30d 結果 doughnut - 取代部分 col-md-2 卡片佈局 - 通過(綠)/失敗(黃)/錯誤(紅)/跳過(灰) 圓餅 - 6 個 KPI 卡併入右側 col-6 grid(總筆數/通過率/通過/issue/失敗/錯誤) - 統一視覺語言:「圖+表」雙視角 S-3: budget 當月各 provider 成本 doughnut - 新加 query:ai_calls.cost_usd GROUP BY provider 月初至今 - 8 個 provider 分色(本地 Ollama 綠系 vs 付費 LLM 橘紫系) - 左圓餅 + 右表格(供應商/成本/佔比)+ 總計列 chart.js 視覺化從 7 個 → 10 個: - hourly trend line - 30d cost stacked bar - 三主機 sparkline × 3 - RAG feedback doughnut - KPI sparkline × 3 (calls/cost/errors) - verdict doughnut - heal 7d trend - **promotion_review status doughnut(新)** - **ppt_audit pass/fail doughnut(新)** - **provider cost doughnut(新)** Phase 38→55 累計 20 commits / 10 觀測頁 / 10 chart.js / DB 100%。 Co-Authored-By: Claude Opus 4.7 (1M context) --- routes/admin_observability_routes.py | 16 ++++ templates/admin/budget.html | 71 ++++++++++++++++ templates/admin/ppt_audit_history.html | 113 +++++++++++++++++-------- templates/admin/promotion_review.html | 96 ++++++++++++++++----- 4 files changed, 241 insertions(+), 55 deletions(-) diff --git a/routes/admin_observability_routes.py b/routes/admin_observability_routes.py index 4fa609f..c44e733 100644 --- a/routes/admin_observability_routes.py +++ b/routes/admin_observability_routes.py @@ -1575,6 +1575,17 @@ def budget_dashboard(): 'cost': float(r[2] or 0), }) + # Phase 55 S-3: 當月各 provider cost 分布(給圓餅圖用) + provider_cost_month = session.execute( + sa_text(""" + SELECT provider, COALESCE(SUM(cost_usd), 0) AS cost + FROM ai_calls + WHERE called_at >= :ms AND cost_usd > 0 + GROUP BY provider ORDER BY cost DESC + """), + {'ms': month_start}, + ).fetchall() + # Phase 47 K-3: top 5 cost-burning caller (當月) top_cost_callers = session.execute( sa_text(""" @@ -1643,6 +1654,10 @@ def budget_dashboard(): } for r in top_cost_callers ], + provider_cost_month=[ + {'provider': r[0], 'cost': float(r[1] or 0)} + for r in provider_cost_month + ], price_rec_7d=[ { 'strategy': r[0], 'count': int(r[1] or 0), @@ -1656,6 +1671,7 @@ def budget_dashboard(): return render_template('admin/budget.html', active_page='obs_budget', rows=[], budget_strategies=[], cost_trend_30d=[], top_cost_callers=[], price_rec_7d=[], + provider_cost_month=[], error=f'查詢失敗: {type(e).__name__}: {str(e)[:200]}') finally: session.close() diff --git a/templates/admin/budget.html b/templates/admin/budget.html index 0691a71..6262fb4 100644 --- a/templates/admin/budget.html +++ b/templates/admin/budget.html @@ -99,6 +99,44 @@ + + {% if provider_cost_month %} +
+
當月各供應商成本分布 + 資料來源:ai_calls.cost_usd GROUP BY provider · 月初至今 +
+
+
+
+ +
+
+ + + + + + {% set total_pc = (provider_cost_month | sum(attribute='cost')) or 0.0001 %} + {% for p in provider_cost_month %} + + + + + + {% endfor %} + + + + + + +
供應商成本佔比
{{ p.provider }}${{ "%.4f"|format(p.cost) }}{{ "%.1f"|format(p.cost / total_pc * 100) }}%
總計${{ "%.2f"|format(total_pc) }}100%
+
+
+
+
+ {% endif %} + {% if top_cost_callers %}
@@ -173,6 +211,39 @@