Demo clip:
Advanced Geospatial Visualization Platform with AI-Powered Analysis
DeepGIS-XR is a comprehensive geospatial visualization and analysis platform that combines advanced 3D mapping, AI-powered image analysis, and adaptive sampling systems for Earth and lunar exploration.
Segment Anything Model (SAM): Universal image segmentation with no training required
YOLOv8 Detection: Ultra-fast real-time object detection
Grounding DINO: Open-vocabulary text-based object detection
"rock . boulder . crater . debris"Zero-Shot Object Detection: Pre-trained COCO model for 80 object categories
Mask2Former: State-of-the-art instance segmentation
B keyS to share current viewClone the repository
git clone https://github.com/Earth-Innovation-Hub/deepgis-xr.git
cd deepgis-xr
Start with Docker Compose
docker compose up -d
Brings up four services by default: web (Django + gunicorn, GPU),
redis (Celery broker for the admin-only model-training queue),
celery_worker (single replica, GPU-pinned), and tileserver. The
optional db (Postgres 16) service is gated behind a profile โ
bring it up with docker compose --profile postgres up -d db and
follow docs/migration-sqlite-to-postgres.md if you're moving off
the SQLite default.
Access the application
Sync runtime assets (large MBTiles, models, analysis results)
bash scripts/sync_assets.sh # from /mnt/dreamslab-store by default
Override the source with STORE=/path/to/store bash scripts/sync_assets.sh.
Install dependencies
pip install -r requirements.txt # runtime
pip install -r requirements-dev.txt # + pytest, ruff, black, pip-tools
Run migrations
python manage.py migrate
Start development server
python manage.py runserver
Run tests / lint
pytest # requires requirements-dev.txt
ruff check .
black --check .
Backend:
GUNICORN_* env vars).
manage.py runserver is reserved for local development only.db.sqlite3) โ
PostgreSQL 16 (opt-in via DATABASE_URL; the compose db service is
gated behind the postgres profile, with dj-database-url and
psycopg2-binary already in requirements.txt). Cutover runbook:
docs/migration-sqlite-to-postgres.md.apps/api/v1/views/training.py::train_model_task). The world sampler
itself is synchronous; Celery is not used for per-viewport requests.django-phonenumber-field (phone-number authentication)services/topology/Frontend:
staticfiles/web/js/ (no build step)src/ was empty
and the pipeline was never wired into collectstatic. The bundle-chunking
plan preserved in the refactoring note will be revisited in Tier D.)AI/ML:
sam service (port 5010)ultralytics)transformers)services/maskrcnn-rocks/ Docker image, one container per family:
rocks, house, hypolith, litter, roadkill, newlife, brent-moon,
harish-moon). Phase-1 of the consolidation is wired in the
analyzer dispatch: set MASKRCNN_API_URL to a single unified
container that exposes the full registry and the analyzers route
there with the correct family model_id injected per-request; the
per-family MASKRCNN_*_API_URL vars take precedence when set so
rollout can be gradual. Detectron2 is no longer installed in the
web image (it had no in-process callers after the Tier-E cleanup).kernelcal โ Kernel Dynamics / MaxCal integration (in progress;
bind-mount overlays distinction_game, urban, fluid until the
wheel is published with these subpackages)Infrastructure:
deepgis-xr/
โโโ deepgis_xr/ # Django project
โ โโโ apps/
โ โ โโโ api/v1/ # DRF v1 (serializers, urls)
โ โ โโโ auth/ # phone-based auth (Twilio)
โ โ โโโ core/ # core models, admin, image processing
โ โ โโโ ml/ # ML helpers
โ โ โโโ tile_catalog/ # SiteโDatasetโTimestepโProduct registry
โ โ โ โโโ models.py, admin.py, serializers.py, views.py, urls.py
โ โ โ โโโ management/commands/
โ โ โ โโโ seed_tile_catalog.py # idempotent bootstrap
โ โ โ โโโ validate_tile_catalog.py # /data.json drift sentry
โ โ โโโ web/ # main web app
โ โ โโโ views/ # request handlers (Tier B split)
โ โ โ โโโ pages.py, missions.py, auth_ajax.py, ai_reports.py,
โ โ โ โโโ training_datasets.py, semi_supervised.py, models_3d.py
โ โ โ โโโ legacy.py # remaining un-split handlers
โ โ โโโ world_sampler.py # adaptive spatial sampler
โ โ โโโ world_sampler_api/ # sampling + AI viewport API (Tier C split)
โ โ โ โโโ core.py, http.py # helpers + 9 HTTP endpoints
โ โ โ โโโ analyzers/ # 7 analyzers + ANALYZER_REGISTRY
โ โ โ โโโ legacy.py
โ โ โโโ urls.py # 50+ routes
โ โ โโโ admin.py, models.py, middleware/, templates/
โ โ โโโ management/commands/ # e.g. import_rocks_labels
โ โโโ settings.py
โโโ services/
โ โโโ topology/ # standalone Flask tile/3D-tiles server
โ โโโ server.py # (was deepgis_topology_server.py)
โ โโโ prepare_data.py
โ โโโ Dockerfile # own runtime, no CUDA
โโโ examples/ # kernelcal demos, vegetation segmentation
โ โโโ bf_kernelcal_demo.py
โ โโโ bf_vegetation_segment.py
โโโ scripts/ # utility scripts
โ โโโ sync_assets.sh # pull data/models from lab store
โ โโโ optimize_large_glb.py
โ โโโ grounding_dino_api_client.py
โโโ staticfiles/web/ # hand-written JS, CSS, vendor libs
โโโ static/, media/, stl_models/ # runtime assets (gitignored)
โโโ data/ # MBTiles (gitignored)
โโโ models/ # ML model weights (gitignored)
โโโ deepgis_results/ # AI-analysis outputs (gitignored)
โโโ GroundingDINO/ # vendored upstream repo
โโโ Dockerfile # web container (CUDA 12.1, torch 2.5)
โโโ docker-compose.yml # web + tileserver (+ topology, optional)
โโโ requirements.txt # pinned runtime deps
โโโ requirements-dev.txt # pytest, ruff, black, pip-tools
โโโ README.md
A companion refactoring plan lives in the integration manuscript workspace at
notes/2026-04-22-deepgis-xr-refactoring.md. Tiers AโD have all landed
(layer manager, static-tree consolidation, and Cesium FPS work) and Tier E's
forward-compat prep is in; the Tier E version bumps and Tier F are scheduled
on the roadmap below.
POST /webclient/sampler/initialize - Initialize new samplerPOST /webclient/sampler/sample - Get sample locationsPOST /webclient/sampler/update - Update distributionGET /webclient/sampler/query - Query spatial regionGET /webclient/sampler/statistics - Get distribution statsPOST /webclient/sampler/reset - Reset samplerGET /webclient/sampler/history - View sample historyPOST /webclient/sampler/analyze-viewport - Analyze viewport with AI
Parameters:
model_type โ one of (live as of April 2026):
'sam', 'yolov8', 'mask2former', 'zero_shot',
'prithvi', 'urban_spectral''grounding_dino', 'grounded_sam''maskrcnn_rocks', 'maskrcnn_house',
'maskrcnn_hypolith', 'maskrcnn_litter', 'maskrcnn_roadkill',
'maskrcnn_newlife', 'maskrcnn_brent_moon_craters',
'maskrcnn_harish_moon_craters'. Set MASKRCNN_API_URL to
consolidate behind a single container with all families served
from one process; per-family MASKRCNN_*_API_URL vars take
precedence when set so rollout can be gradual.image: Base64-encoded viewport imagelocation: Camera position metadatasam_model: 'vit_b', 'vit_l', or 'vit_h'min_area: Minimum segment area in pixelsyolo_model: 'yolov8n', 'yolov8s', 'yolov8m', 'yolov8l', 'yolov8x'confidence_threshold: 0.0-1.0class_filter: Comma-separated class names (e.g., "person,car,truck")text_prompt: Dot-separated object descriptions (e.g., "rock . boulder . crater")box_threshold: Detection confidence threshold (default: 0.3)text_threshold: Text matching threshold (default: 0.25)maskrcnn_* family):
model_id: explicit checkpoint id from the upstream registry
(overrides the family default; see
services/maskrcnn-rocks/README.md for the canonical defaults
per family)score_threshold: 0.0-1.0max_detections: int (default 100)confidence_threshold: 0.0-1.0Returns: GeoJSON FeatureCollection with detections, metadata, and saved on-host artefact paths.
Graceful degradation contract. When a remote AI service is
unconfigured, unreachable, or times out, the endpoint returns
HTTP 200 (not 503) with an empty FeatureCollection plus:
degraded: trueunavailable_reason: one of "not_configured",
"connection_error", "timeout"device_info.available: falseRetry-After HTTP header (30 s default; 60 s on timeout)This keeps the frontend's per-viewport-change poll loop from
spamming error toasts during transient outages โ clients that
check response.ok && result.status === 'success' see a normal
empty response and continue rendering. Clients that want an "AI
offline" badge can opt in by reading result.degraded === true.
Genuine HTTP 5xx from a reachable upstream and unhandled
exceptions inside the analyzer still surface as 502/500 โ those
are bugs, not unavailability, and they are deliberately not masked.
POST /label/semi-supervised/api/generate-labels/ - Generate assisted labelsPOST /label/semi-supervised/api/save-labels/ - Save labelsGET /label/semi-supervised/api/get-images/ - Get label imagesGET /api/v1/tile-catalog/ โ hierarchical layer registry consumed
by the Cesium frontend.
Returns a JSON tree of Site โ Dataset โ Timestep โ Product for
every active Product in the database, denormalised so the
frontend can render the layer panel without further round-trips.
Versioned ("version": 1); response shape:
{
"version": 1,
"generated_at": "2026-04-27T...",
"sites": [
{ "slug": "phx_wildfire", "name": "Phoenix wildfire site",
"bounds": [...], "default_zoom": 18,
"datasets": [
{ "slug": "wildfire_orthos", "kind": "timeseries",
"timesteps": [
{ "label": "2020-08", "sort_key": "2020-08-02",
"products": [
{ "layer_id": "bf_aug_2020_raster", "kind": "orthophoto",
"label": "Orthophoto (Aug 2020)", "default_opacity": 0.7 }
]}
]}
]},
{ "slug": "bishop_ca", "...": "..." }
]
}
Edited via the Django admin at /label/admin/tile_catalog/.
Bootstrap with python manage.py seed_tile_catalog; audit drift
against tileserver-gl /data.json with
python manage.py validate_tile_catalog.
The AI Viewport Analysis system supports multiple detection models, including remote API deployment for GPU-intensive models like Grounding DINO.
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ DeepGIS-XR Frontend โ
โ AI Viewport Analysis panel โ text prompts, sliders, model picker โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ POST /webclient/sampler/analyze-viewport
โ {image, location, model_type, model_id?, โฆ}
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ DeepGIS-XR Django Backend (gunicorn, GPU-attached) โ
โ apps/web/world_sampler_api/http.py::analyze_viewport() โ
โ โโ analyzers/ANALYZER_REGISTRY[model_type] โ dispatches to: โ
โ โ
โ LOCAL inference (in the web container): โ
โ sam ยท yolov8 ยท mask2former ยท zero_shot ยท โ
โ prithvi ยท urban_spectral โ
โ โ
โ REMOTE inference (Flask services on the GPU host): โ
โ grounding_dino ยท grounded_sam ยท sam (remote) โ
โ maskrcnn_{rocks ยท house ยท hypolith ยท litter ยท โ
โ roadkill ยท newlife ยท โ
โ brent_moon_craters ยท harish_moon_craters} โ
โ โ
โ Mask R-CNN dispatch (resolve_remote_maskrcnn_url): โ
โ โ if MASKRCNN_*_API_URL set for this family โ use it โ
โ โก else if MASKRCNN_API_URL set โ use it + inject family โ
โ default into the per-request `model_id` form field โ
โ โข else โ _unavailable_response("not_configured") โ
โ โ
โ On AI-down (not_configured ยท connection_error ยท timeout): โ
โ โ HTTP 200 + {status:"success", degraded:true, โ
โ detections:[], unavailable_reason, โฆ} โ
โ Retry-After: 30s (60s on timeout) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Remote AI host 192.168.0.232 (Flask + CUDA) โ
โ :5000 grounding_dino :5006 maskrcnn_roadkill โ
โ :5001 grounded_sam_2 :5007 maskrcnn_newlife โ
โ :5002 maskrcnn_rocks :5008 maskrcnn_brent_moon โ
โ :5003 maskrcnn_house :5009 maskrcnn_harish_moon โ
โ :5004 maskrcnn_hypolith :5010 sam (classic v1) โ
โ :5005 maskrcnn_litter โ
โ โ
โ Phase-1 consolidation: collapse :5002โ:5009 to ONE container โ
โ on :5002 with all eight weight bundles mounted; legacy direct โ
โ callers preserved by services/maskrcnn-rocks/scripts/ โ
โ port_shim.py (Python stdlib, no nginx-lua) which injects the โ
โ correct model_id and proxies to the unified upstream. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
GPU-accelerated AI services on dedicated server for open-vocabulary detection and segmentation.
Grounding DINO (port 5000): Text-based detection
Grounded-SAM-2 (port 5001): Detection + high-quality segmentation
# Grounding DINO - Detection only
curl -X POST http://192.168.0.232:5000/api/predict \
-F "file=@image.jpg" -F "text_prompt=rock . boulder . crater"
# Grounded-SAM-2 - Detection + Segmentation
curl -X POST http://192.168.0.232:5001/detect \
-F "image=@image.jpg" -F "text_prompt=rock . boulder . crater"
# Python client
./grounding_dino_api_client.py --image viewport.jpg --prompt "rock . boulder"
Example Prompts: Geology: "rock . boulder . crater" | Urban: "building . car . tree" | Wildlife: "animal . bird . nest"
/label/3d/search/)"rock . crater . boulder"), thresholds/label/3d/moon/)/label/3d/search/)B key to toggle instantlyV to switch to 3D)/label/3d/search/)V to toggleS or click the Share button| Parameter | Description |
|---|---|
lon, lat, alt | Camera position |
heading, pitch, roll | Camera orientation |
viewMode | 2D, 3D, or Columbus |
flyDist, hSpeed, vSpeed | Drone fly settings |
orbRadius, orbPitch, orbYaw | Orbit settings |
orbiting, flying, takeoff, landing | Active mode flags |
Press H to view all shortcuts in-app. Key shortcuts include:
| Key | Action |
|---|---|
B | Toggle 3D Buildings |
V | Toggle View Mode (2D/3D/Columbus) |
F | Toggle Full Screen |
H | Show Keyboard Shortcuts Help |
S | Share Current View |
Q | Toggle QR Code |
T | Hide/Show Toolbars |
W | Toggle Wireframe |
D | Drone Fly Forward |
U | Takeoff (Up) |
L | Land |
O | Start Orbit |
P | Pause/Stop Orbit |
J | Toggle Virtual Joysticks |
โ โ โ โ | Camera Perspectives (N/S/W/E) |
ESC | Stop Orbit / Close Panels |
The full, authoritative list lives in
.env.example. Copy it to .env and edit. The
operationally important knobs are:
# Core (production posture by default)
DEBUG=False
DJANGO_SETTINGS_MODULE=deepgis_xr.settings
SECRET_KEY= # generate with: openssl rand -hex 32
ALLOWED_HOSTS=deepgis.org,localhost,127.0.0.1
NVIDIA_VISIBLE_DEVICES=all # GPU passthrough
# Web โ gunicorn (defaults match the Dockerfile CMD)
GUNICORN_WORKERS=2
GUNICORN_THREADS=4
GUNICORN_TIMEOUT=600
# Database โ leave unset for the legacy SQLite default; flip to
# `postgres://deepgis:deepgis@db:5432/deepgis` after running
# `docs/migration-sqlite-to-postgres.md`. The bundled `db` service is
# off until you `docker compose --profile postgres up -d db`.
# DATABASE_URL=postgres://deepgis:deepgis@db:5432/deepgis
POSTGRES_DB=deepgis
POSTGRES_USER=deepgis
POSTGRES_PASSWORD=deepgis
# Celery broker / result backend (auto-wired by the redis service)
REDIS_URL=redis://redis:6379/0
# Remote AI services (Flask containers on a separate GPU host)
# Phase-1 consolidation: set this to point all Mask R-CNN families at
# a single upstream container; per-family vars below override it.
# MASKRCNN_API_URL=http://192.168.0.232:5002
GROUNDING_DINO_API_URL=http://192.168.0.232:5000
GROUNDED_SAM_API_URL=http://192.168.0.232:5001
SAM_API_URL=http://192.168.0.232:5010
# MASKRCNN_ROCKS_API_URL=http://192.168.0.232:5002
# โฆ see .env.example for the full eight-family list (5002โ5009)
The docker-compose.yml ships the following services.
Default (docker compose up -d):
| Service | Image | Role |
|---|---|---|
web | built locally (Dockerfile) | Django + DRF behind gunicorn (workers=2, threads=4, timeout=600); GPU-attached; runs manage.py migrate --noinput once on boot |
redis | redis:7-alpine | Celery broker + result backend (healthchecked, no host port) |
celery_worker | reuses the web image | Single replica (--concurrency=1 because the training task takes the whole GPU); waits on redis healthcheck |
tileserver | maptiler/tileserver-gl | Serves MBTiles raster + vector tiles |
Optional (profile-gated):
| Service | Image | Profile | Notes |
|---|---|---|---|
db | postgres:16-alpine | postgres | Bring up only when you're ready to migrate off SQLite. Runbook: docs/migration-sqlite-to-postgres.md. |
Volume mounts:
dreams_laboratory/scripts โ ML model scripts (read-only)deepgis_results โ AI analysis artefacts (shared with host)redis_data, postgres_data โ named volumes for service persistenceTo enable GPU for AI features:
docker-compose.ymlNVIDIA_VISIBLE_DEVICES=all is setThe flat raster/vector checkbox lists in the layer panel have been
replaced with a hierarchical Site โ Dataset โ Timestep โ Product
catalog backed by a new Django app (apps.tile_catalog) and a single
GET /api/v1/tile-catalog/ endpoint. Per the data shape that emerged
from the April tileserver audit โ one timeseries site (PHX wildfire,
5 dates) and one single-shot site (Bishop, CA) live today, with
Hawaii / Italy / others queued for activation โ the new panel
reorganises the UI around three independent axes:
Timestep, sorted by sort_key) with
per-tick coverage dots โ small colored dots showing which product
kinds (orthophoto / vector / 3D mesh / โฆ) exist at that timestep.
Pin-by-click; prev/next stepper buttons; readout below shows the
active timestep label.Plus three modes that compose with the above:
single | swipe | overlay
selector. Swipe uses Cesium's splitDirection to render A on the
left and B on the right of a draggable vertical split; shift-click
any timestep to move the B pin. Overlay blends both at half opacity
so spatial differences read visually. Mode selector lives inside
the timeseries panel because it's per-dataset, not per-site.camera.moveEnd. Day-to-day clutter killer once the catalog grows
past a handful of sites.tileserver-gl serves that the
catalog doesn't know about appear in a collapsed "Uncategorized"
group at the bottom โ reachable, but the visual cue is "please
curate this in the admin." python manage.py validate_tile_catalog
reports drift in both directions for CI / cron use.Editing happens entirely through the Django admin
(/label/admin/tile_catalog/), which uses inline forms so opening a
Site shows its Datasets, opening a Dataset shows its Timesteps, and
so on. Initial bootstrap is python manage.py seed_tile_catalog
(idempotent; admin edits survive subsequent runs unless
--force-update is passed).
GUNICORN_* overridable);
DEBUG defaults to False; manage.py migrate --noinput runs once
on container start. Compose file ships redis (the broker the
training queue had been quietly assuming) and a single-replica
celery_worker so train_model_task.delay(โฆ) actually runs end-to-
end. Postgres 16 is wired and waiting behind the postgres profile
with dj-database-url + psycopg2-binary already in
requirements.txt; cutover from the legacy 1.7 GB db.sqlite3 is
operator-driven via docs/migration-sqlite-to-postgres.md โ nothing
is forced.analyze-viewport no longer returns
hard 503s when a remote AI service is unconfigured / unreachable /
timing out. New _unavailable_response(...) helper (in
analyzers/_helpers.py) returns HTTP 200 with
{status:"success", degraded:true, detections:[], unavailable_reason, โฆ} plus a Retry-After header (30 s default; 60 s on timeout) so
the frontend's per-viewport-change poll loop stops spamming error
toasts during transient outages. Reserved for unavailability only โ
real upstream 5xx and analyzer crashes still surface as 502/500.MASKRCNN_*_API_URL services on :5002โ:5009 all run the same
services/maskrcnn-rocks/ Docker image with different
DEFAULT_MODEL_IDs. New analyzer dispatch helper
(resolve_remote_maskrcnn_url) prefers a single MASKRCNN_API_URL
when set and injects the family default into the per-request
model_id form field; the per-family vars take precedence so
rollout is gradual. Backward-compat for legacy direct clients on
the old port range is provided by
services/maskrcnn-rocks/scripts/port_shim.py โ a stdlib-only
Python proxy (no nginx-lua) that injects the correct model_id and
forwards to the unified upstream. Phase 2 (operator-side) collapses
to one upstream container with all weight bundles mounted.requirements.txt; added
requirements-dev.txt; relocated root .py scripts into
services/topology/, examples/, scripts/; kernelcal installed as a
real dep; scripts/sync_assets.sh syncs data//models//deepgis_results/
from /mnt/dreamslab-store; dead Vite config removed.apps/web/views.py
monolith is now a views/ package โ pages, missions, auth_ajax,
ai_reports, training_datasets, semi_supervised, models_3d plus a
shrinking legacy.py, with __init__.py preserving every public name
urls.py routes to.world_sampler_api.py is now a
package with core.py (helpers), http.py (9 endpoints), and an
analyzers/ subpackage (7 analyzers + 3 shared helpers) exposed through
an ANALYZER_REGISTRY. This unblocks the MaxCal / Model-Kernel Selector
work in kernelcal.toggleOSMBuildings
paths onto one canonical helper in cesium-init.js; a new feature-layer
registry in staticfiles/web/js/core/feature-layers.js normalises
heterogeneous layer toggles (OSM Buildings, World Terrain, โฆ) behind
a single window.FeatureLayers.set(id, enabled) / renderToggles(โฆ)
API; Tier D3 lifted the OSM-Buildings toggle onto label_topology
via the registry.USE_L10N = True (removed in Django 5.0) and the stale
default_app_config pointer in apps/auth/__init__.py (removed in
4.2, already redundant given INSTALLED_APPS lists AuthConfig
directly); removed an unused shapely.geometry.shape import in
views/legacy.py. All three edits are no-ops on the current Django
3.2 / Shapely 1.8 stack and shrink the actual bump commit to a
four-line requirements.txt change.BASE_DIR/staticfiles/ into STATICFILES_DIRS so Django's finders
actually resolve {% static 'web/js/main.js' %} to the tracked tree.
Without this, the Tier D frontend work had been sitting in the repo
but not being served โ the app had been falling back to an older,
untracked deepgis_xr/apps/web/static/ tree. Orphaned assets
(mask2former-corrector.css/.js, responsive.css) parked under
staticfiles/web/legacy/ with a README.cesium-init.js โ globe enableLighting, uncapped
resolutionScale ร devicePixelRatio on Retina/4K (now capped at 1.5ร
with ?hidpi=1 opt-in), tileLoadProgressEvent โ requestRender
spam, and fxaa on an already-supersampled scene. 60 FPS restored
on iGPU / Retina.B key; free and open data (ODbL)Contributions are welcome! Please follow these guidelines:
git checkout -b feature/amazing-feature)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)This project is licensed under the MIT License - see the LICENSE file for details.
DeepGISโXR builds on concepts and systems originally developed for the Oceanographic Decision Support System (ODSS, MBARI), the Agricultural Decision Support System (AgDSS, University of Pennsylvania), the OpenUAV Project (University of Pennsylvania, Arizona State University), and DeepGIS (Arizona State University). The DeepGIS project acknowledges support from the National Science Foundation, the United States Department of Agriculture, and the National Aeronautics and Space Administration.
Tiers AโC and the Tier-D prep steps (D0, D0.5) have landed. Remaining work
is tracked alongside feature work. See
notes/2026-04-22-deepgis-xr-refactoring.md in the integration workspace
for the full plan.
apps/web/views.py โ views/ package of 7 focused
modules + shrinking legacy.py (PR #4)world_sampler_api.py โ package with core.py, http.py
(9 endpoints), analyzers/ subpackage, and ANALYZER_REGISTRY
(PR #5; unblocks kernelcal Threads 1 + 2)core/feature-layers.js with a window.FeatureLayers API;
registry-driven toggles on label_topologystaticfiles/ wired into STATICFILES_DIRS so the
tracked frontend tree is actually served; orphaned assets parked in
staticfiles/web/legacy/ (PR #8)cesium-init.js; 60 FPS restored on iGPU/Retina (PR #8)requirements.txt change pending container regression sweep. Full
recon in TIER_E_MIGRATION_NOTES.md at the repo root (local-only).
Django 5.0/5.1 is tracked separately (needs Python 3.10+).kernelcal integration: MaxCal World Sampler, Model-Kernel
Selector, terrain diagnostics endpointDEBUG=False + redis + celery_worker services
shipped; Postgres 16 wired behind a postgres profile with a
cutover runbook (docs/migration-sqlite-to-postgres.md);
_unavailable_response graceful-degradation contract added to
analyze-viewport; Mask R-CNN dispatch consolidated behind
MASKRCNN_API_URL + per-family fallback + port_shim.py.
Phase 2 (operator-side, pending): collapse
services/maskrcnn-rocks/ to one upstream container with all
eight weight bundles mounted; SQLite โ Postgres data cutover.This software is provided "as is" without warranty. Use at your own risk. Intended for research and educational purposes. AI analysis results should be validated independently for critical applications.
Powered by Earth Innovation Hub (Arizona STEAM non-profit corporation)
296 commits
JavaScript
66.8%
HTML
15.7%
Python
15.3%
CSS
1.5%
Demo clip:
Advanced Geospatial Visualization Platform with AI-Powered Analysis
DeepGIS-XR is a comprehensive geospatial visualization and analysis platform that combines advanced 3D mapping, AI-powered image analysis, and adaptive sampling systems for Earth and lunar exploration.
Segment Anything Model (SAM): Universal image segmentation with no training required
YOLOv8 Detection: Ultra-fast real-time object detection
Grounding DINO: Open-vocabulary text-based object detection
"rock . boulder . crater . debris"Zero-Shot Object Detection: Pre-trained COCO model for 80 object categories
Mask2Former: State-of-the-art instance segmentation
B keyS to share current viewClone the repository
git clone https://github.com/Earth-Innovation-Hub/deepgis-xr.git
cd deepgis-xr
Start with Docker Compose
docker compose up -d
Brings up four services by default: web (Django + gunicorn, GPU),
redis (Celery broker for the admin-only model-training queue),
celery_worker (single replica, GPU-pinned), and tileserver. The
optional db (Postgres 16) service is gated behind a profile โ
bring it up with docker compose --profile postgres up -d db and
follow docs/migration-sqlite-to-postgres.md if you're moving off
the SQLite default.
Access the application
Sync runtime assets (large MBTiles, models, analysis results)
bash scripts/sync_assets.sh # from /mnt/dreamslab-store by default
Override the source with STORE=/path/to/store bash scripts/sync_assets.sh.
Install dependencies
pip install -r requirements.txt # runtime
pip install -r requirements-dev.txt # + pytest, ruff, black, pip-tools
Run migrations
python manage.py migrate
Start development server
python manage.py runserver
Run tests / lint
pytest # requires requirements-dev.txt
ruff check .
black --check .
Backend:
GUNICORN_* env vars).
manage.py runserver is reserved for local development only.db.sqlite3) โ
PostgreSQL 16 (opt-in via DATABASE_URL; the compose db service is
gated behind the postgres profile, with dj-database-url and
psycopg2-binary already in requirements.txt). Cutover runbook:
docs/migration-sqlite-to-postgres.md.apps/api/v1/views/training.py::train_model_task). The world sampler
itself is synchronous; Celery is not used for per-viewport requests.django-phonenumber-field (phone-number authentication)services/topology/Frontend:
staticfiles/web/js/ (no build step)src/ was empty
and the pipeline was never wired into collectstatic. The bundle-chunking
plan preserved in the refactoring note will be revisited in Tier D.)AI/ML:
sam service (port 5010)ultralytics)transformers)services/maskrcnn-rocks/ Docker image, one container per family:
rocks, house, hypolith, litter, roadkill, newlife, brent-moon,
harish-moon). Phase-1 of the consolidation is wired in the
analyzer dispatch: set MASKRCNN_API_URL to a single unified
container that exposes the full registry and the analyzers route
there with the correct family model_id injected per-request; the
per-family MASKRCNN_*_API_URL vars take precedence when set so
rollout can be gradual. Detectron2 is no longer installed in the
web image (it had no in-process callers after the Tier-E cleanup).kernelcal โ Kernel Dynamics / MaxCal integration (in progress;
bind-mount overlays distinction_game, urban, fluid until the
wheel is published with these subpackages)Infrastructure:
deepgis-xr/
โโโ deepgis_xr/ # Django project
โ โโโ apps/
โ โ โโโ api/v1/ # DRF v1 (serializers, urls)
โ โ โโโ auth/ # phone-based auth (Twilio)
โ โ โโโ core/ # core models, admin, image processing
โ โ โโโ ml/ # ML helpers
โ โ โโโ tile_catalog/ # SiteโDatasetโTimestepโProduct registry
โ โ โ โโโ models.py, admin.py, serializers.py, views.py, urls.py
โ โ โ โโโ management/commands/
โ โ โ โโโ seed_tile_catalog.py # idempotent bootstrap
โ โ โ โโโ validate_tile_catalog.py # /data.json drift sentry
โ โ โโโ web/ # main web app
โ โ โโโ views/ # request handlers (Tier B split)
โ โ โ โโโ pages.py, missions.py, auth_ajax.py, ai_reports.py,
โ โ โ โโโ training_datasets.py, semi_supervised.py, models_3d.py
โ โ โ โโโ legacy.py # remaining un-split handlers
โ โ โโโ world_sampler.py # adaptive spatial sampler
โ โ โโโ world_sampler_api/ # sampling + AI viewport API (Tier C split)
โ โ โ โโโ core.py, http.py # helpers + 9 HTTP endpoints
โ โ โ โโโ analyzers/ # 7 analyzers + ANALYZER_REGISTRY
โ โ โ โโโ legacy.py
โ โ โโโ urls.py # 50+ routes
โ โ โโโ admin.py, models.py, middleware/, templates/
โ โ โโโ management/commands/ # e.g. import_rocks_labels
โ โโโ settings.py
โโโ services/
โ โโโ topology/ # standalone Flask tile/3D-tiles server
โ โโโ server.py # (was deepgis_topology_server.py)
โ โโโ prepare_data.py
โ โโโ Dockerfile # own runtime, no CUDA
โโโ examples/ # kernelcal demos, vegetation segmentation
โ โโโ bf_kernelcal_demo.py
โ โโโ bf_vegetation_segment.py
โโโ scripts/ # utility scripts
โ โโโ sync_assets.sh # pull data/models from lab store
โ โโโ optimize_large_glb.py
โ โโโ grounding_dino_api_client.py
โโโ staticfiles/web/ # hand-written JS, CSS, vendor libs
โโโ static/, media/, stl_models/ # runtime assets (gitignored)
โโโ data/ # MBTiles (gitignored)
โโโ models/ # ML model weights (gitignored)
โโโ deepgis_results/ # AI-analysis outputs (gitignored)
โโโ GroundingDINO/ # vendored upstream repo
โโโ Dockerfile # web container (CUDA 12.1, torch 2.5)
โโโ docker-compose.yml # web + tileserver (+ topology, optional)
โโโ requirements.txt # pinned runtime deps
โโโ requirements-dev.txt # pytest, ruff, black, pip-tools
โโโ README.md
A companion refactoring plan lives in the integration manuscript workspace at
notes/2026-04-22-deepgis-xr-refactoring.md. Tiers AโD have all landed
(layer manager, static-tree consolidation, and Cesium FPS work) and Tier E's
forward-compat prep is in; the Tier E version bumps and Tier F are scheduled
on the roadmap below.
POST /webclient/sampler/initialize - Initialize new samplerPOST /webclient/sampler/sample - Get sample locationsPOST /webclient/sampler/update - Update distributionGET /webclient/sampler/query - Query spatial regionGET /webclient/sampler/statistics - Get distribution statsPOST /webclient/sampler/reset - Reset samplerGET /webclient/sampler/history - View sample historyPOST /webclient/sampler/analyze-viewport - Analyze viewport with AI
Parameters:
model_type โ one of (live as of April 2026):
'sam', 'yolov8', 'mask2former', 'zero_shot',
'prithvi', 'urban_spectral''grounding_dino', 'grounded_sam''maskrcnn_rocks', 'maskrcnn_house',
'maskrcnn_hypolith', 'maskrcnn_litter', 'maskrcnn_roadkill',
'maskrcnn_newlife', 'maskrcnn_brent_moon_craters',
'maskrcnn_harish_moon_craters'. Set MASKRCNN_API_URL to
consolidate behind a single container with all families served
from one process; per-family MASKRCNN_*_API_URL vars take
precedence when set so rollout can be gradual.image: Base64-encoded viewport imagelocation: Camera position metadatasam_model: 'vit_b', 'vit_l', or 'vit_h'min_area: Minimum segment area in pixelsyolo_model: 'yolov8n', 'yolov8s', 'yolov8m', 'yolov8l', 'yolov8x'confidence_threshold: 0.0-1.0class_filter: Comma-separated class names (e.g., "person,car,truck")text_prompt: Dot-separated object descriptions (e.g., "rock . boulder . crater")box_threshold: Detection confidence threshold (default: 0.3)text_threshold: Text matching threshold (default: 0.25)maskrcnn_* family):
model_id: explicit checkpoint id from the upstream registry
(overrides the family default; see
services/maskrcnn-rocks/README.md for the canonical defaults
per family)score_threshold: 0.0-1.0max_detections: int (default 100)confidence_threshold: 0.0-1.0Returns: GeoJSON FeatureCollection with detections, metadata, and saved on-host artefact paths.
Graceful degradation contract. When a remote AI service is
unconfigured, unreachable, or times out, the endpoint returns
HTTP 200 (not 503) with an empty FeatureCollection plus:
degraded: trueunavailable_reason: one of "not_configured",
"connection_error", "timeout"device_info.available: falseRetry-After HTTP header (30 s default; 60 s on timeout)This keeps the frontend's per-viewport-change poll loop from
spamming error toasts during transient outages โ clients that
check response.ok && result.status === 'success' see a normal
empty response and continue rendering. Clients that want an "AI
offline" badge can opt in by reading result.degraded === true.
Genuine HTTP 5xx from a reachable upstream and unhandled
exceptions inside the analyzer still surface as 502/500 โ those
are bugs, not unavailability, and they are deliberately not masked.
POST /label/semi-supervised/api/generate-labels/ - Generate assisted labelsPOST /label/semi-supervised/api/save-labels/ - Save labelsGET /label/semi-supervised/api/get-images/ - Get label imagesGET /api/v1/tile-catalog/ โ hierarchical layer registry consumed
by the Cesium frontend.
Returns a JSON tree of Site โ Dataset โ Timestep โ Product for
every active Product in the database, denormalised so the
frontend can render the layer panel without further round-trips.
Versioned ("version": 1); response shape:
{
"version": 1,
"generated_at": "2026-04-27T...",
"sites": [
{ "slug": "phx_wildfire", "name": "Phoenix wildfire site",
"bounds": [...], "default_zoom": 18,
"datasets": [
{ "slug": "wildfire_orthos", "kind": "timeseries",
"timesteps": [
{ "label": "2020-08", "sort_key": "2020-08-02",
"products": [
{ "layer_id": "bf_aug_2020_raster", "kind": "orthophoto",
"label": "Orthophoto (Aug 2020)", "default_opacity": 0.7 }
]}
]}
]},
{ "slug": "bishop_ca", "...": "..." }
]
}
Edited via the Django admin at /label/admin/tile_catalog/.
Bootstrap with python manage.py seed_tile_catalog; audit drift
against tileserver-gl /data.json with
python manage.py validate_tile_catalog.
The AI Viewport Analysis system supports multiple detection models, including remote API deployment for GPU-intensive models like Grounding DINO.
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ DeepGIS-XR Frontend โ
โ AI Viewport Analysis panel โ text prompts, sliders, model picker โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ POST /webclient/sampler/analyze-viewport
โ {image, location, model_type, model_id?, โฆ}
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ DeepGIS-XR Django Backend (gunicorn, GPU-attached) โ
โ apps/web/world_sampler_api/http.py::analyze_viewport() โ
โ โโ analyzers/ANALYZER_REGISTRY[model_type] โ dispatches to: โ
โ โ
โ LOCAL inference (in the web container): โ
โ sam ยท yolov8 ยท mask2former ยท zero_shot ยท โ
โ prithvi ยท urban_spectral โ
โ โ
โ REMOTE inference (Flask services on the GPU host): โ
โ grounding_dino ยท grounded_sam ยท sam (remote) โ
โ maskrcnn_{rocks ยท house ยท hypolith ยท litter ยท โ
โ roadkill ยท newlife ยท โ
โ brent_moon_craters ยท harish_moon_craters} โ
โ โ
โ Mask R-CNN dispatch (resolve_remote_maskrcnn_url): โ
โ โ if MASKRCNN_*_API_URL set for this family โ use it โ
โ โก else if MASKRCNN_API_URL set โ use it + inject family โ
โ default into the per-request `model_id` form field โ
โ โข else โ _unavailable_response("not_configured") โ
โ โ
โ On AI-down (not_configured ยท connection_error ยท timeout): โ
โ โ HTTP 200 + {status:"success", degraded:true, โ
โ detections:[], unavailable_reason, โฆ} โ
โ Retry-After: 30s (60s on timeout) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Remote AI host 192.168.0.232 (Flask + CUDA) โ
โ :5000 grounding_dino :5006 maskrcnn_roadkill โ
โ :5001 grounded_sam_2 :5007 maskrcnn_newlife โ
โ :5002 maskrcnn_rocks :5008 maskrcnn_brent_moon โ
โ :5003 maskrcnn_house :5009 maskrcnn_harish_moon โ
โ :5004 maskrcnn_hypolith :5010 sam (classic v1) โ
โ :5005 maskrcnn_litter โ
โ โ
โ Phase-1 consolidation: collapse :5002โ:5009 to ONE container โ
โ on :5002 with all eight weight bundles mounted; legacy direct โ
โ callers preserved by services/maskrcnn-rocks/scripts/ โ
โ port_shim.py (Python stdlib, no nginx-lua) which injects the โ
โ correct model_id and proxies to the unified upstream. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
GPU-accelerated AI services on dedicated server for open-vocabulary detection and segmentation.
Grounding DINO (port 5000): Text-based detection
Grounded-SAM-2 (port 5001): Detection + high-quality segmentation
# Grounding DINO - Detection only
curl -X POST http://192.168.0.232:5000/api/predict \
-F "file=@image.jpg" -F "text_prompt=rock . boulder . crater"
# Grounded-SAM-2 - Detection + Segmentation
curl -X POST http://192.168.0.232:5001/detect \
-F "image=@image.jpg" -F "text_prompt=rock . boulder . crater"
# Python client
./grounding_dino_api_client.py --image viewport.jpg --prompt "rock . boulder"
Example Prompts: Geology: "rock . boulder . crater" | Urban: "building . car . tree" | Wildlife: "animal . bird . nest"
/label/3d/search/)"rock . crater . boulder"), thresholds/label/3d/moon/)/label/3d/search/)B key to toggle instantlyV to switch to 3D)/label/3d/search/)V to toggleS or click the Share button| Parameter | Description |
|---|---|
lon, lat, alt | Camera position |
heading, pitch, roll | Camera orientation |
viewMode | 2D, 3D, or Columbus |
flyDist, hSpeed, vSpeed | Drone fly settings |
orbRadius, orbPitch, orbYaw | Orbit settings |
orbiting, flying, takeoff, landing | Active mode flags |
Press H to view all shortcuts in-app. Key shortcuts include:
| Key | Action |
|---|---|
B | Toggle 3D Buildings |
V | Toggle View Mode (2D/3D/Columbus) |
F | Toggle Full Screen |
H | Show Keyboard Shortcuts Help |
S | Share Current View |
Q | Toggle QR Code |
T | Hide/Show Toolbars |
W | Toggle Wireframe |
D | Drone Fly Forward |
U | Takeoff (Up) |
L | Land |
O | Start Orbit |
P | Pause/Stop Orbit |
J | Toggle Virtual Joysticks |
โ โ โ โ | Camera Perspectives (N/S/W/E) |
ESC | Stop Orbit / Close Panels |
The full, authoritative list lives in
.env.example. Copy it to .env and edit. The
operationally important knobs are:
# Core (production posture by default)
DEBUG=False
DJANGO_SETTINGS_MODULE=deepgis_xr.settings
SECRET_KEY= # generate with: openssl rand -hex 32
ALLOWED_HOSTS=deepgis.org,localhost,127.0.0.1
NVIDIA_VISIBLE_DEVICES=all # GPU passthrough
# Web โ gunicorn (defaults match the Dockerfile CMD)
GUNICORN_WORKERS=2
GUNICORN_THREADS=4
GUNICORN_TIMEOUT=600
# Database โ leave unset for the legacy SQLite default; flip to
# `postgres://deepgis:deepgis@db:5432/deepgis` after running
# `docs/migration-sqlite-to-postgres.md`. The bundled `db` service is
# off until you `docker compose --profile postgres up -d db`.
# DATABASE_URL=postgres://deepgis:deepgis@db:5432/deepgis
POSTGRES_DB=deepgis
POSTGRES_USER=deepgis
POSTGRES_PASSWORD=deepgis
# Celery broker / result backend (auto-wired by the redis service)
REDIS_URL=redis://redis:6379/0
# Remote AI services (Flask containers on a separate GPU host)
# Phase-1 consolidation: set this to point all Mask R-CNN families at
# a single upstream container; per-family vars below override it.
# MASKRCNN_API_URL=http://192.168.0.232:5002
GROUNDING_DINO_API_URL=http://192.168.0.232:5000
GROUNDED_SAM_API_URL=http://192.168.0.232:5001
SAM_API_URL=http://192.168.0.232:5010
# MASKRCNN_ROCKS_API_URL=http://192.168.0.232:5002
# โฆ see .env.example for the full eight-family list (5002โ5009)
The docker-compose.yml ships the following services.
Default (docker compose up -d):
| Service | Image | Role |
|---|---|---|
web | built locally (Dockerfile) | Django + DRF behind gunicorn (workers=2, threads=4, timeout=600); GPU-attached; runs manage.py migrate --noinput once on boot |
redis | redis:7-alpine | Celery broker + result backend (healthchecked, no host port) |
celery_worker | reuses the web image | Single replica (--concurrency=1 because the training task takes the whole GPU); waits on redis healthcheck |
tileserver | maptiler/tileserver-gl | Serves MBTiles raster + vector tiles |
Optional (profile-gated):
| Service | Image | Profile | Notes |
|---|---|---|---|
db | postgres:16-alpine | postgres | Bring up only when you're ready to migrate off SQLite. Runbook: docs/migration-sqlite-to-postgres.md. |
Volume mounts:
dreams_laboratory/scripts โ ML model scripts (read-only)deepgis_results โ AI analysis artefacts (shared with host)redis_data, postgres_data โ named volumes for service persistenceTo enable GPU for AI features:
docker-compose.ymlNVIDIA_VISIBLE_DEVICES=all is setThe flat raster/vector checkbox lists in the layer panel have been
replaced with a hierarchical Site โ Dataset โ Timestep โ Product
catalog backed by a new Django app (apps.tile_catalog) and a single
GET /api/v1/tile-catalog/ endpoint. Per the data shape that emerged
from the April tileserver audit โ one timeseries site (PHX wildfire,
5 dates) and one single-shot site (Bishop, CA) live today, with
Hawaii / Italy / others queued for activation โ the new panel
reorganises the UI around three independent axes:
Timestep, sorted by sort_key) with
per-tick coverage dots โ small colored dots showing which product
kinds (orthophoto / vector / 3D mesh / โฆ) exist at that timestep.
Pin-by-click; prev/next stepper buttons; readout below shows the
active timestep label.Plus three modes that compose with the above:
single | swipe | overlay
selector. Swipe uses Cesium's splitDirection to render A on the
left and B on the right of a draggable vertical split; shift-click
any timestep to move the B pin. Overlay blends both at half opacity
so spatial differences read visually. Mode selector lives inside
the timeseries panel because it's per-dataset, not per-site.camera.moveEnd. Day-to-day clutter killer once the catalog grows
past a handful of sites.tileserver-gl serves that the
catalog doesn't know about appear in a collapsed "Uncategorized"
group at the bottom โ reachable, but the visual cue is "please
curate this in the admin." python manage.py validate_tile_catalog
reports drift in both directions for CI / cron use.Editing happens entirely through the Django admin
(/label/admin/tile_catalog/), which uses inline forms so opening a
Site shows its Datasets, opening a Dataset shows its Timesteps, and
so on. Initial bootstrap is python manage.py seed_tile_catalog
(idempotent; admin edits survive subsequent runs unless
--force-update is passed).
GUNICORN_* overridable);
DEBUG defaults to False; manage.py migrate --noinput runs once
on container start. Compose file ships redis (the broker the
training queue had been quietly assuming) and a single-replica
celery_worker so train_model_task.delay(โฆ) actually runs end-to-
end. Postgres 16 is wired and waiting behind the postgres profile
with dj-database-url + psycopg2-binary already in
requirements.txt; cutover from the legacy 1.7 GB db.sqlite3 is
operator-driven via docs/migration-sqlite-to-postgres.md โ nothing
is forced.analyze-viewport no longer returns
hard 503s when a remote AI service is unconfigured / unreachable /
timing out. New _unavailable_response(...) helper (in
analyzers/_helpers.py) returns HTTP 200 with
{status:"success", degraded:true, detections:[], unavailable_reason, โฆ} plus a Retry-After header (30 s default; 60 s on timeout) so
the frontend's per-viewport-change poll loop stops spamming error
toasts during transient outages. Reserved for unavailability only โ
real upstream 5xx and analyzer crashes still surface as 502/500.MASKRCNN_*_API_URL services on :5002โ:5009 all run the same
services/maskrcnn-rocks/ Docker image with different
DEFAULT_MODEL_IDs. New analyzer dispatch helper
(resolve_remote_maskrcnn_url) prefers a single MASKRCNN_API_URL
when set and injects the family default into the per-request
model_id form field; the per-family vars take precedence so
rollout is gradual. Backward-compat for legacy direct clients on
the old port range is provided by
services/maskrcnn-rocks/scripts/port_shim.py โ a stdlib-only
Python proxy (no nginx-lua) that injects the correct model_id and
forwards to the unified upstream. Phase 2 (operator-side) collapses
to one upstream container with all weight bundles mounted.requirements.txt; added
requirements-dev.txt; relocated root .py scripts into
services/topology/, examples/, scripts/; kernelcal installed as a
real dep; scripts/sync_assets.sh syncs data//models//deepgis_results/
from /mnt/dreamslab-store; dead Vite config removed.apps/web/views.py
monolith is now a views/ package โ pages, missions, auth_ajax,
ai_reports, training_datasets, semi_supervised, models_3d plus a
shrinking legacy.py, with __init__.py preserving every public name
urls.py routes to.world_sampler_api.py is now a
package with core.py (helpers), http.py (9 endpoints), and an
analyzers/ subpackage (7 analyzers + 3 shared helpers) exposed through
an ANALYZER_REGISTRY. This unblocks the MaxCal / Model-Kernel Selector
work in kernelcal.toggleOSMBuildings
paths onto one canonical helper in cesium-init.js; a new feature-layer
registry in staticfiles/web/js/core/feature-layers.js normalises
heterogeneous layer toggles (OSM Buildings, World Terrain, โฆ) behind
a single window.FeatureLayers.set(id, enabled) / renderToggles(โฆ)
API; Tier D3 lifted the OSM-Buildings toggle onto label_topology
via the registry.USE_L10N = True (removed in Django 5.0) and the stale
default_app_config pointer in apps/auth/__init__.py (removed in
4.2, already redundant given INSTALLED_APPS lists AuthConfig
directly); removed an unused shapely.geometry.shape import in
views/legacy.py. All three edits are no-ops on the current Django
3.2 / Shapely 1.8 stack and shrink the actual bump commit to a
four-line requirements.txt change.BASE_DIR/staticfiles/ into STATICFILES_DIRS so Django's finders
actually resolve {% static 'web/js/main.js' %} to the tracked tree.
Without this, the Tier D frontend work had been sitting in the repo
but not being served โ the app had been falling back to an older,
untracked deepgis_xr/apps/web/static/ tree. Orphaned assets
(mask2former-corrector.css/.js, responsive.css) parked under
staticfiles/web/legacy/ with a README.cesium-init.js โ globe enableLighting, uncapped
resolutionScale ร devicePixelRatio on Retina/4K (now capped at 1.5ร
with ?hidpi=1 opt-in), tileLoadProgressEvent โ requestRender
spam, and fxaa on an already-supersampled scene. 60 FPS restored
on iGPU / Retina.B key; free and open data (ODbL)Contributions are welcome! Please follow these guidelines:
git checkout -b feature/amazing-feature)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)This project is licensed under the MIT License - see the LICENSE file for details.
DeepGISโXR builds on concepts and systems originally developed for the Oceanographic Decision Support System (ODSS, MBARI), the Agricultural Decision Support System (AgDSS, University of Pennsylvania), the OpenUAV Project (University of Pennsylvania, Arizona State University), and DeepGIS (Arizona State University). The DeepGIS project acknowledges support from the National Science Foundation, the United States Department of Agriculture, and the National Aeronautics and Space Administration.
Tiers AโC and the Tier-D prep steps (D0, D0.5) have landed. Remaining work
is tracked alongside feature work. See
notes/2026-04-22-deepgis-xr-refactoring.md in the integration workspace
for the full plan.
apps/web/views.py โ views/ package of 7 focused
modules + shrinking legacy.py (PR #4)world_sampler_api.py โ package with core.py, http.py
(9 endpoints), analyzers/ subpackage, and ANALYZER_REGISTRY
(PR #5; unblocks kernelcal Threads 1 + 2)core/feature-layers.js with a window.FeatureLayers API;
registry-driven toggles on label_topologystaticfiles/ wired into STATICFILES_DIRS so the
tracked frontend tree is actually served; orphaned assets parked in
staticfiles/web/legacy/ (PR #8)cesium-init.js; 60 FPS restored on iGPU/Retina (PR #8)requirements.txt change pending container regression sweep. Full
recon in TIER_E_MIGRATION_NOTES.md at the repo root (local-only).
Django 5.0/5.1 is tracked separately (needs Python 3.10+).kernelcal integration: MaxCal World Sampler, Model-Kernel
Selector, terrain diagnostics endpointDEBUG=False + redis + celery_worker services
shipped; Postgres 16 wired behind a postgres profile with a
cutover runbook (docs/migration-sqlite-to-postgres.md);
_unavailable_response graceful-degradation contract added to
analyze-viewport; Mask R-CNN dispatch consolidated behind
MASKRCNN_API_URL + per-family fallback + port_shim.py.
Phase 2 (operator-side, pending): collapse
services/maskrcnn-rocks/ to one upstream container with all
eight weight bundles mounted; SQLite โ Postgres data cutover.This software is provided "as is" without warranty. Use at your own risk. Intended for research and educational purposes. AI analysis results should be validated independently for critical applications.
Powered by Earth Innovation Hub (Arizona STEAM non-profit corporation)
296 commits
JavaScript
66.8%
HTML
15.7%
Python
15.3%
CSS
1.5%