release: freeze Nexus One AI 1.0.0-rc1
This commit is contained in:
1 parent
63acefd890
commit
4f1419ca93
152 files changed
+9445
-828
No files matched your search
+113
-13
@@ -55,6 +55,8 @@
|
||||
.badge-status.failed { background:#FEE2E2; color:#B91C1C; }
|
||||
.badge-status.pending { background:rgba(234,179,8,.15); color:#92400E; }
|
||||
.badge-status.cancelled { background:#F3F4F6; color:#6B7280; }
|
||||
.badge-status.approved { background:rgba(34,197,94,.15); color:#15803D; }
|
||||
.badge-status.rejected { background:#FEE2E2; color:#B91C1C; }
|
||||
|
||||
/* ── Log viewer ───────────────────────────────────────────── */
|
||||
.log-wrap { background:#0F1117; border-radius:8px; padding:14px 16px; font-family:monospace; font-size:11px; line-height:1.6; color:#A3E635; max-height:220px; overflow-y:auto; margin-top:14px; display:none; white-space:pre-wrap; word-break:break-all; }
|
||||
@@ -77,6 +79,15 @@
|
||||
|
||||
/* ── Toolbar ──────────────────────────────────────────────── */
|
||||
.tr-toolbar { display:flex; align-items:center; gap:10px; margin-bottom:16px; flex-wrap:wrap; }
|
||||
.creator-grid { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:14px; }
|
||||
.creator-grid .full { grid-column:1/-1; }
|
||||
.creator-actions { display:flex; gap:10px; align-items:center; flex-wrap:wrap; }
|
||||
.sample-card { border:1px solid var(--bdr); border-radius:10px; padding:16px; margin-top:12px; background:rgba(255,255,255,.02); }
|
||||
.sample-head { display:flex; justify-content:space-between; align-items:center; gap:12px; margin-bottom:12px; }
|
||||
.sample-fields { display:grid; grid-template-columns:1fr 1fr; gap:12px; }
|
||||
.sample-fields textarea { min-height:110px; resize:vertical; }
|
||||
.source-preview { margin-top:10px; font-size:11px; color:var(--lt); max-height:70px; overflow:auto; white-space:pre-wrap; }
|
||||
@media(max-width:720px){ .creator-grid,.sample-fields { grid-template-columns:1fr; } }
|
||||
</style>
|
||||
</head>
|
||||
<body data-role="admin">
|
||||
@@ -104,40 +115,35 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-dropdown">
|
||||
<button class="nav-drop-btn active">Admin ▾</button>
|
||||
<button class="nav-drop-btn">Admin ▾</button>
|
||||
<div class="nav-drop-menu nav-drop-menu-wide">
|
||||
<span class="nav-drop-cat">DOCS /</span>
|
||||
<a href="security.html">Security & Privacy</a>
|
||||
<a href="admin.html">Admin Guide</a>
|
||||
<span class="nav-drop-cat">MONITOR /</span>
|
||||
<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>
|
||||
<a href="teams.html">Teams</a>
|
||||
<a href="models-admin.html">Model Catalog</a>
|
||||
<a href="training.html" class="active">Training</a>
|
||||
<a href="knowledge.html">Knowledge Base</a>
|
||||
<span class="nav-drop-cat">TOOLS /</span>
|
||||
<a href="apikeys.html">API Keys</a>
|
||||
<a href="benchmark.html">Benchmarking</a>
|
||||
<a href="model-compare.html">Model Compare</a>
|
||||
<a href="model-compare.html">Response Comparison</a>
|
||||
<a href="api-playground.html">API Playground</a>
|
||||
<a href="guardrails.html">Guardrails</a>
|
||||
<a href="rag-quality.html">RAG Quality</a>
|
||||
<a href="router.html">Model Router</a>
|
||||
<a href="connectors.html">MCP & Enterprise Connectors</a>
|
||||
<span class="nav-drop-cat">SYSTEM /</span>
|
||||
<a href="console.html">Console</a>
|
||||
<a href="settings.html">Settings</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-dropdown">
|
||||
<button class="nav-drop-btn">AI Tools ▾</button>
|
||||
<button class="nav-drop-btn active">AI Tools ▾</button>
|
||||
<div class="nav-drop-menu">
|
||||
<span class="nav-drop-cat">MODEL BUILD /</span>
|
||||
<a href="dataset-creation.html">Dataset Creation</a>
|
||||
<a href="training.html" class="active">Model Training</a>
|
||||
<span class="nav-drop-cat">INTELLIGENCE /</span>
|
||||
<a href="documents.html">Document Intelligence</a>
|
||||
<a href="chat-multi.html">AI Workspace</a>
|
||||
@@ -310,6 +316,7 @@ const MOCK_JOBS = [
|
||||
let datasetsCache = [];
|
||||
let jobRefreshTimer = null;
|
||||
let lossCharts = {};
|
||||
let generationRefreshTimer = null;
|
||||
|
||||
// ── Helpers ──────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -337,6 +344,99 @@ function statusBadge(s) {
|
||||
return `<span class="badge-status ${s}">${s}</span>`;
|
||||
}
|
||||
|
||||
function escapeHtml(value) {
|
||||
return String(value ?? '').replace(/[&<>'"]/g, c => ({'&':'&','<':'<','>':'>',"'":''','"':'"'}[c]));
|
||||
}
|
||||
|
||||
async function startDatasetCreation() {
|
||||
const name = document.getElementById('dc-name').value.trim();
|
||||
const model = document.getElementById('dc-model').value;
|
||||
const file = document.getElementById('dc-file').files[0];
|
||||
if (!name || !model || !file) return toast('Dataset name, local model, and source document are required', true);
|
||||
const button = document.getElementById('dc-start');
|
||||
button.disabled = true;
|
||||
const fd = new FormData();
|
||||
fd.append('name', name); fd.append('model', model); fd.append('file', file);
|
||||
fd.append('format', document.getElementById('dc-format').value);
|
||||
fd.append('target_count', document.getElementById('dc-count').value);
|
||||
try {
|
||||
const res = await fetch(`${_API}/training/dataset-generation`, {method:'POST', credentials:'include', body:fd});
|
||||
const data = await res.json();
|
||||
if (!res.ok) throw new Error(data.detail || 'Could not start generation');
|
||||
toast('Dataset generation started');
|
||||
document.getElementById('dc-status').textContent = 'Generation is running locally. You can leave this page and return.';
|
||||
loadGenerationJobs();
|
||||
} catch (e) { toast(e.message, true); }
|
||||
finally { button.disabled = false; }
|
||||
}
|
||||
|
||||
async function loadGenerationJobs() {
|
||||
const tbody = document.getElementById('dc-jobs');
|
||||
try {
|
||||
const res = await fetch(`${_API}/training/dataset-generation`, {credentials:'include'});
|
||||
const data = await res.json();
|
||||
if (!res.ok) throw new Error(data.detail || 'Could not load generation jobs');
|
||||
const jobs = data.jobs || [];
|
||||
tbody.innerHTML = jobs.length ? jobs.map(job => `<tr>
|
||||
<td><strong>${escapeHtml(job.name)}</strong></td><td>${escapeHtml(job.source_name)}</td>
|
||||
<td>${escapeHtml(job.model)}</td><td>${job.generated_count}/${job.target_count}</td>
|
||||
<td>${statusBadge(job.status)}${job.error_msg ? `<div class="lf-hint">${escapeHtml(job.error_msg)}</div>` : ''}</td>
|
||||
<td>${job.generated_count ? `<button class="tr-btn ghost" onclick="reviewGeneration(${job.id},'${escapeHtml(job.name)}')">Review</button>` : ''}</td>
|
||||
</tr>`).join('') : '<tr><td colspan="6" class="tr-empty">No generation jobs yet.</td></tr>';
|
||||
const running = jobs.some(job => ['pending','running'].includes(job.status));
|
||||
if (running && !generationRefreshTimer) generationRefreshTimer = setInterval(loadGenerationJobs, 5000);
|
||||
if (!running && generationRefreshTimer) { clearInterval(generationRefreshTimer); generationRefreshTimer = null; }
|
||||
} catch (e) { tbody.innerHTML = `<tr><td colspan="6" class="tr-empty">${escapeHtml(e.message)}</td></tr>`; }
|
||||
}
|
||||
|
||||
async function reviewGeneration(jobId, name) {
|
||||
const review = document.getElementById('dc-review');
|
||||
const res = await fetch(`${_API}/training/dataset-generation/${jobId}/samples`, {credentials:'include'});
|
||||
const data = await res.json();
|
||||
if (!res.ok) return toast(data.detail || 'Could not load samples', true);
|
||||
const samples = data.samples || [];
|
||||
review.innerHTML = `<div class="tr-toolbar" style="margin-top:22px"><strong>Review: ${escapeHtml(name)}</strong>
|
||||
<button class="tr-btn ghost" onclick="setAllSamples(${jobId},'approved')">Approve all</button>
|
||||
<button class="tr-btn primary" onclick="publishGeneration(${jobId})">Publish approved to Dataset Manager</button></div>` +
|
||||
(samples.length ? samples.map(s => `<div class="sample-card" id="sample-${s.id}">
|
||||
<div class="sample-head"><strong>Sample ${s.id}</strong>${statusBadge(s.status)}</div>
|
||||
<div class="sample-fields"><div><label class="lf-label">Instruction</label><textarea class="lf-input" id="si-${s.id}">${escapeHtml(s.instruction)}</textarea></div>
|
||||
<div><label class="lf-label">Output</label><textarea class="lf-input" id="so-${s.id}">${escapeHtml(s.output)}</textarea></div></div>
|
||||
<details class="source-preview"><summary>Grounding source</summary>${escapeHtml(s.source_text)}</details>
|
||||
<div class="creator-actions" style="margin-top:12px"><button class="tr-btn ghost" onclick="saveSample(${s.id},'approved')">Approve & Save</button>
|
||||
<button class="tr-btn danger" onclick="saveSample(${s.id},'rejected')">Reject</button></div></div>`).join('') : '<div class="tr-empty">No samples generated.</div>');
|
||||
review.dataset.jobId = jobId; review.dataset.jobName = name;
|
||||
}
|
||||
|
||||
async function saveSample(id, status) {
|
||||
const body = {instruction:document.getElementById(`si-${id}`).value, output:document.getElementById(`so-${id}`).value, status};
|
||||
const res = await fetch(`${_API}/training/dataset-generation/samples/${id}`, {method:'PATCH', credentials:'include', headers:{'Content-Type':'application/json'}, body:JSON.stringify(body)});
|
||||
const data = await res.json().catch(()=>({}));
|
||||
if (!res.ok) return toast(data.detail || 'Could not save sample', true);
|
||||
toast(status === 'approved' ? 'Sample approved' : 'Sample rejected');
|
||||
reviewGeneration(document.getElementById('dc-review').dataset.jobId, document.getElementById('dc-review').dataset.jobName);
|
||||
}
|
||||
|
||||
async function setAllSamples(jobId, status) {
|
||||
const cards = [...document.querySelectorAll('.sample-card')];
|
||||
for (const card of cards) {
|
||||
const id = Number(card.id.replace('sample-',''));
|
||||
const body = {instruction:document.getElementById(`si-${id}`).value, output:document.getElementById(`so-${id}`).value, status};
|
||||
const res = await fetch(`${_API}/training/dataset-generation/samples/${id}`, {method:'PATCH', credentials:'include', headers:{'Content-Type':'application/json'}, body:JSON.stringify(body)});
|
||||
if (!res.ok) return toast('Could not update every sample', true);
|
||||
}
|
||||
toast('All samples approved');
|
||||
reviewGeneration(jobId, document.getElementById('dc-review').dataset.jobName);
|
||||
}
|
||||
|
||||
async function publishGeneration(jobId) {
|
||||
const res = await fetch(`${_API}/training/dataset-generation/${jobId}/publish`, {method:'POST', credentials:'include'});
|
||||
const data = await res.json().catch(()=>({}));
|
||||
if (!res.ok) return toast(data.detail || 'Could not publish dataset', true);
|
||||
toast(`Published ${data.filename} with ${data.row_count} rows`);
|
||||
loadDatasets();
|
||||
}
|
||||
|
||||
// ── Drag and drop ─────────────────────────────────────────────────────────────
|
||||
|
||||
const zone = document.getElementById('upload-zone');
|
||||
@@ -725,7 +825,7 @@ loadDatasets();
|
||||
loadModels();
|
||||
loadJobs();
|
||||
</script>
|
||||
<script src="auth.js"></script>
|
||||
<script src="branding.js?v=3"></script>
|
||||
<script src="auth.js?v=20260721-consolidated"></script>
|
||||
<script src="branding.js?v=20260721-consolidated"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user