A service where an AI analyzes two photos uploaded by a user, creates a "Moment Frame", and connects them with other moments worldwide based on semantic similarity and geographic distance.
| Category | Stack |
|---|---|
| Frontend | Next.js 16, React 19, TypeScript, MapLibre GL, h3-js |
| Backend | FastAPI, Motor (async MongoDB), Celery |
| AI | OpenAI / Google Gemini (Vision & Embeddings) |
| Storage | MongoDB Atlas Local ($vectorSearch), Redis (Celery broker) |
| Geo | H3 (Uber's Hexagonal Hierarchical Spatial Index) |
| Infra | Docker Compose (MongoDB + Redis), Makefile |
- Docker Desktop
- Python 3.11+
- Node.js 20+
make
# 1. Install dependencies (Python venv + npm)
make install
# 2. Configure backend/.env (refer to the Environment Variables section below)# 3. Initialize DB + Vector Index (first time only)
make setup
# 4. Start all services (Backend + Worker + Frontend)
make devAfter starting:
- Frontend: http://localhost:3000
- Backend API: http://localhost:8000/docs
| Command | Description |
|---|---|
make / make help | Print available Makefile target help center (default command) |
make install | Create Python venv + Install packages + npm install |
make setup | Start Docker → Wait for MongoDB boot (25s) → Create vector index |
make up | Start only MongoDB + Redis containers |
make down | Stop Docker containers |
make dev | Run all services in background (Docker + Backend + Worker + Frontend) |
make backend / worker / frontend | Run each service individually in the foreground |
make stop | Terminate all processes + Docker containers |
make status | Check Docker/process status |
make logs-backend / logs-worker / logs-frontend | Tail logs |
make endpoints | Print all available endpoints |
make reset | Clear DB volumes/uploads/build caches completely |
Running
make devdirectly aftermake resetwithoutmake setupwill cause the vector search index to be missing, and matching will not work.
# First install or full DB reset
make reset # Clear DB volumes + uploads + build caches
make setup # Start Docker → Wait for MongoDB Search engine (25s) → Create 3072-dim index
make dev # Start all services# Routine restart (keep DB)
make stop
make dev# InfrastructureMONGO_URI=mongodb://localhost:27018/?directConnection=trueMONGO_DB_NAME=paralineREDIS_URL=redis://localhost:6380/0# AI Provider Selection (openai | google)VISION_PROVIDER=googleEMBED_PROVIDER=google# OpenAI ConfigurationOPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxOPENAI_BASE_URL=https://api.openai.com/v1OPENAI_VISION_URI=/chat/completionsOPENAI_EMBEDDING_URI=/embeddingsOPENAI_VISION_MODEL=gpt-4oOPENAI_EMBEDDING_MODEL=text-embedding-3-large# Google Gemini ConfigurationGOOGLE_API_KEY=AIzaSyA...GOOGLE_BASE_URL=https://generativelanguage.googleapis.com/v1betaGOOGLE_VISION_URI=/models/{model}:generateContentGOOGLE_EMBEDDING_URI=/models/{model}:embedContentGOOGLE_VISION_MODEL=gemini-2.5-flashGOOGLE_EMBEDDING_MODEL=gemini-embedding-001# Common AI SettingsEMBEDDING_DIMENSIONS=3072# google: 3072, openai text-embedding-3-large: 3072, text-embedding-3-small: 1536AI_TEMPERATURE=0.7# Matching EngineSIMILARITY_THRESHOLD=0.75HORIZONTAL_MIN_DISTANCE_KM=200MAX_CONNECTIONS_PER_MOMENT=10# ServerBACKEND_PORT=8000PHOTO_UPLOAD_DIR=uploadsLOG_LEVEL=INFOparaline2/
├── backend/
│ ├── api/ # FastAPI Routers (upload, moments, connections, ...)
│ ├── services/ # ai_service, matching_service, exif_service
│ ├── scripts/ # init_vector_index, rebuild_connections, etc.
│ ├── main.py # FastAPI Entry Point
│ ├── celery_app.py # Celery Instance
│ ├── models.py # Pydantic Models
│ └── requirements.txt
├── frontend/
│ ├── app/ # Next.js App Router Pages
│ ├── components/
│ └── lib/ # API Client, deviceId, etc.
├── docs/ # Plannings, Task Specs
├── docker-compose.yml # MongoDB + Redis
└── Makefile
[Upload 2 photos]
↓
Extract EXIF (GPS + H3 Index)
↓
Save to Mongo (status=processing)
↓
Celery: analyze_moment_task
├─ AI Vision API → Output JSON
├─ AI Embeddings → High-dimensional Vector
└─ Update Mongo (status=completed)
↓
Celery: match_moment_task
└─ Mongo $vectorSearch → Match Similar Moments → Save connections → Create Notification
- Vertical (Same Location): At least one H3 grid cell overlaps between two moments.
- Horizontal (Distant Location): No H3 overlap + central coordinate distance ≥
HORIZONTAL_MIN_DISTANCE_KM(default 200km). - Distances in between are intentionally excluded from connection.
- Only candidates with Cosine Similarity ≥
SIMILARITY_THRESHOLD(default 0.75) are evaluated.
Non-standard ports are used to avoid conflicts with other projects:
| Service | Host Port | Container Port |
|---|---|---|
| MongoDB | 27018 | 27017 |
| Redis | 6380 | 6379 |
| Backend | 8000 | - |
| Frontend | 3000 | - |
