Recall – 로컬 멀티모달 시맨틱 검색 for your files
Source: Hacker News
Local multimodal memory with semantic search.
이미지, 오디오, 비디오, PDF 및 텍스트를 로컬 벡터 데이터베이스에 임베드하고 — 자연어 쿼리로 모든 것을 찾을 수 있습니다. *“team dinner”*에 대한 텍스트 검색으로 사진을 찾아낼 수 있습니다. 사진에 텍스트 메타데이터가 없더라도 말이죠.
Comes with an animated setup wizard and a Raycast extension for instant visual search.
애니메이션 설정 마법사와 즉시 시각 검색을 위한 Raycast 확장이 포함되어 있습니다.
Powered by Gemini Embedding 2 (768‑dim, free tier) and ChromaDB stored entirely on your machine.
Gemini Embedding 2 (768‑차원, 무료 티어)와 ChromaDB를 기반으로 하며, 모든 데이터는 완전히 사용자의 머신에 저장됩니다.
작동 방식
You Gemini Embedding 2 ChromaDB (local)
| | |
|-- team-dinner.jpg -------->|-- 768-dim vector ------>|-- stored on disk
|-- meeting-notes.pdf ------>|-- 768-dim vector ------>|-- stored on disk
|-- "team dinner" (query) -->|-- query vector -------->|-- cosine search
|, validates your key, saves to `.env` |
| **Folder picker**| Checkbox list of your home folders with live file counts |
| **Indexing** | Progress bar with current filename, auto‑retries on rate limits |
| **Raycast card**| Prints pre‑filled Python Package Path and Python Binary — just copy‑paste |
수동 키 설정 (필요한 경우)
cp .env.example .env
# then edit .env and add:
# GEMINI_API_KEY=your_key
Python API
from vector_embedded_finder import search, ingest_file, ingest_directory, count
# Embed a single file — image, PDF, audio, video, or text
ingest_file("~/Photos/team-dinner.jpg")
# Embed an entire directory (recursive by default)
ingest_directory("~/Documents/", source="docs")
# Search with natural language
matches = search("team dinner at the rooftop", n_results=5)
for m in matches:
print(f"{m['file_name']} {m['similarity']:.0%} match {m['file_path']}")
# Housekeeping
print(f"{count()} items indexed")
ingest_file은 "status"("embedded" | "skipped" | "error")를 포함하는 dict를 반환합니다. 파일은 SHA‑256으로 중복 제거되며, 동일한 파일을 다시 삽입해도 아무 작업도 수행되지 않습니다.
Raycast 확장
런처에서 바로 이미지 썸네일이 포함된 시각적 그리드 검색.
Setup
cd raycast
npm install
npx ray develop
Raycast를 열고 Memory Search를 검색하세요. 첫 실행 시, 환경설정으로 이동하여 다음을 설정합니다:
| Preference | Value (example) |
|---|---|
| Python Package Path | /Users/you/vector-embedded-finder |
| Python Binary | /usr/bin/python3 |
| Gemini API Key | your key (or leave blank if set in .env) |
팁: 먼저 python setup_wizard.py를 실행하세요 — 해당 값들이 미리 채워진 형태로 출력됩니다.
Commands
| Command | What it does |
|---|---|
| Memory Search | 이미지/비디오 썸네일이 포함된 그리드 UI, 400 ms 디바운스 실시간 검색 |
| Memory Open | 헤드리스 — 쿼리를 입력하면 가장 일치하는 파일을 즉시 엽니다 |
지원되는 파일 유형
| 카테고리 | 형식 |
|---|---|
| 이미지 | .png .jpg .jpeg .webp .gif .bmp .tiff |
| 오디오 | .mp3 .wav .m4a .ogg .flac .aac |
| 비디오 | .mp4 .mov .avi .mkv .webm |
| 문서 | .pdf |
| 텍스트 | .txt .md .csv .json .yaml .yml .toml .py .js .ts .go .rs .sh 등 |
구성
| Variable | Default | Description |
|---|---|---|
GEMINI_API_KEY | (required) | Google Gemini에서 제공하는 무료 키 |
VEF_DATA_DIR | ./data | ChromaDB가 벡터를 저장하는 디렉터리 |
아키텍처
vector_embedded_finder/
config.py — env, API key, supported types, paths
embedder.py — Gemini Embedding 2 (text, image, audio, video, PDF)
store.py — ChromaDB layer: cosine distance, SHA‑256 dedup, upsert
search.py — natural language search with similarity scoring
ingest.py — file detection → embedding → storage pipeline
utils.py — hashing, MIME detection, timestamp helpers
raycast/
src/lib/runner.ts — Python bridge: spawnSync + JSON envelope protocol
src/search-memory.tsx — grid search UI with thumbnails
src/open-memory.tsx — headless instant file opener
setup_wizard.py — animated CLI setup: key → folders → index → Raycast card
모든 벡터는 data/chromadb/에 로컬로 저장됩니다. 외부로 나가는 트래픽은 Google에 대한 임베딩 API 호출뿐이며, 파일은 절대 머신을 떠나지 않습니다.
라이선스
MIT