Fix PPT auto generation and analytics fallbacks
Some checks failed
CD Pipeline / deploy (push) Failing after 26s

This commit is contained in:
OoO
2026-05-18 11:52:31 +08:00
parent 3284b1cf82
commit c420d48263
26 changed files with 1559 additions and 258 deletions

View File

@@ -2,159 +2,11 @@
{% block title %}PPT 視覺 QA 產線{% endblock %}
{% block ewooo_content %}
<style>
.ppt-hero, .ppt-panel, .ppt-table-shell {
border: 1px solid var(--obs-line);
border-radius: 26px;
background: var(--obs-card);
box-shadow: 0 16px 38px rgba(70, 46, 28, .08);
}
.ppt-hero {
padding: 1.4rem;
background: radial-gradient(circle at 12% 14%, rgba(201,100,66,.18), transparent 24rem),
radial-gradient(circle at 88% 8%, rgba(79,111,143,.14), transparent 22rem),
linear-gradient(135deg, rgba(255,248,239,.98), rgba(255,255,255,.74));
}
.ppt-kicker {
color: var(--obs-accent);
font-size: .76rem;
letter-spacing: .13em;
text-transform: uppercase;
font-weight: 850;
}
.ppt-title {
margin: .45rem 0 .25rem;
font-family: var(--momo-font-display, "Inter", "Noto Sans TC", system-ui, sans-serif);
font-size: var(--obs-title-size);
letter-spacing: 0;
line-height: .98;
}
.ppt-subtitle {
color: var(--obs-muted);
max-width: 860px;
line-height: 1.7;
}
.ppt-command {
display: grid;
grid-template-columns: repeat(4, minmax(0,1fr));
gap: .75rem;
margin-top: 1rem;
}
.ppt-signal {
padding: .95rem;
border: 1px solid var(--obs-line);
border-radius: 20px;
background: rgba(255,255,255,.62);
}
.ppt-label {
color: var(--obs-muted);
font-size: .72rem;
letter-spacing: .1em;
text-transform: uppercase;
}
.ppt-value {
display: block;
margin-top: .28rem;
font-size: var(--obs-value-size);
font-weight: 880;
letter-spacing: 0;
}
.ppt-toolbar {
margin-top: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
gap: .75rem;
flex-wrap: wrap;
}
.ppt-type-tabs {
display: flex;
flex-wrap: wrap;
gap: .45rem;
}
.ppt-type-chip {
display: inline-flex;
align-items: center;
gap: .35rem;
}
.ppt-grid {
display: grid;
grid-template-columns: minmax(0,1.2fr) minmax(330px,.8fr);
gap: 1rem;
margin-top: 1rem;
}
.ppt-stack { display: grid; gap: 1rem; }
.ppt-panel-head, .ppt-table-title {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 1rem;
padding: 1.05rem 1.1rem .25rem;
}
.ppt-panel-title, .ppt-table-title h3 {
margin: .15rem 0 0;
font-size: 1.1rem;
font-weight: 850;
letter-spacing: 0;
}
.ppt-panel-body {
padding: 1rem 1.1rem 1.1rem;
}
.ppt-table-shell {
overflow: hidden;
margin-top: 1rem;
}
.ppt-table-shell .table {
min-width: 760px;
}
.ppt-mini-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0,1fr));
gap: .7rem;
}
.ppt-mini {
padding: .85rem;
border: 1px solid var(--obs-line);
border-radius: 18px;
background: rgba(255,255,255,.58);
}
.ppt-mini strong {
display: block;
margin-top: .24rem;
font-size: 1.35rem;
letter-spacing: 0;
}
.fix-card {
padding: .85rem;
border: 1px solid var(--obs-line);
border-radius: 18px;
background: rgba(255,255,255,.58);
margin-bottom: .7rem;
}
.status-good { color: var(--obs-green); }
.status-warn { color: var(--obs-amber); }
.status-bad { color: var(--obs-red); }
.status-blue { color: var(--obs-blue); }
.ppt-file-actions {
display: flex;
gap: .4rem;
flex-wrap: wrap;
}
.ppt-file-actions .btn {
display: inline-flex;
align-items: center;
gap: .3rem;
}
@media(max-width:1100px) {
.ppt-command, .ppt-mini-grid { grid-template-columns: repeat(2,minmax(0,1fr)); }
.ppt-grid { grid-template-columns: 1fr; }
}
@media(max-width:720px) {
.ppt-command { grid-template-columns: 1fr; }
}
</style>
{% block extra_css %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/page-ppt-audit-history.css') }}">
{% endblock %}
{% block ewooo_content %}
{% import "admin/_observability_labels.html" as obs_label %}
{% set report_is_daily = report_type == 'daily' %}
@@ -188,6 +40,13 @@
</span>
<small class="text-muted">視覺問題數</small>
</div>
<div class="ppt-signal">
<div class="ppt-label">定義覆蓋</div>
<span class="ppt-value {% if auto_generation.missing_count == 0 and auto_generation.total > 0 %}status-good{% elif auto_generation.missing_count > 0 %}status-warn{% else %}status-blue{% endif %}">
{{ auto_generation.ready_count }}/{{ auto_generation.total }}
</span>
<small class="text-muted">自動簡報產線</small>
</div>
</div>
</section>
{% if error %}<div class="alert alert-warning mt-3"><strong><i class="fas fa-triangle-exclamation me-1"></i></strong>{{ error }}</div>{% endif %}
@@ -214,6 +73,40 @@
{% endfor %}
</div>
</section>
<section class="ppt-panel mt-3"
data-ppt-auto-generation
data-auto-start="{{ 'true' if auto_generation.can_auto_start else 'false' }}"
data-report-types="{{ auto_generation_missing_report_types | join(',') }}">
<div class="ppt-panel-head">
<div>
<div class="ppt-label">自動產生定義</div>
<h2 class="ppt-panel-title">簡報產線覆蓋狀態</h2>
</div>
<button class="btn btn-sm btn-outline-primary" type="button" data-ppt-generate-missing {% if not auto_generation.enabled or auto_generation.missing_count == 0 %}disabled{% endif %}>
<i class="fas fa-wand-magic-sparkles me-1" aria-hidden="true"></i>補齊缺漏簡報
</button>
</div>
<div class="ppt-panel-body">
<div class="ppt-auto-grid">
{% for item in auto_generation_items %}
<div class="ppt-mini">
<span class="ppt-label">{{ item.label }}</span>
<strong class="{% if item.ready %}status-good{% else %}status-warn{% endif %}">
{{ '已產生' if item.ready else '待補齊' }}
</strong>
<small class="text-muted">{{ item.count }} 筆{% if item.sources %} · {{ item.sources|join(' + ') }}{% endif %}</small>
</div>
{% endfor %}
</div>
<div class="ppt-auto-status small text-muted mt-3" data-ppt-auto-status>
{% if auto_generation.enabled %}
每日 20:30 會自動補齊定義簡報;目前缺漏 {{ auto_generation.missing_count }} 類。
{% else %}
PPT_AUTO_GENERATION_ENABLED=false已停用自動補齊。
{% endif %}
</div>
</div>
</section>
<section class="ppt-grid">
<div class="ppt-stack">
<article class="ppt-table-shell">
@@ -245,7 +138,17 @@
<td class="text-end">{{ "%.2f"|format(r.confidence) }}</td>
<td class="text-end">{{ r.duration_ms }}</td>
<td><small class="text-muted">{{ (r.error_msg or '')[:80] }}</small></td>
<td>{% if r.audit_status in ('failed','error') %}<button class="btn btn-sm btn-outline-warning" onclick="triggerAiderHeal({{ r.pptx_filename|tojson }}, {{ (r.error_msg or '')|tojson }})"><i class="fas fa-wrench me-1"></i>AiderHeal</button>{% endif %}</td>
<td>
{% if r.audit_status in ('failed','error') %}
<button class="btn btn-sm btn-outline-warning"
type="button"
data-ppt-aider-heal
data-ppt-filename="{{ r.pptx_filename }}"
data-ppt-error="{{ r.error_msg or '' }}">
<i class="fas fa-wrench me-1"></i>AiderHeal
</button>
{% endif %}
</td>
</tr>
{% else %}
<tr><td colspan="8" class="text-center text-muted">目前無 daily 審核歷史;請確認 {{ report_month }} 是否已完成 22:00 排程。</td></tr>