This repository turns the course's notebook memory into a continuously running device. The central design rule is simple: robot/device can import robot/brain, but robot/brain never imports robot/device. You can therefore understand and test the memory logic without a camera, browser, web server, or thread.
| Course Concept | Implementation |
|---|---|
| Store vectors and payloads in an embedded shard | Memory in robot/brain/memory.py |
| Search notes by meaning | Nomic text vectors in robot/brain/models.py and Memory.best_taught |
| Transcribe voice locally | models.transcribe with Whisper |
| Teach an object with image examples | Robot.teach and Memory.teach |
| Recognize with nearest search and a threshold | Memory.recognize |
| Calibrate with held-out views | testdata/verify_scores.py |
The robot adds object detection, tracking, a live camera loop, persistent sightings, and a phone interface around those same ideas.
robot/brain/core.py:Robot.process_frameconnects the full recognition loop.teachandaskare the two voice actions.robot/brain/memory.py: the Qdrant Edge schema, writes, recognition query, and recall query.robot/brain/models.py: lazy loaders for CLIP, Nomic, and Whisper.robot/brain/detect.py: YOLOE detection, BoT-SORT tracking, crop masks, and the stability gate.robot/device/live.py: camera and worker threads, button actions, and the bridge toRobot.robot/device/server.pyandrobot/device/page.html: HTTP routes and the browser interface.robot/app.py: command-line setup, live startup, and file replay.
For each stable tracked object:
camera frame
-> Detector.process
-> padded object crop
-> models.embed_crop
-> Memory.recognize
-> nearest taught image vector
-> score compared with RECOGNIZE_THRESHOLD
Detector discards YOLOE's class label. It uses only the box, segmentation mask, confidence, and tracking ID. That makes teaching a memory operation instead of detector retraining.
Robot.process_frame limits memory queries to stable tracks and rechecks them every two seconds. When a track matches, the robot writes one seen point for that tracked appearance. It also chooses one prominent unknown as the teach target so background detections do not compete for the button.
TEACH press
-> save the current unknown crop
-> record WAV
-> Whisper transcript
-> labels.parse_label
-> CLIP image vector + Nomic text vector
-> Memory.teach
A taught view contains both named vectors. Teaching the same label again adds a point. It does not overwrite the first view. Recognition asks for the closest of all taught views, which is why two or three angles work better than one.
ASK press
-> record WAV
-> Whisper question
-> Nomic query vector
-> choose the taught object
-> retrieve its latest sightings by time
If the question contains an exact taught name, recall narrows candidates to named objects first. This prevents a semantically similar but differently named object from replacing an explicit request. The final answer comes from stored payload fields such as label, ts, where, and thumb; no language model generates it.
One Qdrant Edge shard lives in edge-data/. Points use one of three kind values:
| Kind | Vectors | Purpose |
|---|---|---|
taught |
image and text |
A named example view and its spoken description. |
seen |
image |
A later sighting of a known object. |
ignored |
image |
A dismissed piece of clutter that should remain hidden. |
The image vector has 512 dimensions and uses CLIP. The text vector has 768 dimensions and uses Nomic. Both use cosine distance. Payloads hold the human-readable label, transcript, timestamp, location, and thumbnail paths.
The application flushes after each write because disconnecting power is the physical robot's normal shutdown. The R control closes and reloads the shard to demonstrate that recall comes from device storage.
LiveApp keeps camera rendering responsive by separating four jobs:
| Job | Responsibility |
|---|---|
| Main loop | Read frames, draw boxes, and publish JPEG images. |
| Detection worker | Run YOLOE, embed crops, and query memory. |
| Key worker | Process button and keyboard actions in order. |
| Voice worker | Record or receive audio, transcribe it, then teach or ask. |
Shard access is serialized inside Memory. Live tracking state is protected by LiveApp.lock. The lock order is live state first, then memory.
.envcontains camera-dependent settings.robot/config.pyvalidates and loads them.edge-data/contains the Qdrant shard, thumbnails, and saved location.~/.cache/fastembed/contains downloaded embedding models.cert/contains a generated local HTTPS certificate when a phone connects.
Configuration precedence is: source defaults, .env, exported environment variables, then command-line flags where a flag exists.
- Change recognition and detection thresholds in
.env, then usetestdata/verify_scores.py. - Change spoken label parsing in
robot/brain/labels.py. - Change recall behavior in
Robot.askand the correspondingMemoryqueries. - Change the browser presentation in
robot/device/page.htmlwithout touching memory.
Run the bundled image replay after changing detection, cropping, encoders, or recognition:
uv run python -m robot.app --source testdata/Do not test destructive changes against a shard you want to keep. Pass --data with a separate directory.