diff --git a/routes/admin_observability_routes.py b/routes/admin_observability_routes.py index 25834af..07caf07 100644 --- a/routes/admin_observability_routes.py +++ b/routes/admin_observability_routes.py @@ -111,6 +111,7 @@ def ai_calls_dashboard(): return render_template( 'admin/ai_calls_dashboard.html', + active_page='obs_ai_calls', hours=hours, caller_filter=caller_filter, provider_filter=provider_filter, @@ -144,6 +145,7 @@ def ai_calls_dashboard(): except Exception as e: return render_template( 'admin/ai_calls_dashboard.html', + active_page='obs_ai_calls', hours=hours, caller_filter=caller_filter, provider_filter=provider_filter, summary={}, by_provider=[], recent=[], callers=[], @@ -187,12 +189,14 @@ def promotion_review_list(): return render_template( 'admin/promotion_review.html', + active_page='obs_promotion_review', episodes=episodes, error=None, ) except Exception as e: return render_template( 'admin/promotion_review.html', + active_page='obs_promotion_review', episodes=[], error=f'查詢失敗: {type(e).__name__}: {str(e)[:200]}', ) @@ -254,6 +258,7 @@ def quality_trend_dashboard(): return render_template( 'admin/quality_trend.html', + active_page='obs_quality_trend', days=days, trends=[(c, info) for c, info in sorted_trends], recommendations=recommendations, @@ -262,6 +267,7 @@ def quality_trend_dashboard(): except Exception as e: return render_template( 'admin/quality_trend.html', + active_page='obs_quality_trend', days=days, trends=[], recommendations=[], error=f'查詢失敗: {type(e).__name__}: {str(e)[:200]}', ) @@ -322,9 +328,9 @@ def budget_dashboard(): 'updated_at': b[5].strftime('%Y-%m-%d %H:%M') if b[5] else '-', }) - return render_template('admin/budget.html', rows=rows, error=None) + return render_template('admin/budget.html', active_page='obs_budget', rows=rows, error=None) except Exception as e: - return render_template('admin/budget.html', rows=[], + return render_template('admin/budget.html', active_page='obs_budget', rows=[], error=f'查詢失敗: {type(e).__name__}: {str(e)[:200]}') finally: session.close() @@ -408,6 +414,7 @@ def ppt_audit_history(): return render_template( 'admin/ppt_audit_history.html', + active_page='obs_ppt_audit', files=files, vision_enabled=vision_enabled, error=error, @@ -467,6 +474,7 @@ def host_health_dashboard(): return render_template( 'admin/host_health.html', + active_page='obs_host_health', ollama_hosts=ollama_hosts, mcp_status=mcp_status, throttle_state=throttle_state, diff --git a/templates/admin/ai_calls_dashboard.html b/templates/admin/ai_calls_dashboard.html index 434ab02..2ab9103 100644 --- a/templates/admin/ai_calls_dashboard.html +++ b/templates/admin/ai_calls_dashboard.html @@ -1,15 +1,15 @@ {% extends "base.html" %} -{% block title %}AI Calls Dashboard{% endblock %} +{% block title %}AI 呼叫總覽{% endblock %} {% block content %}
-

📊 AI Calls Dashboard +

AI 呼叫總覽 過去 {{ hours }} 小時

{% if error %} -
⚠️ {{ error }}
+
{{ error }}
{% endif %} @@ -25,7 +25,7 @@
- + {% for p in ['gcp_ollama','ollama_secondary','ollama_111','gemini','claude','nim','openrouter','nim_via_elephant'] %} {% endfor %} @@ -46,21 +46,21 @@
-
Total Calls

{{ "{:,}".format(summary.total_calls or 0) }}

-
Tokens

{{ "{:,}".format(summary.total_tokens or 0) }}

-
Cost USD

${{ "%.2f"|format(summary.total_cost or 0) }}

-
Avg Duration

{{ summary.avg_duration or 0 }} ms

-
RAG Hits

{{ summary.rag_hits or 0 }}

-
Errors

{{ summary.error_calls or 0 }}

+
呼叫次數

{{ "{:,}".format(summary.total_calls or 0) }}

+
Token 用量

{{ "{:,}".format(summary.total_tokens or 0) }}

+
成本 (USD)

${{ "%.2f"|format(summary.total_cost or 0) }}

+
平均耗時

{{ summary.avg_duration or 0 }} ms

+
RAG 命中

{{ summary.rag_hits or 0 }}

+
錯誤次數

{{ summary.error_calls or 0 }}

-
By Provider
+
依供應商分組
- + {% for row in by_provider %} @@ -78,14 +78,14 @@
-
Recent Calls (TOP 100)
+
最近呼叫(最新 100 筆)
ProviderCallsTokensCost USD
供應商呼叫數Token 用量成本 (USD)
- - - + + + @@ -102,8 +102,8 @@ {% endfor %} @@ -113,12 +113,7 @@

- 🤖 Operation Ollama-First v5.0 / Phase 29 — Admin Observability - | Promotion Review - | Quality Trend - | Host Health - | Budget - | PPT Audit + Operation Ollama-First v5.0 / Phase 29 — AI 呼叫總覽

{% endblock %} diff --git a/templates/admin/budget.html b/templates/admin/budget.html index 8ab14dd..231b4d4 100644 --- a/templates/admin/budget.html +++ b/templates/admin/budget.html @@ -1,29 +1,29 @@ {% extends "base.html" %} -{% block title %}Budget Manager{% endblock %} +{% block title %}預算控管{% endblock %} {% block content %}
-

💰 Budget Manager - ai_call_budgets × 當月 spent 即時對比 +

預算控管 + ai_call_budgets × 當月實際支出即時對比

- {% if error %}
⚠️ {{ error }}
{% endif %} + {% if error %}
{{ error }}
{% endif %}

- 依 ADR-028 預算 + Phase 20 cost_throttle:每小時 cron 檢查當月 spent, - 線性外推月底成本超 110% → 自動 throttle(claude→gemini fallback)。 - 手動編輯 budget 後立即生效(不需 restart)。 + 依 ADR-028 預算 + Phase 20 成本節流:每小時 cron 檢查當月支出, + 線性外推月底成本超 110% → 自動節流(claude→gemini fallback)。 + 手動編輯預算後立即生效(不需重啟)。

IDTimeCallerProviderModelInOutmsStatus$Flags編號時間呼叫端供應商模型輸入輸出耗時 ms狀態成本 $標記
{{ r.status }} ${{ "%.4f"|format(r.cost) }} - {% if r.cache_hit %}cache{% endif %} - {% if r.rag_hit %}rag{% endif %} + {% if r.cache_hit %}快取{% endif %} + {% if r.rag_hit %}RAG{% endif %}
- - - - - + + + + + @@ -49,32 +49,29 @@ {% else %} - + {% endfor %}
PeriodProviderSpent (USD)Budget (USD)Alert %Ratio狀態Last Update動作週期供應商已花費 (USD)預算 (USD)警示閾值 %使用率狀態更新時間動作
{% if r.throttled %} - ⚠️ THROTTLED + 已節流 {% elif r.ratio >= 0.8 %} - ⚠ 接近上限 + 接近上限 {% else %} - ✅ 正常 + 正常 {% endif %} {{ r.updated_at }}
無預算資料(先跑 migrations/025)
無預算資料(需先跑 migrations/025)

- 🤖 Operation Ollama-First v5.0 / Phase 29 — Budget Manager - | AI Calls - | Host Health - | Promotion Review + Operation Ollama-First v5.0 / Phase 29 — 預算控管

@@ -83,7 +80,7 @@ async function saveBudget(id) { const budgetInput = document.querySelector(`.budget-input[data-budget-id="${id}"]`); const alertInput = document.querySelector(`.alert-input[data-budget-id="${id}"]`); const btn = document.querySelector(`.save-budget-btn[data-budget-id="${id}"]`); - btn.disabled = true; btn.innerText = '⏳'; + btn.disabled = true; btn.innerHTML = ''; try { const r = await fetch(`/observability/budget/update/${id}`, { method: 'POST', @@ -95,15 +92,15 @@ async function saveBudget(id) { }); const d = await r.json(); if (d.ok) { - btn.innerText = '✅'; - setTimeout(() => { btn.innerText = '💾 儲存'; btn.disabled = false; }, 1500); + btn.innerHTML = ' 已儲存'; + setTimeout(() => { btn.innerHTML = '儲存'; btn.disabled = false; }, 1500); } else { - alert('更新失敗: ' + (d.error || 'unknown')); - btn.disabled = false; btn.innerText = '💾 儲存'; + alert('更新失敗:' + (d.error || 'unknown')); + btn.disabled = false; btn.innerHTML = '儲存'; } } catch (e) { - alert('Error: ' + e); - btn.disabled = false; btn.innerText = '💾 儲存'; + alert('Error:' + e); + btn.disabled = false; btn.innerHTML = '儲存'; } } diff --git a/templates/admin/host_health.html b/templates/admin/host_health.html index aafa1a6..e410355 100644 --- a/templates/admin/host_health.html +++ b/templates/admin/host_health.html @@ -1,20 +1,20 @@ {% extends "base.html" %} -{% block title %}Host Health Dashboard{% endblock %} +{% block title %}主機健康監控{% endblock %} {% block content %}
-

🏥 Host Health Dashboard - 三主機 + MCP + Cost Throttle 即時狀態 +

主機健康監控 + 三主機 Ollama + MCP + 成本節流即時狀態

-
🤖 Ollama 三主機(HTTP /api/tags 即時 probe)
+
Ollama 三主機(HTTP /api/tags 即時 probe)
- + {% for h in ollama_hosts %} @@ -23,14 +23,14 @@ {% else %} @@ -43,16 +43,13 @@
角色主機HTTP 健康unhealthy mark已載入模型
角色主機HTTP 健康異常標記已載入模型
{{ h.host }} {% if h.healthy %} - ✅ HTTP OK + HTTP 正常 {% else %} - ❌ DOWN + 離線 {% endif %} {% if h.unhealthy_mark %} - ⚠️ marked unhealthy (30s) + 已標記異常(30 秒) {% else %} {% endif %} @@ -50,11 +50,11 @@
-
🔌 MCP Servers(Phase 10/10.5)
+
MCP 服務(Phase 10/10.5)
- + {% for server, healthy in mcp_status.items() %} @@ -62,14 +62,14 @@ {% else %} - + {% endfor %}
Server狀態
服務名稱狀態
{{ server }} {% if healthy %} - ✅ healthy + 正常 {% else %} - — 未啟用 / DOWN + — 未啟用 / 離線 {% endif %}
MCP_ROUTER_ENABLED=false 或 mcp-stack 未 deploy
MCP_ROUTER_ENABLED=false 或 mcp-stack 未部署
@@ -78,12 +78,12 @@
-
💰 Cost Throttle 狀態(Phase 20)
+
成本節流狀態(Phase 20)
{% if throttle_state %} - + {% for provider, info in throttle_state.items() %} @@ -95,9 +95,9 @@ @@ -106,19 +106,14 @@
ProviderSpentBudget月底推估Ratio狀態
供應商已花費預算月底推估使用率狀態
{{ "%.0f"|format(info.ratio * 100) }}% {% if info.throttled %} - ⚠️ THROTTLED + 已節流 {% else %} - ✅ 正常 + 正常 {% endif %}
{% else %}

- COST_THROTTLE_ENABLED=false 或尚未首次 evaluate(每小時 cron 跑) + COST_THROTTLE_ENABLED=false 或尚未首次評估(每小時 cron 執行)

{% endif %}

- 🤖 Operation Ollama-First v5.0 / Phase 29 — Host Health Dashboard - | AI Calls - | Promotion Review - | Quality Trend - | Budget - | PPT Audit + Operation Ollama-First v5.0 / Phase 29 — 主機健康監控

{% endblock %} diff --git a/templates/admin/ppt_audit_history.html b/templates/admin/ppt_audit_history.html index 502e8cd..09d1744 100644 --- a/templates/admin/ppt_audit_history.html +++ b/templates/admin/ppt_audit_history.html @@ -1,21 +1,21 @@ {% extends "base.html" %} -{% block title %}PPT Audit History{% endblock %} +{% block title %}PPT 視覺審核歷史{% endblock %} {% block content %}
-

🔍 PPT 視覺審核歷史 - reports/ 過去 7 日 .pptx +

PPT 視覺審核歷史 + reports/ 目錄過去 7 日 .pptx

- {% if error %}
⚠️ {{ error }}
{% endif %} + {% if error %}
{{ error }}
{% endif %}
- PPT_VISION_ENABLED: + PPT_VISION_ENABLED: {% if vision_enabled %} - ✅ 已啟用 — daily 22:00 cron 自動跑 minicpm-v 視覺檢查,有 issues 推 Telegram + 已啟用 — 每日 22:00 cron 自動跑 minicpm-v 視覺檢查,發現問題推送 Telegram {% else %} - ⏸ 未啟用 — 設 PPT_VISION_ENABLED=true + 188 安裝 LibreOffice 即生效 + 未啟用 — 設 PPT_VISION_ENABLED=true 並在 188 主機安裝 LibreOffice 即生效 {% endif %}
@@ -33,7 +33,7 @@
{{ f.size_kb }} {{ f.mtime }} - audit cron 22:00 自動跑 + 由 audit cron 22:00 自動執行

- 審核結果:有 issues 才推 Telegram(避免靜默無問題洗版)。 - 手動觸發單檔審核需 SSH 188 跑: + 審核結果:有問題才推 Telegram(避免靜默無問題洗版)。 + 手動觸發單檔審核需 SSH 到 188 主機執行: python3 -c "from services.ppt_vision_service import ppt_vision_service; print(ppt_vision_service.check_ppt_file('reports/xxx.pptx'))"

- 🤖 Operation Ollama-First v5.0 / Phase 29 — PPT Audit History - | AI Calls - | Host Health - | Budget + Operation Ollama-First v5.0 / Phase 29 — PPT 視覺審核歷史

{% endblock %} diff --git a/templates/admin/promotion_review.html b/templates/admin/promotion_review.html index ec5f882..a5f361a 100644 --- a/templates/admin/promotion_review.html +++ b/templates/admin/promotion_review.html @@ -1,34 +1,34 @@ {% extends "base.html" %} -{% block title %}Promotion Review · RAG 自主學習{% endblock %} +{% block title %}RAG 學習晉升審核{% endblock %} {% block content %}
-

🧠 RAG 學習晉升審核 - awaiting_review × {{ episodes|length }} 筆 +

RAG 學習晉升審核 + 待審核 × {{ episodes|length }} 筆

{% if error %} -
⚠️ {{ error }}
+
{{ error }}
{% endif %} {% if episodes %}

- ⚠️ Phase 11 PromotionGate Stage 4 強制門檻:weight >= 0.8 的 episode 必經統帥審核, - 24h 無回應自動 expired(weight 降為 0.5 不晉升)。 - 點 ✅ 通過 → 寫入 ai_insights 供 RAG 檢索;點 ❌ 拒絕 → 永不晉升(learning_episodes 留存)。 + Phase 11 PromotionGate Stage 4 強制門檻:weight ≥ 0.8 的 episode 必經統帥審核, + 24 小時無回應自動過期(weight 降為 0.5 不晉升)。 + 點「通過晉升」→ 寫入 ai_insights 供 RAG 檢索;點「拒絕」→ 永不晉升(learning_episodes 留存)。

{% for ep in episodes %}
- Episode #{{ ep.id }} + 學習片段 #{{ ep.id }} {{ ep.episode_type }} {% if ep.source_table %} {{ ep.source_table }}#{{ ep.source_id }}{% endif %} - weight: {{ "%.2f"|format(ep.weight) }} - quality: {{ "%.2f"|format(ep.quality_score) }} + 權重:{{ "%.2f"|format(ep.weight) }} + 品質:{{ "%.2f"|format(ep.quality_score) }}
{{ ep.created_at }}
@@ -37,34 +37,29 @@
{% endfor %} {% else %}
- ✨ 目前無 awaiting_review episodes。 - (RAG 未啟用 / 無高 weight episode / 全部已 24h 過期) + 目前無待審核片段。 + (RAG 未啟用 / 無高權重片段 / 全部已 24 小時過期)
{% endif %}

- 🤖 Operation Ollama-First v5.0 / Phase 29 — PromotionGate Web 審核頁 - | AI Calls - | Quality Trend - | Host Health - | Budget - | PPT Audit + Operation Ollama-First v5.0 / Phase 29 — RAG 學習晉升審核

diff --git a/templates/admin/quality_trend.html b/templates/admin/quality_trend.html index 9a689af..5d33533 100644 --- a/templates/admin/quality_trend.html +++ b/templates/admin/quality_trend.html @@ -1,15 +1,15 @@ {% extends "base.html" %} -{% block title %}Caller Quality Trend{% endblock %} +{% block title %}Caller 反饋趨勢{% endblock %} {% block content %}
-

💬 Caller 反饋趨勢 +

Caller 反饋趨勢 過去 {{ days }} 日

{% if error %} -
⚠️ {{ error }}
+
{{ error }}
{% endif %}
@@ -25,13 +25,13 @@ {% if recommendations %}
-
🔮 智能建議
+
智能建議
    {% for rec in recommendations %}
  • - {% if rec.action == 'review' %}⚠️{% else %}✅{% endif %} - {{ rec.caller }}: {{ rec.reason }} + {% if rec.action == 'review' %}{% else %}{% endif %} + {{ rec.caller }}:{{ rec.reason }}
  • {% endfor %}
@@ -40,16 +40,17 @@ {% endif %}
-
Caller × 反饋分佈 - (avg_score 升序,最差先看) +
呼叫端 × 反饋分佈 + (平均分數升序排列,最差先看)
- - - + + + + @@ -64,13 +65,13 @@
CallerAvg👍👎NTrendBar呼叫端平均總數趨勢分布
{{ info.total_feedback }} {% if info.trend == 'positive' %} - ✅ Positive + 正向 {% elif info.trend == 'negative' %} - ⚠️ Negative + 負向 {% elif info.trend == 'neutral' %} - ➖ Neutral + 中性 {% else %} - ❓ No Data + 無資料 {% endif %} @@ -93,12 +94,7 @@

- 🤖 Operation Ollama-First v5.0 / Phase 29 — Caller Quality Trend - | AI Calls - | Promotion Review - | Host Health - | Budget - | PPT Audit + Operation Ollama-First v5.0 / Phase 29 — Caller 反饋趨勢

{% endblock %} diff --git a/templates/components/_navbar.html b/templates/components/_navbar.html index 233c956..4726757 100755 --- a/templates/components/_navbar.html +++ b/templates/components/_navbar.html @@ -110,6 +110,49 @@ + + +