統帥要求: 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>
58 lines
2.8 KiB
SQL
58 lines
2.8 KiB
SQL
-- =============================================================================
|
||
-- Migration 030: ppt_audit_results — PPT 視覺審核歷史持久化
|
||
-- Operation Ollama-First v5.0 — Phase 38
|
||
-- 日期: 2026-05-04 台北
|
||
-- 對應頁面: /observability/ppt_audit_history
|
||
-- =============================================================================
|
||
-- 說明:
|
||
-- 原本 ppt_audit_history 頁面只 os.listdir(reports/) 列檔,
|
||
-- PPT_VISION minicpm-v 跑出的審核結論(issues_found, confidence)完全遺失。
|
||
-- 本 migration 加表,audit 完一律寫入,方便:
|
||
-- 1. 觀測頁面顯示「audit 結果」而不只「檔案存在」
|
||
-- 2. 趨勢分析(過去 30 天 PPT 通過率?常見 issue 類型?)
|
||
-- 3. Telegram 推播去重(同檔案同問題 7 天內不重推)
|
||
--
|
||
-- 寫入點:
|
||
-- 1. services/ppt_vision_service.py::check_ppt_file 跑完 minicpm-v 後寫
|
||
-- 2. scheduler.py daily 22:00 cron 跑完所有當日 PPT 後 batch 寫
|
||
--
|
||
-- 索引設計:
|
||
-- - (audited_at DESC) 最新 audit
|
||
-- - (pptx_filename) 同檔多次審核
|
||
-- - (audit_status) 篩選 failed only
|
||
-- =============================================================================
|
||
|
||
CREATE TABLE IF NOT EXISTS ppt_audit_results (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
audited_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||
pptx_filename VARCHAR(256) NOT NULL,
|
||
pptx_size_kb INTEGER,
|
||
pptx_mtime TIMESTAMPTZ, -- 檔案本身 mtime(區分同名重生)
|
||
vision_enabled BOOLEAN NOT NULL, -- audit 當時 PPT_VISION_ENABLED 狀態
|
||
audit_status VARCHAR(32) NOT NULL, -- 'passed' / 'failed' / 'skipped' / 'error'
|
||
issues_count INTEGER DEFAULT 0,
|
||
issues_found JSONB, -- ppt_vision_service 回傳的 issues 陣列
|
||
confidence NUMERIC(4,3), -- 0-1 minicpm-v 信心度
|
||
duration_ms INTEGER, -- audit 耗時
|
||
error_msg TEXT, -- 失敗時的 exception
|
||
reviewer_notes TEXT, -- 人工補註(admin 介面後續可加)
|
||
|
||
CONSTRAINT chk_audit_status_030
|
||
CHECK (audit_status IN ('passed', 'failed', 'skipped', 'error', 'pending'))
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_ppt_audit_at
|
||
ON ppt_audit_results (audited_at DESC);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_ppt_audit_filename
|
||
ON ppt_audit_results (pptx_filename);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_ppt_audit_failed
|
||
ON ppt_audit_results (audited_at DESC)
|
||
WHERE audit_status = 'failed';
|
||
|
||
COMMENT ON TABLE ppt_audit_results IS
|
||
'PPT 視覺審核結果歷史;by services/ppt_vision_service.py minicpm-v 推論';
|
||
COMMENT ON COLUMN ppt_audit_results.issues_found IS
|
||
'JSONB 陣列:[{type, severity, description, slide_index}]';
|