File size: 14,141 Bytes
f4cd8a9 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | const db = window.ARCHITECTURE;
const $ = id => document.getElementById(id);
const esc = value => String(value ?? '').replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
const icon = name => `<img src="assets/icons/${name}.svg" alt="">`;
const byId = new Map(db.models.map(m=>[m.id,m]));
const roleNames = {ar:'Autoregressive backbone',flow:'Generation architecture',encoder:'Encoder',codec:'Codec / vocoder',head:'Prediction',dsp:'Frontend / DSP',io:'Input / output'};
const state = {mode:'shared',selected:new Set(['higgs_audio_tts','soprano_tts','miotts']),model:'higgs_audio_tts',compare:null,component:'ar-qwen3',node:null,routes:{},blocks:[],zoom:1};
let overview=null, graphResult=null;
const route = model => model.routes[state.routes[model.id] || 0];
const technology = model => [...new Set(model.routes.flatMap(r=>r.nodes.filter(n=>n.component).map(n=>db.components[n.component].name)))];
const visible = () => {
const q=$('search').value.toLowerCase();
return db.models.filter(m=>(!$('task').value||m.task===$('task').value)&&[m.name,m.family,...m.variants,...technology(m)].join(' ').toLowerCase().includes(q)).sort((a,b)=>a.name.localeCompare(b.name));
};
$('count').textContent=db.models.length;
$('coverage').textContent=`Run ${db.models.length} models locally with audio.cpp`;
$('snapshot').textContent=`Spec snapshot ${db.revision.slice(0,8)}`;
$('task').innerHTML='<option value="">All tasks</option>'+db.tasks.map(t=>`<option value="${t.id}">${esc(t.name)}</option>`).join('');
$('task').value='';
function focusComponent(id,node=null){state.component=id;state.node=node;state.blocks=[];}
function selectedNode(){
if(state.mode==='shared')return null;
const comparison=state.node?.startsWith('compare:')&&state.compare;
const model=byId.get(comparison?state.compare:state.model);
return state.node?route(model).nodes.find(n=>n.id===(comparison?state.node.slice(8):state.node)):route(model).nodes.find(n=>n.component===state.component);
}
function firstComponent(model){return route(model).nodes.find(n=>n.component&&db.components[n.component].role==='ar')?.component||route(model).nodes.find(n=>n.component)?.component;}
function openModel(id){
if(state.mode==='shared')overview={component:state.component,blocks:[...state.blocks],zoom:state.zoom,scroll:[$('graph').scrollLeft,$('graph').scrollTop]};
state.mode='model';state.model=id;state.compare=null;focusComponent(firstComponent(byId.get(id)));state.zoom=1;
render();fit();$('title').focus({preventScroll:true});
}
function back(){
state.mode='shared';state.compare=null;
if(overview){state.component=overview.component;state.blocks=[...overview.blocks];state.zoom=overview.zoom;}
render();if(overview){[$('graph').scrollLeft,$('graph').scrollTop]=overview.scroll;}
}
function toggle(id){state.selected.has(id)?state.selected.delete(id):state.selected.add(id);render();fit();}
function library(){
$('models').innerHTML=visible().map(m=>{
const active=state.mode==='shared'?state.selected.has(m.id):state.model===m.id;
return `<div class="model-row"><button class="model ${active?'active':''}" aria-pressed="${active}" data-model="${m.id}"><span class="model-name">${esc(m.name)}</span><small>${esc(technology(m).join(' · '))}</small></button><button class="open-model" data-open="${m.id}" aria-label="Open ${esc(m.name)} pipeline" title="Open ${esc(m.name)} pipeline">${icon('arrow-up-right')}</button></div>`;
}).join('')||'<p class="empty">No matching models</p>';
$('models').querySelectorAll('[data-model]').forEach(b=>b.onclick=()=>state.mode==='shared'?toggle(b.dataset.model):openModel(b.dataset.model));
$('models').querySelectorAll('[data-open]').forEach(b=>b.onclick=()=>openModel(b.dataset.open));
}
function graphNode(n,prefix=''){
const c=n.component?db.components[n.component]:null;
return {id:prefix+n.id,label:c?.name||n.label,role:c?.role||n.kind||'input',component:n.component,optional:n.optional,description:n.detail||c?.summary||n.label,action:c?'component':null};
}
function modelGraph(model,prefix=''){
const r=route(model);
return {nodes:r.nodes.map(n=>graphNode(n,prefix)),edges:r.edges.map(e=>({...e,from:prefix+e.from,to:prefix+e.to}))};
}
function sharedGraph(){
const filtered=visible();
const chosen=$('scope-filter').value==='selected'?filtered.filter(m=>state.selected.has(m.id)):filtered;
const nodes=new Map(),edges=new Map();
for(const model of chosen){
const r=route(model),mapped=new Map();
for(const n of r.nodes){
if(!n.component)continue;
const c=db.components[n.component];
if(!$('frontends').checked&&['dsp','io'].includes(c.role))continue;
const repeat=r.nodes.filter(other=>other.component===n.component).length>1;
const key=n.component+(repeat?'@'+n.id:'');
mapped.set(n.id,key);
if(!nodes.has(key))nodes.set(key,{...graphNode(n),id:key,models:new Set()});
nodes.get(key).models.add(model.id);
}
// Collapse omitted input / DSP nodes without inventing conditioning edges.
function successors(id,visited=new Set()){
if(visited.has(id))return [];
visited.add(id);
return r.edges.filter(e=>e.from===id).flatMap(e=>mapped.has(e.to)?[mapped.get(e.to)]:successors(e.to,new Set(visited)));
}
for(const [id,key] of mapped){
const next=successors(id);
const targets=next.length?next:['model:'+model.id];
for(const target of targets){const ekey=key+'|'+target;if(!edges.has(ekey))edges.set(ekey,{from:key,to:target,models:new Set()});edges.get(ekey).models.add(model.id);}
}
nodes.set('model:'+model.id,{id:'model:'+model.id,label:model.name,role:'model',action:'toggle',model:model.id,models:new Set([model.id]),pressed:state.selected.has(model.id)});
}
const focused=chosen.some(m=>state.selected.has(m.id));
const dim=ids=>focused&&![...ids].some(id=>state.selected.has(id));
return {nodes:[...nodes.values()].map(n=>({...n,dim:dim(n.models)})),edges:[...edges.values()].map(e=>({...e,dim:dim(e.models),highlight:!dim(e.models)}))};
}
function graph(){
let data;
if(state.mode==='shared')data=sharedGraph();
else{
data=modelGraph(byId.get(state.model));
if(state.compare){const other=modelGraph(byId.get(state.compare),'compare:');data.nodes.push(...other.nodes);data.edges.push(...other.edges);}
}
if(!data.nodes.length){$('graph').innerHTML='<p class="empty">No models selected in this filter.</p>';graphResult=null;return;}
graphResult=AtlasGraph.render($('graph'),data.nodes,data.edges,{active:state.mode==='shared'?state.component:state.node||selectedNode()?.id,onNode:n=>{
if(n.action==='toggle'){toggle(n.model);return;}
focusComponent(n.component,state.mode==='model'?n.id:null);
if(state.mode==='shared'){
const users=visible().filter(m=>route(m).nodes.some(n=>n.component===state.component));
const all=users.every(m=>state.selected.has(m.id));users.forEach(m=>all?state.selected.delete(m.id):state.selected.add(m.id));
}
render();
}});
sizeGraph();
}
function sizeGraph(){if(graphResult){graphResult.svg.style.width=graphResult.width*state.zoom+'px';graphResult.svg.style.height=graphResult.height*state.zoom+'px';}$('zoom-level').textContent=Math.round(state.zoom*100)+'%';}
function fit(){if(graphResult){state.zoom=Math.min(1,($('graph').clientWidth-8)/graphResult.width,($('graph').clientHeight-8)/graphResult.height);sizeGraph();}}
function setZoom(value){state.zoom=Math.max(.15,Math.min(2.5,value));sizeGraph();}
function links(urls){return urls.map((url,i)=>`<a href="${esc(url)}" target="_blank" rel="noopener noreferrer">${i===0?'Architecture source':'Reference '+(i+1)} ↗</a>`).join('');}
function inspect(){
const c=db.components[state.component];
if(!c){$('component-title').textContent='Select a component';return;}
const [ink,fill]=AtlasGraph.colors[c.role]||AtlasGraph.colors.dsp;
$('component-title').textContent=c.name;$('component-role').textContent=roleNames[c.role]||c.role;$('component-role').style.cssText=`color:${ink};background:${fill}`;
$('component-description').textContent=c.summary;
const instance=selectedNode()?.detail;
$('instance-description').hidden=!instance;$('instance-description').textContent=instance||'';
$('evidence').innerHTML=links(c.sources||[]);
const stack=c.diagram?[c.diagram,...state.blocks]:[];
$('block-nav').innerHTML=stack.slice(0,-1).map((id,i)=>`<button data-depth="${i}">${esc(db.diagrams[id].title)}</button>`).join('');
$('block-nav').querySelectorAll('button').forEach(b=>b.onclick=()=>{state.blocks=state.blocks.slice(0,Number(b.dataset.depth));inspect();});
if(!stack.length){$('scope').textContent='Block diagram not yet curated';$('blocks').replaceChildren();$('block-caption').textContent='';return;}
const diagram=db.diagrams[stack.at(-1)];
$('scope').textContent=diagram.title;$('block-caption').textContent=diagram.scope;
AtlasGraph.render($('blocks'),diagram.blocks.map(n=>({...n,role:n.kind||c.role,action:n.expand?'expand':null,sublabel:n.expand?'EXPAND BLOCK':'',actionLabel:n.expand?'Expand '+n.label:n.label})),diagram.edges.map(([from,to])=>({from,to})),{compact:true,residuals:diagram.residuals,onNode:n=>{state.blocks.push(n.expand);inspect();}});
}
function peers(){
const c=db.components[state.component];$('relation-name').textContent=c?'/ '+c.name:'';
const related=db.models.filter(m=>(state.mode==='shared'||m.id!==state.model)&&m.routes.some(r=>r.nodes.some(n=>n.component===state.component)));
$('peers').innerHTML=related.map(m=>`<button data-peer="${m.id}" title="${state.mode==='shared'?'Open pipeline':'Compare pipeline'}">${esc(m.name)} ${state.mode==='shared'?'↗':'↔'}</button>`).join('')||'<p class="empty">No other family uses this component in the current registry.</p>';
$('peers').querySelectorAll('button').forEach(b=>b.onclick=()=>{if(state.mode==='shared')openModel(b.dataset.peer);else{state.compare=b.dataset.peer;focusComponent(state.component);render();fit();}});
}
function heading(){
const model=byId.get(state.model),shared=state.mode==='shared';
$('breadcrumb').hidden=shared;$('breadcrumb-model').textContent=model.name;
$('view-label').textContent=shared?'ARCHITECTURE EXPLORER':'MODEL DETAIL';
$('title').textContent=shared?'Shared building blocks':state.compare?model.name+' + '+byId.get(state.compare).name:model.name;
$('title').tabIndex=-1;
$('family').hidden=shared;$('family').textContent=model.family+(state.compare?' / '+byId.get(state.compare).family:'');
$('variants').hidden=shared;$('variants').innerHTML=model.variants.map(v=>`<span>${esc(v)}</span>`).join('');
$('subtitle').textContent=shared?`${state.selected.size} selected · ${visible().length} matching models`:db.tasks.find(t=>t.id===model.task).name;
$('clear').hidden=shared?!state.selected.size:!state.compare;$('clear').textContent=shared?'Clear selection':'Clear comparison';
$('model-info').hidden=shared;$('summary').textContent=model.summary;
$('detail-status').textContent=model.detailStatus;
$('inputs').innerHTML=(route(model).inputs||model.inputs).map(i=>`<span>${esc(i.type.toUpperCase())} · ${esc(i.label)}<em>${i.required?'required':'optional'}</em></span>`).join('');
$('model-links').innerHTML=links(model.sources.slice(0,2))+`<a href="https://github.com/0xShug0/audio.cpp/blob/${db.revision}/${esc(model.usageDoc)}" target="_blank" rel="noopener noreferrer">audio.cpp usage ↗</a>`;
$('graph-label').textContent=shared?'SHARED ARCHITECTURE':state.compare?'PIPELINE COMPARISON':'MODEL PIPELINE';
$('scope-filter').hidden=!shared;$('frontend-control').hidden=!shared;
$('variant-wrap').hidden=shared||model.routes.length<2;
$('variant').innerHTML=model.routes.map((r,i)=>`<option value="${i}">${esc(r.name)}</option>`).join('');$('variant').value=state.routes[model.id]||0;
$('packages').hidden=shared||!model.packages.length;
$('package-list').innerHTML=model.packages.map(p=>`<div>${esc(p.display_name)}<br><code>${esc(p.id)}</code></div>`).join('');
}
function render(){heading();library();graph();inspect();peers();}
$('search').oninput=()=>{render();fit();};$('task').onchange=()=>{render();fit();};$('scope-filter').onchange=()=>{graph();fit();};$('frontends').onchange=()=>{graph();fit();};
$('variant').onchange=()=>{state.routes[state.model]=Number($('variant').value);focusComponent(firstComponent(byId.get(state.model)));render();fit();};
$('back').onclick=back;$('clear').onclick=()=>{if(state.mode==='shared')state.selected.clear();else{state.compare=null;focusComponent(firstComponent(byId.get(state.model)));}render();fit();};
$('zoom-in').onclick=()=>setZoom(state.zoom*1.2);$('zoom-out').onclick=()=>setZoom(state.zoom/1.2);$('fit').onclick=fit;
$('export').onclick=()=>{
if(!graphResult){$('status').textContent='No graph to export.';return;}
const svg=graphResult.svg.cloneNode(true);svg.removeAttribute('style');
const style=document.createElementNS('http://www.w3.org/2000/svg','style');style.textContent='text{font-family:"Noto Sans",sans-serif}.dim{opacity:.2}';svg.prepend(style);
const url=URL.createObjectURL(new Blob([new XMLSerializer().serializeToString(svg)],{type:'image/svg+xml'}));
const a=document.createElement('a');a.href=url;a.download=state.mode==='shared'?'shared-architecture.svg':state.model+'-pipeline.svg';a.click();setTimeout(()=>URL.revokeObjectURL(url),1000);
};
document.querySelector('.brand').onclick=e=>{e.preventDefault();if(state.mode==='model')back();};
const inspector=document.querySelector('.inspector');
$('expand-detail').onclick=()=>{
if($('detail-dialog').open){$('detail-dialog').close();return;}
$('detail-dialog').append(inspector);
$('expand-detail').innerHTML=icon('x');
$('expand-detail').title='Close component detail';
$('expand-detail').setAttribute('aria-label','Close component detail');
$('detail-dialog').showModal();
};
$('detail-dialog').onclose=()=>{
document.querySelector('.workspace').append(inspector);
$('expand-detail').innerHTML=icon('maximize');
$('expand-detail').title='Expand component detail';
$('expand-detail').setAttribute('aria-label','Expand component detail');
$('expand-detail').focus({preventScroll:true});
};
window.addEventListener('resize',fit);
document.fonts.ready.then(()=>{render();fit();});
|