Hybrid RAG + Knowledge Graph API for Satellite Data Intelligence
The intelligent backend powering AstraQ — an AI assistant for ISRO's MOSDAC satellite data portal. Answers natural-language questions about Indian satellites and their data products by combining semantic document retrieval (RAG) with a Neo4j knowledge graph, synthesized by Google Gemini.
Architecture • Tech Stack • Getting Started • API Reference • Deployment • Contributing
flowchart TD
Q[User Question] --> R{Intent Router<br/>Regex-based, no LLM cost}
R -->|greeting / memory| CHAT[Deterministic Reply<br/>Zero API cost]
R -->|glossary term| GLOSS[Glossary Lookup<br/>Cached]
R -->|listing question| KG[Knowledge Graph<br/>Cypher Templates]
R -->|explanation| RAG[FAISS Retrieval<br/>fastembed ONNX]
R -->|entity + explanation| BOTH[KG + RAG Fusion]
KG -->|no results| RAG
RAG --> GEM{Gemini Synthesis<br/>Model Fallback Chain}
BOTH --> GEM
GEM -->|quota exhausted| FB[Deterministic Fallback<br/>Retrieved Snippets]
GEM --> A[Answer + Sources + Citations]
KG --> A
CHAT --> A
GLOSS --> A
flowchart LR
subgraph Client
FE[React SPA]
end
subgraph Backend["FastAPI Service"]
MW[Middleware<br/>CORS + Security Headers + Request-ID]
ROUTES[API Routers]
SVC[Chat Service<br/>Intent Routing + Fusion]
RL[Rate Limiter]
AC[Answer Cache]
end
subgraph Data
FS[(Firestore)]
NEO[(Neo4j AuraDB)]
FAISS[(FAISS Index)]
end
GEM[Gemini API]
FBA[Firebase Auth]
FE -->|Bearer Token| MW --> ROUTES --> SVC
ROUTES --> RL
SVC --> AC
ROUTES -->|Verify Token| FBA
SVC --> FS
SVC --> NEO
SVC --> FAISS
SVC --> GEM
| Principle | Implementation |
|---|---|
| Cheap first | Greetings, memory, and glossary terms never touch an LLM. Answers are cached so repeated questions cost nothing. |
| Graceful degradation | If Neo4j is paused, KG questions fall back to RAG. If Gemini quota is exhausted, retrieved document snippets are returned directly. |
| Free-tier friendly | Embeddings run via fastembed (ONNX runtime, no PyTorch), fitting the entire service in a 512 MB instance. |
| Lazy loading | FAISS index and Gemini clients initialize on first use, not at import time. Boot succeeds with missing credentials. |
| Offline testable | All 61 tests run without network access, credentials, or external services. |
| Concern | Technology |
|---|---|
| API Framework | FastAPI + Uvicorn (ASGI) |
| Authentication | Firebase Auth (Bearer ID tokens, server-side verification with revocation check) |
| Session Storage | Google Cloud Firestore (users/{uid}/threads/{id}/messages) |
| Knowledge Graph | Neo4j AuraDB (Satellite→Product→Parameter, Region, Payload, Algorithm) |
| Vector Search | FAISS + all-MiniLM-L6-v2 via fastembed (ONNX, no PyTorch) |
| LLM Synthesis | Google Gemini (configurable model fallback chain) |
| Rate Limiting | In-memory sliding window (single-instance design) |
| Caching | In-memory TTL cache for repeated queries |
| Containerization | Docker (multi-stage build, ~180 MB image) |
| CI/CD | GitHub Actions (lint, test, Docker build, secret scanning) |
- Python 3.11+
- Firebase project with Authentication + Firestore enabled
- Neo4j AuraDB Free instance (optional — app starts degraded without it)
- Google Gemini API key (optional — deterministic fallbacks work without it)
git clone https://github.com/a6hinandh/AstraQ_Backend.git
cd AstraQ_Backend
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt -r requirements-dev.txtcp .env.example .env| Variable | Required | Description |
|---|---|---|
FIREBASE_SERVICE_ACCOUNT_B64 |
Yes (prod) | Base64-encoded Firebase service account JSON |
GEMINI_API_KEY |
Yes | Google AI Studio API key |
GEMINI_MODELS |
No | Comma-separated model fallback chain (default: gemini-2.5-flash-lite,gemini-2.5-flash) |
NEO4J_URI |
No | neo4j+s://<id>.databases.neo4j.io |
NEO4J_USERNAME / NEO4J_PASSWORD |
No | AuraDB credentials |
ENABLE_KG |
No | true to enable knowledge graph features |
AUTH_REQUIRED |
No | false for local dev (skips token verification) |
FRONTEND_ORIGINS |
Yes (prod) | Comma-separated allowed CORS origins |
CHAT_RATE_LIMIT_PER_MINUTE |
No | Per-user rate limit (default: 20) |
LOG_FORMAT |
No | json (production) or text (local dev) |
uvicorn backend.main:app --reload
# API: http://127.0.0.1:8000
# OpenAPI docs: http://127.0.0.1:8000/docs
# Health check: http://127.0.0.1:8000/healthThe app boots without any credentials in degraded mode. Component status is reported at /health.
pytest # 61 tests, fully offline
ruff check backend rag_pipeline kg_pipeline testsTests use a FakeFirestore fixture and monkeypatched RAG/KG entry points — no network calls, no credentials required.
# Rebuild the FAISS vector index (after corpus changes)
pip install -r requirements-pipeline.txt
python -m rag_pipeline.build_vector_index
# Populate the Neo4j knowledge graph
python kg_pipeline/populate_kg.pyThe FAISS index ships with the repo (
rag_pipeline/faiss_store/, ~13 MB) so RAG works immediately after clone.
Base path: /api. Full interactive documentation at /docs (OpenAPI/Swagger UI).
All endpoints require Authorization: Bearer <Firebase ID token> unless noted. With AUTH_REQUIRED=false (dev only), unauthenticated requests use a shared anonymous user.
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/chat |
Yes | Main Q&A — returns answer, sources, mode, thread_id |
POST |
/suggestions |
Yes | AI-generated follow-up question chips |
GET |
/threads |
Yes | List all user threads |
GET |
/thread/{id} |
Yes | Full message history with citations |
DELETE |
/threads/{id} |
Yes | Delete thread and messages |
POST |
/threads/{id}/favorite |
Yes | Toggle favorite status |
GET |
/threads/favorites |
Yes | List favorited threads |
POST |
/threads/{id}/share |
Yes | Generate public share token |
DELETE |
/threads/{id}/share |
Yes | Revoke share link |
GET |
/share/{token} |
No | Public read-only conversation view |
GET |
/kg/graph |
Yes | Full knowledge graph (nodes + edges, capped at 200) |
GET |
/kg/satellites |
Yes | Satellite catalog with product lists |
GET |
/kg/satellites/{name} |
Yes | Satellite detail (products, payloads, metadata) |
GET |
/search?q= |
Yes | Personal message history search |
GET |
/search/docs?q= |
Yes | Semantic document corpus search |
POST |
/upload |
Yes | Text extraction from PDF/DOCX/TXT (max 10 MB) |
GET/PATCH |
/user/me |
Yes | User preferences |
POST |
/feedback |
Yes | Submit rating and feedback |
GET |
/health |
No | Component status (firebase, neo4j, faiss) |
GET |
/health/ready |
No | Readiness probe for orchestrators |
Endpoints marked with rate limiting enforce a per-user sliding window. Responses include:
X-RateLimit-Limit— maximum requests per windowX-RateLimit-Remaining— remaining requests429 Too Many RequestswithRetry-Afterheader when exceeded
Standard FastAPI error shape: { "detail": "message" } with appropriate HTTP status codes (401, 404, 422, 429, 503).
Full API documentation: docs/API.md
backend/
├── main.py # App factory, middleware, CORS, health probes
├── api/
│ ├── routes/ # One router per concern (chat, threads, kg, search, share, upload)
│ ├── schemas.py # Pydantic request/response models
│ ├── router_logic.py # Intent classification (regex-based)
│ └── deps.py # Dependency injection (auth, rate limiting)
├── services/ # Chat orchestration, follow-up generation
├── auth/ # Firebase token verification
├── session/ # Firestore + Neo4j data access layer
├── rate_limit.py # In-memory sliding window rate limiter
├── answer_cache.py # In-memory TTL answer cache
├── domain_terms.py # Satellite/product keyword vocabularies
└── logging_config.py # Structured JSON logging with request-id
rag_pipeline/
├── build_vector_index.py # Corpus → FAISS index builder
├── faiss_store/ # Pre-built FAISS index (committed, ~13 MB)
└── retrieve.py # Query expansion → retrieval → Gemini synthesis
kg_pipeline/
├── populate_kg.py # JSON → Neo4j graph population
├── kg_nl_demo.py # NL → Cypher translation + execution
└── queries.py # Cypher template library
static_pipeline/ # MOSDAC scraping & parsing (offline, not deployed)
├── crawlers/ # Web crawlers for MOSDAC portal
├── parsers/ # PDF/DOCX/HTML parsing
└── output/ # Parsed corpus (source for FAISS index)
tests/ # 61 offline tests (FakeFirestore, monkeypatched externals)
docs/ # Architecture, API reference, deployment guide
The recommended deployment target is Render's Docker web service:
- Connect repo → New Web Service (Docker runtime)
- Set environment variables (see table above)
- Health check path:
/health/ready - Instance: Free tier (512 MB) is sufficient
Full step-by-step guide: docs/DEPLOYMENT.md
| Aspect | Details |
|---|---|
| Cold start | ~50s after 15 min idle (free tier). Frontend shows warm-up banner. |
| Memory | Fits in 512 MB — fastembed ONNX, no PyTorch/spaCy |
| Scaling | Single-instance by design (in-memory cache/limiter). Swap for Redis to scale horizontally. |
| Neo4j pauses | AuraDB Free pauses after ~3 idle days. KG falls back to RAG; resume from console. |
| Observability | Structured JSON logs with request-id propagation via X-Request-ID header |
See docs/ARCHITECTURE.md for:
- Complete request lifecycle (
POST /api/chat) - Firestore data model
- Neo4j schema
- FAISS index specifications
- Operational design decisions and rationale
- Authentication: Firebase ID tokens verified server-side with revocation checking on every request
- Authorization: All user data (threads, messages, preferences) is scoped by Firebase Auth UID
- Secrets management: Service account keys are never in the Docker image; injected via
FIREBASE_SERVICE_ACCOUNT_B64at runtime - Rate limiting: Per-user sliding window prevents abuse (configurable via environment)
- CORS: Restricted to explicitly configured frontend origins
- Input validation: Pydantic models enforce type safety; message length capped at 4000 chars; file uploads capped at 10 MB
- Prompt injection guard: Retrieved RAG context is sanitized before LLM synthesis
- No PII in logs: Request-id tracing without user content in structured logs
See CONTRIBUTING.md for development setup, coding standards, and PR requirements.
This project is licensed under the MIT License — see the LICENSE file for details.
- ISRO / MOSDAC — Source satellite data documentation, product specifications, and ATBDs
- AstraMind — Student-led team of data engineers, AI researchers, and space enthusiasts
- Built with FastAPI, Firebase, Neo4j, and the open-source Python ecosystem
