Complete dashboard demo QA and localization
Browse files- index.html +254 -37
index.html
CHANGED
|
@@ -184,6 +184,15 @@
|
|
| 184 |
margin-top: 3px;
|
| 185 |
}
|
| 186 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 187 |
.sample-btn:hover {
|
| 188 |
border-color: var(--accent);
|
| 189 |
color: var(--accent);
|
|
@@ -220,6 +229,7 @@
|
|
| 220 |
}
|
| 221 |
.btn-main:hover { transform: translateY(-2px); box-shadow: 0 8px 25px var(--accent-glow); filter: brightness(1.1); }
|
| 222 |
.btn-main:active { transform: translateY(0); }
|
|
|
|
| 223 |
|
| 224 |
.meta-item { background: rgba(255, 255, 255, 0.02); padding: 14px; border-radius: 10px; border: 1px solid var(--border); }
|
| 225 |
.meta-val { font-size: 14px; font-weight: 700; color: var(--accent); margin-top: 6px; font-family: 'JetBrains Mono'; }
|
|
@@ -402,7 +412,7 @@
|
|
| 402 |
<a href="https://github.com/aclascollege/aegis-graph" target="_blank" style="font-size: 10px; color: var(--accent); text-decoration: none; margin-top: 12px; display: inline-block; font-weight: 700; letter-spacing: 0.5px;">PROTOCOL SOURCE ↗</a>
|
| 403 |
</div>
|
| 404 |
</div>
|
| 405 |
-
<div class="bento"><p class="label" data-i18n="label_hub">Evidence Processing</p><div class="center-hub" style="height: 100%;"><div class="drop-zone" id="drop-zone"><div style="font-size: 32px; color: var(--accent); margin-bottom: 12px;">✧</div><p style="font-size: 15px; font-weight: 700; font-family: 'Outfit'; letter-spacing: 1px;" data-i18n="drop_text">INGEST CREDENTIAL</p><p style="font-size: 10px; color: var(--dim); margin-top: 4px;">PDF, JPG, PNG SUPPORTED</p><p style="font-size: 9px; color: #ffcc66; margin-top: 8px; max-width: 260px; line-height: 1.4;">DEMO MODE: local preview only. Final credential verification requires a server-signed audit.</p><input type="file" id="f-input" accept=".pdf,image/png,image/jpeg" style="display: none"></div><div class="sample-grid"><button class="sample-btn" data-sample="aclas_alumni_2025.png">VERIFIED<span>ACLAS</span></button><button class="sample-btn" data-sample="fake_degree_sample.png">FRAUD<span>Pacific Western</span></button><button class="sample-btn" data-sample="graham_university_transcript.pdf">BLACKLIST<span>Graham</span></button></div></div></div>
|
| 406 |
<div class="bento" style="grid-row: span 2;"><p class="label" data-i18n="label_telemetry">Live Telemetry</p><div class="terminal" id="console"><div>[SYSTEM] Sovereign Node Active. Waiting for ingestion...</div></div></div>
|
| 407 |
<div class="bento">
|
| 408 |
<p class="label" data-i18n="label_metadata">Sovereign Analytics</p>
|
|
@@ -416,19 +426,215 @@
|
|
| 416 |
|
| 417 |
<script>
|
| 418 |
const i18n = {
|
| 419 |
-
en: { btn_audit: "START AUDIT", label_agents: "System Agents", agent_v: "Vision Forensics", agent_g: "Graph Navigator", agent_l: "Logic Auditor", label_node_title: "Institutional Node", label_hub: "Evidence Processing", drop_text: "Ingest Credential", label_telemetry: "Live Telemetry", label_metadata: "Metadata Analytics", meta_issuer: "Issuer", meta_status: "Status", verdict_ok: "SERVER AUDIT REQUIRED", verdict_no: "AUDIT REJECTED" },
|
| 420 |
-
cn: { btn_audit: "开始审计", label_agents: "系统代理", agent_v: "视觉法证", agent_g: "图谱导航", agent_l: "逻辑审计", label_node_title: "主权节点", label_hub: "证据处理中心", drop_text: "载入凭证", label_telemetry: "实时遥测", label_metadata: "元数据分析", meta_issuer: "签发机构", meta_status: "状态", verdict_ok: "需要服务端审计", verdict_no: "审计拒绝" },
|
| 421 |
-
es: { btn_audit: "INICIAR AUDITORÍA", label_agents: "Agentes de Sistema", agent_v: "Forense Visual", agent_g: "Navegador de Grafos", agent_l: "Auditor Lógico", label_node_title: "Nodo Institucional", label_hub: "Procesamiento", drop_text: "Ingresar Credencial", label_telemetry: "Telemetría", label_metadata: "Metadatos", meta_issuer: "Emisor", meta_status: "Estado", verdict_ok: "AUDITORÍA REQUERIDA", verdict_no: "RECHAZADO" },
|
| 422 |
-
fr: { btn_audit: "LANCER L'AUDIT", label_agents: "Agents Système", agent_v: "Forensique Visuelle", agent_g: "Navigateur", agent_l: "Auditeur Logique", label_node_title: "Nœud Institutionnel", label_hub: "Traitement", drop_text: "Ingérer", label_telemetry: "Télémétrie", label_metadata: "Métadonnées", meta_issuer: "Émetteur", meta_status: "Statut", verdict_ok: "AUDIT REQUIS", verdict_no: "REJETÉ" },
|
| 423 |
-
de: { btn_audit: "AUDIT STARTEN", label_agents: "System-Agenten", agent_v: "Visuelle Forensik", agent_g: "Graph-Navigator", agent_l: "Logik-Auditor", label_node_title: "Institutioneller Knoten", label_hub: "Verarbeitung", drop_text: "Nachweis Einreichen", label_telemetry: "Telemetrie", label_metadata: "Metadaten", meta_issuer: "Aussteller", meta_status: "Status", verdict_ok: "SERVER-AUDIT ERFORDERLICH", verdict_no: "ABGELEHNT" },
|
| 424 |
-
jp: { btn_audit: "監査開始", label_agents: "システムエージェント", agent_v: "視覚法医学", agent_g: "グラフナビ", agent_l: "ロジック監査", label_node_title: "機関ノード", label_hub: "証拠処理", drop_text: "資格情報を入れる", label_telemetry: "テレメトリ", label_metadata: "メタデータ", meta_issuer: "発行者", meta_status: "ステータス", verdict_ok: "サーバー監査が必要", verdict_no: "拒否" },
|
| 425 |
-
kr: { btn_audit: "감사 시작", label_agents: "시스템 에이전트", agent_v: "시각적 법의학", agent_g: "그래프 탐색", agent_l: "논리 감사", label_node_title: "기관 노드", label_hub: "증거 처리", drop_text: "자격 증명 제출", label_telemetry: "원격 측정", label_metadata: "메타데이터", meta_issuer: "발행자", meta_status: "상태", verdict_ok: "서버 감사 필요", verdict_no: "거부" },
|
| 426 |
-
pt: { btn_audit: "INICIAR AUDITORIA", label_agents: "Agentes de Sistema", agent_v: "Forense Visual", agent_g: "Navegador", agent_l: "Auditor Lógico", label_node_title: "Nó Institucional", label_hub: "Processamento", drop_text: "Inserir Credencial", label_telemetry: "Telemetria", label_metadata: "Metadados", meta_issuer: "Emissor", meta_status: "Estado", verdict_ok: "AUDITORIA REQUERIDA", verdict_no: "REJEITADO" }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 427 |
};
|
| 428 |
|
| 429 |
const dropdown = document.getElementById('lang-dropdown');
|
| 430 |
const langCurrent = document.getElementById('lang-current');
|
| 431 |
let currentLang = 'en';
|
|
|
|
| 432 |
|
| 433 |
dropdown.onclick = (e) => {
|
| 434 |
dropdown.classList.toggle('open');
|
|
@@ -445,6 +651,7 @@
|
|
| 445 |
document.querySelectorAll('.dropdown-option').forEach(opt => {
|
| 446 |
opt.onclick = (e) => {
|
| 447 |
currentLang = opt.getAttribute('data-value');
|
|
|
|
| 448 |
langCurrent.replaceChildren();
|
| 449 |
langCurrent.appendChild(document.createTextNode(`${opt.innerText} `));
|
| 450 |
const arrow = document.createElement('span');
|
|
@@ -455,6 +662,9 @@
|
|
| 455 |
const key = el.getAttribute('data-i18n');
|
| 456 |
if(i18n[currentLang][key]) el.innerText = i18n[currentLang][key];
|
| 457 |
});
|
|
|
|
|
|
|
|
|
|
| 458 |
e.stopPropagation();
|
| 459 |
dropdown.classList.remove('open');
|
| 460 |
};
|
|
@@ -464,6 +674,10 @@
|
|
| 464 |
const cons = document.getElementById('console');
|
| 465 |
let file = null;
|
| 466 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 467 |
function log(msg) {
|
| 468 |
const d = document.createElement('div');
|
| 469 |
const prompt = document.createElement('span');
|
|
@@ -485,9 +699,9 @@
|
|
| 485 |
function resetRunState() {
|
| 486 |
btn.disabled = false;
|
| 487 |
btn.innerText = i18n[currentLang].btn_audit;
|
| 488 |
-
setAgent('v', '
|
| 489 |
-
setAgent('g', '
|
| 490 |
-
setAgent('l', '
|
| 491 |
document.getElementById('modal').style.display = 'none';
|
| 492 |
}
|
| 493 |
|
|
@@ -516,7 +730,7 @@
|
|
| 516 |
document.getElementById('f-input').onchange = (e) => {
|
| 517 |
if(e.target.files.length) {
|
| 518 |
file = e.target.files[0];
|
| 519 |
-
showSelectedFile(file.name, '
|
| 520 |
log(`INGESTED: ${file.name}`);
|
| 521 |
}
|
| 522 |
};
|
|
@@ -526,7 +740,7 @@
|
|
| 526 |
resetRunState();
|
| 527 |
const mimeType = sampleName.endsWith('.pdf') ? 'application/pdf' : 'image/png';
|
| 528 |
file = { name: sampleName, type: mimeType, demoSample: true };
|
| 529 |
-
showSelectedFile(sampleName, '
|
| 530 |
log(`SAMPLE LOADED: ${sampleName}`);
|
| 531 |
setTimeout(() => btn.click(), 80);
|
| 532 |
}
|
|
@@ -540,35 +754,36 @@
|
|
| 540 |
});
|
| 541 |
|
| 542 |
btn.onclick = async () => {
|
|
|
|
| 543 |
if(!file) {
|
| 544 |
-
log(
|
| 545 |
document.getElementById('drop-zone').style.borderColor = '#ffcc66';
|
| 546 |
return;
|
| 547 |
}
|
| 548 |
btn.disabled = true;
|
| 549 |
-
btn.innerText = '
|
| 550 |
-
setAgent('v', '
|
| 551 |
-
setAgent('g', '
|
| 552 |
-
setAgent('l', '
|
| 553 |
-
log(
|
| 554 |
|
| 555 |
// Vision Agent
|
| 556 |
-
setAgent('v', '
|
| 557 |
-
log(
|
| 558 |
await new Promise(r => setTimeout(r, 800));
|
| 559 |
-
setAgent('v', '
|
| 560 |
|
| 561 |
// Graph Agent
|
| 562 |
-
setAgent('g', '
|
| 563 |
-
log(
|
| 564 |
await new Promise(r => setTimeout(r, 1500)); // Simulating a deeper search
|
| 565 |
-
setAgent('g', '
|
| 566 |
|
| 567 |
// Logic Agent
|
| 568 |
-
setAgent('l', '
|
| 569 |
-
log(
|
| 570 |
await new Promise(r => setTimeout(r, 800));
|
| 571 |
-
setAgent('l', '
|
| 572 |
|
| 573 |
await finish();
|
| 574 |
};
|
|
@@ -596,7 +811,7 @@
|
|
| 596 |
|
| 597 |
async function finish() {
|
| 598 |
let verdict = 'NEEDS_REVIEW';
|
| 599 |
-
let reason = '
|
| 600 |
let status_code = 'DEMO_ONLY';
|
| 601 |
let issuer = 'UNVERIFIED';
|
| 602 |
let ror_id = '--';
|
|
@@ -607,7 +822,7 @@
|
|
| 607 |
if (!fileTypeKnown) {
|
| 608 |
verdict = 'REJECTED';
|
| 609 |
status_code = 'UNSUPPORTED_TYPE';
|
| 610 |
-
reason = '
|
| 611 |
log('SYSTEM: REJECTED - Unsupported file type for audit intake.');
|
| 612 |
} else if (inferDemoOutcome(file)) {
|
| 613 |
const fixture = inferDemoOutcome(file);
|
|
@@ -615,12 +830,12 @@
|
|
| 615 |
if (fixture.verdict === 'REJECTED') {
|
| 616 |
verdict = 'REJECTED';
|
| 617 |
status_code = 'DEMO_BLACKLIST_MATCH';
|
| 618 |
-
reason =
|
| 619 |
log(`SYSTEM: DEMO REJECTED - ${fixture.issuer} matched the local demo blacklist fixture.`);
|
| 620 |
} else {
|
| 621 |
verdict = 'APPROVED';
|
| 622 |
status_code = 'DEMO_VERIFIED';
|
| 623 |
-
reason =
|
| 624 |
log(`SYSTEM: DEMO VERIFIED - ${fixture.issuer} matched the local verified fixture.`);
|
| 625 |
}
|
| 626 |
} else {
|
|
@@ -631,11 +846,13 @@
|
|
| 631 |
const modal = document.getElementById('modal');
|
| 632 |
modal.style.display = 'flex';
|
| 633 |
const t = i18n[currentLang];
|
|
|
|
|
|
|
| 634 |
|
| 635 |
document.getElementById('m-issuer').innerText = issuer;
|
| 636 |
document.getElementById('m-status').innerText = status_code;
|
| 637 |
|
| 638 |
-
const verdictTitle = verdict === 'REJECTED' ? t.verdict_no : (verdict === 'APPROVED' ? '
|
| 639 |
const verdictColor = verdict === 'REJECTED' ? '#ff3366' : (verdict === 'APPROVED' ? '#00ffaa' : '#ffcc66');
|
| 640 |
|
| 641 |
const report = document.getElementById('rep-body');
|
|
@@ -667,13 +884,13 @@
|
|
| 667 |
|
| 668 |
const fraudSample = document.createElement('button');
|
| 669 |
fraudSample.className = 'btn-main';
|
| 670 |
-
fraudSample.innerText = '
|
| 671 |
fraudSample.onclick = () => runSampleAudit('fake_degree_sample.png');
|
| 672 |
sampleActions.appendChild(fraudSample);
|
| 673 |
|
| 674 |
const verifiedSample = document.createElement('button');
|
| 675 |
verifiedSample.className = 'btn-main';
|
| 676 |
-
verifiedSample.innerText = '
|
| 677 |
verifiedSample.onclick = () => runSampleAudit('aclas_alumni_2025.png');
|
| 678 |
sampleActions.appendChild(verifiedSample);
|
| 679 |
|
|
@@ -683,7 +900,7 @@
|
|
| 683 |
const done = document.createElement('button');
|
| 684 |
done.className = 'btn-main';
|
| 685 |
done.style.width = '100%';
|
| 686 |
-
done.innerText = '
|
| 687 |
done.onclick = resetRunState;
|
| 688 |
report.appendChild(done);
|
| 689 |
}
|
|
|
|
| 184 |
margin-top: 3px;
|
| 185 |
}
|
| 186 |
|
| 187 |
+
.sample-btn span:first-child {
|
| 188 |
+
color: inherit;
|
| 189 |
+
font-size: 10px;
|
| 190 |
+
font-family: 'Outfit';
|
| 191 |
+
font-weight: 800;
|
| 192 |
+
letter-spacing: 0.5px;
|
| 193 |
+
margin-top: 0;
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
.sample-btn:hover {
|
| 197 |
border-color: var(--accent);
|
| 198 |
color: var(--accent);
|
|
|
|
| 229 |
}
|
| 230 |
.btn-main:hover { transform: translateY(-2px); box-shadow: 0 8px 25px var(--accent-glow); filter: brightness(1.1); }
|
| 231 |
.btn-main:active { transform: translateY(0); }
|
| 232 |
+
.btn-main:disabled { opacity: 0.65; cursor: wait; transform: none; }
|
| 233 |
|
| 234 |
.meta-item { background: rgba(255, 255, 255, 0.02); padding: 14px; border-radius: 10px; border: 1px solid var(--border); }
|
| 235 |
.meta-val { font-size: 14px; font-weight: 700; color: var(--accent); margin-top: 6px; font-family: 'JetBrains Mono'; }
|
|
|
|
| 412 |
<a href="https://github.com/aclascollege/aegis-graph" target="_blank" style="font-size: 10px; color: var(--accent); text-decoration: none; margin-top: 12px; display: inline-block; font-weight: 700; letter-spacing: 0.5px;">PROTOCOL SOURCE ↗</a>
|
| 413 |
</div>
|
| 414 |
</div>
|
| 415 |
+
<div class="bento"><p class="label" data-i18n="label_hub">Evidence Processing</p><div class="center-hub" style="height: 100%;"><div class="drop-zone" id="drop-zone"><div style="font-size: 32px; color: var(--accent); margin-bottom: 12px;">✧</div><p style="font-size: 15px; font-weight: 700; font-family: 'Outfit'; letter-spacing: 1px;" data-i18n="drop_text">INGEST CREDENTIAL</p><p style="font-size: 10px; color: var(--dim); margin-top: 4px;" data-i18n="file_support">PDF, JPG, PNG SUPPORTED</p><p style="font-size: 9px; color: #ffcc66; margin-top: 8px; max-width: 260px; line-height: 1.4;" data-i18n="demo_disclaimer">DEMO MODE: local preview only. Final credential verification requires a server-signed audit.</p><input type="file" id="f-input" accept=".pdf,image/png,image/jpeg" style="display: none"></div><div class="sample-grid"><button class="sample-btn" data-sample="aclas_alumni_2025.png"><span data-i18n="sample_verified_main">VERIFIED</span><span data-i18n="sample_verified_sub">ACLAS</span></button><button class="sample-btn" data-sample="fake_degree_sample.png"><span data-i18n="sample_fraud_main">FRAUD</span><span data-i18n="sample_fraud_sub">Pacific Western</span></button><button class="sample-btn" data-sample="graham_university_transcript.pdf"><span data-i18n="sample_blacklist_main">BLACKLIST</span><span data-i18n="sample_blacklist_sub">Graham</span></button></div></div></div>
|
| 416 |
<div class="bento" style="grid-row: span 2;"><p class="label" data-i18n="label_telemetry">Live Telemetry</p><div class="terminal" id="console"><div>[SYSTEM] Sovereign Node Active. Waiting for ingestion...</div></div></div>
|
| 417 |
<div class="bento">
|
| 418 |
<p class="label" data-i18n="label_metadata">Sovereign Analytics</p>
|
|
|
|
| 426 |
|
| 427 |
<script>
|
| 428 |
const i18n = {
|
| 429 |
+
en: { btn_audit: "START AUDIT", label_agents: "System Agents", agent_v: "Vision Forensics", agent_g: "Graph Navigator", agent_l: "Logic Auditor", label_node_title: "Institutional Node", label_hub: "Evidence Processing", drop_text: "Ingest Credential", file_support: "PDF, JPG, PNG SUPPORTED", demo_disclaimer: "DEMO MODE: local preview only. Final credential verification requires a server-signed audit.", label_telemetry: "Live Telemetry", label_metadata: "Metadata Analytics", meta_issuer: "Issuer", meta_status: "Status", sample_verified_main: "VERIFIED", sample_verified_sub: "ACLAS", sample_fraud_main: "FRAUD", sample_fraud_sub: "Pacific Western", sample_blacklist_main: "BLACKLIST", sample_blacklist_sub: "Graham", verdict_ok: "SERVER AUDIT REQUIRED", verdict_no: "AUDIT REJECTED" },
|
| 430 |
+
cn: { btn_audit: "开始审计", label_agents: "系统代理", agent_v: "视觉法证", agent_g: "图谱导航", agent_l: "逻辑审计", label_node_title: "主权节点", label_hub: "证据处理中心", drop_text: "载入凭证", file_support: "支持 PDF、JPG、PNG", demo_disclaimer: "演示模式:仅本地预览。正式凭证验证需要服务端签名审计。", label_telemetry: "实时遥测", label_metadata: "元数据分析", meta_issuer: "签发机构", meta_status: "状态", sample_verified_main: "通过样本", sample_verified_sub: "ACLAS", sample_fraud_main: "欺诈样本", sample_fraud_sub: "Pacific Western", sample_blacklist_main: "黑名单", sample_blacklist_sub: "Graham", verdict_ok: "需要服务端审计", verdict_no: "审计拒绝" },
|
| 431 |
+
es: { btn_audit: "INICIAR AUDITORÍA", label_agents: "Agentes de Sistema", agent_v: "Forense Visual", agent_g: "Navegador de Grafos", agent_l: "Auditor Lógico", label_node_title: "Nodo Institucional", label_hub: "Procesamiento", drop_text: "Ingresar Credencial", file_support: "PDF, JPG, PNG SOPORTADOS", demo_disclaimer: "MODO DEMO: vista previa local. La verificación final requiere auditoría firmada por servidor.", label_telemetry: "Telemetría", label_metadata: "Metadatos", meta_issuer: "Emisor", meta_status: "Estado", sample_verified_main: "VÁLIDA", sample_verified_sub: "ACLAS", sample_fraud_main: "FRAUDE", sample_fraud_sub: "Pacific Western", sample_blacklist_main: "LISTA NEGRA", sample_blacklist_sub: "Graham", verdict_ok: "AUDITORÍA REQUERIDA", verdict_no: "RECHAZADO" },
|
| 432 |
+
fr: { btn_audit: "LANCER L'AUDIT", label_agents: "Agents Système", agent_v: "Forensique Visuelle", agent_g: "Navigateur", agent_l: "Auditeur Logique", label_node_title: "Nœud Institutionnel", label_hub: "Traitement", drop_text: "Ingérer", file_support: "PDF, JPG, PNG PRIS EN CHARGE", demo_disclaimer: "MODE DÉMO: aperçu local. La vérification finale exige un audit signé serveur.", label_telemetry: "Télémétrie", label_metadata: "Métadonnées", meta_issuer: "Émetteur", meta_status: "Statut", sample_verified_main: "VÉRIFIÉ", sample_verified_sub: "ACLAS", sample_fraud_main: "FRAUDE", sample_fraud_sub: "Pacific Western", sample_blacklist_main: "LISTE NOIRE", sample_blacklist_sub: "Graham", verdict_ok: "AUDIT REQUIS", verdict_no: "REJETÉ" },
|
| 433 |
+
de: { btn_audit: "AUDIT STARTEN", label_agents: "System-Agenten", agent_v: "Visuelle Forensik", agent_g: "Graph-Navigator", agent_l: "Logik-Auditor", label_node_title: "Institutioneller Knoten", label_hub: "Verarbeitung", drop_text: "Nachweis Einreichen", file_support: "PDF, JPG, PNG UNTERSTÜTZT", demo_disclaimer: "DEMO-MODUS: lokale Vorschau. Finale Verifikation erfordert serverseitig signierten Audit.", label_telemetry: "Telemetrie", label_metadata: "Metadaten", meta_issuer: "Aussteller", meta_status: "Status", sample_verified_main: "VERIFIZIERT", sample_verified_sub: "ACLAS", sample_fraud_main: "BETRUG", sample_fraud_sub: "Pacific Western", sample_blacklist_main: "BLACKLIST", sample_blacklist_sub: "Graham", verdict_ok: "SERVER-AUDIT ERFORDERLICH", verdict_no: "ABGELEHNT" },
|
| 434 |
+
jp: { btn_audit: "監査開始", label_agents: "システムエージェント", agent_v: "視覚法医学", agent_g: "グラフナビ", agent_l: "ロジック監査", label_node_title: "機関ノード", label_hub: "証拠処理", drop_text: "資格情報を入れる", file_support: "PDF、JPG、PNG対応", demo_disclaimer: "デモモード: ローカルプレビューのみ。最終検証にはサーバー署名監査が必要です。", label_telemetry: "テレメトリ", label_metadata: "メタデータ", meta_issuer: "発行者", meta_status: "ステータス", sample_verified_main: "検証済み", sample_verified_sub: "ACLAS", sample_fraud_main: "不正", sample_fraud_sub: "Pacific Western", sample_blacklist_main: "ブラックリスト", sample_blacklist_sub: "Graham", verdict_ok: "サーバー監査が必要", verdict_no: "拒否" },
|
| 435 |
+
kr: { btn_audit: "감사 시작", label_agents: "시스템 에이전트", agent_v: "시각적 법의학", agent_g: "그래프 탐색", agent_l: "논리 감사", label_node_title: "기관 노드", label_hub: "증거 처리", drop_text: "자격 증명 제출", file_support: "PDF, JPG, PNG 지원", demo_disclaimer: "데모 모드: 로컬 미리보기 전용. 최종 검증에는 서버 서명 감사가 필요합니다.", label_telemetry: "원격 측정", label_metadata: "메타데이터", meta_issuer: "발행자", meta_status: "상태", sample_verified_main: "검증됨", sample_verified_sub: "ACLAS", sample_fraud_main: "사기", sample_fraud_sub: "Pacific Western", sample_blacklist_main: "블랙리스트", sample_blacklist_sub: "Graham", verdict_ok: "서버 감사 필요", verdict_no: "거부" },
|
| 436 |
+
pt: { btn_audit: "INICIAR AUDITORIA", label_agents: "Agentes de Sistema", agent_v: "Forense Visual", agent_g: "Navegador", agent_l: "Auditor Lógico", label_node_title: "Nó Institucional", label_hub: "Processamento", drop_text: "Inserir Credencial", file_support: "PDF, JPG, PNG SUPORTADOS", demo_disclaimer: "MODO DEMO: prévia local. A verificação final requer auditoria assinada pelo servidor.", label_telemetry: "Telemetria", label_metadata: "Metadados", meta_issuer: "Emissor", meta_status: "Estado", sample_verified_main: "VERIFICADO", sample_verified_sub: "ACLAS", sample_fraud_main: "FRAUDE", sample_fraud_sub: "Pacific Western", sample_blacklist_main: "LISTA NEGRA", sample_blacklist_sub: "Graham", verdict_ok: "AUDITORIA REQUERIDA", verdict_no: "REJEITADO" }
|
| 437 |
+
};
|
| 438 |
+
|
| 439 |
+
const extraText = {
|
| 440 |
+
en: {
|
| 441 |
+
auditing: "AUDITING...",
|
| 442 |
+
idle: "IDLE",
|
| 443 |
+
scanning: "SCANNING",
|
| 444 |
+
resolving: "RESOLVING",
|
| 445 |
+
done: "DONE",
|
| 446 |
+
logicAuditing: "AUDITING",
|
| 447 |
+
needsReview: "NEEDS REVIEW",
|
| 448 |
+
demoVerified: "DEMO VERIFIED",
|
| 449 |
+
runAnother: "RUN ANOTHER AUDIT",
|
| 450 |
+
runFraud: "RUN FRAUD SAMPLE",
|
| 451 |
+
runVerified: "RUN VERIFIED SAMPLE",
|
| 452 |
+
uploadNote: "Demo intake only; no browser-side approval will be issued.",
|
| 453 |
+
sampleNote: "Built-in demo fixture selected.",
|
| 454 |
+
noFile: "SYSTEM: Select a PDF, PNG, or JPEG credential before starting the demo audit.",
|
| 455 |
+
init: "INIT: Preparing local demo intake...",
|
| 456 |
+
vision: "VISION: Demo animation only; document bytes are not authenticated in-browser...",
|
| 457 |
+
graph: "GRAPH: Resolving institution evidence in local demo mode...",
|
| 458 |
+
logic: "LOGIC: Applying demo policy rules...",
|
| 459 |
+
unsupported: "Unsupported file type. Upload a PDF, PNG, or JPEG credential for a production server-side audit.",
|
| 460 |
+
unknownReason: "This uploaded file is accepted by the demo intake, but this static browser page cannot read document contents or issue credential approval. Use the built-in samples to demonstrate verified and rejected outcomes, or connect a server-side audit API for real files.",
|
| 461 |
+
rejectedReason: issuer => `${issuer} matches the public demo blacklist fixture. This is a browser-side demo result only; production rejection still requires a server-signed audit trail.`,
|
| 462 |
+
verifiedReason: issuer => `${issuer} matches the built-in verified demo fixture. This browser-side status is only a UI demonstration, not a production credential approval.`
|
| 463 |
+
},
|
| 464 |
+
cn: {
|
| 465 |
+
auditing: "审计中...",
|
| 466 |
+
idle: "待命",
|
| 467 |
+
scanning: "扫描中",
|
| 468 |
+
resolving: "解析中",
|
| 469 |
+
done: "完成",
|
| 470 |
+
logicAuditing: "审计中",
|
| 471 |
+
needsReview: "需要复核",
|
| 472 |
+
demoVerified: "演示验证通过",
|
| 473 |
+
runAnother: "继续测试",
|
| 474 |
+
runFraud: "运行欺诈样本",
|
| 475 |
+
runVerified: "运行通过样本",
|
| 476 |
+
uploadNote: "仅演示载入;浏览器端不会签发审核结论。",
|
| 477 |
+
sampleNote: "已选择内置演示样本。",
|
| 478 |
+
noFile: "系统:请先选择 PDF、PNG 或 JPEG 凭证。",
|
| 479 |
+
init: "初始化:准备本地演示审计...",
|
| 480 |
+
vision: "视觉:浏览器演示不会认证文件字节...",
|
| 481 |
+
graph: "图谱:正在本地演示模式解析机构证据...",
|
| 482 |
+
logic: "逻辑:正在应用演示规则...",
|
| 483 |
+
unsupported: "文件类型不支持。请上传 PDF、PNG 或 JPEG。",
|
| 484 |
+
unknownReason: "该文件已进入演示流程,但静态网页无法读取文件内容或签发凭证结论。请使用内置样本演示通过/拒绝结果,或接入服务端审计 API 处理真实文件。",
|
| 485 |
+
rejectedReason: issuer => `${issuer} 命中公开演示黑名单样本。该结果仅为浏览器端演示;正式拒绝仍需要服务端签名审计轨迹。`,
|
| 486 |
+
verifiedReason: issuer => `${issuer} 命中内置通过样本。该状态仅为界面演示,不代表正式凭证批准。`
|
| 487 |
+
},
|
| 488 |
+
es: {
|
| 489 |
+
auditing: "AUDITANDO...",
|
| 490 |
+
idle: "INACTIVO",
|
| 491 |
+
scanning: "ESCANEANDO",
|
| 492 |
+
resolving: "RESOLVIENDO",
|
| 493 |
+
done: "LISTO",
|
| 494 |
+
logicAuditing: "AUDITANDO",
|
| 495 |
+
needsReview: "REVISIÓN NECESARIA",
|
| 496 |
+
demoVerified: "DEMO VERIFICADA",
|
| 497 |
+
runAnother: "EJECUTAR OTRA AUDITORÍA",
|
| 498 |
+
runFraud: "EJECUTAR MUESTRA FRAUDE",
|
| 499 |
+
runVerified: "EJECUTAR MUESTRA VÁLIDA",
|
| 500 |
+
uploadNote: "Solo entrada demo; no se emite aprobación en el navegador.",
|
| 501 |
+
sampleNote: "Muestra demo integrada seleccionada.",
|
| 502 |
+
noFile: "SISTEMA: Seleccione PDF, PNG o JPEG antes de iniciar.",
|
| 503 |
+
init: "INIT: Preparando auditoría demo local...",
|
| 504 |
+
vision: "VISIÓN: La demo no autentica bytes del documento en navegador...",
|
| 505 |
+
graph: "GRAFO: Resolviendo evidencia institucional en modo demo...",
|
| 506 |
+
logic: "LÓGICA: Aplicando reglas demo...",
|
| 507 |
+
unsupported: "Tipo de archivo no compatible. Suba PDF, PNG o JPEG.",
|
| 508 |
+
unknownReason: "El archivo fue aceptado por la demo, pero esta página estática no puede leer contenidos ni emitir aprobación. Use las muestras integradas o conecte una API de auditoría.",
|
| 509 |
+
rejectedReason: issuer => `${issuer} coincide con la lista negra demo. Es solo un resultado de navegador; producción requiere auditoría firmada por servidor.`,
|
| 510 |
+
verifiedReason: issuer => `${issuer} coincide con la muestra verificada demo. Es solo demostración de UI, no aprobación real.`
|
| 511 |
+
},
|
| 512 |
+
fr: {
|
| 513 |
+
auditing: "AUDIT EN COURS...",
|
| 514 |
+
idle: "INACTIF",
|
| 515 |
+
scanning: "ANALYSE",
|
| 516 |
+
resolving: "RÉSOLUTION",
|
| 517 |
+
done: "TERMINÉ",
|
| 518 |
+
logicAuditing: "AUDIT",
|
| 519 |
+
needsReview: "REVUE REQUISE",
|
| 520 |
+
demoVerified: "DÉMO VÉRIFIÉE",
|
| 521 |
+
runAnother: "RELANCER UN AUDIT",
|
| 522 |
+
runFraud: "LANCER ÉCHANTILLON FRAUDE",
|
| 523 |
+
runVerified: "LANCER ÉCHANTILLON VALIDE",
|
| 524 |
+
uploadNote: "Entrée de démonstration uniquement; aucune approbation navigateur.",
|
| 525 |
+
sampleNote: "Échantillon démo intégré sélectionné.",
|
| 526 |
+
noFile: "SYSTÈME: Sélectionnez un PDF, PNG ou JPEG avant l'audit.",
|
| 527 |
+
init: "INIT: Préparation de l'audit démo local...",
|
| 528 |
+
vision: "VISION: La démo n'authentifie pas les octets du document...",
|
| 529 |
+
graph: "GRAPHE: Résolution des preuves institutionnelles en mode démo...",
|
| 530 |
+
logic: "LOGIQUE: Application des règles de démonstration...",
|
| 531 |
+
unsupported: "Type de fichier non pris en charge. Chargez un PDF, PNG ou JPEG.",
|
| 532 |
+
unknownReason: "Le fichier est accepté par la démo, mais cette page statique ne peut pas lire le contenu ni approuver un diplôme. Utilisez les exemples intégrés ou connectez une API serveur.",
|
| 533 |
+
rejectedReason: issuer => `${issuer} correspond à la liste noire de démonstration. Résultat navigateur uniquement; la production exige un audit signé serveur.`,
|
| 534 |
+
verifiedReason: issuer => `${issuer} correspond à l'exemple vérifié intégré. C'est une démonstration UI, pas une approbation réelle.`
|
| 535 |
+
},
|
| 536 |
+
de: {
|
| 537 |
+
auditing: "AUDIT LÄUFT...",
|
| 538 |
+
idle: "BEREIT",
|
| 539 |
+
scanning: "SCANNT",
|
| 540 |
+
resolving: "PRÜFT",
|
| 541 |
+
done: "FERTIG",
|
| 542 |
+
logicAuditing: "AUDIT",
|
| 543 |
+
needsReview: "PRÜFUNG NÖTIG",
|
| 544 |
+
demoVerified: "DEMO VERIFIZIERT",
|
| 545 |
+
runAnother: "WEITEREN AUDIT STARTEN",
|
| 546 |
+
runFraud: "BETRUGSBEISPIEL",
|
| 547 |
+
runVerified: "VERIFIZIERTES BEISPIEL",
|
| 548 |
+
uploadNote: "Nur Demo-Eingabe; keine Browser-Freigabe.",
|
| 549 |
+
sampleNote: "Integriertes Demo-Beispiel ausgewählt.",
|
| 550 |
+
noFile: "SYSTEM: Bitte PDF, PNG oder JPEG auswählen.",
|
| 551 |
+
init: "INIT: Lokalen Demo-Audit vorbereiten...",
|
| 552 |
+
vision: "VISION: Browser-Demo authentifiziert keine Dokumentbytes...",
|
| 553 |
+
graph: "GRAPH: Institutionelle Evidenz im Demo-Modus wird geprüft...",
|
| 554 |
+
logic: "LOGIK: Demo-Regeln werden angewendet...",
|
| 555 |
+
unsupported: "Nicht unterstützter Dateityp. PDF, PNG oder JPEG hochladen.",
|
| 556 |
+
unknownReason: "Die Datei wurde angenommen, aber diese statische Seite kann Inhalte nicht lesen oder genehmigen. Nutzen Sie die Beispiele oder verbinden Sie eine Server-API.",
|
| 557 |
+
rejectedReason: issuer => `${issuer} passt zum Demo-Blacklist-Beispiel. Nur Browser-Demo; Produktion braucht serverseitig signierten Audit.`,
|
| 558 |
+
verifiedReason: issuer => `${issuer} passt zum verifizierten Demo-Beispiel. Das ist UI-Demo, keine echte Freigabe.`
|
| 559 |
+
},
|
| 560 |
+
jp: {
|
| 561 |
+
auditing: "監査中...",
|
| 562 |
+
idle: "待機",
|
| 563 |
+
scanning: "解析中",
|
| 564 |
+
resolving: "照合中",
|
| 565 |
+
done: "完了",
|
| 566 |
+
logicAuditing: "監査中",
|
| 567 |
+
needsReview: "レビュー必要",
|
| 568 |
+
demoVerified: "デモ検証済み",
|
| 569 |
+
runAnother: "別の監査を実行",
|
| 570 |
+
runFraud: "不正サンプル実行",
|
| 571 |
+
runVerified: "検証サンプル実行",
|
| 572 |
+
uploadNote: "デモ取込のみ。ブラウザでは承認しません。",
|
| 573 |
+
sampleNote: "内蔵デモサンプルを選択しました。",
|
| 574 |
+
noFile: "システム: PDF、PNG、JPEGを選択してください。",
|
| 575 |
+
init: "INIT: ローカルデモ監査を準備中...",
|
| 576 |
+
vision: "VISION: ブラウザデモでは文書バイトを認証しません...",
|
| 577 |
+
graph: "GRAPH: デモモードで機関証拠を照合中...",
|
| 578 |
+
logic: "LOGIC: デモルールを適用中...",
|
| 579 |
+
unsupported: "非対応ファイルです。PDF、PNG、JPEGをアップロードしてください。",
|
| 580 |
+
unknownReason: "ファイルはデモに受理されましたが、静的ページでは内容読取や承認はできません。内蔵サンプルを使うか、サーバーAPIを接続してください。",
|
| 581 |
+
rejectedReason: issuer => `${issuer} はデモ用ブラックリストに一致しました。これはブラウザデモであり、本番拒否には署名済み監査が必要です。`,
|
| 582 |
+
verifiedReason: issuer => `${issuer} は検証済みデモサンプルに一致しました。これはUIデモであり正式承認ではありません。`
|
| 583 |
+
},
|
| 584 |
+
kr: {
|
| 585 |
+
auditing: "감사 중...",
|
| 586 |
+
idle: "대기",
|
| 587 |
+
scanning: "스캔 중",
|
| 588 |
+
resolving: "확인 중",
|
| 589 |
+
done: "완료",
|
| 590 |
+
logicAuditing: "감사 중",
|
| 591 |
+
needsReview: "검토 필요",
|
| 592 |
+
demoVerified: "데모 검증됨",
|
| 593 |
+
runAnother: "다른 감사 실행",
|
| 594 |
+
runFraud: "사기 샘플 실행",
|
| 595 |
+
runVerified: "검증 샘플 실행",
|
| 596 |
+
uploadNote: "데모 입력 전용이며 브라우저 승인은 발급되지 않습니다.",
|
| 597 |
+
sampleNote: "내장 데모 샘플이 선택되었습니다.",
|
| 598 |
+
noFile: "시스템: PDF, PNG 또는 JPEG를 먼저 선택하세요.",
|
| 599 |
+
init: "INIT: 로컬 데모 감사를 준비 중...",
|
| 600 |
+
vision: "VISION: 브라우저 데모는 문서 바이트를 인증하지 않습니다...",
|
| 601 |
+
graph: "GRAPH: 데모 모드에서 기관 증거를 확인 중...",
|
| 602 |
+
logic: "LOGIC: 데모 정책 규칙 적용 중...",
|
| 603 |
+
unsupported: "지원하지 않는 파일 형식입니다. PDF, PNG 또는 JPEG를 업로드하세요.",
|
| 604 |
+
unknownReason: "파일은 데모 입력으로 허용되었지만 정적 페이지는 내용을 읽거나 승인할 수 없습니다. 내장 샘플을 사용하거나 서버 감사 API를 연결하세요.",
|
| 605 |
+
rejectedReason: issuer => `${issuer} 이 데모 블랙리스트 샘플과 일치합니다. 브라우저 데모 결과이며 실제 거부에는 서버 서명 감사가 필요합니다.`,
|
| 606 |
+
verifiedReason: issuer => `${issuer} 이 내장 검증 샘플과 일치합니다. UI 데모일 뿐 실제 승인이 아닙니다.`
|
| 607 |
+
},
|
| 608 |
+
pt: {
|
| 609 |
+
auditing: "AUDITANDO...",
|
| 610 |
+
idle: "OCIOSO",
|
| 611 |
+
scanning: "ESCANEANDO",
|
| 612 |
+
resolving: "RESOLVENDO",
|
| 613 |
+
done: "CONCLUÍDO",
|
| 614 |
+
logicAuditing: "AUDITANDO",
|
| 615 |
+
needsReview: "REVISÃO NECESSÁRIA",
|
| 616 |
+
demoVerified: "DEMO VERIFICADA",
|
| 617 |
+
runAnother: "EXECUTAR OUTRA AUDITORIA",
|
| 618 |
+
runFraud: "EXECUTAR AMOSTRA FRAUDE",
|
| 619 |
+
runVerified: "EXECUTAR AMOSTRA VÁLIDA",
|
| 620 |
+
uploadNote: "Entrada de demo; nenhuma aprovação no navegador.",
|
| 621 |
+
sampleNote: "Amostra demo integrada selecionada.",
|
| 622 |
+
noFile: "SISTEMA: selecione PDF, PNG ou JPEG antes de iniciar.",
|
| 623 |
+
init: "INIT: Preparando auditoria demo local...",
|
| 624 |
+
vision: "VISÃO: a demo não autentica bytes do documento no navegador...",
|
| 625 |
+
graph: "GRAFO: resolvendo evidências institucionais em modo demo...",
|
| 626 |
+
logic: "LÓGICA: aplicando regras de demo...",
|
| 627 |
+
unsupported: "Tipo de arquivo não suportado. Envie PDF, PNG ou JPEG.",
|
| 628 |
+
unknownReason: "O arquivo foi aceito pela demo, mas esta página estática não lê conteúdo nem emite aprovação. Use as amostras integradas ou conecte uma API de auditoria.",
|
| 629 |
+
rejectedReason: issuer => `${issuer} corresponde à lista negra de demonstração. É apenas resultado no navegador; produção exige auditoria assinada pelo servidor.`,
|
| 630 |
+
verifiedReason: issuer => `${issuer} corresponde à amostra verificada integrada. É demonstração de UI, não aprovação real.`
|
| 631 |
+
}
|
| 632 |
};
|
| 633 |
|
| 634 |
const dropdown = document.getElementById('lang-dropdown');
|
| 635 |
const langCurrent = document.getElementById('lang-current');
|
| 636 |
let currentLang = 'en';
|
| 637 |
+
const htmlLangMap = { en: 'en', cn: 'zh-CN', es: 'es', fr: 'fr', de: 'de', jp: 'ja', kr: 'ko', pt: 'pt' };
|
| 638 |
|
| 639 |
dropdown.onclick = (e) => {
|
| 640 |
dropdown.classList.toggle('open');
|
|
|
|
| 651 |
document.querySelectorAll('.dropdown-option').forEach(opt => {
|
| 652 |
opt.onclick = (e) => {
|
| 653 |
currentLang = opt.getAttribute('data-value');
|
| 654 |
+
document.documentElement.lang = htmlLangMap[currentLang] || 'en';
|
| 655 |
langCurrent.replaceChildren();
|
| 656 |
langCurrent.appendChild(document.createTextNode(`${opt.innerText} `));
|
| 657 |
const arrow = document.createElement('span');
|
|
|
|
| 662 |
const key = el.getAttribute('data-i18n');
|
| 663 |
if(i18n[currentLang][key]) el.innerText = i18n[currentLang][key];
|
| 664 |
});
|
| 665 |
+
if (!btn.disabled && document.getElementById('modal').style.display !== 'flex') {
|
| 666 |
+
resetRunState();
|
| 667 |
+
}
|
| 668 |
e.stopPropagation();
|
| 669 |
dropdown.classList.remove('open');
|
| 670 |
};
|
|
|
|
| 674 |
const cons = document.getElementById('console');
|
| 675 |
let file = null;
|
| 676 |
|
| 677 |
+
function tx(key) {
|
| 678 |
+
return (extraText[currentLang] && extraText[currentLang][key]) || extraText.en[key];
|
| 679 |
+
}
|
| 680 |
+
|
| 681 |
function log(msg) {
|
| 682 |
const d = document.createElement('div');
|
| 683 |
const prompt = document.createElement('span');
|
|
|
|
| 699 |
function resetRunState() {
|
| 700 |
btn.disabled = false;
|
| 701 |
btn.innerText = i18n[currentLang].btn_audit;
|
| 702 |
+
setAgent('v', tx('idle'), '0%', 'var(--dim)');
|
| 703 |
+
setAgent('g', tx('idle'), '0%', 'var(--dim)');
|
| 704 |
+
setAgent('l', tx('idle'), '0%', 'var(--dim)');
|
| 705 |
document.getElementById('modal').style.display = 'none';
|
| 706 |
}
|
| 707 |
|
|
|
|
| 730 |
document.getElementById('f-input').onchange = (e) => {
|
| 731 |
if(e.target.files.length) {
|
| 732 |
file = e.target.files[0];
|
| 733 |
+
showSelectedFile(file.name, tx('uploadNote'));
|
| 734 |
log(`INGESTED: ${file.name}`);
|
| 735 |
}
|
| 736 |
};
|
|
|
|
| 740 |
resetRunState();
|
| 741 |
const mimeType = sampleName.endsWith('.pdf') ? 'application/pdf' : 'image/png';
|
| 742 |
file = { name: sampleName, type: mimeType, demoSample: true };
|
| 743 |
+
showSelectedFile(sampleName, tx('sampleNote'));
|
| 744 |
log(`SAMPLE LOADED: ${sampleName}`);
|
| 745 |
setTimeout(() => btn.click(), 80);
|
| 746 |
}
|
|
|
|
| 754 |
});
|
| 755 |
|
| 756 |
btn.onclick = async () => {
|
| 757 |
+
if (document.getElementById('modal').style.display === 'flex') return;
|
| 758 |
if(!file) {
|
| 759 |
+
log(tx('noFile'));
|
| 760 |
document.getElementById('drop-zone').style.borderColor = '#ffcc66';
|
| 761 |
return;
|
| 762 |
}
|
| 763 |
btn.disabled = true;
|
| 764 |
+
btn.innerText = tx('auditing');
|
| 765 |
+
setAgent('v', tx('idle'), '0%', 'var(--dim)');
|
| 766 |
+
setAgent('g', tx('idle'), '0%', 'var(--dim)');
|
| 767 |
+
setAgent('l', tx('idle'), '0%', 'var(--dim)');
|
| 768 |
+
log(tx('init'));
|
| 769 |
|
| 770 |
// Vision Agent
|
| 771 |
+
setAgent('v', tx('scanning'), '100%');
|
| 772 |
+
log(tx('vision'));
|
| 773 |
await new Promise(r => setTimeout(r, 800));
|
| 774 |
+
setAgent('v', tx('done'), '100%');
|
| 775 |
|
| 776 |
// Graph Agent
|
| 777 |
+
setAgent('g', tx('resolving'), '100%');
|
| 778 |
+
log(tx('graph'));
|
| 779 |
await new Promise(r => setTimeout(r, 1500)); // Simulating a deeper search
|
| 780 |
+
setAgent('g', tx('done'), '100%');
|
| 781 |
|
| 782 |
// Logic Agent
|
| 783 |
+
setAgent('l', tx('logicAuditing'), '100%');
|
| 784 |
+
log(tx('logic'));
|
| 785 |
await new Promise(r => setTimeout(r, 800));
|
| 786 |
+
setAgent('l', tx('done'), '100%');
|
| 787 |
|
| 788 |
await finish();
|
| 789 |
};
|
|
|
|
| 811 |
|
| 812 |
async function finish() {
|
| 813 |
let verdict = 'NEEDS_REVIEW';
|
| 814 |
+
let reason = tx('unknownReason');
|
| 815 |
let status_code = 'DEMO_ONLY';
|
| 816 |
let issuer = 'UNVERIFIED';
|
| 817 |
let ror_id = '--';
|
|
|
|
| 822 |
if (!fileTypeKnown) {
|
| 823 |
verdict = 'REJECTED';
|
| 824 |
status_code = 'UNSUPPORTED_TYPE';
|
| 825 |
+
reason = tx('unsupported');
|
| 826 |
log('SYSTEM: REJECTED - Unsupported file type for audit intake.');
|
| 827 |
} else if (inferDemoOutcome(file)) {
|
| 828 |
const fixture = inferDemoOutcome(file);
|
|
|
|
| 830 |
if (fixture.verdict === 'REJECTED') {
|
| 831 |
verdict = 'REJECTED';
|
| 832 |
status_code = 'DEMO_BLACKLIST_MATCH';
|
| 833 |
+
reason = tx('rejectedReason')(fixture.issuer);
|
| 834 |
log(`SYSTEM: DEMO REJECTED - ${fixture.issuer} matched the local demo blacklist fixture.`);
|
| 835 |
} else {
|
| 836 |
verdict = 'APPROVED';
|
| 837 |
status_code = 'DEMO_VERIFIED';
|
| 838 |
+
reason = tx('verifiedReason')(fixture.issuer);
|
| 839 |
log(`SYSTEM: DEMO VERIFIED - ${fixture.issuer} matched the local verified fixture.`);
|
| 840 |
}
|
| 841 |
} else {
|
|
|
|
| 846 |
const modal = document.getElementById('modal');
|
| 847 |
modal.style.display = 'flex';
|
| 848 |
const t = i18n[currentLang];
|
| 849 |
+
btn.disabled = false;
|
| 850 |
+
btn.innerText = i18n[currentLang].btn_audit;
|
| 851 |
|
| 852 |
document.getElementById('m-issuer').innerText = issuer;
|
| 853 |
document.getElementById('m-status').innerText = status_code;
|
| 854 |
|
| 855 |
+
const verdictTitle = verdict === 'REJECTED' ? t.verdict_no : (verdict === 'APPROVED' ? tx('demoVerified') : tx('needsReview'));
|
| 856 |
const verdictColor = verdict === 'REJECTED' ? '#ff3366' : (verdict === 'APPROVED' ? '#00ffaa' : '#ffcc66');
|
| 857 |
|
| 858 |
const report = document.getElementById('rep-body');
|
|
|
|
| 884 |
|
| 885 |
const fraudSample = document.createElement('button');
|
| 886 |
fraudSample.className = 'btn-main';
|
| 887 |
+
fraudSample.innerText = tx('runFraud');
|
| 888 |
fraudSample.onclick = () => runSampleAudit('fake_degree_sample.png');
|
| 889 |
sampleActions.appendChild(fraudSample);
|
| 890 |
|
| 891 |
const verifiedSample = document.createElement('button');
|
| 892 |
verifiedSample.className = 'btn-main';
|
| 893 |
+
verifiedSample.innerText = tx('runVerified');
|
| 894 |
verifiedSample.onclick = () => runSampleAudit('aclas_alumni_2025.png');
|
| 895 |
sampleActions.appendChild(verifiedSample);
|
| 896 |
|
|
|
|
| 900 |
const done = document.createElement('button');
|
| 901 |
done.className = 'btn-main';
|
| 902 |
done.style.width = '100%';
|
| 903 |
+
done.innerText = tx('runAnother');
|
| 904 |
done.onclick = resetRunState;
|
| 905 |
report.appendChild(done);
|
| 906 |
}
|