fix: simplify edge governance copy

This commit is contained in:
ogt
2026-06-26 07:28:15 +08:00
parent c1b375f41c
commit fec7b5c778
8 changed files with 19 additions and 9 deletions

View File

@@ -402,7 +402,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '')
# ==========================================
# 系統版本與路徑
# ==========================================
SYSTEM_VERSION = "V10.699"
SYSTEM_VERSION = "V10.700"
LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log')
public_url = PUBLIC_URL # 用於模板顯示

View File

@@ -776,3 +776,4 @@ POSTGRES_HOST=momo-db
| 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、欄位或模型品牌。 |
| 2026-06-25 | 工具頁與簡報頁也必須使用作戰語言Google Drive token 必須固定到持久化掛載 | V10.699 起簡報預覽、品牌素材、比價、匯入、缺貨與觀測台操作提示移除英文/內部流程字,改成可直接理解的狀態與下一步;正式容器明確指定 `/app/config/google_token.json``/app/config/google_credentials.json`,背景匯入不得因主機重啟或工作目錄變動而改找瀏覽器授權。 |
| 2026-06-26 | 邊角治理頁不得把 raw caller、模型資料或推版代碼當主訊息 | V10.700 起 AI 流量、主機健康、通知模板與缺貨匯入提示再收斂為「使用情境、建議路徑、服務資料、更新摘要、先選擇供應商缺貨檔」等營運語言,避免低頻治理頁回流 `原始`、模型品牌、commit/pipeline 欄位或泛用檔案提示。 |

View File

@@ -121,7 +121,7 @@
'ollama_111': '第三建議路徑',
'nim_via_elephant': 'NIM Elephant',
'gemini': '雲端備援',
'claude': 'Claude',
'claude': '雲端審查備援',
'nim': 'NIM',
'openrouter': 'OpenRouter',
'unknown': '未分類供應商'

View File

@@ -119,13 +119,13 @@
{% if by_model %}
<section class="calls-table-shell">
<div class="calls-table-title"><div><div class="calls-label">路徑成本</div><h3>依建議路徑細分</h3></div></div>
<div class="table-responsive"><table class="table table-sm mb-0"><thead class="table-light"><tr><th>建議路徑</th><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">錯誤</th></tr></thead><tbody>{% for m in by_model %}<tr><td><span class="badge bg-secondary">{{ obs_label.provider(m.provider) }}</span></td><td><span class="badge bg-secondary">{{ obs_label.provider(m.provider) }}</span></td><td class="text-end">{{ "{:,}".format(m.calls) }}</td><td class="text-end">{{ "{:,}".format(m.tokens) }}</td><td class="text-end">${{ "%.4f"|format(m.cost) }}</td><td class="text-end">{{ m.avg_ms }} ms</td><td class="text-end">{% if m.errors > 0 %}<span class="status-bad">{{ m.errors }}</span>{% else %}<small class="text-muted">0</small>{% endif %}</td></tr>{% endfor %}</tbody></table></div>
<div class="table-responsive"><table class="table table-sm 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">錯誤</th></tr></thead><tbody>{% for m in by_model %}<tr><td><span class="badge bg-secondary">{{ obs_label.provider(m.provider) }}</span></td><td class="text-end">{{ "{:,}".format(m.calls) }}</td><td class="text-end">{{ "{:,}".format(m.tokens) }}</td><td class="text-end">${{ "%.4f"|format(m.cost) }}</td><td class="text-end">{{ m.avg_ms }} ms</td><td class="text-end">{% if m.errors > 0 %}<span class="status-bad">{{ m.errors }}</span>{% else %}<small class="text-muted">0</small>{% endif %}</td></tr>{% endfor %}</tbody></table></div>
</section>
{% endif %}
<section class="calls-table-shell">
<div class="calls-table-title"><div><div class="calls-label">最近呼叫</div><h3>最近呼叫 100 筆</h3></div></div>
<div class="table-responsive"><table class="table table-sm table-striped mb-0"><thead class="table-light"><tr><th>編號</th><th>時間</th><th>呼叫端</th><th>供應商</th><th>建議路徑</th><th class="text-end">輸入</th><th class="text-end">輸出</th><th class="text-end">耗時</th><th>狀態</th><th class="text-end">成本</th><th>標記</th></tr></thead><tbody>{% for r in recent %}<tr {% if r.status not in ['ok','cache_only'] %}class="table-warning"{% endif %}><td>{{ r.id }}</td><td><small>{{ r.called_at }}</small></td><td><code>{{ r.caller_display or r.caller }}</code>{% if r.caller_display and r.caller_display != r.caller %}<br><small class="text-muted">原始:{{ r.caller }}</small>{% endif %}</td><td><small>{{ obs_label.provider(r.provider) }}</small></td><td><small>{{ obs_label.provider(r.provider) }}</small></td><td class="text-end">{{ r.in_tokens }}</td><td class="text-end">{{ r.out_tokens }}</td><td class="text-end">{{ r.duration_ms }}</td><td><small>{{ obs_label.status(r.status, '-') }}</small></td><td class="text-end">${{ "%.4f"|format(r.cost) }}</td><td>{% for badge in r.route_badges %}<span class="badge bg-secondary me-1">{{ badge }}</span>{% endfor %}{% if r.cache_hit %}<span class="badge bg-success">快取</span>{% endif %}{% if r.rag_hit %}<span class="badge bg-info">知識命中</span>{% endif %}</td></tr>{% endfor %}</tbody></table></div>
<div class="table-responsive"><table class="table table-sm table-striped mb-0"><thead class="table-light"><tr><th>編號</th><th>時間</th><th>使用情境</th><th>建議路徑</th><th class="text-end">輸入</th><th class="text-end">輸出</th><th class="text-end">耗時</th><th>狀態</th><th class="text-end">成本</th><th>標記</th></tr></thead><tbody>{% for r in recent %}<tr {% if r.status not in ['ok','cache_only'] %}class="table-warning"{% endif %}><td>{{ r.id }}</td><td><small>{{ r.called_at }}</small></td><td><span>{{ r.caller_display or '營運建議流程' }}</span></td><td><small>{{ obs_label.provider(r.provider) }}</small></td><td class="text-end">{{ r.in_tokens }}</td><td class="text-end">{{ r.out_tokens }}</td><td class="text-end">{{ r.duration_ms }}</td><td><small>{{ obs_label.status(r.status, '-') }}</small></td><td class="text-end">${{ "%.4f"|format(r.cost) }}</td><td>{% for badge in r.route_badges %}<span class="badge bg-secondary me-1">{{ badge }}</span>{% endfor %}{% if r.cache_hit %}<span class="badge bg-success">快取</span>{% endif %}{% if r.rag_hit %}<span class="badge bg-info">知識命中</span>{% endif %}</td></tr>{% endfor %}</tbody></table></div>
</section>
<p class="text-muted mt-3"><small><i class="fas fa-robot me-1"></i>AI 流量控制塔</small></p>

View File

@@ -90,7 +90,7 @@
{% if h.error %}<div class="text-danger small mt-1">{{ h.error }}</div>{% endif %}
<div class="model-cloud">
{% for m in h.models %}<span class="model-chip">{{ m }}</span>{% endfor %}
{% if not h.models %}<span class="text-muted small">模型資料 / 未連線</span>{% endif %}
{% if not h.models %}<span class="text-muted small">服務資料 / 未連線</span>{% endif %}
</div>
</div>
<div class="runtime-actions">

View File

@@ -360,8 +360,8 @@ const SAMPLE_TEMPLATE_VALUES = {
new_usage_percent: '75.2', results: '已完成清理並釋放空間',
status: '需確認', database: '資料連線需確認', deployment: '主系統',
issues: '網站憑證將於 10 天後到期', error: '找不到最新備份檔案',
project: 'PChome 業績成長系統', branch: '正式版', pipeline_id: '123',
commit_message: '更新業績流程', author: '系統管理員', duration: '2 分 30 秒',
project: 'PChome 業績成長系統', branch: '正式版', deploy_id: '123',
update_summary: '更新業績流程', author: '系統管理員', duration: '2 分 30 秒',
url: 'https://mo.wooo.work',
date: '2026-01-25', app_status: '正常', backup_status: '正常',
crawler_status: '需檢查', last_backup: '最新備份已建立',

View File

@@ -606,19 +606,28 @@ def test_utility_pages_keep_operator_copy_professional():
ppt_preview = (ROOT / "templates/admin/ppt_audit_preview.html").read_text(encoding="utf-8")
auto_import = (ROOT / "templates/auto_import_index.html").read_text(encoding="utf-8")
stockout_import = (ROOT / "templates/vendor_stockout_import_v2.html").read_text(encoding="utf-8")
vendor_import_js = (ROOT / "web/static/js/page-vendor-import.js").read_text(encoding="utf-8")
ai_calls = (ROOT / "templates/admin/ai_calls_dashboard.html").read_text(encoding="utf-8")
host_health = (ROOT / "templates/admin/host_health.html").read_text(encoding="utf-8")
observability_js = (ROOT / "web/static/js/observability-charts.js").read_text(encoding="utf-8")
combined = "\n".join([ppt_history, ppt_preview, auto_import, stockout_import, observability_js])
combined = "\n".join([ppt_history, ppt_preview, auto_import, stockout_import, vendor_import_js, ai_calls, host_health, observability_js])
assert "簡報線上預覽" in ppt_preview
assert "下載簡報檔" in ppt_history
assert "送出後更新日報、成長分析與今日作戰清單" in auto_import
assert "缺少必要資料時,會先停止匯入" in stockout_import
assert "先選擇供應商缺貨 Excel 檔。" in vendor_import_js
assert "使用情境" in ai_calls
assert "無服務資料 / 未連線" in host_health
assert "部署檢查已排入背景處理" in observability_js
forbidden = [
"PPT Online Preview",
"Preview unavailable",
"原始 PPTX",
"原始:",
"無模型資料",
"請選擇 Excel 檔案",
"系統會去重",
"系統會拒絕",
"管線 ID",

View File

@@ -35,7 +35,7 @@
function handleFile(file) {
if (!file) return;
if (!file.name.match(/\.(xlsx|xls)$/i)) {
errorMessage.textContent = '選擇 Excel 檔案 (.xlsx 或 .xls)';
errorMessage.textContent = '選擇供應商缺貨 Excel 檔';
show(errorPanel);
return;
}