Skip to content

Commit 07f7a87

Browse files
authored
Merge pull request #737 from zackproser/codex/make-demos-embeddings-interactive-demo
Make embeddings demo standalone
2 parents e528bd0 + bd20954 commit 07f7a87

File tree

2 files changed

+53
-87
lines changed

2 files changed

+53
-87
lines changed

src/app/demos/embeddings/EmbeddingsDemoClient.tsx

Lines changed: 33 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import embedDiagram from '@/images/neural-network-transform.webp';
77
import { track } from '@vercel/analytics';
88
import NewsletterWrapper from '@/components/NewsletterWrapper';
99
import dynamic from 'next/dynamic';
10+
import { HARD_CODED_EMBEDDINGS } from './hardcodedEmbeddings';
1011

1112
// Add keyframes for the animation
1213
const animateFadeInUp = `
@@ -66,6 +67,23 @@ function getRandomVector(dimension: number = 20): number[] {
6667
return Array.from({ length: dimension }, () => (Math.random() * 2 - 1));
6768
}
6869

70+
// Deterministically generate a vector based on input text so results
71+
// remain the same across sessions without calling an API
72+
function getDeterministicVector(text: string, dimension: number = 20): number[] {
73+
let seed = 0;
74+
for (const char of text) {
75+
seed = (seed + char.charCodeAt(0)) % 2147483647;
76+
seed = (seed * 16807) % 2147483647;
77+
}
78+
const vector: number[] = [];
79+
for (let i = 0; i < dimension; i++) {
80+
seed = (seed * 16807) % 2147483647;
81+
const value = (seed / 2147483647) * 2 - 1;
82+
vector.push(parseFloat(value.toFixed(3)));
83+
}
84+
return vector;
85+
}
86+
6987
// Mini component to show a portion of the vector in a more readable way
7088
const EmbeddingVisualizer = ({ embeddings, inputText }: EmbeddingVisualizerProps) => {
7189
// If we have a lot of dimensions, just show a subset
@@ -309,7 +327,7 @@ export default function EmbeddingsDemoClient() {
309327
const [expandedSections, setExpandedSections] = useState([false, false, false, false]);
310328
const [selectedModel, setSelectedModel] = useState('text-embedding-ada-002');
311329
const [showSimilarityExamples, setShowSimilarityExamples] = useState(false);
312-
const [demoEmbeddings, setDemoEmbeddings] = useState<{[key: string]: number[]}>({});
330+
const [demoEmbeddings, setDemoEmbeddings] = useState<{[key: string]: number[]}>(HARD_CODED_EMBEDDINGS);
313331
const [quickStartStep, setQuickStartStep] = useState(0);
314332
const [completedSteps, setCompletedSteps] = useState([false, false, false, false]);
315333
const [interactedWithDemo, setInteractedWithDemo] = useState(false);
@@ -327,71 +345,14 @@ export default function EmbeddingsDemoClient() {
327345
if (Object.keys(demoEmbeddings).includes(text.toLowerCase())) {
328346
setEmbeddings(demoEmbeddings[text.toLowerCase()]);
329347
} else {
330-
// For other examples, generate random embeddings
331-
setEmbeddings(getRandomVector(20));
348+
// Generate deterministic embeddings for other examples
349+
setEmbeddings(getDeterministicVector(text));
332350
}
333351
}, [completedSteps, demoEmbeddings, setCompletedSteps, setEmbeddings, setInputText]);
334352

353+
// Pre-select a default example to show visualization immediately
335354
useEffect(() => {
336-
const examples = {
337-
// Animals - cluster 1
338-
"dog": getRandomVector(),
339-
"puppy": getRandomVector(),
340-
"cat": getRandomVector(),
341-
"kitten": getRandomVector(),
342-
"animal": getRandomVector(),
343-
344-
// Technology - cluster 2
345-
"computer": getRandomVector(),
346-
"laptop": getRandomVector(),
347-
"smartphone": getRandomVector(),
348-
"technology": getRandomVector(),
349-
350-
// Places - cluster 3
351-
"paris": getRandomVector(),
352-
"france": getRandomVector(),
353-
"tokyo": getRandomVector(),
354-
"japan": getRandomVector(),
355-
"travel": getRandomVector(),
356-
357-
// Food - cluster 4
358-
"pizza": getRandomVector(),
359-
"pasta": getRandomVector(),
360-
"sushi": getRandomVector(),
361-
"food": getRandomVector(),
362-
};
363-
364-
// Create clear semantic clusters by making similar concepts have similar vectors
365-
// Animal cluster
366-
const animalBase = examples.animal;
367-
examples.dog = animalBase.map((v, i) => v * 0.8 + Math.random() * 0.2);
368-
examples.puppy = examples.dog.map((v, i) => v * 0.9 + Math.random() * 0.1);
369-
examples.cat = animalBase.map((v, i) => v * 0.7 + Math.random() * 0.3);
370-
examples.kitten = examples.cat.map((v, i) => v * 0.9 + Math.random() * 0.1);
371-
372-
// Technology cluster
373-
const techBase = examples.technology;
374-
examples.computer = techBase.map((v, i) => v * 0.8 + Math.random() * 0.2);
375-
examples.laptop = examples.computer.map((v, i) => v * 0.9 + Math.random() * 0.1);
376-
examples.smartphone = techBase.map((v, i) => v * 0.7 + Math.random() * 0.3);
377-
378-
// Places cluster
379-
const travelBase = examples.travel;
380-
examples.paris = travelBase.map((v, i) => v * 0.7 + Math.random() * 0.3);
381-
examples.france = examples.paris.map((v, i) => v * 0.85 + Math.random() * 0.15);
382-
examples.tokyo = travelBase.map((v, i) => v * 0.65 + Math.random() * 0.35);
383-
examples.japan = examples.tokyo.map((v, i) => v * 0.85 + Math.random() * 0.15);
384-
385-
// Food cluster
386-
const foodBase = examples.food;
387-
examples.pizza = foodBase.map((v, i) => v * 0.75 + Math.random() * 0.25);
388-
examples.pasta = foodBase.map((v, i) => v * 0.7 + Math.random() * 0.3);
389-
examples.sushi = foodBase.map((v, i) => v * 0.65 + Math.random() * 0.35);
390-
391-
setDemoEmbeddings(examples);
392-
393-
// Pre-select a default example to show visualization immediately
394-
handleExampleSelect("dog");
355+
handleExampleSelect('dog');
395356
}, [handleExampleSelect]);
396357

397358
useEffect(() => {
@@ -469,34 +430,19 @@ export default function EmbeddingsDemoClient() {
469430

470431
const handleGenerateEmbeddings = async () => {
471432
if (!inputText.trim()) return;
472-
433+
473434
setIsLoading(true);
474435
try {
475-
const response = await fetch('/api/embeddings', {
476-
method: 'POST',
477-
headers: {
478-
'Content-Type': 'application/json',
479-
},
480-
body: JSON.stringify({
481-
inputText,
482-
model: selectedModel
483-
}),
484-
});
485-
486-
const data = await response.json();
487-
if (data && data.embeddings) {
488-
setEmbeddings(data.embeddings);
489-
track('embeddings_generated', { model: selectedModel, textLength: inputText.length });
490-
491-
// Calculate similarity/dissimilarity with existing embeddings
492-
const similarities = Object.entries(demoEmbeddings).map(([key, vector]) => ({
493-
key,
494-
similarity: calculateSimilarity(data.embeddings, vector)
495-
}));
496-
497-
// Log or visualize similarities as needed
498-
console.log('Similarities:', similarities);
436+
let vector: number[];
437+
const key = inputText.toLowerCase();
438+
if (demoEmbeddings[key]) {
439+
vector = demoEmbeddings[key];
440+
} else {
441+
vector = getDeterministicVector(inputText);
499442
}
443+
444+
setEmbeddings(vector);
445+
track('embeddings_generated', { model: selectedModel, textLength: inputText.length });
500446
} catch (error) {
501447
console.error('Error generating embeddings:', error);
502448
setEmbeddings(getRandomVector(20));
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export const HARD_CODED_EMBEDDINGS: Record<string, number[]> = {
2+
"dog": [-0.783, 0.636, 0.566, -0.389, 0.009, -0.207, 0.294, 0.691, -0.667, -0.871, 0.734, -0.17, 0.415, -0.878, 0.033, 0.423, -0.569, 0.794, 0.843, -1.021],
3+
"puppy": [-0.74, 0.611, 0.47, -0.466, -0.045, 0.0, 0.181, 0.552, -0.744, -0.977, 0.585, 0.0, 0.593, -0.855, -0.249, 0.448, -0.541, 0.746, 0.942, -1.065],
4+
"cat": [-0.582, 0.619, 0.601, -0.544, -0.042, -0.105, 0.32, 0.528, -0.86, -0.799, 0.734, -0.246, 0.503, -1.054, -0.236, 0.424, -0.579, 0.974, 0.751, -1.039],
5+
"kitten": [-0.7, 0.723, 0.425, -0.612, -0.096, 0.031, 0.244, 0.531, -0.857, -0.865, 0.723, -0.074, 0.611, -1.108, -0.014, 0.366, -0.621, 0.953, 0.924, -0.848],
6+
"animal": [-0.669, 0.572, 0.618, -0.378, 0.113, -0.038, 0.262, 0.461, -0.683, -0.975, 0.559, -0.107, 0.619, -0.895, -0.244, 0.39, -0.599, 1.037, 0.778, -0.902],
7+
"computer": [-0.973, 0.091, 0.941, -0.373, -0.581, -0.209, -0.796, -0.553, -0.146, 0.081, -0.583, -0.569, -0.61, -0.019, -0.436, -0.821, 0.545, -0.032, 0.423, -0.655],
8+
"laptop": [-0.889, 0.031, 1.022, -0.162, -0.45, -0.23, -1.025, -0.456, -0.236, 0.13, -0.568, -0.535, -0.532, -0.225, -0.539, -0.917, 0.75, 0.058, 0.38, -0.648],
9+
"smartphone": [-1.067, 0.088, 0.92, -0.195, -0.418, -0.205, -1.055, -0.455, -0.165, 0.025, -0.48, -0.683, -0.683, -0.152, -0.431, -1.051, 0.744, 0.076, 0.227, -0.755],
10+
"technology": [-1.057, 0.033, 0.868, -0.354, -0.552, -0.168, -1.09, -0.654, -0.144, -0.056, -0.576, -0.388, -0.666, 0.061, -0.372, -0.921, 0.574, 0.014, 0.255, -0.7],
11+
"paris": [1.041, 0.737, -0.732, -0.44, 0.549, 0.351, 0.896, -0.277, 0.776, 0.473, -0.248, 0.1, 0.882, 0.762, 0.119, 0.2, -0.862, -0.47, 0.636, -0.196],
12+
"france": [0.841, 0.849, -0.735, -0.213, 0.438, 0.509, 0.857, -0.158, 0.663, 0.424, -0.409, 0.291, 0.714, 0.588, -0.132, 0.035, -0.891, -0.468, 0.661, -0.123],
13+
"tokyo": [0.909, 0.616, -0.678, -0.279, 0.419, 0.337, 1.018, -0.229, 0.685, 0.304, -0.519, 0.041, 0.77, 0.717, 0.062, 0.043, -0.803, -0.449, 0.613, -0.096],
14+
"japan": [0.959, 0.839, -0.671, -0.2, 0.548, 0.458, 0.775, -0.12, 0.692, 0.353, -0.529, 0.141, 0.806, 0.754, -0.1, 0.245, -0.99, -0.416, 0.569, -0.134],
15+
"travel": [0.93, 0.727, -0.837, -0.358, 0.303, 0.48, 0.824, -0.062, 0.538, 0.453, -0.315, 0.079, 0.762, 0.69, -0.045, 0.033, -0.803, -0.566, 0.518, -0.31],
16+
"pizza": [-0.699, 0.162, 0.353, 0.274, -0.266, -0.262, 0.165, 0.449, 0.048, -0.255, -0.131, -0.868, -0.826, 0.358, 0.894, 0.175, -0.186, -0.733, 0.109, 0.948],
17+
"pasta": [-0.552, -0.041, 0.302, 0.475, -0.144, -0.01, 0.078, 0.583, 0.033, -0.312, -0.027, -0.832, -0.767, 0.488, 1.062, 0.28, -0.093, -0.748, 0.079, 0.818],
18+
"sushi": [-0.621, 0.16, 0.281, 0.332, -0.331, -0.127, -0.042, 0.675, 0.037, -0.096, -0.163, -0.962, -0.809, 0.554, 0.85, 0.226, -0.115, -0.668, -0.046, 1.072],
19+
"food": [-0.541, 0.158, 0.311, 0.355, -0.184, -0.105, -0.129, 0.513, -0.04, -0.208, -0.027, -0.823, -0.904, 0.503, 0.957, 0.106, -0.299, -0.756, 0.029, 0.921]
20+
};

0 commit comments

Comments
 (0)