Skip to content

The builder's HTTP API

The wizard is a Flask app serving one page, one shared script and fifteen /api/ routes, all under 127.0.0.1. Most return JSON; two do not — /api/staged returns a file and /api/precompute returns a text stream. This page is for someone working on the wizard itself; if you only want to use it, the builder is the page you want.

There is no authentication and no multi-user state. It is a local single-user tool holding one project at a time in the server process.

Page and assets

route
GET / the wizard page — static/index.html
GET /static/<path:fname> builder.js, style.css
GET /vendor/figure-geometry.js the body the step 4 diagram is drawn on, served straight from the DIMS checkout's packages/dims-tabs/

That last route is the mechanism that keeps the wizard's diagram and the dashboard's network tab identical. The wizard is not given a copy — it is served the same file the dashboard vendors, so the two cannot drift. See figure-geometry.md.

Opening or creating a project

route
POST /api/project create a new study at a path, with a visibility. Delegates the skeleton to dims_case.core
POST /api/open reopen a study the builder made earlier, with every step filled in from its config.json

POST /api/project is what the CI smoke test drives: it asserts the result contains config.json, index.html, serve.py, dims-case.json, vendor/dims-core and vendor/dims-tabs — i.e. that the wizard produces a complete study and not a directory that merely looks like one.

Staging files (step 2)

Uploads go to a staging directory inside the package and are only placed into the study at build time.

route
POST /api/upload stage a file. Returns a list of rows — an id, inferred role, guessed session id and measure name each — because a multi-column CSV is split into one staged file per measure
POST /api/assign correct the role, session or measure of a staged file
DELETE /api/upload/<fid> drop a staged file
GET /api/staged/<fid> serve a staged file back, range-enabled so the align step can scrub a video that is not in the study yet
GET /api/sessions the sessions and measures implied by what is currently staged
POST /api/samples stage the example study, generating it on first use

The role is inferred from the extension, then shown for correction rather than assumed — the wizard guesses and says it guessed.

Alignment (step 3)

route
POST /api/trim_video record a trim for a session's video
POST /api/pad_timeseries record zero-padding for a time series

Both routes only record a spec. Nothing is trimmed or padded here; the work happens in /api/build, applied to the copies placed in the study. /api/trim_video does check that an ffmpeg is available before accepting one.

When the work does run, only trimming shells out — media.pad_timeseries is pure-Python CSV rewriting. The ffmpeg comes from imageio-ffmpeg rather than a system install.

Config, validation and build (steps 4–5)

route
GET \| POST /api/config read the assembled config, or merge keys into it. POST updates the server's in-memory state only — it does not write config.json; that happens at build
POST /api/validate the problem list, split into errors and warnings
POST /api/build write the study: place staged files, apply the align specs, then write config.json

validate.py holds the per-file and per-config checks: validate_csv, validate_transcript and validate_eaf per file, then validate_config and validate_network.

The schema check lives elsewhere, in project.schema_problems(), and runs inside write_config against docs/contracts/config.schema.json — the same schema the repository tests treat as authoritative. Two things to know about it: it runs after the staged assets have been copied into the study, so a schema failure leaves files already placed; and it passes silently when jsonschema is not installed or the schema cannot be read.

Running and previewing (steps 6–7)

route
POST /api/precompute run the analyses, streaming the log back as chunked text
POST /api/preview start serve.py in the study and return its URL

precompute creates a virtualenv inside the study and installs the analysis requirements into it, so the run does not inherit however the builder itself was installed. It streams with PYTHONUNBUFFERED set, because a progress log that arrives all at once at the end is not a progress log.

It carries three repairs for requirement files written by older studies: a scipy==1.26.4 pin that never existed is rewritten to an unpinned scipy, json listed as though it were a package is dropped, and numpy is appended in case the study never named it. Without these an old study's requirements simply fail to install.

Where it lives

apps/builder/dims_builder/ — server.py has the routes; project.py creates and reads a study and holds the schema check; validate.py the file and config checks; media.py the trimming and padding; precompute.py the analysis run; example_study.py generates ConvoConnect-Mini.

Tests are split by language: apps/builder/tests/ is the Python, apps/builder/test/ is the JavaScript. See testing.