feat(p55): 3 個圓餅圖補齊 — promotion_review/ppt_audit/budget
All checks were successful
CD Pipeline / deploy (push) Successful in 7m39s
All checks were successful
CD Pipeline / deploy (push) Successful in 7m39s
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) <noreply@anthropic.com>
This commit is contained in:
@@ -99,6 +99,44 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- Phase 55 S-3: 當月各 provider 成本分布圓餅 -->
|
||||
{% if provider_cost_month %}
|
||||
<div class="card mb-3">
|
||||
<div class="card-header"><strong><i class="fas fa-chart-pie me-2"></i>當月各供應商成本分布</strong>
|
||||
<small class="text-muted">資料來源:ai_calls.cost_usd GROUP BY provider · 月初至今</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-2 align-items-center">
|
||||
<div class="col-md-5">
|
||||
<canvas id="providerCostPieChart" height="180"></canvas>
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
<table class="table table-sm mb-0" style="font-size: 0.9em;">
|
||||
<thead class="table-light">
|
||||
<tr><th>供應商</th><th class="text-end">成本</th><th class="text-end">佔比</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% set total_pc = (provider_cost_month | sum(attribute='cost')) or 0.0001 %}
|
||||
{% for p in provider_cost_month %}
|
||||
<tr>
|
||||
<td><code>{{ p.provider }}</code></td>
|
||||
<td class="text-end">${{ "%.4f"|format(p.cost) }}</td>
|
||||
<td class="text-end">{{ "%.1f"|format(p.cost / total_pc * 100) }}%</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr style="border-top: 2px solid #dee2e6;">
|
||||
<td><strong>總計</strong></td>
|
||||
<td class="text-end"><strong>${{ "%.2f"|format(total_pc) }}</strong></td>
|
||||
<td class="text-end"><strong>100%</strong></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Phase 47 K-3: Top 5 cost-burning caller -->
|
||||
{% if top_cost_callers %}
|
||||
<div class="card mb-3">
|
||||
@@ -173,6 +211,39 @@
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
|
||||
<script>
|
||||
// Phase 55 S-3: provider 月度成本圓餅
|
||||
(function() {
|
||||
const data = {{ provider_cost_month | default([]) | tojson }};
|
||||
const el = document.getElementById('providerCostPieChart');
|
||||
if (!el || !data.length) return;
|
||||
const colors = {
|
||||
'gcp_ollama': '#28a745', 'ollama_secondary': '#5cb85c', 'ollama_111': '#a3d9a4',
|
||||
'gemini': '#fd7e14', 'claude': '#6610f2', 'nim': '#0dcaf0',
|
||||
'openrouter': '#6c757d', 'nim_via_elephant': '#20c997',
|
||||
};
|
||||
new Chart(el, {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: data.map(d => d.provider),
|
||||
datasets: [{
|
||||
data: data.map(d => d.cost),
|
||||
backgroundColor: data.map((d, i) => colors[d.provider] || `hsl(${(i*47)%360}, 65%, 55%)`),
|
||||
borderWidth: 1, borderColor: '#fff',
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true, maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: { position: 'right', labels: { font: { size: 11 } } },
|
||||
tooltip: { callbacks: { label: c => {
|
||||
const total = data.reduce((a,b)=>a+b.cost, 0);
|
||||
return `${c.label}: $${c.parsed.toFixed(4)} (${(c.parsed/total*100).toFixed(1)}%)`;
|
||||
}}}
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
// Phase 50 N-2: 30d cost trend stacked bar chart
|
||||
(function() {
|
||||
const raw = {{ cost_trend_30d | tojson }};
|
||||
|
||||
Reference in New Issue
Block a user