diff --git a/config.py b/config.py
index ff56b16..0fb27ea 100644
--- a/config.py
+++ b/config.py
@@ -402,7 +402,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '')
# ==========================================
# 系統版本與路徑
# ==========================================
-SYSTEM_VERSION = "V10.697"
+SYSTEM_VERSION = "V10.698"
LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log')
public_url = PUBLIC_URL # 用於模板顯示
diff --git a/docs/AI_INTELLIGENCE_MODULE_SOT.md b/docs/AI_INTELLIGENCE_MODULE_SOT.md
index 354b181..fb68177 100644
--- a/docs/AI_INTELLIGENCE_MODULE_SOT.md
+++ b/docs/AI_INTELLIGENCE_MODULE_SOT.md
@@ -774,3 +774,4 @@ POSTGRES_HOST=momo-db
| 2026-06-25 | 匯入任務列表只顯示處置提醒 | V10.695 起 `/auto_import` 任務列表不再把 `error_message` 原文當主要欄位顯示,而是由 `buildImportActionHint()` 轉成 Google Drive 授權、當日業績明細檔、重新匯入或通知維護人員等下一步,避免重啟後瀏覽器/授權/同步技術錯誤直接暴露給營運使用者。 |
| 2026-06-25 | 系統設定匯入提示不得顯示資料表或日誌口徑 | V10.696 起 `/system_settings` 不再用 `realtime_sales_monthly` 判斷前端提示,也不再顯示「資料落點、檢查日誌、發生系統錯誤」等內部口徑;所有匯入與備份失敗提示統一走 `toImportActionMessage()`,轉成重新授權、改用正確業績報表、重新匯入或通知維護人員。 |
| 2026-06-25 | 分析與建議頁必須使用 PChome 作戰流程語言 | V10.697 起 `/sales_analysis`、`/monthly_summary_analysis`、`/ai_recommend` 頁首與主要操作區統一使用「主推、守價、補比價、成長缺口、毛利貢獻、品類結構」等營運語言;前台不得把 AI 模型、權杖、資料庫、欄位、英文指標縮寫或內部錯誤作為使用者主訊息。 |
+| 2026-06-25 | 治理與匯入頁也不得外露模型/權杖/欄位口徑 | V10.698 起缺貨匯入、供應商窗口、AI 歷史、預算、AI 流量、AI 分工與主機健康頁統一改用「必要資料、用量、建議引擎、建議路徑、雲端備援、AI 建議服務」等前台可讀詞,避免使用者在營運頁看到 raw model、token、欄位或模型品牌。 |
diff --git a/routes/admin_observability_routes.py b/routes/admin_observability_routes.py
index 4c13752..aa380c4 100644
--- a/routes/admin_observability_routes.py
+++ b/routes/admin_observability_routes.py
@@ -61,7 +61,7 @@ _PPT_INTERNAL_ERROR_MARKERS = (
_PPT_PUBLIC_REPLACEMENTS = (
('AiderHeal', '修復流程'),
('RAG', '知識建議'),
- ('Ollama', 'AI 模型服務'),
+ ('Ollama', 'AI 建議服務'),
('minicpm-v', '視覺模型'),
('LibreOffice', '轉檔服務'),
('runtime', '執行條件'),
@@ -198,10 +198,10 @@ def _build_ai_call_recent_row(row):
if provider == 'gemini':
if caller in _GEMINI_BACKUP_CALLER_DISPLAY:
caller_display = _GEMINI_BACKUP_CALLER_DISPLAY[caller]
- route_badges.append('Gemini 備援')
+ route_badges.append('雲端備援')
route_badges.append('舊 caller')
elif caller in _GEMINI_BACKUP_CALLERS or caller.endswith('_gemini'):
- route_badges.append('Gemini 備援')
+ route_badges.append('雲端備援')
else:
route_badges.append('ADR-028 鎖定/升級')
diff --git a/templates/admin/_observability_labels.html b/templates/admin/_observability_labels.html
index 059f952..58f5da0 100644
--- a/templates/admin/_observability_labels.html
+++ b/templates/admin/_observability_labels.html
@@ -116,11 +116,11 @@
{% macro provider(value, fallback='未分類供應商') -%}
{%- set labels = {
- 'gcp_ollama': '主力 AI 模型',
- 'ollama_secondary': '備援 AI 模型',
- 'ollama_111': '第三 AI 模型',
+ 'gcp_ollama': '主力建議路徑',
+ 'ollama_secondary': '備援建議路徑',
+ 'ollama_111': '第三建議路徑',
'nim_via_elephant': 'NIM Elephant',
- 'gemini': 'Gemini',
+ 'gemini': '雲端備援',
'claude': 'Claude',
'nim': 'NIM',
'openrouter': 'OpenRouter',
diff --git a/templates/admin/agent_orchestration.html b/templates/admin/agent_orchestration.html
index a13bf6c..e400fd6 100644
--- a/templates/admin/agent_orchestration.html
+++ b/templates/admin/agent_orchestration.html
@@ -9,15 +9,15 @@
-
AI 分工指揮台 · {{ hours }} 小時視窗
AI 分工指揮台
確認 AI 分工、本地模型、知識命中與工具編排是否支撐業績決策。
{% if overall %}呼叫總量
{{ "{:,}".format(overall.total_calls) }}{{ "{:,}".format(overall.total_tokens) }} 用量本地模型占比
{{ "%.0f"|format(overall.local_pct) }}%{{ "{:,}".format(overall.local_calls) }} 次本地呼叫付費成本
${{ "%.2f"|format(overall.total_cost) }}{{ "{:,}".format(overall.paid_calls) }} 次付費呼叫知識命中率
{{ "%.0f"|format(overall.rag_rate) }}%{{ "{:,}".format(overall.rag_hits) }} 次命中 {% endif %}
+
AI 分工指揮台 · {{ hours }} 小時視窗
AI 分工指揮台
確認 AI 分工、建議路徑、知識命中與工具編排是否支撐業績決策。
{% if overall %}呼叫總量
{{ "{:,}".format(overall.total_calls) }}{{ "{:,}".format(overall.total_tokens) }} 用量主力路徑占比
{{ "%.0f"|format(overall.local_pct) }}%{{ "{:,}".format(overall.local_calls) }} 次主力呼叫付費成本
${{ "%.2f"|format(overall.total_cost) }}{{ "{:,}".format(overall.paid_calls) }} 次付費呼叫知識命中率
{{ "%.0f"|format(overall.rag_rate) }}%{{ "{:,}".format(overall.rag_hits) }} 次命中 {% endif %}
{% if error %}
{{ error }}
{% endif %}
-
| 分工 | 呼叫 | 成本 | 本地模型 | 付費 | 工具 | 知識 | 錯誤 | 耗時 |
{% for ag in agent_matrix %}| {{ ag.label }}{{ ag.desc }} | {% if ag.calls > 0 %}{{ "{:,}".format(ag.calls) }}{{ "{:,}".format(ag.tokens) }} 用量{% else %}—{% endif %} | {% if ag.calls > 0 %}${{ "%.2f"|format(ag.cost) }}{% else %}—{% endif %} | {% if ag.calls > 0 %}{{ "%.0f"|format(ag.ollama_pct) }}%主力 {{ ag.ollama_gcp_a }} · 備援 {{ ag.ollama_gcp_b }} · 第三 {{ ag.ollama_111 }}{% else %}—{% endif %} | {% if ag.calls > 0 %}{{ "%.0f"|format(ag.paid_pct) }}%Gemini {{ ag.gemini }}{% if ag.other_paid %} · 其他 {{ ag.other_paid }}{% endif %}{% else %}—{% endif %} | {% if ag.calls > 0 %}{{ "%.1f"|format(ag.mcp_rate) }}%{{ ag.mcp_calls }}{% else %}—{% endif %} | {% if ag.calls > 0 %}{{ "%.1f"|format(ag.rag_rate) }}%{{ ag.rag_hits }}{% else %}—{% endif %} | {% if ag.calls > 0 %}{{ "%.1f"|format(ag.error_rate) }}%{{ ag.errors }}{% else %}—{% endif %} | {% if ag.calls > 0 %}{{ ag.avg_ms }} ms{% else %}—{% endif %} |
{% endfor %}
+
| 分工 | 呼叫 | 成本 | 主力路徑 | 付費 | 工具 | 知識 | 錯誤 | 耗時 |
{% for ag in agent_matrix %}| {{ ag.label }}{{ ag.desc }} | {% if ag.calls > 0 %}{{ "{:,}".format(ag.calls) }}{{ "{:,}".format(ag.tokens) }} 用量{% else %}—{% endif %} | {% if ag.calls > 0 %}${{ "%.2f"|format(ag.cost) }}{% else %}—{% endif %} | {% if ag.calls > 0 %}{{ "%.0f"|format(ag.ollama_pct) }}%主力 {{ ag.ollama_gcp_a }} · 備援 {{ ag.ollama_gcp_b }} · 第三 {{ ag.ollama_111 }}{% else %}—{% endif %} | {% if ag.calls > 0 %}{{ "%.0f"|format(ag.paid_pct) }}%雲端備援 {{ ag.gemini }}{% if ag.other_paid %} · 其他 {{ ag.other_paid }}{% endif %}{% else %}—{% endif %} | {% if ag.calls > 0 %}{{ "%.1f"|format(ag.mcp_rate) }}%{{ ag.mcp_calls }}{% else %}—{% endif %} | {% if ag.calls > 0 %}{{ "%.1f"|format(ag.rag_rate) }}%{{ ag.rag_hits }}{% else %}—{% endif %} | {% if ag.calls > 0 %}{{ "%.1f"|format(ag.error_rate) }}%{{ ag.errors }}{% else %}—{% endif %} | {% if ag.calls > 0 %}{{ ag.avg_ms }} ms{% else %}—{% endif %} |
{% endfor %}
diff --git a/templates/admin/ai_calls_dashboard.html b/templates/admin/ai_calls_dashboard.html
index 2f78338..1fd018b 100644
--- a/templates/admin/ai_calls_dashboard.html
+++ b/templates/admin/ai_calls_dashboard.html
@@ -118,14 +118,14 @@
{% if by_model %}
-
- | 模型 | 供應商 | 呼叫 | 用量 | 成本 | 耗時 | 錯誤 |
{% for m in by_model %}{{ m.model[:35] }} | {{ obs_label.provider(m.provider) }} | {{ "{:,}".format(m.calls) }} | {{ "{:,}".format(m.tokens) }} | ${{ "%.4f"|format(m.cost) }} | {{ m.avg_ms }} ms | {% if m.errors > 0 %}{{ m.errors }}{% else %}0{% endif %} |
{% endfor %}
+
+ | 建議路徑 | 供應商 | 呼叫 | 用量 | 成本 | 耗時 | 錯誤 |
{% for m in by_model %}| {{ obs_label.provider(m.provider) }} | {{ obs_label.provider(m.provider) }} | {{ "{:,}".format(m.calls) }} | {{ "{:,}".format(m.tokens) }} | ${{ "%.4f"|format(m.cost) }} | {{ m.avg_ms }} ms | {% if m.errors > 0 %}{{ m.errors }}{% else %}0{% endif %} |
{% endfor %}
{% endif %}
- | 編號 | 時間 | 呼叫端 | 供應商 | 模型 | 輸入 | 輸出 | 耗時 | 狀態 | 成本 | 標記 |
{% for r in recent %}| {{ r.id }} | {{ r.called_at }} | {{ r.caller_display or r.caller }}{% if r.caller_display and r.caller_display != r.caller %} 原始:{{ r.caller }}{% endif %} | {{ obs_label.provider(r.provider) }} | {{ r.model[:25] }} | {{ r.in_tokens }} | {{ r.out_tokens }} | {{ r.duration_ms }} | {{ obs_label.status(r.status, '-') }} | ${{ "%.4f"|format(r.cost) }} | {% for badge in r.route_badges %}{{ badge }}{% endfor %}{% if r.cache_hit %}快取{% endif %}{% if r.rag_hit %}知識命中{% endif %} |
{% endfor %}
+ | 編號 | 時間 | 呼叫端 | 供應商 | 建議路徑 | 輸入 | 輸出 | 耗時 | 狀態 | 成本 | 標記 |
{% for r in recent %}| {{ r.id }} | {{ r.called_at }} | {{ r.caller_display or r.caller }}{% if r.caller_display and r.caller_display != r.caller %} 原始:{{ r.caller }}{% endif %} | {{ obs_label.provider(r.provider) }} | {{ obs_label.provider(r.provider) }} | {{ r.in_tokens }} | {{ r.out_tokens }} | {{ r.duration_ms }} | {{ obs_label.status(r.status, '-') }} | ${{ "%.4f"|format(r.cost) }} | {% for badge in r.route_badges %}{{ badge }}{% endfor %}{% if r.cache_hit %}快取{% endif %}{% if r.rag_hit %}知識命中{% endif %} |
{% endfor %}
AI 流量控制塔
diff --git a/templates/admin/budget.html b/templates/admin/budget.html
index 7ef70ae..3b47bc9 100644
--- a/templates/admin/budget.html
+++ b/templates/admin/budget.html
@@ -70,7 +70,7 @@
{% endif %}
{% if top_cost_callers %}
-
{% set max_cost = (top_cost_callers | map(attribute='cost') | max) or 1 %}{% for c in top_cost_callers %}
{{ c.caller }}${{ "%.2f"|format(c.cost) }}
{{ "{:,}".format(c.calls) }} 次呼叫 · {{ "{:,}".format(c.tokens) }} 權杖{% endfor %}
+
{% set max_cost = (top_cost_callers | map(attribute='cost') | max) or 1 %}{% for c in top_cost_callers %}
{{ c.caller }}${{ "%.2f"|format(c.cost) }}
{{ "{:,}".format(c.calls) }} 次呼叫 · {{ "{:,}".format(c.tokens) }} 用量{% endfor %}
{% endif %}
diff --git a/templates/admin/host_health.html b/templates/admin/host_health.html
index 4a489b1..56b793e 100644
--- a/templates/admin/host_health.html
+++ b/templates/admin/host_health.html
@@ -59,11 +59,11 @@
- 基礎設施生命線 · AI 模型 / 工具服務 / 自癒
+ 基礎設施生命線 · AI 建議服務 / 工具服務 / 自癒
基礎設施生命線
- 先看 AI 模型、工具服務與自癒是否正常,避免 AI 建議與比價流程中斷。
+ 先看 AI 建議服務、工具服務與自癒是否正常,避免 AI 建議與比價流程中斷。
-
AI 模型離線
{{ down.count }}{{ ollama_hosts|length }} 台即時探測
+
建議服務離線
{{ down.count }}{{ ollama_hosts|length }} 台即時探測
AIOps 未解
{{ aiops_summary.incidents_open if aiops_summary else '—' }}7 日事件未解決
自癒成功率
{{ "%.0f"|format(aiops_summary.heal_success_rate) if aiops_summary else '—' }}{% if aiops_summary %}%{% endif %}近 7 日自癒成功率
節流供應商
{{ throttled.count }}成本節流供應商
@@ -74,7 +74,7 @@
-
+
{{ '需要處理' if down.count > 0 else '全部在線' }}
@@ -157,11 +157,11 @@
-
{% if recent_incidents %}{% set task_labels = {'ElephantAlphaAutonomousEngine': 'AI 自癒監控', 'run_icaim_analysis_task': '市場分析任務'} %}{% set error_labels = {'ollama_unhealthy': 'AI 模型主機不穩', 'scheduler_task_failure': '排程任務異常', 'crawler_timeout': '資料擷取逾時', 'python_exception': '程式例外'} %}
| 時間 | 任務 | 問題 | 等級 | 狀態 | 處置提醒 |
{% for i in recent_incidents %}| {{ i.created_at }} | {{ task_labels.get(i.task_name, '系統任務') }} | {{ error_labels.get(i.error_type, '系統異常') }} | {{ i.severity }} | {{ i.status }} | {% if i.error_type == 'ollama_unhealthy' %}AI 模型主機暫時不穩,已進入自癒監控。{% elif i.error_type == 'python_exception' %}資料流程發生程式例外,需由修復流程處理。{% elif i.error_type == 'scheduler_task_failure' %}排程任務異常,需確認下次執行是否恢復。{% else %}系統事件已記錄,請依狀態追蹤後續是否恢復。{% endif %} |
{% endfor %}
{% else %}
尚無事件紀錄
{% endif %}
+
{% if recent_incidents %}{% set task_labels = {'ElephantAlphaAutonomousEngine': 'AI 自癒監控', 'run_icaim_analysis_task': '市場分析任務'} %}{% set error_labels = {'ollama_unhealthy': 'AI 建議服務不穩', 'scheduler_task_failure': '排程任務異常', 'crawler_timeout': '資料擷取逾時', 'python_exception': '程式例外'} %}
| 時間 | 任務 | 問題 | 等級 | 狀態 | 處置提醒 |
{% for i in recent_incidents %}| {{ i.created_at }} | {{ task_labels.get(i.task_name, '系統任務') }} | {{ error_labels.get(i.error_type, '系統異常') }} | {{ i.severity }} | {{ i.status }} | {% if i.error_type == 'ollama_unhealthy' %}AI 建議服務暫時不穩,已進入自癒監控。{% elif i.error_type == 'python_exception' %}資料流程發生程式例外,需由修復流程處理。{% elif i.error_type == 'scheduler_task_failure' %}排程任務異常,需確認下次執行是否恢復。{% else %}系統事件已記錄,請依狀態追蹤後續是否恢復。{% endif %} |
{% endfor %}
{% else %}
尚無事件紀錄
{% endif %}
{% if recent_heals %}
| 時間 | 動作 | 結果 | 耗時 | 細節 |
{% for h in recent_heals %}| {{ h.created_at }} | {{ h.action_type or '—' }} | {% if h.result == 'success' %}成功{% elif h.result == 'failed' %}失敗{% else %}{{ h.result }}{% endif %} | {{ h.duration_ms }} ms | {{ h.action_detail }} |
{% endfor %}
{% else %}
尚無自癒紀錄
{% endif %}
diff --git a/templates/ai_history.html b/templates/ai_history.html
index 254db7a..7c7b7ca 100644
--- a/templates/ai_history.html
+++ b/templates/ai_history.html
@@ -564,7 +564,7 @@ function renderHistory(items) {
- ${item.model_name || '-'}
+ 建議引擎
${item.generation_duration ? `${item.generation_duration}秒` : ''}
${item.input_style ? `${item.input_style}` : ''}
diff --git a/templates/vendor_stockout_import_v2.html b/templates/vendor_stockout_import_v2.html
index 3fe2d73..f1fa07e 100644
--- a/templates/vendor_stockout_import_v2.html
+++ b/templates/vendor_stockout_import_v2.html
@@ -54,13 +54,13 @@