A personal analytics tool that builds interactive visual maps of your life from two data sources:
-
Photo Interest Map — Streams photos from iCloud, generates CLIP embeddings, clusters them semantically, and outputs an interactive 2D scatter plot showing your interests over time.
-
Spending Map — Parses bank statements (CSV, XLSX, PDF, or Plaid API), embeds transactions with sentence-transformers, clusters by entity/purpose (not payment rail), and outputs a 3D force-directed graph of your spending patterns with an AI-generated narrative.
Both pipelines run locally on your GPU. No data leaves your machine (unless you opt into Gemini API for labeling).
- Windows/Linux/macOS
- Python 3.11+
- NVIDIA GPU with CUDA (tested on RTX 4060 8GB)
- ffmpeg (optional, for video keyframe extraction)
git clone https://github.com/youruser/LifeGraph.git
cd LifeGraph
# Create venv
python -m venv venv
source venv/bin/activate # or venv\Scripts\activate on Windows
# Install PyTorch with CUDA
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121
# Install dependencies
pip install -r requirements.txt
# Copy env template and fill in your credentials
cp .env.example .env# Stream from iCloud, embed with CLIP, cluster, visualize
python run.py embed
python run.py cluster
python run.py visualize
# Or all at once
python run.py all
# Re-label clusters with Gemini Vision
python run.py relabel --model gemini-3-flash-preview
# Re-label with a local VLM (no API needed)
python run.py relabel --local --server-url http://localhost:8080Output: output/interest_map.html — interactive scatter plot with temporal slider, hover thumbnails, cluster labels.
# Parse bank statements
python run.py spending-ingest --csv "statements/*.csv"
python run.py spending-ingest --xlsx "statements/*.xlsx"
python run.py spending-ingest --pdf "statements/*.pdf"
# Embed + cluster + visualize
python run.py spending-embed
python run.py spending-cluster
python run.py spending-visualize
# Or full pipeline
python run.py spending-all --csv "statements/*.csv" --currency NGN
# Entity-first reclustering (groups by person/business, not payment platform)
python run.py spending-recluster
# Manage merchant aliases (user corrections)
python run.py spending-aliases --show
python run.py spending-aliases --generate # LLM-suggested aliases
# Generate AI narrative of spending patterns
python run.py spending-narrate --local
python run.py spending-narrate --model gemini-2.5-flash
# Cross-reference photos + spending
python run.py narrate-combined --localOutput: output/spending_map.html — 3D force-directed graph with narrative panel.
The spending pipeline uses a correction file (data/spending/merchant_aliases.json) to map merchant names to human-readable labels. This is where you tell the system that "O.A.S BAKESHOP" is actually a gym, or that "SULAIMAN MURTALA" is your suya guy.
{
"REGISTERED BIZ NAME": {"label": "What it actually is", "macro": "Category"},
"SOME PERSON": {"label": "Friend (nickname)", "macro": "Friends"},
"RANDOM SHOP LLC": {"label": "Grocery store", "macro": "Food"}
}After editing aliases, recluster: python run.py spending-recluster
For cluster labeling without API rate limits or safety filters, use a local LLM via llama-server:
# Download llama.cpp + a vision model
# Start the server
./llama-server -hf ggml-org/Qwen2.5-VL-7B-Instruct-GGUF --port 8080 -ngl 99
# Label photo clusters
python run.py relabel --local
# Label spending clusters
python run.py spending-relabel --local
# Generate narratives
python run.py spending-narrate --localiCloud / Bank CSV / PDF / Plaid
|
v
CLIP (photos) or sentence-transformers (transactions)
|
v embeddings
UMAP -> HDBSCAN -> auto-label clusters
|
v
Interactive HTML visualization (Plotly / 3d-force-graph)
+
AI-generated behavioral narrative
LifeGraph/
├── run.py # CLI entrypoint
├── config.py # All settings
├── .env.example # Credential template
├── requirements.txt
├── src/
│ ├── icloud_stream.py # iCloud auth + photo streaming
│ ├── video_keyframes.py # ffmpeg keyframe extraction
│ ├── embedder.py # CLIP embedding engine
│ ├── cluster.py # UMAP + HDBSCAN (shared)
│ ├── visualize.py # Photo map HTML generation
│ ├── labeler.py # Gemini + local LLM labeling
│ ├── combined_narrative.py # Cross-reference photos + spending
│ └── spending/
│ ├── parser.py # CSV auto-detect + Transaction model
│ ├── xlsx_parser.py # Excel statement parser
│ ├── pdf_parser.py # PDF statement parser
│ ├── plaid_client.py # Optional Plaid API
│ ├── embedder.py # Sentence-transformer embedder
│ ├── labeler.py # Keyword + LLM cluster labeling
│ ├── entities.py # Entity extraction + alias system
│ ├── recluster.py # Entity-first reclustering
│ ├── narrate.py # AI spending narrative
│ └── visualize.py # 3D spending map HTML
├── data/ # gitignored — embeddings, clusters
├── output/ # gitignored — generated HTML + narratives
├── bank_data/ # gitignored — raw bank statements
└── models/ # gitignored — LLM model files
All processing happens locally. Your photos are streamed into memory, embedded, and discarded — raw media is never saved to disk. Bank statements are parsed into structured data stored locally. The only external calls are:
- iCloud API (to stream your photos)
- Gemini API (optional, for cluster labeling)
- Plaid API (optional, for bank transaction import)
- HuggingFace (one-time model download)
You can run the entire pipeline offline after the initial model download by using --local flags.
MIT