File size: 11,502 Bytes
4f1e196 175b650 4f1e196 cb5f524 4f1e196 cb5f524 4f1e196 cb5f524 4f1e196 cb5f524 4f1e196 cb5f524 5ed6f37 cb5f524 4f1e196 cb5f524 4f1e196 cb5f524 4f1e196 cb5f524 c50d15c 5ed6f37 cb5f524 4f1e196 cb5f524 4f1e196 5ed6f37 cb5f524 4f1e196 cb5f524 5ed6f37 cb5f524 5ed6f37 cb5f524 5ed6f37 cb5f524 4f1e196 c50d15c 4f1e196 c50d15c 4f1e196 ee3e8fe db54566 4f1e196 3ad32ba 4f1e196 aaf56bb 4f1e196 aaf56bb 4f1e196 c50d15c bc4fc5c c50d15c 4f1e196 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | # Backend β Django REST API
Stateless REST API serving the PhD research models. No database β PyTorch checkpoints are loaded into memory at startup and used to answer each request independently. Three Django app endpoints expose [COINs](../../docs/glossary.md#coins) link prediction and query answering, [MultiProxAn](../../docs/glossary.md#multiproxan) graph generation, and KG anomaly correction; one global `threading.Lock` serializes inference because the deployed container has no GPU and shares 2 vCPU.
For deeper material:
- [`docs/reference/api.md`](../../docs/reference/api.md) β every endpoint, request and response shape.
- [`docs/reference/sse-protocol.md`](../../docs/reference/sse-protocol.md) β wire format for streaming inference.
- [`docs/reference/backend-services.md`](../../docs/reference/backend-services.md) β module-by-module reference.
- [`docs/explanation/architecture.md`](../../docs/explanation/architecture.md) β how the backend, the SPA and HF Hub fit together.
- [`docs/explanation/inference-lifecycle.md`](../../docs/explanation/inference-lifecycle.md) β boot sequence, lazy weight loading, the inference lock.
- [`docs/glossary.md`](../../docs/glossary.md) β domain vocabulary.
This README covers the practical surface: running the backend, where things live, env vars, the endpoint table, and the streaming protocol summary.
## Prerequisites
1. **Mamba environment** mirroring the deployment image. The repo-root `environment.yml`
captures the conda half (Python 3.9, `rdkit=2023.03.2`, `boost=1.78`, cairo, etc.):
```bash
mamba env create -n website_c -f ../../environment.yml
mamba activate website_c
```
2. **Pip dependencies** (GPU torch, Django, DRF, β¦):
```bash
pip install --extra-index-url https://download.pytorch.org/whl/cu118 -r requirements.txt
```
3. **Model checkpoints** β downloaded automatically from the Hugging Face Hub model repo
`Bani57/checkpoints` on first boot. The remote layout mirrors the on-disk one, so
`huggingface_hub.snapshot_download(local_dir=CHECKPOINTS_ROOT)` drops files directly
into the expected paths:
- `src/research/COINs-KGGeneration/graph_completion/checkpoints/` (COINs: `{dataset}_{algorithm}.tar`)
- `src/research/COINs-KGGeneration/graph_completion/results/{dataset}/` (KBGAT TransE init: `transe_model.tar`)
- `src/research/COINs-KGGeneration/graph_generation/checkpoints/` (KG anomaly: `{dataset}.ckpt`, `{dataset}_correct.ckpt`)
- `src/research/MultiProxAn/checkpoints/` (graph generation: `{dataset}.ckpt`, `{dataset}_c.ckpt`)
To (re-)publish the checkpoints to the Hub from a local copy:
```bash
huggingface-cli login # one-time
python ../../scripts/upload_checkpoints.py --create
```
4. **Dataset files** β the raw KG data files must be present under `src/research/COINs-KGGeneration/data/` (FB15k-237, WN18RR, NELL-995).
## Running
From `src/backend/`:
```bash
# Development server
python manage.py runserver 8000
# With custom settings
DJANGO_DEBUG=True DJANGO_SECRET_KEY=my-secret python manage.py runserver
```
The API is served at `http://localhost:8000/api/v1/`.
## Environment Variables
| Variable | Default | Description |
|---|---|---|
| `DJANGO_SECRET_KEY` | `dev-insecure-key-change-in-production` | Django secret key. **Set in production.** |
| `DJANGO_DEBUG` | `True` | Enable debug mode. Set to `False` in production. |
| `DJANGO_ALLOWED_HOSTS` | `localhost,127.0.0.1` | Comma-separated allowed hosts. |
| `CORS_ALLOWED_ORIGINS` | `https://bani57-website.hf.space` | Comma-separated allowed CORS origins. |
| `TORCH_DEVICE` | Auto (`cuda:0` if available, else `cpu`) | PyTorch device for model inference. |
| `RESEARCH_ROOT` | `<repo>/src/research` (dev), `/app/research` (image) | Where the research-code modules live. |
| `CHECKPOINTS_ROOT` | Same as `RESEARCH_ROOT` | Where `huggingface_hub` deposits weights. Override to e.g. `/data/checkpoints` on a paid HF Space with persistent storage. |
| `HF_CHECKPOINTS_REPO` | `Bani57/checkpoints` | HF Hub model repo holding all weights. |
| `HF_TOKEN` | unset | Recommended. Read-scope token lifts anonymous rate limits and roughly triples cold-start download throughput. Required if the repo is private. Empty values are unset by `entrypoint.sh` to avoid a malformed `Bearer ` header. |
| `HF_HUB_ENABLE_HF_TRANSFER` | `1` (image), unset (dev) | Enables the Rust-accelerated `hf_transfer` backend for `snapshot_download`. |
| `SPA_DIST_DIR` | `<backend>/dist` | Folder containing `index.html` from `npm run build`. WhiteNoise serves assets from here. |
## Startup Sequence
In the deployment container the entrypoint script pre-warms the checkpoint download
from the Hugging Face Hub *before* gunicorn starts, so workers never block on the
network. Then on Django boot (`ApiConfig.ready()`), the `ModelRegistry` initializes:
1. **Verify / download checkpoints** from `Bani57/checkpoints` on HF Hub if any expected
subdir is missing. Idempotent β a no-op when the entrypoint already populated the tree
or when running locally with weights on disk.
2. **Scan checkpoint directories** to detect available models per method
3. **Load lightweight COINs Loaders** β one per dataset (freebase, wordnet, nell), loading graph data, name maps, and train/val/test splits. Heavy arrays (node neighbours ~275MB each, community neighbours, adjacency dicts) are freed after initialization to keep memory low.
4. **Generate sample subgraphs** for KG anomaly using the COINs Loaders
All model weights (COINs inference, graph generation, KG anomaly) are loaded lazily at first inference request.
## Deployment
The site is packaged as a single Docker image and deployed to a Hugging Face Space
(`Bani57/website` -> <https://bani57-website.hf.space>). The image:
- builds the Vue SPA with `npm run build` in a Node 20 stage,
- assembles a `mambaorg/micromamba` runtime mirroring the local `website_c` env from
`environment.yml` + `requirements.txt` (GPU torch wheels, `cu118`),
- copies the SPA `dist/` next to Django so WhiteNoise serves it on the same origin as
`/api/v1/`,
- runs `entrypoint.sh`, which `snapshot_download`s checkpoints from
`Bani57/checkpoints` on HF Hub into `/app/checkpoints` and execs `gunicorn` on `0.0.0.0:7860`.
Local reproduction:
```bash
docker compose up --build
# -> http://localhost:7860
```
Push to the Space (one-time remote setup):
```bash
git remote add hf https://huggingface.co/spaces/Bani57/website
git push hf master:main
```
## API Endpoints
All endpoints are prefixed with `/api/v1/`.
### Health & Discovery
| Method | Path | Description |
|---|---|---|
| `GET` | `/health` | Service health + model availability + inference lock status |
| `GET` | `/methods` | List the 3 research methods |
| `POST` | `/debug/force-unlock` | Release stuck inference lock (debug mode only) |
### COINs β KG Reasoning
| Method | Path | Description |
|---|---|---|
| `GET` | `/coins/datasets` | List datasets with entity/relation counts |
| `GET` | `/coins/datasets/{id}/entities` | Paginated entity search (`?q=&page=&page_size=`) |
| `GET` | `/coins/datasets/{id}/relations` | Paginated relation search (`?q=&page=&page_size=`) |
| `GET` | `/coins/datasets/{id}/sample-triples` | Random training triples (`?count=10&seed=...`); optional `seed` makes sampling deterministic (same `seed+count` β same triples, e.g. seed by ISO date for a day-stable widget). Head/relation/tail each carry a dataset-cleaned `label` alongside `id`, `name` |
| `GET` | `/coins/datasets/{id}/sample-query` | Sample a structurally valid KG query (`?query_structure=2i&count=1&seed=...`). Walks the training graph to produce real paths/intersections. Returns `{anchors, relations, target}` keyed by node/edge IDs from `/coins/query-structures`. Preferred over `sample-triples` for multi-hop/intersection prefills |
| `GET` | `/coins/models` | Available algorithms + supported query structures |
| `GET` | `/coins/query-structures` | Query graph templates for frontend rendering |
| `POST` | `/coins/predict` | Run link prediction / query answering |
### Graph Generation β MultiProxAn
| Method | Path | Description |
|---|---|---|
| `GET` | `/graph-generation/datasets` | List graph types with node/edge types |
| `GET` | `/graph-generation/sampling-modes` | Sampling strategies with parameter specs |
| `POST` | `/graph-generation/generate` | **Streaming SSE.** Generate a graph (standard denoising or MultiProx Gibbs init) |
| `POST` | `/graph-generation/continue` | **Streaming SSE.** Advance a MultiProx Gibbs session by one step |
### KG Anomaly Correction
| Method | Path | Description |
|---|---|---|
| `GET` | `/kg-anomaly/datasets` | List datasets with correction models |
| `GET` | `/kg-anomaly/datasets/{id}/sample-subgraphs` | Pre-computed example subgraphs (`?count=5&noise_level=0.4&task=correct&seed=42`); noise is task-aware |
| `POST` | `/kg-anomaly/correct` | **Streaming SSE.** Correct/regenerate a KG subgraph (standard denoising or MultiProx Gibbs init) |
| `POST` | `/kg-anomaly/continue` | **Streaming SSE.** Advance a MultiProx correction session by one step |
## Streaming Inference Protocol (SSE)
The graph generation endpoints (`/generate`, `/continue`) return **Server-Sent Events** (`text/event-stream`). Three event types are emitted:
**`event: progress`** β phase/step metadata (no images):
```
event: progress
data: {"type":"progress","phase":"denoise","step":42,"total_steps":500,"elapsed_ms":2100}
```
KG-anomaly progress events additionally carry an optional `kg_log_likelihood`
(float) + `kg_log_likelihood_step` (int) on frame boundaries β the mean
log-sigmoid score from the frozen KG embedder + link ranker on the edges
currently present in the argmax reconstruction. Higher = cleaner.
**`event: preview`** β base64 PNG of the graph's current state, emitted at key frames:
```
event: preview
data: data:image/png;base64,...
```
Preview frequency: `denoise` emits at `chain_frames` intervals (~30 over 500 steps), `gibbs` emits every inner step, `refine` emits every ~10% of steps.
**`event: result`** β final payload with image, chain GIF, and timing:
```
event: result
data: {"type":"result","dataset_id":"qm9","model_type":"discrete","sampling_mode":"standard","image":"data:image/png;base64,...","chain_gif":"data:image/gif;base64,...","inference_time_ms":25000}
```
Phases: `denoise` (standard generation loop), `noise_init` (multiprox init noise sampling), `gibbs` (multiprox inner Gibbs steps), `refine` (multiprox refinement denoising).
## Project Structure
```
src/backend/
manage.py
requirements.txt
research_api/ # Django project settings
settings.py
urls.py
wsgi.py
api/ # Django app
apps.py # Triggers ModelRegistry.initialize() on startup
urls.py # Route definitions
pagination.py # Shared pagination helper
exceptions.py # Custom error envelope
services/
constants.py # Dataset metadata, model configs, query structures
registry.py # ModelRegistry β checkpoint download, scanning, Loader init
views/
health.py # /health, /methods
coins.py # /coins/* endpoints
graph_generation.py # /graph-generation/* endpoints
kg_anomaly.py # /kg-anomaly/* endpoints
```
## Testing with Postman
Import the collection and environment from `docs/postman/` to test all discovery endpoints.
|