Files
ewoooc/templates/admin/quality_trend.html
OoO f2fbe5f929
All checks were successful
CD Pipeline / deploy (push) Successful in 2m33s
feat(p30): admin nav 互聯 + deploy doctor v5.0 腳本
(1) 6 個 admin 頁底部導覽全互聯(之前缺 Phase 29 兩頁的反向連結)
   - ai_calls / promotion_review / quality_trend / host_health
     全部加 |Budget|PPT Audit| 連結
   - 統帥從任一頁都可一鍵跳到其他 5 頁

(2) scripts/deploy_doctor_v5.py — 統帥手動待辦自助檢查
   5 階段檢查:env vars / DB migrations / Ollama 三主機 /
                LibreOffice / MCP servers
   - 14 個 v5.0 env vars(含 criticality 分級 FAIL/WARN/INFO)
   - 5 張 v5.0 必備 table(ai_calls/mcp_calls/ai_call_budgets/
     rag_query_log/learning_episodes)
   - ai_call_budgets seed ≥8 筆檢查
   - 三主機 /api/tags HTTP probe + healthy 數判定
   - 退出碼:0=全綠 1=WARN 2=FAIL(可進 CI)
   - SSH 188 / 本機都能跑:python3 scripts/deploy_doctor_v5.py

統帥之後想知道「v5.0 還有啥沒部署」直接跑 doctor 看清單,
不用再口頭追問哪些 env vars / 哪幾張 migration。
2026-05-04 13:48:06 +08:00

105 lines
3.8 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}Caller Quality Trend{% endblock %}
{% block content %}
<div class="container-fluid mt-3">
<h2 class="mb-3">💬 Caller 反饋趨勢
<small class="text-muted">過去 {{ days }} 日</small>
</h2>
{% if error %}
<div class="alert alert-warning"><strong>⚠️</strong> {{ error }}</div>
{% endif %}
<form method="get" class="row g-2 mb-3">
<div class="col-auto">
<select name="days" class="form-select form-select-sm">
{% for d in [7, 14, 30, 90] %}
<option value="{{ d }}" {% if days == d %}selected{% endif %}>{{ d }} 日</option>
{% endfor %}
</select>
</div>
<div class="col-auto"><button class="btn btn-primary btn-sm">查詢</button></div>
</form>
{% if recommendations %}
<div class="card mb-3">
<div class="card-header bg-warning"><strong>🔮 智能建議</strong></div>
<div class="card-body">
<ul class="mb-0">
{% for rec in recommendations %}
<li>
{% if rec.action == 'review' %}⚠️{% else %}✅{% endif %}
<code>{{ rec.caller }}</code>: {{ rec.reason }}
</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
<div class="card">
<div class="card-header"><strong>Caller × 反饋分佈</strong>
<small class="text-muted">avg_score 升序,最差先看)</small>
</div>
<div class="card-body p-0">
<table class="table table-sm mb-0">
<thead class="table-light">
<tr>
<th>Caller</th><th class="text-end">Avg</th>
<th class="text-end">👍</th><th class="text-end">👎</th>
<th class="text-end">N</th><th>Trend</th><th>Bar</th>
</tr>
</thead>
<tbody>
{% for caller, info in trends %}
<tr>
<td><code>{{ caller }}</code></td>
<td class="text-end">
<strong>{{ "%.2f"|format(info.avg_score) }}</strong>/5
</td>
<td class="text-end text-success">{{ info.thumbs_up }}</td>
<td class="text-end text-danger">{{ info.thumbs_down }}</td>
<td class="text-end">{{ info.total_feedback }}</td>
<td>
{% if info.trend == 'positive' %}
<span class="badge bg-success">✅ Positive</span>
{% elif info.trend == 'negative' %}
<span class="badge bg-danger">⚠️ Negative</span>
{% elif info.trend == 'neutral' %}
<span class="badge bg-secondary"> Neutral</span>
{% else %}
<span class="badge bg-light text-dark">❓ No Data</span>
{% endif %}
</td>
<td style="width: 200px;">
<div class="progress" style="height: 8px;">
{% set pct = (info.avg_score / 5 * 100)|int %}
<div class="progress-bar
{% if pct >= 80 %}bg-success
{% elif pct >= 50 %}bg-info
{% else %}bg-danger{% endif %}"
style="width: {{ pct }}%"></div>
</div>
</td>
</tr>
{% else %}
<tr><td colspan="7" class="text-center text-muted">無反饋資料</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<p class="text-muted mt-3"><small>
🤖 Operation Ollama-First v5.0 / Phase 29 — Caller Quality Trend
| <a href="/admin/ai_calls">AI Calls</a>
| <a href="/admin/promotion_review">Promotion Review</a>
| <a href="/admin/host_health">Host Health</a>
| <a href="/admin/budget">Budget</a>
| <a href="/admin/ppt_audit_history">PPT Audit</a>
</small></p>
</div>
{% endblock %}