Upload 7 files
Browse files- web/static/app.css +95 -0
- web/static/app.js +27 -9
web/static/app.css
CHANGED
|
@@ -2261,3 +2261,98 @@ strong,p,h1,h2,h3,h4,span,a,button,div,li{overflow-wrap:break-word;word-break:no
|
|
| 2261 |
.model-prescan-card.running #scanModel{padding:7px 10px!important;font-size:11.5px!important;border-radius:12px!important}
|
| 2262 |
.model-prescan-card.error #scanModel{border-color:rgba(244,63,94,.18)!important;background:linear-gradient(180deg,#fff,#fff7f7)!important}
|
| 2263 |
@media(prefers-reduced-motion:reduce){.prescan-spinner{animation:none!important}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2261 |
.model-prescan-card.running #scanModel{padding:7px 10px!important;font-size:11.5px!important;border-radius:12px!important}
|
| 2262 |
.model-prescan-card.error #scanModel{border-color:rgba(244,63,94,.18)!important;background:linear-gradient(180deg,#fff,#fff7f7)!important}
|
| 2263 |
@media(prefers-reduced-motion:reduce){.prescan-spinner{animation:none!important}}
|
| 2264 |
+
|
| 2265 |
+
/* v186: Eval Archive breathing room + less redundant Model pre-scan summary */
|
| 2266 |
+
.eval-archive-panel{
|
| 2267 |
+
padding:16px!important;
|
| 2268 |
+
display:grid!important;
|
| 2269 |
+
gap:10px!important;
|
| 2270 |
+
}
|
| 2271 |
+
.eval-archive-title-row{
|
| 2272 |
+
margin-bottom:2px!important;
|
| 2273 |
+
align-items:flex-start!important;
|
| 2274 |
+
}
|
| 2275 |
+
.eval-archive-title-row .badge{
|
| 2276 |
+
align-self:start!important;
|
| 2277 |
+
margin-top:0!important;
|
| 2278 |
+
}
|
| 2279 |
+
.eval-archive-summary{
|
| 2280 |
+
margin:0!important;
|
| 2281 |
+
max-width:100%!important;
|
| 2282 |
+
line-height:1.35!important;
|
| 2283 |
+
}
|
| 2284 |
+
.eval-archive-actions{
|
| 2285 |
+
margin-top:8px!important;
|
| 2286 |
+
padding-top:12px!important;
|
| 2287 |
+
border-top:1px solid rgba(226,232,240,.72)!important;
|
| 2288 |
+
gap:10px!important;
|
| 2289 |
+
}
|
| 2290 |
+
.eval-archive-panel.on .eval-archive-actions{border-top-color:rgba(34,197,94,.14)!important}
|
| 2291 |
+
.eval-archive-actions button{
|
| 2292 |
+
min-height:36px!important;
|
| 2293 |
+
padding:8px 12px!important;
|
| 2294 |
+
}
|
| 2295 |
+
|
| 2296 |
+
.model-prescan-card{
|
| 2297 |
+
gap:9px!important;
|
| 2298 |
+
}
|
| 2299 |
+
.model-prescan-card.success{
|
| 2300 |
+
padding:13px!important;
|
| 2301 |
+
}
|
| 2302 |
+
.model-prescan-card.success>p{
|
| 2303 |
+
max-width:52ch!important;
|
| 2304 |
+
}
|
| 2305 |
+
.prescan-compact-grid{
|
| 2306 |
+
grid-template-columns:repeat(3,minmax(0,1fr))!important;
|
| 2307 |
+
gap:6px!important;
|
| 2308 |
+
}
|
| 2309 |
+
.prescan-chip{
|
| 2310 |
+
padding:7px 8px!important;
|
| 2311 |
+
border-radius:13px!important;
|
| 2312 |
+
}
|
| 2313 |
+
.prescan-chip i{
|
| 2314 |
+
width:21px!important;
|
| 2315 |
+
height:21px!important;
|
| 2316 |
+
font-size:11px!important;
|
| 2317 |
+
}
|
| 2318 |
+
.prescan-chip em{font-size:8px!important}
|
| 2319 |
+
.prescan-chip strong{font-size:11px!important}
|
| 2320 |
+
.prescan-decision-line{
|
| 2321 |
+
display:flex!important;
|
| 2322 |
+
align-items:flex-start!important;
|
| 2323 |
+
gap:8px!important;
|
| 2324 |
+
padding:8px 10px!important;
|
| 2325 |
+
border-radius:14px!important;
|
| 2326 |
+
border:1px solid rgba(226,232,240,.84)!important;
|
| 2327 |
+
background:rgba(255,255,255,.78)!important;
|
| 2328 |
+
color:#475569!important;
|
| 2329 |
+
font-size:11.25px!important;
|
| 2330 |
+
line-height:1.25!important;
|
| 2331 |
+
min-width:0!important;
|
| 2332 |
+
}
|
| 2333 |
+
.prescan-decision-line b{
|
| 2334 |
+
flex:0 0 auto!important;
|
| 2335 |
+
color:#0f172a!important;
|
| 2336 |
+
font-size:10px!important;
|
| 2337 |
+
text-transform:uppercase!important;
|
| 2338 |
+
letter-spacing:.12em!important;
|
| 2339 |
+
}
|
| 2340 |
+
.prescan-decision-line span{
|
| 2341 |
+
min-width:0!important;
|
| 2342 |
+
overflow:hidden!important;
|
| 2343 |
+
text-overflow:ellipsis!important;
|
| 2344 |
+
display:-webkit-box!important;
|
| 2345 |
+
-webkit-line-clamp:2!important;
|
| 2346 |
+
-webkit-box-orient:vertical!important;
|
| 2347 |
+
}
|
| 2348 |
+
.prescan-decision-line.success{border-color:rgba(34,197,94,.18)!important;background:rgba(240,253,244,.55)!important}
|
| 2349 |
+
.prescan-decision-line.warn{border-color:rgba(245,158,11,.20)!important;background:rgba(255,251,235,.62)!important}
|
| 2350 |
+
.prescan-decision-line.error{border-color:rgba(244,63,94,.18)!important;background:rgba(255,241,242,.62)!important}
|
| 2351 |
+
.prescan-decision-line.running{border-color:rgba(37,99,235,.16)!important;background:rgba(239,246,255,.58)!important}
|
| 2352 |
+
.model-prescan-card.success .prescan-pill-row .prescan-pill.good{display:none!important}
|
| 2353 |
+
.model-prescan-card.success .model-prescan-signals{gap:7px!important}
|
| 2354 |
+
.model-prescan-card.success #scanModel{margin-top:1px!important}
|
| 2355 |
+
@media(max-width:720px){
|
| 2356 |
+
.eval-archive-actions{padding-top:10px!important}
|
| 2357 |
+
.prescan-decision-line{display:grid!important;gap:4px!important}
|
| 2358 |
+
}
|
web/static/app.js
CHANGED
|
@@ -323,11 +323,13 @@ function renderModelPreScan(scan=null){
|
|
| 323 |
setText('modelPreScanTitle',`${labelMap[verdict]||labelMap.caution}${scoreText}`);
|
| 324 |
setText('modelPreScanSummary',scan.summary||'Model metadata scan completed.');
|
| 325 |
if(badge){badge.textContent=labelMap[verdict]||verdict;badge.className='badge '+cls}
|
| 326 |
-
const
|
| 327 |
-
const
|
|
|
|
|
|
|
| 328 |
const outputType=outputTypeFromModelScan(scan);
|
| 329 |
-
const
|
| 330 |
-
|
| 331 |
if(signals){
|
| 332 |
const metaCards=[
|
| 333 |
outputType?['↳','Output',outputType,verdict==='safe']:null,
|
|
@@ -335,14 +337,20 @@ function renderModelPreScan(scan=null){
|
|
| 335 |
scan.library_name?['◎','Library',scan.library_name,false]:null,
|
| 336 |
].filter(Boolean).slice(0,3);
|
| 337 |
const compactMeta=metaCards.length?`<div class="prescan-meta prescan-compact-grid">${metaCards.map(([icon,k,v,isGood])=>`<span class="prescan-chip ${isGood?'good':''}"><i>${escapeHtml(icon)}</i><em>${escapeHtml(k)}</em><strong>${escapeHtml(String(v))}</strong></span>`).join('')}</div>`:'';
|
| 338 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 339 |
const riskPills=risk.length?`<div class="prescan-pill-row">${risk.map(x=>`<span class="prescan-pill risk"><b class="prescan-icon">!</b>${escapeHtml(x)}</span>`).join('')}</div>`:'';
|
| 340 |
const runningPills=verdict==='scanning'?'<div class="prescan-pill-row"><span class="prescan-pill running"><b class="prescan-icon prescan-spinner">◌</b>Reading model card</span><span class="prescan-pill running"><b class="prescan-icon">◇</b>Checking metadata</span></div>':'';
|
| 341 |
const errorPill=verdict==='error'?`<div class="prescan-pill-row"><span class="prescan-pill risk"><b class="prescan-icon">!</b>${escapeHtml(scan.error||'The scan could not complete. Try again.')}</span></div>`:'';
|
| 342 |
-
const
|
| 343 |
-
const emptyHint=(!compactMeta&&!goodPills&&!riskPills&&!runningPills&&!errorPill&&!recLine)?'<div class="prescan-pill-row"><span class="prescan-pill"><b class="prescan-icon">◇</b>No extra metadata found.</span></div>':'';
|
| 344 |
signals.hidden=false;
|
| 345 |
-
signals.innerHTML=`${compactMeta}${runningPills}${
|
| 346 |
}
|
| 347 |
if(ackWrap)ackWrap.hidden=!(verdict==='risky');
|
| 348 |
}
|
|
@@ -419,7 +427,17 @@ function startPolling(runId,options={}){
|
|
| 419 |
}
|
| 420 |
async function bootstrapRunRecovery(){return restoreActiveRun()}
|
| 421 |
async function restoreActiveRun(){try{const resumable=await apiGet(`/api/runs/resumable?bucket_name=${encodeURIComponent(state.bucketName)}`);if(resumable?.run?.run_id){state.runId=resumable.run.run_id;if(resumable.bucket_source)state.bucketSource=resumable.bucket_source;setBuildModeInspecting(state.runId);if(resumable.view)renderRunViewModel(resumable.view,{progress:0,events:[]});setQuickLinks(resumable.view?.links||{},resumable.view||{});startPolling(state.runId);return true}}catch(e){console.warn('resumable lookup failed',e)}try{const raw=localStorage.getItem('asf.activeRun');if(!raw)return false;const saved=JSON.parse(raw);if(saved?.bucketName)state.bucketName=saved.bucketName;if(saved?.runId){state.runId=saved.runId;setText('detailRunId',saved.runId);setQuickLinks(saved.links||{},{});setBuildModeInspecting(saved.runId);startPolling(saved.runId);return true}}catch(_){}return false}
|
| 422 |
-
async function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 423 |
function renderSignedOut(){const auth=$('authPanel');if(!auth)return;auth.hidden=false;auth.className='auth-panel warning';auth.innerHTML='<strong>Sign in required</strong><p>Use Hugging Face OAuth before launching Jobs or reading your Bucket.</p><a class="link-btn" href="/oauth/huggingface/login">Sign in with Hugging Face ↗</a>'}
|
| 424 |
function renderAuthWarnings(me){const auth=$('authPanel');if(!auth)return;const missing=me.missing_scopes||[];const warnings=me.warnings||[];if(!missing.length&&!warnings.length){auth.hidden=true;auth.innerHTML='';return}auth.hidden=false;auth.className='auth-panel warning';auth.innerHTML=`<strong>OAuth session warning</strong><p>${escapeHtml([...warnings,missing.length?'Missing scopes: '+missing.join(', '):''].filter(Boolean).join(' • '))}</p><a class="link-btn" href="/oauth/huggingface/login">Refresh sign-in ↗</a>`}
|
| 425 |
function renderBillingPanel(info){
|
|
|
|
| 323 |
setText('modelPreScanTitle',`${labelMap[verdict]||labelMap.caution}${scoreText}`);
|
| 324 |
setText('modelPreScanSummary',scan.summary||'Model metadata scan completed.');
|
| 325 |
if(badge){badge.textContent=labelMap[verdict]||verdict;badge.className='badge '+cls}
|
| 326 |
+
const allGood=(scan.good_signals||[]).filter(Boolean);
|
| 327 |
+
const good=allGood.slice(0,2);
|
| 328 |
+
const allRisk=(scan.risk_signals||[]).filter(Boolean);
|
| 329 |
+
const risk=allRisk.slice(0,3);
|
| 330 |
const outputType=outputTypeFromModelScan(scan);
|
| 331 |
+
const recommendations=(scan.recommendations||[]).filter(Boolean);
|
| 332 |
+
const primaryRecommendation=recommendations.find(x=>!String(x).toLowerCase().startsWith('expected output'))||recommendations[0]||'';
|
| 333 |
if(signals){
|
| 334 |
const metaCards=[
|
| 335 |
outputType?['↳','Output',outputType,verdict==='safe']:null,
|
|
|
|
| 337 |
scan.library_name?['◎','Library',scan.library_name,false]:null,
|
| 338 |
].filter(Boolean).slice(0,3);
|
| 339 |
const compactMeta=metaCards.length?`<div class="prescan-meta prescan-compact-grid">${metaCards.map(([icon,k,v,isGood])=>`<span class="prescan-chip ${isGood?'good':''}"><i>${escapeHtml(icon)}</i><em>${escapeHtml(k)}</em><strong>${escapeHtml(String(v))}</strong></span>`).join('')}</div>`:'';
|
| 340 |
+
const signalSummaryParts=[];
|
| 341 |
+
if(allGood.length)signalSummaryParts.push(`${allGood.length} check${allGood.length>1?'s':''} passed`);
|
| 342 |
+
if(allRisk.length)signalSummaryParts.push(`${allRisk.length} risk signal${allRisk.length>1?'s':''}`);
|
| 343 |
+
else if(verdict!=='scanning'&&verdict!=='error')signalSummaryParts.push('No risk signals');
|
| 344 |
+
if(primaryRecommendation)signalSummaryParts.push(primaryRecommendation);
|
| 345 |
+
const summaryTitle=[...allGood,...allRisk,...recommendations].filter(Boolean).join('\n');
|
| 346 |
+
const signalSummary=signalSummaryParts.length?`<div class="prescan-decision-line ${cls}" title="${escapeHtml(summaryTitle)}"><b>${verdict==='safe'?'Ready':verdict==='caution'?'Review':verdict==='risky'?'Risk':verdict==='unsupported'?'Unsupported':verdict==='scanning'?'Scanning':'Issue'}</b><span>${escapeHtml(signalSummaryParts.join(' · '))}</span></div>`:'';
|
| 347 |
+
const goodPreview=(verdict!=='safe'&&good.length)?`<div class="prescan-pill-row">${good.map(x=>`<span class="prescan-pill good"><b class="prescan-icon">✓</b>${escapeHtml(x)}</span>`).join('')}</div>`:'';
|
| 348 |
const riskPills=risk.length?`<div class="prescan-pill-row">${risk.map(x=>`<span class="prescan-pill risk"><b class="prescan-icon">!</b>${escapeHtml(x)}</span>`).join('')}</div>`:'';
|
| 349 |
const runningPills=verdict==='scanning'?'<div class="prescan-pill-row"><span class="prescan-pill running"><b class="prescan-icon prescan-spinner">◌</b>Reading model card</span><span class="prescan-pill running"><b class="prescan-icon">◇</b>Checking metadata</span></div>':'';
|
| 350 |
const errorPill=verdict==='error'?`<div class="prescan-pill-row"><span class="prescan-pill risk"><b class="prescan-icon">!</b>${escapeHtml(scan.error||'The scan could not complete. Try again.')}</span></div>`:'';
|
| 351 |
+
const emptyHint=(!compactMeta&&!signalSummary&&!goodPreview&&!riskPills&&!runningPills&&!errorPill)?'<div class="prescan-pill-row"><span class="prescan-pill"><b class="prescan-icon">◇</b>No extra metadata found.</span></div>':'';
|
|
|
|
| 352 |
signals.hidden=false;
|
| 353 |
+
signals.innerHTML=`${compactMeta}${runningPills}${signalSummary}${goodPreview}${riskPills}${errorPill}${emptyHint}`;
|
| 354 |
}
|
| 355 |
if(ackWrap)ackWrap.hidden=!(verdict==='risky');
|
| 356 |
}
|
|
|
|
| 427 |
}
|
| 428 |
async function bootstrapRunRecovery(){return restoreActiveRun()}
|
| 429 |
async function restoreActiveRun(){try{const resumable=await apiGet(`/api/runs/resumable?bucket_name=${encodeURIComponent(state.bucketName)}`);if(resumable?.run?.run_id){state.runId=resumable.run.run_id;if(resumable.bucket_source)state.bucketSource=resumable.bucket_source;setBuildModeInspecting(state.runId);if(resumable.view)renderRunViewModel(resumable.view,{progress:0,events:[]});setQuickLinks(resumable.view?.links||{},resumable.view||{});startPolling(state.runId);return true}}catch(e){console.warn('resumable lookup failed',e)}try{const raw=localStorage.getItem('asf.activeRun');if(!raw)return false;const saved=JSON.parse(raw);if(saved?.bucketName)state.bucketName=saved.bucketName;if(saved?.runId){state.runId=saved.runId;setText('detailRunId',saved.runId);setQuickLinks(saved.links||{},{});setBuildModeInspecting(saved.runId);startPolling(saved.runId);return true}}catch(_){}return false}
|
| 430 |
+
async function refreshAnonymousEvalStatus(){
|
| 431 |
+
try{
|
| 432 |
+
const anonymous_eval=await apiGet('/api/eval-archive/status');
|
| 433 |
+
renderAnonymousEvalStatus({anonymous_eval});
|
| 434 |
+
return anonymous_eval;
|
| 435 |
+
}catch(e){
|
| 436 |
+
renderAnonymousEvalStatus({anonymous_eval:{enabled:false,reason:'status_unavailable',managed_by:'instance owner'}});
|
| 437 |
+
return null;
|
| 438 |
+
}
|
| 439 |
+
}
|
| 440 |
+
async function loadAppInfo(){setOperation('Checking sign-in and run storage…','loading');setBucketFeedback('checking','Checking private bucket access…');try{const me=await apiGet('/api/me');state.user=me;renderAnonymousEvalStatus(me);setText('userChip','@'+me.username);const userChip=$('userChip');if(userChip)userChip.href=`https://huggingface.co/${me.username}`;const logout=$('logoutLink');if(logout){logout.hidden=false;logout.href=me.logout_url||'/logout'}state.bucketSource=me.username+'/'+state.bucketName;setText('bucketInlineLabel',state.bucketSource);renderAuthWarnings(me);renderBillingPanel(me);loadBillingStatus().catch(()=>{});await checkBucket(false);await loadRuns(true);clearSavedRun();if(!state.bucketReady)setOperation('Create your private run bucket before launching builds.','warning');else setOperation('')}catch(e){state.user=null;await refreshAnonymousEvalStatus();setText('userChip','Sign in');const userChip=$('userChip');if(userChip)userChip.href='/oauth/huggingface/login';const logout=$('logoutLink');if(logout)logout.hidden=true;renderSignedOut();renderBillingPanel(null);setBucketReady(false,'Sign in with Hugging Face first.');showMessage('Please sign in with Hugging Face, then refresh this page.',true)}}
|
| 441 |
function renderSignedOut(){const auth=$('authPanel');if(!auth)return;auth.hidden=false;auth.className='auth-panel warning';auth.innerHTML='<strong>Sign in required</strong><p>Use Hugging Face OAuth before launching Jobs or reading your Bucket.</p><a class="link-btn" href="/oauth/huggingface/login">Sign in with Hugging Face ↗</a>'}
|
| 442 |
function renderAuthWarnings(me){const auth=$('authPanel');if(!auth)return;const missing=me.missing_scopes||[];const warnings=me.warnings||[];if(!missing.length&&!warnings.length){auth.hidden=true;auth.innerHTML='';return}auth.hidden=false;auth.className='auth-panel warning';auth.innerHTML=`<strong>OAuth session warning</strong><p>${escapeHtml([...warnings,missing.length?'Missing scopes: '+missing.join(', '):''].filter(Boolean).join(' • '))}</p><a class="link-btn" href="/oauth/huggingface/login">Refresh sign-in ↗</a>`}
|
| 443 |
function renderBillingPanel(info){
|