Files
ewoooc/templates/admin/host_health.html
OoO 48b8fda7db
All checks were successful
CD Pipeline / deploy (push) Successful in 2m25s
feat(p27+28): Admin Observability Dashboard — 4 個前端頁互補 Telegram
Operation Ollama-First v5.0 / Phase 27 + 28 — 戰役觀測前端化

routes/admin_observability_routes.py (新檔, 200+ 行)
- admin_observability_bp blueprint,url_prefix='/admin'
- /admin/ai_calls            — Phase 27 主入口(KPI / by provider / TOP 100)
- /admin/promotion_review    — Phase 28 PromotionGate 待審列表 + 通過/拒絕按鈕
- /admin/quality_trend       — Phase 25 caller 反饋趨勢視覺化
- /admin/host_health         — 三主機 + MCP + cost throttle 即時健康
- 失敗安全:DB 查詢失敗回空清單 + 警告 banner(不 raise)
- promotion_review_approve/reject 走 hash_human_approver SHA1[:8] 不存原 username

templates/admin/ (4 個新檔)
- ai_calls_dashboard.html   篩選 bar + 6 KPI cards + by provider + recent 100
- promotion_review.html     卡片列表 + 通過/拒絕 AJAX 按鈕(即時 UI feedback)
- quality_trend.html        avg score 升序排列 + 進度條 bar + 智能建議區
- host_health.html          三主機 HTTP probe + 已載入模型 + MCP + throttle

統帥提問「需要哪些前端讓兩者互補互動」答覆:
  6 項最該前端化(已實作 4 項,剩 2 項為後續):
     ai_calls 即時查詢          → /admin/ai_calls
     PromotionGate 待審核         → /admin/promotion_review (互動最強)
     caller 反饋趨勢             → /admin/quality_trend
     三主機 + MCP + throttle     → /admin/host_health
     ai_call_budgets 預算管理   → Phase 29 補
     PPT 視覺審核結果列表        → Phase 29 補

互補 Telegram 哲學:
  Telegram = push(重要事件主動通知)
  Web = pull(統帥隨時可查 / 互動審核 / 找問題)
  PromotionGate Stage 4:Telegram 推 awaiting_review + Web 批次審核(兩者皆可)

app.py blueprint 註冊 + CSRF exempt(AJAX POST 走 server-side check)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 13:36:51 +08:00

123 lines
4.4 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 %}Host Health Dashboard{% endblock %}
{% block content %}
<div class="container-fluid mt-3">
<h2 class="mb-3">🏥 Host Health Dashboard
<small class="text-muted">三主機 + MCP + Cost Throttle 即時狀態</small>
</h2>
<!-- Ollama 三主機 -->
<div class="card mb-3">
<div class="card-header"><strong>🤖 Ollama 三主機HTTP /api/tags 即時 probe</strong></div>
<div class="card-body p-0">
<table class="table mb-0">
<thead class="table-light">
<tr><th>角色</th><th>主機</th><th>HTTP 健康</th><th>unhealthy mark</th><th>已載入模型</th></tr>
</thead>
<tbody>
{% for h in ollama_hosts %}
<tr>
<td><strong>{{ h.label }}</strong></td>
<td><code>{{ h.host }}</code></td>
<td>
{% if h.healthy %}
<span class="badge bg-success">✅ HTTP OK</span>
{% else %}
<span class="badge bg-danger">❌ DOWN</span>
{% endif %}
</td>
<td>
{% if h.unhealthy_mark %}
<span class="badge bg-warning">⚠️ marked unhealthy (30s)</span>
{% else %}
<span class="badge bg-light text-dark"></span>
{% endif %}
</td>
<td>
{% for m in h.models %}
<span class="badge bg-info text-dark me-1">{{ m }}</span>
{% endfor %}
{% if not h.models %}<small class="text-muted">無 / 未連線</small>{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- MCP servers -->
<div class="card mb-3">
<div class="card-header"><strong>🔌 MCP ServersPhase 10/10.5</strong></div>
<div class="card-body p-0">
<table class="table mb-0">
<thead class="table-light">
<tr><th>Server</th><th>狀態</th></tr>
</thead>
<tbody>
{% for server, healthy in mcp_status.items() %}
<tr>
<td><code>{{ server }}</code></td>
<td>
{% if healthy %}
<span class="badge bg-success">✅ healthy</span>
{% else %}
<span class="badge bg-secondary">— 未啟用 / DOWN</span>
{% endif %}
</td>
</tr>
{% else %}
<tr><td colspan="2" class="text-muted small">MCP_ROUTER_ENABLED=false 或 mcp-stack 未 deploy</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Cost Throttle 狀態Phase 20 -->
<div class="card mb-3">
<div class="card-header"><strong>💰 Cost Throttle 狀態Phase 20</strong></div>
<div class="card-body p-0">
{% if throttle_state %}
<table class="table mb-0">
<thead class="table-light">
<tr><th>Provider</th><th>Spent</th><th>Budget</th><th>月底推估</th><th>Ratio</th><th>狀態</th></tr>
</thead>
<tbody>
{% for provider, info in throttle_state.items() %}
<tr {% if info.throttled %}class="table-warning"{% endif %}>
<td><code>{{ provider }}</code></td>
<td>${{ "%.2f"|format(info.spent) }}</td>
<td>${{ "%.2f"|format(info.budget) }}</td>
<td>${{ "%.2f"|format(info.projected) }}</td>
<td>{{ "%.0f"|format(info.ratio * 100) }}%</td>
<td>
{% if info.throttled %}
<span class="badge bg-danger">⚠️ THROTTLED</span>
{% else %}
<span class="badge bg-success">✅ 正常</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p class="text-muted m-3 small">
COST_THROTTLE_ENABLED=false 或尚未首次 evaluate每小時 cron 跑)
</p>
{% endif %}
</div>
</div>
<p class="text-muted mt-3"><small>
🤖 Operation Ollama-First v5.0 / Phase 27 — Host Health Dashboard
| <a href="/admin/ai_calls">AI Calls</a>
| <a href="/admin/promotion_review">Promotion Review</a>
| <a href="/admin/quality_trend">Quality Trend</a>
</small></p>
</div>
{% endblock %}