Spaces:
				
			
			
	
			
			
		Sleeping
		
	
	
	
			
			
	
	
	
	
		
		
		Sleeping
		
	Commit 
							
							·
						
						76f2906
	
1
								Parent(s):
							
							84b80eb
								
Update index.html
Browse files- index.html +76 -3
    	
        index.html
    CHANGED
    
    | @@ -215,13 +215,86 @@ | |
| 215 | 
             
                }catch(e){ console.error(e); showError(e); setStatus('Error'); } finally{ busy=false; }
         | 
| 216 | 
             
              }
         | 
| 217 |  | 
| 218 | 
            -
              // Embedding Viewer
         | 
| 219 | 
             
              function getEmbState(){ if(!EmbCache[currentModel]) EmbCache[currentModel]={coords:null,neigh:null,ids:null,baseDrawn:false}; return EmbCache[currentModel]; }
         | 
| 220 | 
            -
              async function ensureEmbeddings(){ | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 221 | 
             
              function getBounds(coords){ const pts=Object.values(coords); let minX=Infinity,minY=Infinity,maxX=-Infinity,maxY=-Infinity; for(const [x,y] of pts){ if(x<minX)minX=x; if(y<minY)minY=y; if(x>maxX)maxX=x; if(y>maxY)maxY=y; } return {minX,minY,maxX,maxY}; }
         | 
| 222 | 
             
              function makeToXY(coords){ const {minX,minY,maxX,maxY}=getBounds(coords); const pad=18,w=canvas.width-pad*2,h=canvas.height-pad*2; return([x,y])=>{const nx=(x-minX)/(maxX-minX); const ny=(y-minY)/(maxY-minY); return [pad+nx*w,pad+(1-ny)*h];}; }
         | 
| 223 | 
             
              function drawBase(emb,toXY){ ctx.clearRect(0,0,canvas.width,canvas.height); ctx.fillStyle='#1a2a3a'; for(const id in emb.coords){ const [x,y]=toXY(emb.coords[id]); ctx.beginPath(); ctx.arc(x,y,2,0,Math.PI*2); ctx.fill(); } emb.baseDrawn=true; }
         | 
| 224 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 225 |  | 
| 226 | 
             
              // Events
         | 
| 227 | 
             
              let debounceId;
         | 
|  | |
| 215 | 
             
                }catch(e){ console.error(e); showError(e); setStatus('Error'); } finally{ busy=false; }
         | 
| 216 | 
             
              }
         | 
| 217 |  | 
| 218 | 
            +
              // Embedding Viewer (with cache)
         | 
| 219 | 
             
              function getEmbState(){ if(!EmbCache[currentModel]) EmbCache[currentModel]={coords:null,neigh:null,ids:null,baseDrawn:false}; return EmbCache[currentModel]; }
         | 
| 220 | 
            +
              async function ensureEmbeddings(){
         | 
| 221 | 
            +
                const emb=getEmbState();
         | 
| 222 | 
            +
                if(emb.coords&&emb.neigh&&emb.ids) return emb;
         | 
| 223 | 
            +
                const files=MODELS[currentModel].emb;
         | 
| 224 | 
            +
                emb.coords=await fetch(files.coords).then(r=>r.json());
         | 
| 225 | 
            +
                emb.neigh =await fetch(files.neigh ).then(r=>r.json());
         | 
| 226 | 
            +
                emb.ids   =new Set(Object.keys(emb.coords).map(Number));
         | 
| 227 | 
            +
                emb.baseDrawn=false;
         | 
| 228 | 
            +
                return emb;
         | 
| 229 | 
            +
              }
         | 
| 230 | 
            +
             | 
| 231 | 
             
              function getBounds(coords){ const pts=Object.values(coords); let minX=Infinity,minY=Infinity,maxX=-Infinity,maxY=-Infinity; for(const [x,y] of pts){ if(x<minX)minX=x; if(y<minY)minY=y; if(x>maxX)maxX=x; if(y>maxY)maxY=y; } return {minX,minY,maxX,maxY}; }
         | 
| 232 | 
             
              function makeToXY(coords){ const {minX,minY,maxX,maxY}=getBounds(coords); const pad=18,w=canvas.width-pad*2,h=canvas.height-pad*2; return([x,y])=>{const nx=(x-minX)/(maxX-minX); const ny=(y-minY)/(maxY-minY); return [pad+nx*w,pad+(1-ny)*h];}; }
         | 
| 233 | 
             
              function drawBase(emb,toXY){ ctx.clearRect(0,0,canvas.width,canvas.height); ctx.fillStyle='#1a2a3a'; for(const id in emb.coords){ const [x,y]=toXY(emb.coords[id]); ctx.beginPath(); ctx.arc(x,y,2,0,Math.PI*2); ctx.fill(); } emb.baseDrawn=true; }
         | 
| 234 | 
            +
             | 
| 235 | 
            +
              // ---- Fallback-aware neighborhood lookup ----
         | 
| 236 | 
            +
              async function drawNeighborhood(tokenId){
         | 
| 237 | 
            +
                const emb = await ensureEmbeddings();
         | 
| 238 | 
            +
             | 
| 239 | 
            +
                // If direct match is missing, try space-prefixed and lowercase variants.
         | 
| 240 | 
            +
                let id = tokenId;
         | 
| 241 | 
            +
                if (!emb.ids.has(id)) {
         | 
| 242 | 
            +
                  try {
         | 
| 243 | 
            +
                    const decoded = decodeId(tokenId);
         | 
| 244 | 
            +
                    // try " space + token"
         | 
| 245 | 
            +
                    const sp = await tokenizer(' ' + decoded, { add_special_tokens:false });
         | 
| 246 | 
            +
                    const cand1 = Array.isArray(sp.input_ids) ? sp.input_ids.at(-1) : null;
         | 
| 247 | 
            +
                    if (cand1 != null && emb.ids.has(cand1)) id = cand1;
         | 
| 248 | 
            +
                  } catch {}
         | 
| 249 | 
            +
                }
         | 
| 250 | 
            +
                if (!emb.ids.has(id)) {
         | 
| 251 | 
            +
                  try {
         | 
| 252 | 
            +
                    const low = await tokenizer(decodeId(tokenId).toLowerCase(), { add_special_tokens:false });
         | 
| 253 | 
            +
                    const cand2 = Array.isArray(low.input_ids) ? low.input_ids.at(-1) : null;
         | 
| 254 | 
            +
                    if (cand2 != null && emb.ids.has(cand2)) id = cand2;
         | 
| 255 | 
            +
                  } catch {}
         | 
| 256 | 
            +
                }
         | 
| 257 | 
            +
             | 
| 258 | 
            +
                // Still not found: show message and (re)draw base if needed
         | 
| 259 | 
            +
                if (!emb.ids.has(id)) {
         | 
| 260 | 
            +
                  embInfo.innerHTML = '<span class="warn">Neighborhood unavailable for this token (not in the current map).</span>';
         | 
| 261 | 
            +
                  nbrsEl.innerHTML = '';
         | 
| 262 | 
            +
                  if (!emb.baseDrawn) {
         | 
| 263 | 
            +
                    const toXY = makeToXY(emb.coords);
         | 
| 264 | 
            +
                    drawBase(emb, toXY);
         | 
| 265 | 
            +
                  }
         | 
| 266 | 
            +
                  return;
         | 
| 267 | 
            +
                }
         | 
| 268 | 
            +
             | 
| 269 | 
            +
                const toXY = makeToXY(emb.coords);
         | 
| 270 | 
            +
                drawBase(emb, toXY); // refresh for clarity
         | 
| 271 | 
            +
             | 
| 272 | 
            +
                const targetXY = toXY(emb.coords[id]);
         | 
| 273 | 
            +
                const list = (emb.neigh.neighbors?.[id]) || [];
         | 
| 274 | 
            +
             | 
| 275 | 
            +
                // neighbors
         | 
| 276 | 
            +
                ctx.fillStyle = '#93c5fd';
         | 
| 277 | 
            +
                for (const [nid] of list){
         | 
| 278 | 
            +
                  const pt = emb.coords[nid];
         | 
| 279 | 
            +
                  if (!pt) continue;
         | 
| 280 | 
            +
                  const [x,y] = toXY(pt);
         | 
| 281 | 
            +
                  ctx.beginPath(); ctx.arc(x, y, 3.4, 0, Math.PI*2); ctx.fill();
         | 
| 282 | 
            +
                }
         | 
| 283 | 
            +
                // target
         | 
| 284 | 
            +
                ctx.fillStyle = '#22d3ee';
         | 
| 285 | 
            +
                ctx.beginPath(); ctx.arc(targetXY[0], targetXY[1], 4.8, 0, Math.PI*2); ctx.fill();
         | 
| 286 | 
            +
             | 
| 287 | 
            +
                // chips
         | 
| 288 | 
            +
                nbrsEl.innerHTML = '';
         | 
| 289 | 
            +
                embInfo.textContent = 'Nearest neighbors:';
         | 
| 290 | 
            +
                for (const [nid, sim] of list.slice(0,18)){
         | 
| 291 | 
            +
                  const tok = decodeId(nid);
         | 
| 292 | 
            +
                  const b = document.createElement('div');
         | 
| 293 | 
            +
                  b.className = 'chip';
         | 
| 294 | 
            +
                  b.textContent = `${tok}  ${(sim*100).toFixed(1)}%`;
         | 
| 295 | 
            +
                  nbrsEl.appendChild(b);
         | 
| 296 | 
            +
                }
         | 
| 297 | 
            +
              }
         | 
| 298 |  | 
| 299 | 
             
              // Events
         | 
| 300 | 
             
              let debounceId;
         | 
