Sync cezen-portal/ from live working copy (V1.0 GA polish + search-icon ordering fix)
Brings the ISO-packaged portal copy current with the live cezen-portal/ working directory, which had drifted across the entire V1.0 GA polish initiative (Phases 1-10) plus this session's topnav icon-order bugfix. - 52 existing files updated, 2 new pages added (about.html, health.html) - cgit/cezen-portal/ is now byte-identical to cezen-portal/ - Backend files (rag_ingest.py, cezen_license.py) already in sync; main.py intentionally left as-is (cgit is ahead there with workstation-category commercial-fit logic not yet backported to the live working copy) Next: rebuild the ISO (bash autoinstall/build-iso.sh) to bake this in.
This commit is contained in:
1 parent
7540da04a8
commit
b3eec34158
57 files changed
+2832
-1354
No files matched your search
+43
-28
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>AI Evaluation Suite — Nexus One AI</title>
|
||||
<link rel="stylesheet" href="style.css?v=4">
|
||||
<link rel="stylesheet" href="style.css?v=12">
|
||||
<style>
|
||||
/* ── Layout ── */
|
||||
.ev-layout { display:grid; grid-template-columns:280px 1fr; min-height:calc(100vh - 64px); }
|
||||
@@ -28,7 +28,8 @@
|
||||
|
||||
/* ── Empty state ── */
|
||||
.ev-empty { text-align:center; padding:80px 20px; color:var(--lt); }
|
||||
.ev-empty-icon { font-size:56px; margin-bottom:16px; }
|
||||
.ev-empty-icon { width:56px; height:56px; margin:0 auto 16px; color:var(--purple); }
|
||||
.ev-empty-icon svg { width:100%; height:100%; }
|
||||
.ev-empty-title { font-size:20px; font-weight:700; color:var(--ink); margin-bottom:8px; }
|
||||
.ev-empty-sub { font-size:14px; max-width:420px; margin:0 auto; line-height:1.6; }
|
||||
|
||||
@@ -123,7 +124,8 @@
|
||||
.ev-modal { background:var(--navy2); border-radius:14px; padding:28px; max-width:720px; width:90%; max-height:82vh; display:flex; flex-direction:column; }
|
||||
.ev-modal-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:16px; }
|
||||
.ev-modal-title { font-size:15px; font-weight:700; color:var(--ink); }
|
||||
.ev-modal-close { background:none; border:none; font-size:20px; cursor:pointer; color:var(--lt); }
|
||||
.ev-modal-close { background:none; border:none; cursor:pointer; color:var(--lt); width:20px; height:20px; padding:0; }
|
||||
.ev-modal-close svg { width:100%; height:100%; }
|
||||
.ev-modal-body { overflow-y:auto; flex:1; }
|
||||
.ev-modal-prompt { font-size:12px; color:var(--lt); margin-bottom:8px; }
|
||||
.ev-modal-output { font-size:13px; color:var(--ink); line-height:1.7; white-space:pre-wrap; word-break:break-word; background:rgba(255,255,255,.03); border-radius:8px; padding:14px; }
|
||||
@@ -168,6 +170,7 @@
|
||||
<a href="dashboard.html">Dashboard</a>
|
||||
<a href="analytics.html">Usage Analytics</a>
|
||||
<a href="audit.html">Governance & Audit</a>
|
||||
<a href="health.html">Health Center</a>
|
||||
<a href="feedback.html">Feedback & Ratings</a>
|
||||
<span class="nav-drop-cat">MANAGE /</span>
|
||||
<a href="users.html">Users</a>
|
||||
@@ -207,7 +210,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<a href="notifications.html" style="position:relative">🔔</a>
|
||||
<a href="notifications.html" class="nav-icon-btn" style="position:relative" aria-label="Notifications">
|
||||
<span class="icon-svg icon-md" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg></span>
|
||||
</a>
|
||||
<span class="badge" data-brand="tier">Basic Tier</span>
|
||||
<div id="nav-org-logo" class="nav-org-logo"></div>
|
||||
</header>
|
||||
@@ -218,10 +223,10 @@
|
||||
<aside class="ev-sidebar">
|
||||
<div class="ev-sidebar-header">
|
||||
<h3>Eval Suites</h3>
|
||||
<button class="ev-new-btn" onclick="newSuite()">+ New Suite</button>
|
||||
<button class="ev-new-btn" onclick="newSuite()"><span class="icon-label"><span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M12 5v14M5 12h14"/></svg></span><span>New Suite</span></span></button>
|
||||
</div>
|
||||
<div class="ev-suite-list" id="suite-list">
|
||||
<div style="padding:16px;font-size:12px;color:var(--lt);text-align:center">No suites yet</div>
|
||||
<div class="cezen-list-empty">No suites yet — <a onclick="newSuite()">create your first one</a>.</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
@@ -230,15 +235,15 @@
|
||||
|
||||
<!-- Empty -->
|
||||
<div class="ev-empty" id="ev-empty">
|
||||
<div class="ev-empty-icon">🧪</div>
|
||||
<div class="ev-empty-icon icon-svg" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M9 3v5l-5 9a2 2 0 0 0 1.75 3h12.5A2 2 0 0 0 20 17l-5-9V3"/><path d="M9 8h6"/></svg></div>
|
||||
<div class="ev-empty-title">AI Evaluation Suite</div>
|
||||
<div class="ev-empty-sub">
|
||||
Build test suites with prompt cases, run them across multiple models, and get automatic quality, relevance, and safety scores — so you know exactly how your models perform.
|
||||
</div>
|
||||
<div style="margin-top:24px;display:flex;gap:12px;justify-content:center;flex-wrap:wrap">
|
||||
<button class="btn btn-primary" onclick="newSuite('qa')">❓ Q&A Accuracy</button>
|
||||
<button class="btn btn-ghost" onclick="newSuite('safety')">🛡 Safety Checks</button>
|
||||
<button class="btn btn-ghost" onclick="newSuite('compare')">⚖️ Model Comparison</button>
|
||||
<button class="btn btn-primary" onclick="newSuite('qa')"><span class="icon-label"><span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M9.09 9a3 3 0 1 1 5.82 1c0 2-3 3-3 3"/><path d="M12 17h.01"/><circle cx="12" cy="12" r="9"/></svg></span><span>Q&A Accuracy</span></span></button>
|
||||
<button class="btn btn-ghost" onclick="newSuite('safety')"><span class="icon-label"><span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg></span><span>Safety Checks</span></span></button>
|
||||
<button class="btn btn-ghost" onclick="newSuite('compare')"><span class="icon-label"><span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M3 7h7v7H3z"/><path d="M14 10h7v7h-7z"/><path d="M14 3h7v4M21 3l-5 5"/><path d="M3 21v-4h7"/><path d="m3 21 5-5"/></svg></span><span>Model Comparison</span></span></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -247,8 +252,8 @@
|
||||
|
||||
<!-- Tabs -->
|
||||
<div class="ev-tabs">
|
||||
<button class="ev-tab active" id="tab-build" onclick="showTab('build')">🔧 Suite Builder</button>
|
||||
<button class="ev-tab" id="tab-run" onclick="showTab('run')">▶ Run & Results</button>
|
||||
<button class="ev-tab active" id="tab-build" onclick="showTab('build')">Suite Builder</button>
|
||||
<button class="ev-tab" id="tab-run" onclick="showTab('run')">Run & Results</button>
|
||||
</div>
|
||||
|
||||
<!-- ── Build tab ── -->
|
||||
@@ -256,8 +261,8 @@
|
||||
|
||||
<div class="ev-card">
|
||||
<div class="ev-card-title">
|
||||
<span>📋 Suite Details</span>
|
||||
<button class="btn btn-ghost" style="font-size:12px;color:#B91C1C;border-color:#FCA5A5" onclick="deleteSuite()">🗑 Delete Suite</button>
|
||||
<span class="icon-label"><span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M9 3h6"/><path d="M10 7h4"/><rect x="5" y="5" width="14" height="16" rx="2"/></svg></span><span>Suite Details</span></span>
|
||||
<button class="btn btn-ghost" style="font-size:12px;color:#B91C1C;border-color:#FCA5A5" onclick="deleteSuite()"><span class="icon-label"><span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M3 6h18"/><path d="M8 6V4h8v2"/><path d="M19 6l-1 14H6L5 6"/></svg></span><span>Delete Suite</span></span></button>
|
||||
</div>
|
||||
<div class="ev-field">
|
||||
<label>Suite Name</label>
|
||||
@@ -267,13 +272,13 @@
|
||||
<label>Description</label>
|
||||
<input type="text" id="suite-desc" placeholder="What this eval suite tests">
|
||||
</div>
|
||||
<button class="btn btn-primary" onclick="saveSuite()">💾 Save Suite</button>
|
||||
<button class="btn btn-primary" onclick="saveSuite()"><span class="icon-label"><span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M5 21h14"/><path d="M19 21V7l-3-3H5v17"/><path d="M9 10h6"/><path d="M9 14h6"/></svg></span><span>Save Suite</span></span></button>
|
||||
</div>
|
||||
|
||||
<div class="ev-card">
|
||||
<div class="ev-card-title">
|
||||
<span>🧪 Test Cases <span id="case-count-badge" style="font-size:12px;font-weight:400;color:var(--lt)"></span></span>
|
||||
<button class="btn btn-ghost" style="font-size:12px" onclick="addCase()">+ Add Case</button>
|
||||
<span class="icon-label"><span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M9 3v5l-5 9a2 2 0 0 0 1.75 3h12.5A2 2 0 0 0 20 17l-5-9V3"/><path d="M9 8h6"/></svg></span><span>Test Cases <span id="case-count-badge" style="font-size:12px;font-weight:400;color:var(--lt)"></span></span></span>
|
||||
<button class="btn btn-ghost" style="font-size:12px" onclick="addCase()"><span class="icon-label"><span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M12 5v14M5 12h14"/></svg></span><span>Add Case</span></span></button>
|
||||
</div>
|
||||
|
||||
<div id="cases-list">
|
||||
@@ -287,7 +292,7 @@
|
||||
<div id="pane-run" style="display:none">
|
||||
|
||||
<div class="ev-card">
|
||||
<div class="ev-card-title">▶ Start New Run</div>
|
||||
<div class="ev-card-title"><span class="icon-label"><span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="m8 5 11 7-11 7z"/></svg></span><span>Start New Run</span></span></div>
|
||||
|
||||
<div class="ev-field">
|
||||
<label>Select Models to Evaluate</label>
|
||||
@@ -304,7 +309,7 @@
|
||||
<span style="font-size:11px;color:var(--lt);margin-top:4px">The judge model reads each response and assigns quality, relevance, and safety scores (1–5).</span>
|
||||
</div>
|
||||
|
||||
<button id="start-run-btn" onclick="startRun()">🚀 Start Evaluation</button>
|
||||
<button id="start-run-btn" onclick="startRun()"><span class="icon-label"><span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="m8 5 11 7-11 7z"/></svg></span><span>Start Evaluation</span></span></button>
|
||||
|
||||
<!-- Active run progress -->
|
||||
<div id="run-progress" style="display:none;margin-top:16px">
|
||||
@@ -320,7 +325,7 @@
|
||||
|
||||
<!-- Past runs -->
|
||||
<div class="ev-card" id="runs-history-card">
|
||||
<div class="ev-card-title">📊 Past Runs</div>
|
||||
<div class="ev-card-title"><span class="icon-label"><span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M4 19h16"/><path d="M7 16V8"/><path d="M12 16V5"/><path d="M17 16v-3"/></svg></span><span>Past Runs</span></span></div>
|
||||
<div id="runs-history"><div style="color:var(--lt);font-size:13px">No runs yet</div></div>
|
||||
</div>
|
||||
|
||||
@@ -328,7 +333,7 @@
|
||||
<div class="ev-card" id="results-card" style="display:none">
|
||||
<div class="ev-card-title">
|
||||
<span id="results-title">Results</span>
|
||||
<button class="btn btn-ghost" style="font-size:12px" onclick="exportCSV()">⬇ Export CSV</button>
|
||||
<button class="btn btn-ghost" style="font-size:12px" onclick="exportCSV()"><span class="icon-label"><span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M12 3v12"/><path d="m7 10 5 5 5-5"/><path d="M5 21h14"/></svg></span><span>Export CSV</span></span></button>
|
||||
</div>
|
||||
|
||||
<div class="ev-summary" id="results-summary"></div>
|
||||
@@ -351,7 +356,7 @@
|
||||
<div class="ev-modal">
|
||||
<div class="ev-modal-header">
|
||||
<span class="ev-modal-title" id="modal-title">Response</span>
|
||||
<button class="ev-modal-close" onclick="document.getElementById('ev-modal').classList.remove('open')">✕</button>
|
||||
<button class="ev-modal-close" onclick="document.getElementById('ev-modal').classList.remove('open')" aria-label="Close"><svg viewBox="0 0 24 24"><path d="M6 6l12 12M18 6 6 18"/></svg></button>
|
||||
</div>
|
||||
<div class="ev-modal-body">
|
||||
<div class="ev-modal-prompt" id="modal-prompt"></div>
|
||||
@@ -364,6 +369,16 @@
|
||||
|
||||
<script>
|
||||
const _API = '/api';
|
||||
function evIconSvg(name, sizeClass = 'icon-sm') {
|
||||
const icons = {
|
||||
check:'<svg viewBox="0 0 24 24"><path d="m20 6-11 11-5-5"/></svg>',
|
||||
plus:'<svg viewBox="0 0 24 24"><path d="M12 5v14M5 12h14"/></svg>',
|
||||
save:'<svg viewBox="0 0 24 24"><path d="M5 21h14"/><path d="M19 21V7l-3-3H5v17"/><path d="M9 10h6"/><path d="M9 14h6"/></svg>',
|
||||
trash:'<svg viewBox="0 0 24 24"><path d="M3 6h18"/><path d="M8 6V4h8v2"/><path d="M19 6l-1 14H6L5 6"/></svg>',
|
||||
close:'<svg viewBox="0 0 24 24"><path d="M6 6l12 12M18 6 6 18"/></svg>'
|
||||
};
|
||||
return `<span class="icon-svg ${sizeClass}" aria-hidden="true">${icons[name] || icons.plus}</span>`;
|
||||
}
|
||||
|
||||
const MOCK_SUITES = [
|
||||
{id:1, name:'HR Policy Accuracy', description:'Tests retrieval and answer accuracy for HR docs', case_count:24, last_run:'2026-06-25T14:00:00Z', pass_rate:0.87},
|
||||
@@ -532,7 +547,7 @@ function renderCases() {
|
||||
document.getElementById('case-count-badge').textContent = cases.length ? `(${cases.length})` : '';
|
||||
|
||||
if (!cases.length) {
|
||||
el.innerHTML = '<div style="text-align:center;padding:32px;color:var(--lt);font-size:13px">No test cases yet — click <strong>+ Add Case</strong> to begin</div>';
|
||||
el.innerHTML = '<div style="text-align:center;padding:32px;color:var(--lt);font-size:13px">No test cases yet. Click <strong>Add Case</strong> to begin.</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -541,7 +556,7 @@ function renderCases() {
|
||||
<div class="ev-case-header" onclick="toggleCase(${i})">
|
||||
<span class="ev-case-num">${i+1}</span>
|
||||
<span class="ev-case-label">${esc(c.name || c.prompt_text.slice(0,60))}</span>
|
||||
<button class="ev-case-del" onclick="event.stopPropagation();removeCase(${i})">✕</button>
|
||||
<button class="ev-case-del" onclick="event.stopPropagation();removeCase(${i})">${evIconSvg('close', 'icon-sm')}</button>
|
||||
</div>
|
||||
<div class="ev-case-body">
|
||||
<div class="ev-case-grid">
|
||||
@@ -562,10 +577,10 @@ function renderCases() {
|
||||
<label>Expected Output <span style="font-weight:400;text-transform:none;letter-spacing:0;color:var(--lt)">(optional — used by judge model for scoring)</span></label>
|
||||
<textarea rows="2" onchange="cases[${i}].expected_output=this.value" placeholder="Leave blank for open-ended evaluation">${esc(c.expected_output)}</textarea>
|
||||
</div>
|
||||
${c.id ? `<button class="btn btn-ghost" style="font-size:12px" onclick="saveCase(${i})">💾 Save Case</button>` : '<span style="font-size:11px;color:var(--purple)">✓ Will be saved with suite</span>'}
|
||||
${c.id ? `<button class="btn btn-ghost" style="font-size:12px" onclick="saveCase(${i})"><span class="icon-label">${evIconSvg('save', 'icon-sm')}<span>Save Case</span></span></button>` : '<span style="font-size:11px;color:var(--purple)">Will be saved with suite</span>'}
|
||||
</div>
|
||||
</div>
|
||||
`).join('') + `<button class="ev-add-case" onclick="addCase()">+ Add Test Case</button>`;
|
||||
`).join('') + `<button class="ev-add-case" onclick="addCase()"><span class="icon-label">${evIconSvg('plus', 'icon-sm')}<span>Add Test Case</span></span></button>`;
|
||||
}
|
||||
|
||||
function toggleCase(i) {
|
||||
@@ -815,7 +830,7 @@ function renderModelChips() {
|
||||
}
|
||||
el.innerHTML = models.map(m => `
|
||||
<div class="ev-model-chip${selectedModels.has(m) ? ' selected' : ''}" onclick="toggleModel('${esc(m)}')">
|
||||
<span class="chip-check">✓</span> ${esc(m)}
|
||||
<span class="chip-check">${evIconSvg('check', 'icon-sm')}</span> ${esc(m)}
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
@@ -847,6 +862,6 @@ function esc(s) {
|
||||
</script>
|
||||
|
||||
<script src="auth.js"></script>
|
||||
<script src="branding.js"></script>
|
||||
<script src="branding.js?v=3"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user