統帥要求: 1. 所有 6 個觀測頁的功能和數據都要完整寫入資料庫儲存 2. Ollama 切 GCP 順序 GCP-A → GCP-B → 111 盤點結果: - 4/6 頁面已有 DB 表(ai_calls / learning_episodes / rag_query_log / ai_call_budgets) - 2/6 頁面是即時查詢無歷史:host_health(HTTP probe)、ppt_audit(os.listdir) - Ollama 99% 已合規,僅 1 處過時註解 修補(B-1): - services/code_review_pipeline_service.py:207 註解更新 「直呼內網 Ollama (192.168.0.188)」→ 「走 resolve_ollama_host 三主機級聯 ADR-027」 新增(B-2): - migrations/029_create_host_health_probes.sql - 三主機健康歷史表(label/url/healthy/response_ms/error_msg) - 索引:probed_at / (host_label, probed_at) - 30 天保留(cron 清理) - migrations/030_create_ppt_audit_results.sql - PPT 視覺審核結果表(status/issues_count/issues_found JSONB/confidence) - 索引:audited_at / pptx_filename / failed-only partial - routes/admin_observability_routes.py:host_health_dashboard - 每次 probe 寫入 host_health_probes(失敗安全) - 新增 24h 健康趨勢卡片(uptime % / 平均 ms) - routes/admin_observability_routes.py:ppt_audit_history - 從 ppt_audit_results 讀過去 7 日 audit 紀錄 - 顯示審核時間/檔名/結果/問題數/信心度/耗時 - services/ppt_vision_service.py:check_ppt_file - 新增 _persist_audit_result() 跑完寫入 DB(status/issues/confidence/duration) - 失敗安全:DB 寫入失敗只 log warning,不擋主流程 - templates/admin/host_health.html + ppt_audit_history.html - 新增「24h 健康趨勢」card(host_health) - 新增「視覺審核歷史紀錄」card(ppt_audit) DoD: - 程式碼語法 ✓ - Jinja 平衡 ✓ - 失敗安全(DB 寫入或讀取失敗都不擋頁面渲染)✓ Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
159 lines
6.1 KiB
HTML
159 lines
6.1 KiB
HTML
{% extends "base.html" %}
|
||
|
||
{% block title %}主機健康監控{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="container-fluid mt-3">
|
||
<h2 class="mb-3"><i class="fas fa-heartbeat me-2"></i>主機健康監控
|
||
<small class="text-muted">三主機 Ollama + MCP + 成本節流即時狀態</small>
|
||
</h2>
|
||
|
||
<!-- Ollama 三主機 -->
|
||
<div class="card mb-3">
|
||
<div class="card-header"><strong><i class="fas fa-server me-2"></i>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>異常標記</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"><i class="fas fa-check me-1"></i>HTTP 正常</span>
|
||
{% else %}
|
||
<span class="badge bg-danger"><i class="fas fa-times me-1"></i>離線</span>
|
||
{% endif %}
|
||
</td>
|
||
<td>
|
||
{% if h.unhealthy_mark %}
|
||
<span class="badge bg-warning"><i class="fas fa-exclamation-triangle me-1"></i>已標記異常(30 秒)</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><i class="fas fa-plug me-2"></i>MCP 服務(Phase 10/10.5)</strong></div>
|
||
<div class="card-body p-0">
|
||
<table class="table mb-0">
|
||
<thead class="table-light">
|
||
<tr><th>服務名稱</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"><i class="fas fa-check me-1"></i>正常</span>
|
||
{% else %}
|
||
<span class="badge bg-secondary">— 未啟用 / 離線</span>
|
||
{% endif %}
|
||
</td>
|
||
</tr>
|
||
{% else %}
|
||
<tr><td colspan="2" class="text-muted small">MCP_ROUTER_ENABLED=false 或 mcp-stack 未部署</td></tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Cost Throttle 狀態(Phase 20) -->
|
||
<div class="card mb-3">
|
||
<div class="card-header"><strong><i class="fas fa-dollar-sign me-2"></i>成本節流狀態(Phase 20)</strong></div>
|
||
<div class="card-body p-0">
|
||
{% if throttle_state %}
|
||
<table class="table mb-0">
|
||
<thead class="table-light">
|
||
<tr><th>供應商</th><th>已花費</th><th>預算</th><th>月底推估</th><th>使用率</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"><i class="fas fa-exclamation-triangle me-1"></i>已節流</span>
|
||
{% else %}
|
||
<span class="badge bg-success"><i class="fas fa-check me-1"></i>正常</span>
|
||
{% endif %}
|
||
</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
{% else %}
|
||
<p class="text-muted m-3 small">
|
||
COST_THROTTLE_ENABLED=false 或尚未首次評估(每小時 cron 執行)
|
||
</p>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 過去 24h 健康趨勢(Phase 38 新增) -->
|
||
{% if health_history %}
|
||
<div class="card mb-3">
|
||
<div class="card-header"><strong><i class="fas fa-chart-line me-2"></i>過去 24 小時健康趨勢</strong>
|
||
<small class="text-muted">資料來源:host_health_probes(每次刷新自動寫入)</small>
|
||
</div>
|
||
<div class="card-body p-0">
|
||
<table class="table mb-0">
|
||
<thead class="table-light">
|
||
<tr>
|
||
<th>角色</th>
|
||
<th class="text-end">總探針次數</th>
|
||
<th class="text-end">正常次數</th>
|
||
<th class="text-end">離線次數</th>
|
||
<th class="text-end">在線率</th>
|
||
<th class="text-end">平均回應 ms</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for h in health_history %}
|
||
<tr>
|
||
<td><strong>{{ h.host_label }}</strong></td>
|
||
<td class="text-end">{{ h.total }}</td>
|
||
<td class="text-end text-success">{{ h.up_count }}</td>
|
||
<td class="text-end text-danger">{{ h.down_count }}</td>
|
||
<td class="text-end">
|
||
<strong class="{% if h.uptime_pct >= 99 %}text-success{% elif h.uptime_pct >= 90 %}text-warning{% else %}text-danger{% endif %}">
|
||
{{ "%.1f"|format(h.uptime_pct) }}%
|
||
</strong>
|
||
</td>
|
||
<td class="text-end">{{ h.avg_ms }}</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
|
||
<p class="text-muted mt-3"><small>
|
||
<i class="fas fa-robot me-1"></i>Operation Ollama-First v5.0 / Phase 38 — 主機健康監控(含 24h 歷史)
|
||
</small></p>
|
||
</div>
|
||
{% endblock %}
|