Self-hosted retrieval-augmented generation stack for searching and chatting over your personal Telegram history. The project ships with ingestion, hybrid retrieval, and an authenticated UI; everything runs locally via Docker Compose.
- Index DMs, groups, channels, and Saved Messages with Telethon and store content in Postgres
- Hybrid Vespa retrieval (vector + BM25 + recency) with optional VoyageAI rerank
- Chat workflow that compresses context, answers strictly from your data, and returns citations
- Astro + React interface with login, filters, live search results, and model selection
- Docker-first deployment with automatic Vespa package activation on startup
[indexer] Telethon daemon or one-shot -> chunk -> cache -> OpenAI embed -> Vespa upsert
|-- Postgres (sync state, embedding cache, chunks)
`-- Telethon session persisted on Docker volume
[api] FastAPI -> /auth, /models, /search, /chat (LLM answer + citations)
[ui] Astro + React -> login, filters, hybrid search, chat
[vespa] Hybrid retrieval + recency boosting (auto-deployed on startup)
- Docker and Docker Compose
- Telegram API ID + hash and a phone number for login
- OpenAI API key (for embeddings/LLM)
- Optional: VoyageAI API key for reranking
- Clone and configure the repository:
git clone <repo> telegram-rag cd telegram-rag cp .env.example .env
- Edit
.envwith your credentials. Required values includeAPP_USER,APP_USER_HASH_BCRYPT,TELEGRAM_API_ID,TELEGRAM_API_HASH,OPENAI_API_KEY. Optional keys such asVOYAGE_API_KEYenable reranking. - Install local tooling (recommended for contributors):
make install # api + indexer dependencies make ui-install # ui dependencies pre-commit install # enable formatting/lint hooks
To generate a bcrypt hash for the login password:
python - <<'PY'
import bcrypt; print(bcrypt.hashpw(b"your-password", bcrypt.gensalt()).decode())
PYdocker compose up -d api vespa postgres indexer vespa-deploy
(cd ui && npm run dev)- UI: http://localhost:4321 (development server)
- API: http://localhost:8000 (health probe at
/healthz) - Vespa status: http://localhost:19071/ApplicationStatus
docker compose up -d --buildThe vespa-deploy service waits for Vespa to become healthy and then pushes vespa/application automatically.
-
Near-live daemon:
python main.py(no--once) attaches Telethon event handlers, replays the last few minutes on startup/reconnect, and streams new messages into Vespa. -
Initial backfill: progress is checkpointed per chat in
/sessions/backfill_state.json(override with--backfill-state-path). The daemon resumes from the last storedmessage_idautomatically. -
Hourly sweep: by default the daemon re-scans the last 7 days every 60 minutes to catch late edits; tune with
--hourly-sweep-daysand--hourly-sweep-interval-minutes. -
Telegram deletions are intentionally ignored—once ingested, messages remain searchable to preserve historical context.
-
First full sync:
docker compose run --rm indexer python main.py --once -
Target specific chats/dates (example):
docker compose run --rm indexer python main.py --once \ --chats '<Saved Messages>' --days 30 --limit-messages 50After the backfill finishes, run the daemon without
--onceto stay current.
Common daemon tuning flags:
--daemon-lookback-minutes(default 5) — replay window on startup/reconnect.--lookback-message-limit(default 250) — cap per-chat catch-up volume.--backfill-checkpoint-interval(default 50) — persist JSON progress every N messages.
- Login at
/loginusing the credentials from.env; an HTTP-only session cookie is issued. - Core endpoints:
/models,/search, and/chat. Seeapi/for request/response schemas. - Model labels shown in the UI map to OpenAI IDs defined in the environment variables (e.g.,
gpt-5,gpt-5-mini).
- Format and lint before committing:
make precommitorpre-commit run --all-files - Python tests (api + indexer):
make test-python - UI unit tests:
make test-ui - UI end-to-end tests:
make test-ui-e2e - Optional smoke checks against a running stack:
./scripts/smoke_tests.sh
api/ FastAPI service (auth, models, search, chat)
indexer/ Telethon ingestion, chunking, embeddings, Vespa upserts
ui/ Astro + React front-end
vespa/application/ Vespa schemas and services (auto-deployed)
scripts/ Helpers: deploy-vespa.sh, wait_for_health.sh, smoke_tests.sh
- Cannot log in: confirm
APP_USERandAPP_USER_HASH_BCRYPT; check system clock for cookie expiry. - Indexer stalled: ensure the Telethon
.sessionfile exists on the Docker volume and inspectdocker compose logs indexerfor rate limiting. - Empty search results: verify Vespa deployment (
docker compose logs vespa-deploy) and that embeddings populated successfully. - Rerank skipped: set
VOYAGE_API_KEYandRERANK_ENABLED=true.
- Single-user authentication backed by bcrypt; cookies are HTTP-only.
- Secrets stay in
.envand are never committed. Copy.env.exampleas a starting point. - Telethon sessions and Postgres data live on Docker volumes you control.
- If exposing the stack, front it with TLS termination and consider IP allow-listing.
./scripts/wait_for_health.sh- wait until API and Vespa report healthy./scripts/deploy-vespa.sh- redeploy the Vespa package manually./scripts/smoke_tests.sh- basic functional checks against a running stack
For additional implementation details, browse the relevant module directories noted above.