Spaces:
Paused
Paused
Download static/model-menu.js from vllm-sr/decision1-studio: direct link, hf CLI and curl.
- Browser
- Download file 14.2 kB
-
https://huggingface.co/spaces/vllm-sr/decision1-studio/resolve/main/static/model-menu.js
- Command line
-
hf download hf://spaces/vllm-sr/decision1-studio/static/model-menu.js
-
curl -L -o model-menu.js https://huggingface.co/spaces/vllm-sr/decision1-studio/resolve/main/static/model-menu.js
14.2 kB
| // Registry-driven model presentation. No backend IDs, weights or readiness are invented. | |
| const esc = value => String(value).replace(/[&<>"']/g,x=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[x])); | |
| export function validateRegistry(result) { | |
| if(!Array.isArray(result?.models)||!result.models.length||(result.default!==undefined&&!result.models.some(m=>m.id===result.default)))throw Error('Invalid model registry.'); | |
| const text=(v,max)=>typeof v==='string'&&v.trim()&&v.length<=max; | |
| const ids=new Set(),wireIds=new Set(); | |
| for(const m of result.models){ | |
| if(!text(m.id,128)||!text(m.wire_id,128)||ids.has(m.id)||wireIds.has(m.wire_id)||!text(m.label,64)||!text(m.version,32)||!/^[0-9a-f]{64}$/.test(m.manifest_sha256)||!Number.isInteger(m.complete_input_tokens)||m.complete_input_tokens<1)throw Error('Invalid model identity.'); | |
| ids.add(m.id);wireIds.add(m.wire_id); | |
| if(m.description!==undefined&&!text(m.description,240)||m.parameter_label!==undefined&&!text(m.parameter_label,32))throw Error('Invalid model description.'); | |
| if(m.example_ids!==undefined&&(!Array.isArray(m.example_ids)||!m.example_ids.length||m.example_ids.some(x=>!text(x,128))||new Set(m.example_ids).size!==m.example_ids.length))throw Error('Invalid model examples.'); | |
| if(m.default_example_id!==undefined&&!text(m.default_example_id,128))throw Error('Invalid default example.'); | |
| if(m.release_date!==undefined&&!/^\d{4}-\d{2}-\d{2}$/.test(m.release_date))throw Error('Invalid model release date.'); | |
| } | |
| return result; | |
| } | |
| // Presentation facts come only from registry fields and the canonical Hub ID | |
| // (Decision-<version>-<Codename>-<Size>[-Reasoning]). | |
| export function modelPresentation(model) { | |
| const repo=String(model.repo_id||model.id||'').split('/').pop(); | |
| const parsed=/^Decision-(\d+(?:\.\d+)*)-(.+?)-(\d+(?:\.\d+)?[BM])(?:-(Reasoning))?$/i.exec(repo); | |
| const reasoning=/-reasoning$/i.test(repo)||/\breasoning\b/i.test(model.label||''); | |
| const codename=String(model.label||parsed?.[2]||repo).replace(/[\s-]*reasoning$/i,'').trim()||repo; | |
| const size=model.parameter_label||parsed?.[3]||''; | |
| const generation=model.version||parsed?.[1]||''; | |
| const name=[codename,size].filter(Boolean).join(' ')+(reasoning?' Reasoning':''); | |
| return {codename,size,generation,reasoning,name,description:model.description||'', | |
| release:model.release_date||'',releaseLabel:formatRelease(model.release_date)}; | |
| } | |
| export function formatRelease(iso) { | |
| if(typeof iso!=='string'||!/^\d{4}-\d{2}-\d{2}$/.test(iso))return ''; | |
| const date=new Date(iso+'T00:00:00Z'); | |
| return Number.isNaN(date.getTime())?'':new Intl.DateTimeFormat('en',{month:'short',day:'numeric',year:'numeric',timeZone:'UTC'}).format(date); | |
| } | |
| const versionParts=v=>String(v).split('.').map(x=>Number.parseInt(x,10)||0); | |
| export function compareVersions(a,b){const x=versionParts(a),y=versionParts(b);for(let i=0;i<Math.max(x.length,y.length);i++){const d=(y[i]||0)-(x[i]||0);if(d)return d;}return 0;} | |
| // Newest generation first; the registry's own order is kept inside a generation. | |
| export function groupModels(models) { | |
| const groups=new Map(); | |
| for(const model of models){const generation=modelPresentation(model).generation;if(!groups.has(generation))groups.set(generation,[]);groups.get(generation).push(model);} | |
| return [...groups].sort((a,b)=>compareVersions(a[0],b[0])).map(([generation,items])=>({generation,label:generation?`Decision ${generation}`:'Decision',models:items})); | |
| } | |
| export function orderedModels(models){return groupModels(models).flatMap(group=>group.models);} | |
| // The first base (non-Reasoning) model of the newest generation. A server | |
| // default is honoured only inside that generation. | |
| export function preferredModel(models,serverDefault) { | |
| const newest=groupModels(models)[0]?.models||[]; | |
| const named=newest.find(m=>m.id===serverDefault&&!modelPresentation(m).reasoning); | |
| return named||newest.find(m=>!modelPresentation(m).reasoning)||newest[0]||null; | |
| } | |
| export function statusName(model,models) { | |
| const p=modelPresentation(model),newest=groupModels(models)[0]?.generation; | |
| return p.generation&&newest&&p.generation!==newest?`${p.name} (${p.generation})`:p.name; | |
| } | |
| export function examplesForModel(model,catalog) { | |
| if(!Array.isArray(catalog)||!catalog.length||new Set(catalog.map(e=>e.id)).size!==catalog.length)throw Error('Invalid example catalog.'); | |
| const byId=new Map(catalog.map(e=>[e.id,e])); | |
| const examples=model.example_ids===undefined?catalog:model.example_ids.map(id=>{if(!byId.has(id))throw Error('Model example is missing.');return byId.get(id);}); | |
| if(model.default_example_id!==undefined&&!examples.some(e=>e.id===model.default_example_id))throw Error('Default example is outside this model’s catalog.'); | |
| return {examples,defaultExample:examples.find(e=>e.id===model.default_example_id)||examples[0]}; | |
| } | |
| export const exampleMode = example => example.surface === 'routing' ? 'routing' : Array.isArray(example.states) ? 'batch' : 'single'; | |
| // These are presentation prompts only. Runtime identity and answer semantics stay unchanged. | |
| function routingExampleForModel(example,model) { | |
| const modelId=model.wire_id||model.id; | |
| const variant=example.model_variants?.[modelId]; | |
| if(!variant)return example; | |
| if(variant&&( | |
| variant.state!==undefined&&(typeof variant.state!=='string'||!variant.state.trim()) | |
| ||Object.keys(variant).some(key=>!['state','questions'].includes(key)) | |
| ||Object.keys(variant.questions||{}).some(key=>!example.questions[key]) | |
| ))throw Error('Invalid model-specific routing example.'); | |
| const questions=Object.fromEntries(Object.entries(example.questions).map(([key,question])=>{ | |
| const override=variant?.questions?.[key]||{}; | |
| if(Object.keys(override).some(field=>!['instructions','criteria'].includes(field)))throw Error('Invalid routing question override.'); | |
| if(override.instructions!==undefined&&(typeof override.instructions!=='string'||!override.instructions.trim()))throw Error('Invalid routing question wording.'); | |
| if(override.criteria!==undefined&&( | |
| !question.criteria||Array.isArray(question.criteria)||!override.criteria||typeof override.criteria!=='object' | |
| ||Object.keys(override.criteria).some(candidate=>!(candidate in question.criteria)||typeof override.criteria[candidate]!=='string'||!override.criteria[candidate].trim()) | |
| ))throw Error('Invalid routing choice override.'); | |
| return [key,{...question,...override, | |
| ...(override.criteria?{criteria:{...question.criteria,...override.criteria}}:{})}]; | |
| })); | |
| return {...example,state:variant?.state||example.state,questions}; | |
| } | |
| export function studioExamplesForModel(model,catalog) { | |
| const modelCatalog=examplesForModel(model,catalog); | |
| const routing=catalog.filter(example=>exampleMode(example)==='routing').map(example=>routingExampleForModel(example,model)); | |
| // Without an allowlist the catalog holds one model-tuned copy of each | |
| // scenario per model; show each title once. | |
| const titles=new Set(); | |
| const scenarios=modelCatalog.examples.filter(example=>exampleMode(example)!=='routing'&&(model.example_ids!==undefined||!titles.has(example.title)&&titles.add(example.title))); | |
| return { | |
| examples:[...routing,...scenarios], | |
| defaultExample:routing[0]||modelCatalog.defaultExample, | |
| }; | |
| } | |
| export function modelReadiness(status) { | |
| if(!status)return {label:'Checking',state:'checking'}; | |
| if(!status.configured||status.phase==='unavailable')return {label:'Unavailable',state:'offline'}; | |
| if(!status.loaded||status.phase==='loading')return {label:'Connecting',state:'loading'}; | |
| if(status.running||status.phase==='running')return {label:'Working',state:'working'}; | |
| return {label:'Ready',state:'ready'}; | |
| } | |
| const tokenLabel=n=>n%1024===0?`${n/1024}K`:n.toLocaleString('en'); | |
| function optionHTML(m,selected) { | |
| const p=modelPresentation(m); | |
| const meta=[p.description,p.releaseLabel&&`Released ${p.releaseLabel}`].filter(Boolean).join(' · '); | |
| return `<button type="button" role="option" class="model-option" data-model="${esc(m.id)}" aria-selected="${m.id===selected}" tabindex="-1">` | |
| +`<span class="status-dot" aria-hidden="true"></span><span class="model-option-copy">` | |
| +`<span class="model-option-title"><span class="model-option-name">${esc(p.codename)}</span>${p.size?`<span class="model-option-size">${esc(p.size)}</span>`:''}${p.reasoning?'<span class="badge badge-reasoning">Reasoning</span>':''}<span class="model-option-state"></span></span>` | |
| +`${meta?`<span class="model-option-meta">${esc(meta)}</span>`:''}</span>` | |
| +`<svg class="model-option-check" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"><path d="m3.5 8.5 3 3 6-7"/></svg></button>`; | |
| } | |
| export function createModelMenu({getModels,getSelected,getStatus,onSelect,onOpen,reducedMotion}) { | |
| const $=id=>document.getElementById(id),trigger=$('model-trigger'),popover=$('model-popover'),options=$('model-options'); | |
| let open=false,focusIndex=0; | |
| const buttons=()=>Array.from(options.querySelectorAll('[role=option]')); | |
| function position(){ | |
| if(!open)return; | |
| const r=trigger.getBoundingClientRect(),margin=12,gap=8,width=Math.min(368,innerWidth-margin*2); | |
| const below=innerHeight-r.bottom-gap-margin,above=r.top-gap-margin,side=below>=Math.min(420,above)?'below':'above'; | |
| popover.style.width=width+'px';popover.style.maxHeight=Math.max(160,Math.min(560,side==='below'?below:above))+'px'; | |
| const height=popover.offsetHeight,left=Math.max(margin,Math.min(innerWidth-width-margin,r.right-width)); | |
| popover.style.left=left+'px';popover.style.top=(side==='below'?r.bottom+gap:r.top-gap-height)+'px';popover.dataset.side=side; | |
| } | |
| function focusAt(index){const list=buttons();focusIndex=(index+list.length)%list.length;list.forEach((b,i)=>b.tabIndex=i===focusIndex?0:-1);list[focusIndex]?.focus({preventScroll:true});list[focusIndex]?.scrollIntoView({block:'nearest'});} | |
| function updateStatuses(){ | |
| for(const button of buttons()){ | |
| const status=modelReadiness(getStatus(button.dataset.model));button.dataset.readiness=status.state;button.setAttribute('aria-description',status.label); | |
| button.querySelector('.model-option-state').textContent=status.state==='ready'||status.state==='checking'?'':status.label; | |
| button.setAttribute('aria-selected',String(button.dataset.model===getSelected())); | |
| } | |
| } | |
| function render(){ | |
| const selected=getSelected(); | |
| options.innerHTML=groupModels(getModels()).map((group,index)=>`<div class="model-group" role="group" aria-labelledby="model-group-${index}"><div class="model-group-label" id="model-group-${index}" role="presentation">${esc(group.label)}</div>${group.models.map(m=>optionHTML(m,selected)).join('')}</div>`).join(''); | |
| updateStatuses(); | |
| } | |
| function close(returnFocus=false){open=false;popover.hidden=true;trigger.setAttribute('aria-expanded','false');if(returnFocus)trigger.focus({preventScroll:true});} | |
| function show(index){ | |
| if(getModels().length<2||trigger.disabled)return; | |
| render();open=true;popover.hidden=false;trigger.setAttribute('aria-expanded','true');position(); | |
| const selected=buttons().findIndex(b=>b.dataset.model===getSelected());focusAt(index??Math.max(0,selected));onOpen?.(); | |
| } | |
| function choose(button){const id=button.dataset.model;close(true);if(id!==getSelected())onSelect(id);} | |
| trigger.addEventListener('click',()=>open?close(true):show()); | |
| trigger.addEventListener('keydown',e=>{if(e.key==='ArrowDown'||e.key==='ArrowUp'){e.preventDefault();show(e.key==='ArrowUp'?buttons().length-1:undefined);}else if(e.key==='Escape')close(true);}); | |
| options.addEventListener('click',e=>{const b=e.target.closest('[role=option]');if(b)choose(b);}); | |
| options.addEventListener('keydown',e=>{ | |
| if(['ArrowDown','ArrowUp','Home','End'].includes(e.key)){e.preventDefault();const index=e.key==='Home'?0:e.key==='End'?buttons().length-1:focusIndex+(e.key==='ArrowDown'?1:-1);focusAt(index);} | |
| else if(e.key==='Escape'){e.preventDefault();e.stopPropagation();close(true);} | |
| else if(e.key==='Tab')close(true); | |
| else if(e.key==='Enter'||e.key===' '){e.preventDefault();const b=document.activeElement.closest('[role=option]');if(b)choose(b);} | |
| }); | |
| document.addEventListener('pointerdown',e=>{if(open&&!popover.contains(e.target)&&!trigger.contains(e.target))close(false);}); | |
| document.addEventListener('focusin',e=>{if(open&&!popover.contains(e.target)&&!trigger.contains(e.target))close(false);}); | |
| addEventListener('resize',position);addEventListener('scroll',e=>{if(!popover.contains(e.target))position();},true); | |
| function identity(model,{animate=false,enabled=true}={}){ | |
| const p=modelPresentation(model),name=$('model-name'),previous=name.textContent; | |
| document.querySelectorAll('.model-name-ghost').forEach(e=>e.remove());name.getAnimations().forEach(a=>a.cancel()); | |
| name.textContent=p.codename;$('model-size').textContent=p.size; | |
| $('model-version').textContent=p.generation;$('model-version').hidden=!p.generation;$('model-badge').hidden=!p.reasoning; | |
| $('model-spec').textContent=[p.size,`Complete ${tokenLabel(model.complete_input_tokens)}`].filter(Boolean).join(' · '); | |
| $('input-budget').textContent=`Complete ${model.complete_input_tokens.toLocaleString('en')}-token input per question. Nothing is truncated.`; | |
| const many=getModels().length>1; | |
| trigger.disabled=!enabled||!many;trigger.dataset.single=String(!many);trigger.setAttribute('aria-label',`${p.name}${p.generation?`, Decision ${p.generation}`:''}. ${many?'Switch decision model.':'Decision model.'}`); | |
| if(animate&&!reducedMotion.matches&&previous!==p.codename){ | |
| const ghost=document.createElement('span');ghost.className='model-name-ghost';ghost.textContent=previous;ghost.setAttribute('aria-hidden','true');name.parentNode.append(ghost); | |
| const a=ghost.animate([{opacity:1,transform:'translateY(0)'},{opacity:0,transform:'translateY(-6px)'}],{duration:170,easing:'ease-out'});a.onfinish=()=>ghost.remove(); | |
| name.animate([{opacity:0,transform:'translateY(5px)'},{opacity:1,transform:'translateY(0)'}],{duration:190,easing:'ease-out'}); | |
| } | |
| updateStatuses(); | |
| } | |
| return {identity,updateStatuses,close,isOpen:()=>open}; | |
| } | |