Skip to content

Commit a245df7

Browse files
authored
Merge pull request #124 from DenisValeev/codex/fix-embedding-explorer
Fix Embedding Explorer script duplication
2 parents c4dba0c + 7ae3947 commit a245df7

1 file changed

Lines changed: 7 additions & 323 deletions

File tree

apps/embedding-explorer/app.js

Lines changed: 7 additions & 323 deletions
Original file line numberDiff line numberDiff line change
@@ -49,314 +49,6 @@
4949
return;
5050
}
5151

52-
const summaryCells = summaryGrid ? Array.from(summaryGrid.querySelectorAll('dd')) : [];
53-
const valueTableBody = valueTable;
54-
let activeSampleId = '';
55-
56-
function formatDecimal(value) {
57-
if (!Number.isFinite(value)) {
58-
return '0.000';
59-
}
60-
const rounded = Math.round(value * 1000) / 1000;
61-
return rounded.toFixed(3);
62-
}
63-
64-
function formatRange(min, max) {
65-
if (!Number.isFinite(min) || !Number.isFinite(max)) {
66-
return '— / —';
67-
}
68-
return `${formatDecimal(min)} / ${formatDecimal(max)}`;
69-
}
70-
71-
function calculateStats(vector) {
72-
const values = Array.isArray(vector) ? vector.map((entry) => Number(entry)).filter((entry) => Number.isFinite(entry)) : [];
73-
const length = values.length;
74-
75-
if (!length) {
76-
return {
77-
values: [],
78-
dimensions: 0,
79-
magnitude: 0,
80-
mean: 0,
81-
deviation: 0,
82-
min: null,
83-
max: null,
84-
zeroShare: 0,
85-
};
86-
}
87-
88-
let sum = 0;
89-
let sumSquares = 0;
90-
let min = values[0];
91-
let max = values[0];
92-
let zeroCount = 0;
93-
94-
values.forEach((value) => {
95-
sum += value;
96-
sumSquares += value * value;
97-
if (value < min) {
98-
min = value;
99-
}
100-
if (value > max) {
101-
max = value;
102-
}
103-
if (Math.abs(value) < 1e-9) {
104-
zeroCount += 1;
105-
}
106-
});
107-
108-
const mean = sum / length;
109-
let variance = 0;
110-
values.forEach((value) => {
111-
const delta = value - mean;
112-
variance += delta * delta;
113-
});
114-
variance /= length;
115-
116-
return {
117-
values,
118-
dimensions: length,
119-
magnitude: Math.sqrt(sumSquares),
120-
mean,
121-
deviation: Math.sqrt(variance),
122-
min,
123-
max,
124-
zeroShare: length ? zeroCount / length : 0,
125-
};
126-
}
127-
128-
function updateSummary(stats) {
129-
if (!summaryCells.length) {
130-
return;
131-
}
132-
133-
const entries = [
134-
stats.dimensions.toLocaleString(),
135-
formatDecimal(stats.magnitude),
136-
formatDecimal(stats.mean),
137-
formatDecimal(stats.deviation),
138-
formatRange(stats.min, stats.max),
139-
`${Math.round(stats.zeroShare * 100)}%`,
140-
];
141-
142-
entries.forEach((value, index) => {
143-
if (summaryCells[index]) {
144-
summaryCells[index].textContent = value;
145-
}
146-
});
147-
}
148-
149-
function renderExtrema(listElement, entries, placeholder) {
150-
if (!listElement) {
151-
return;
152-
}
153-
154-
listElement.innerHTML = '';
155-
156-
if (!entries.length) {
157-
const item = document.createElement('li');
158-
const text = document.createElement('span');
159-
text.className = 'placeholder';
160-
text.textContent = placeholder;
161-
item.appendChild(text);
162-
listElement.appendChild(item);
163-
return;
164-
}
165-
166-
entries.forEach((entry) => {
167-
const item = document.createElement('li');
168-
item.textContent = `#${entry.index}${formatDecimal(entry.value)}`;
169-
listElement.appendChild(item);
170-
});
171-
}
172-
173-
function renderValueRows(values) {
174-
if (!valueTableBody) {
175-
return;
176-
}
177-
178-
valueTableBody.innerHTML = '';
179-
180-
if (!values.length) {
181-
const row = document.createElement('tr');
182-
const cell = document.createElement('td');
183-
cell.colSpan = 3;
184-
cell.innerHTML = '<p class="placeholder">Enter an embedding vector to populate this table.</p>';
185-
row.appendChild(cell);
186-
valueTableBody.appendChild(row);
187-
return;
188-
}
189-
190-
const maxAbs = values.reduce((max, value) => {
191-
const magnitude = Math.abs(value);
192-
return magnitude > max ? magnitude : max;
193-
}, 0);
194-
195-
values.forEach((value, index) => {
196-
const row = document.createElement('tr');
197-
const indexCell = document.createElement('td');
198-
indexCell.textContent = `#${index + 1}`;
199-
200-
const valueCell = document.createElement('td');
201-
const valueSpan = document.createElement('span');
202-
valueSpan.textContent = formatDecimal(value);
203-
valueCell.appendChild(valueSpan);
204-
205-
const normalizedCell = document.createElement('td');
206-
const normalizedSpan = document.createElement('span');
207-
const normalized = maxAbs > 0 ? Math.abs(value) / maxAbs : 0;
208-
normalizedSpan.textContent = formatDecimal(normalized);
209-
normalizedCell.appendChild(normalizedSpan);
210-
211-
row.append(indexCell, valueCell, normalizedCell);
212-
valueTableBody.appendChild(row);
213-
});
214-
}
215-
216-
function updateInsights(vector) {
217-
const stats = calculateStats(vector);
218-
updateSummary(stats);
219-
220-
const entries = stats.values.map((value, index) => ({ index: index + 1, value }));
221-
const positive = entries
222-
.filter((entry) => entry.value > 0)
223-
.sort((a, b) => b.value - a.value)
224-
.slice(0, 3);
225-
const negative = entries
226-
.filter((entry) => entry.value < 0)
227-
.sort((a, b) => a.value - b.value)
228-
.slice(0, 3);
229-
230-
renderExtrema(positiveList, positive, 'Positive values appear here.');
231-
renderExtrema(negativeList, negative, 'Negative values appear here.');
232-
renderValueRows(stats.values);
233-
}
234-
235-
function formatVectorForInput(values) {
236-
return values.map((value) => formatDecimal(value)).join(', ');
237-
}
238-
239-
function setSampleMeta(description) {
240-
if (!sampleMeta) {
241-
return;
242-
}
243-
244-
sampleMeta.innerHTML = '';
245-
const paragraph = document.createElement('p');
246-
paragraph.textContent = description || 'Choose a sample to populate its description.';
247-
sampleMeta.appendChild(paragraph);
248-
}
249-
250-
function highlightSampleButtons() {
251-
if (!sampleList) {
252-
return;
253-
}
254-
255-
const buttons = sampleList.querySelectorAll('.sample-button');
256-
buttons.forEach((button) => {
257-
const isActive = button.dataset.sampleId === activeSampleId;
258-
button.classList.toggle('is-active', isActive);
259-
button.setAttribute('aria-pressed', isActive ? 'true' : 'false');
260-
});
261-
}
262-
263-
function parseVectorInput(input) {
264-
if (typeof input !== 'string') {
265-
return [];
266-
}
267-
268-
return input
269-
.split(/[,\s]+/)
270-
.map((chunk) => Number.parseFloat(chunk))
271-
.filter((value) => Number.isFinite(value));
272-
}
273-
274-
function selectSample(sample) {
275-
if (!sample) {
276-
activeSampleId = '';
277-
highlightSampleButtons();
278-
updateInsights([]);
279-
setSampleMeta('Choose a sample to populate its description.');
280-
return;
281-
}
282-
283-
activeSampleId = sample.id;
284-
highlightSampleButtons();
285-
const vector = Array.isArray(sample.vector) ? sample.vector : [];
286-
updateInsights(vector);
287-
setSampleMeta(sample.description || '');
288-
289-
if (embeddingInput) {
290-
embeddingInput.value = formatVectorForInput(vector);
291-
}
292-
}
293-
294-
function renderSampleToolbar() {
295-
if (!sampleList) {
296-
return;
297-
}
298-
299-
sampleList.innerHTML = '';
300-
301-
if (!samples.length) {
302-
const placeholder = document.createElement('p');
303-
placeholder.className = 'placeholder';
304-
placeholder.textContent = 'No curated samples available.';
305-
sampleList.appendChild(placeholder);
306-
return;
307-
}
308-
309-
const fragment = document.createDocumentFragment();
310-
samples.slice(0, 3).forEach((sample, index) => {
311-
const button = document.createElement('button');
312-
button.type = 'button';
313-
button.className = 'sample-button';
314-
button.dataset.sampleId = sample.id;
315-
button.textContent = sample.label || `Sample ${index + 1}`;
316-
button.addEventListener('click', () => {
317-
selectSample(sample);
318-
});
319-
fragment.appendChild(button);
320-
});
321-
322-
sampleList.appendChild(fragment);
323-
}
324-
325-
function setupSamples() {
326-
if (!sampleList || !sampleMeta || !summaryGrid || !valueTableBody) {
327-
return;
328-
}
329-
330-
renderSampleToolbar();
331-
if (samples.length) {
332-
selectSample(samples[0]);
333-
} else {
334-
updateInsights([]);
335-
}
336-
}
337-
338-
function setupManualInput() {
339-
if (!updateButton || !embeddingInput) {
340-
return;
341-
}
342-
343-
updateButton.addEventListener('click', () => {
344-
const values = parseVectorInput(embeddingInput.value);
345-
if (!values.length) {
346-
activeSampleId = '';
347-
highlightSampleButtons();
348-
updateInsights([]);
349-
setSampleMeta('Enter numbers separated by commas or spaces to update the insights.');
350-
return;
351-
}
352-
353-
activeSampleId = '';
354-
highlightSampleButtons();
355-
updateInsights(values);
356-
setSampleMeta('Custom embedding applied.');
357-
});
358-
}
359-
36052
const datasetCache = new Map();
36153
let activeDatasetId = '';
36254
let activeRecordId = '';
@@ -394,7 +86,6 @@
39486
const NEGATIVE_PLACEHOLDER = 'Negative values appear here.';
39587
const SAMPLE_PLACEHOLDER = 'Choose a sample to populate its description.';
39688
let activeSampleId = '';
397-
let currentVectorValues = [];
39889

39990
function safeText(value) {
40091
return typeof value === 'string' ? value.trim() : '';
@@ -715,17 +406,13 @@
715406

716407
if (!values.length) {
717408
const row = document.createElement('tr');
718-
const indexCell = document.createElement('td');
719-
indexCell.textContent = '#1';
720-
const valueCell = document.createElement('td');
721-
const valueSpan = document.createElement('span');
722-
valueSpan.textContent = '0.000';
723-
valueCell.appendChild(valueSpan);
724-
const normalizedCell = document.createElement('td');
725-
const normalizedSpan = document.createElement('span');
726-
normalizedSpan.textContent = '0.000';
727-
normalizedCell.appendChild(normalizedSpan);
728-
row.append(indexCell, valueCell, normalizedCell);
409+
const cell = document.createElement('td');
410+
cell.colSpan = 3;
411+
const message = document.createElement('p');
412+
message.className = 'placeholder';
413+
message.textContent = 'Enter an embedding vector to populate this table.';
414+
cell.appendChild(message);
415+
row.appendChild(cell);
729416
valueTable.appendChild(row);
730417
return;
731418
}
@@ -777,7 +464,6 @@
777464

778465
function updateSummaryForVector(values) {
779466
const stats = computeVectorStats(values);
780-
currentVectorValues = stats.values;
781467
renderSummary(stats);
782468

783469
const entries = stats.values.map((value, index) => ({ index: index + 1, value }));
@@ -2054,8 +1740,6 @@
20541740
applyFilter();
20551741
});
20561742

2057-
setupSamples();
2058-
setupManualInput();
20591743
populateDatasetSelect();
20601744

20611745
if (datasetSelect.value) {

0 commit comments

Comments
 (0)