Repo for the Google partner project with UNOPS.
This project currently includes:
- An Earth Engine pipeline that trains a classifier and starts CSV table exports to GCS.
- A FastAPI backend that manages export jobs and file discovery.
- A simple frontend POC that starts exports, polls file readiness, downloads directly from GCS, and then deletes exported files.
- Frontend calls
POST /exports. - Backend creates a job and returns identifiers including
taskIdandfileId. - Backend runs
run_export(...)asynchronously and starts Earth Engine table exports to GCS. - Frontend polls
GET /export-status/{fileId}. - Backend lists matching GCS objects and returns:
{
"ready": true,
"files": [
{
"name": "...",
"url": "..."
}
]
}- Frontend stores
files[0].urlasdownloadUrl. - On download click, frontend triggers a hidden
<a>download (target="_blank",download=""). - Frontend calls
DELETE /export-delete/{fileId}to clean up files.
Important: backend does not stream file bytes; browser downloads directly from GCS using URL returned by backend.
pipeline/main.py runs a classification workflow and starts two Earth Engine table exports (ee.batch.Export.table.toCloudStorage) with fileFormat="CSV":
*_prediction_stats.csv*_yearly_urban_area.csv
So yes, this implementation is currently CSV-only.
pipeline/main.pyrun_export(...)reusable pipeline function- CLI entrypoint for manual runs
pipeline/api.py- FastAPI app
- async job creation and status tracking
- GCS file discovery, download URL generation, and cleanup endpoints
frontend/index.html- simple dashboard for starting export + polling + direct download + cleanup
GET /health
-
POST /exports- Starts async export job.
- Returns job status + identifiers (including
taskIdandfileId).
-
GET /exports/{job_id}- Returns backend job record.
- Can include Earth Engine task status refresh when available.
-
GET /export-status/{fileId}- Returns
{ ready, files }for matching GCS objects.
- Returns
-
GET /download-links/{fileId}- Same
{ ready, files }response shape.
- Same
-
DELETE /export-delete/{fileId}- Deletes matching files in bucket and returns deletion summary.
pipeline/api.py supports GCS_URL_MODE:
signed: always return signed URLs (requires signing configuration)public: always returnhttps://storage.googleapis.com/{bucket}/{object}auto(default): try signed URL, fall back to public URL
If using signed mode (or auto with private bucket), set:
SIGNING_SERVICE_ACCOUNT_EMAIL=<service-account-email>
And grant required IAM (e.g. token creator + object read path, depending on runtime identity model).
From repo root:
python -m uvicorn orbit_unops.pipeline.api:app --reloadOptional environment examples:
# Use direct public object URLs
set GCS_URL_MODE=public
# Or force signed URLs
set GCS_URL_MODE=signed
set SIGNING_SERVICE_ACCOUNT_EMAIL=your-sa@your-project.iam.gserviceaccount.compython -m http.server 5500 --directory orbit_unops/frontendhttp://127.0.0.1:5500
- Earth Engine exports are asynchronous; delays in
Submitted to serverare usually EE queue/compute behavior. - Current
run_export(...)includes diagnostics and multiple.getInfo()calls before/around task startup, which can add latency. - If you see
AccessDeniedon direct GCS URL downloads, either:- use signed URLs correctly, or
- use public URL mode + public read access (if allowed by your org policy).