File size: 6,649 Bytes
322102c
 
 
 
 
 
 
 
 
 
b16a546
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
---
title: Vector DB Explorer
emoji: πŸ”
colorFrom: indigo
colorTo: purple
sdk: docker
app_port: 7860
pinned: false
---

# Vector DB Explorer

A from-scratch vector database with a web UI β€” built to make embeddings, cosine similarity, and semantic search tangible and interactive.

---

## What it does

You give it text. It converts the text into a list of numbers (an **embedding**) that captures the meaning of the text, not just its keywords. When you search, your query goes through the same process and the system finds stored documents whose number-lists point in the same "direction" β€” that direction is **meaning**.

This is how production AI search works (Pinecone, Weaviate, pgvector). This project does the same thing from scratch with plain Python and a JSON file.

---

## Project structure

```
vector-db/
β”œβ”€β”€ vector_db.py          # The database: embed β†’ store β†’ search
β”œβ”€β”€ app.py                # FastAPI web server (3 API routes)
β”œβ”€β”€ demo.py               # CLI demo: populates the DB and prints results
β”œβ”€β”€ static/
β”‚   └── index.html        # Single-page UI (HTML + CSS + JS, no build step)
β”œβ”€β”€ data.json             # Auto-generated: stores all documents + embeddings
β”œβ”€β”€ requirements.txt      # Python dependencies
└── VECTOR_DB_EXPLAINED.md  # Deep-dive explanation of every concept
```

---

## How to run

### Prerequisites

- Python 3.10 or newer
- pip

### 1. Clone / download the project

```bash
cd path/to/vector-db
```

### 2. Create a virtual environment

```bash
# Windows
python -m venv venv
.\venv\Scripts\activate

# macOS / Linux
python3 -m venv venv
source venv/bin/activate
```

### 3. Install dependencies

```bash
pip install -r requirements.txt
```

> The first install downloads PyTorch + sentence-transformers (~1 GB total).  
> Subsequent installs are instant (everything is cached).

### 4. Seed the database (optional but recommended)

This populates `data.json` with 16 sample documents across tech, science, food, history, and sports.

```bash
python demo.py
```

You can skip this step and add documents through the UI instead.

### 5. Start the web server

```bash
python app.py
```

Open **http://127.0.0.1:8000** in your browser.

> The first startup downloads the `all-MiniLM-L6-v2` embedding model (~80 MB) from  
> Hugging Face. This only happens once β€” it is cached locally after the first run.

---

## Using the UI

### Search

Type anything in the search bar and press **Enter** or click **Search**.  
The query does not need to share any words with the stored documents β€” it searches by *meaning*.

Use the example chips below the search bar to try pre-built queries instantly.

**Reading the results:**

| Element | What it means |
|---|---|
| Score % (large number) | Cosine similarity Γ— 100. Higher = more similar. |
| Filled bar | Visual representation of the score. Color: green β‰₯ 50%, amber β‰₯ 30%, red below. |
| "Strong / Partial / Weak match" | Human-readable label for the score range. |
| `cosine = 0.XXXX` | The raw cosine similarity value (0 to 1). |
| Category / Topic badges | Metadata stored alongside the document. |

Clicking any document card in the **Corpus** section fires a search for that document automatically.

### Add a document

Fill in the text area, set a category and topic, then click **+ Add Document**.  
The server embeds the text and saves it to `data.json`. The corpus updates immediately.

### Filter the corpus

Use the filter input in the **Corpus** section to narrow documents by text, category, or topic.

---

## How it works (code level)

### Embedding (`vector_db.py β†’ VectorDB.add`)

```
"Machine learning models learn patterns from data"
          |
    SentenceTransformer("all-MiniLM-L6-v2")
          |
    [0.12, -0.44, 0.87, ..., 0.03]   ← 384 floats
```

The model was pre-trained on hundreds of millions of sentence pairs. It maps similar sentences to nearby regions of a 384-dimensional space.

### Storage (`vector_db.py β†’ VectorDB.save`)

Records are saved to `data.json` as plain JSON:

```json
{
  "id": 1,
  "text": "Machine learning models...",
  "metadata": { "category": "tech", "topic": "AI/ML" },
  "embedding": [0.048, -0.047, 0.070, ...]
}
```

No external database is needed. The downside is that large corpora (10k+ documents) become slow to load and search β€” that is why production systems use binary formats and vector indexes.

### Search (`vector_db.py β†’ VectorDB.search`)

```
Query: "how do computers learn from data?"
    |
embed query β†’ [0.11, -0.39, ...]
    |
compare against every stored embedding using cosine similarity
    |
sort by score, return top-k
```

**Cosine similarity formula:**

```
similarity(A, B) = (A Β· B) / (|A| Γ— |B|)
```

A score of `1.0` means identical direction (same meaning). A score of `0.0` means orthogonal (unrelated). The search is a **linear scan** β€” every stored vector is compared β€” which is exact but O(n). Production vector databases replace this with an HNSW index (O(log n)).

### Web server (`app.py`)

| Route | Method | Description |
|---|---|---|
| `/` | GET | Serves the single-page UI (`static/index.html`) |
| `/api/documents` | GET | Returns all documents without their embedding arrays |
| `/api/search` | POST | Embeds the query and returns ranked results |
| `/api/add` | POST | Embeds a new document and appends it to `data.json` |

Embedding is CPU-bound. The server runs it in a thread pool (`run_in_threadpool`) so the async event loop stays responsive during encoding.

---

## Running the CLI demo instead of the UI

```bash
python demo.py
```

This rebuilds `data.json` from scratch, then runs five example queries and prints ranked results to the terminal. Useful for quick testing without a browser.

---

## Dependency overview

| Package | Role |
|---|---|
| `sentence-transformers` | Loads `all-MiniLM-L6-v2` and converts text β†’ embeddings |
| `torch` | Neural network runtime (pulled in by sentence-transformers) |
| `numpy` | Efficient array operations used by the model |
| `fastapi` | Web framework for the API routes |
| `uvicorn` | ASGI server that runs the FastAPI app |
| `pydantic` | Request / response schema validation (used by FastAPI) |

---

## Going further

| What to try | How |
|---|---|
| Different embedding model | Change `model_name` in `VectorDB.__init__` to e.g. `"all-mpnet-base-v2"` (768 dims, higher quality) |
| More documents | Add via the UI or extend the `DOCUMENTS` list in `demo.py` |
| Explore `data.json` | Open it in any editor to see the raw 384-float vectors |
| See the concept deep-dive | Read `VECTOR_DB_EXPLAINED.md` |