Skip to content

Replace a phase still with a coach-picked frame

POST
/api/solutions/runs/{run_id}/phase-frame/
curl --request POST \
--url http://localhost:8000/api/solutions/runs/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/phase-frame/ \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "block_id": "phase-slider-1", "phase_id": "take_off", "attempt_id": "", "session_id": "6f1d3a2e-8c4b-4f4e-9d2a-1b2c3d4e5f60", "timestamp_ms": 2440 }'

Phase-frame re-pick (#1382): when phase detection lands on the wrong still, the coach scrubs the clip in the report lightbox and submits a timestamp; the API extracts that frame from the bound session’s annotated clip and stores it as a RUN-scoped override. The override is what the report, the public share link and the PDF export all render for that phase; a new run of the same Solution starts from the analyzer’s own frames again. block_id / phase_id / attempt_id / session_id are echoed from the phase block’s repick context in the report payload. Team-scoped; cross-team run ids are a 404.

run_id
required
string format: uuid

Request body for POST /api/solutions/runs/<id>/phase-frame/ — replace one phase’s still with a frame the coach picked from the clip (#1382). block_id + phase_id + attempt_id identify the phase (the FE echoes them from the block’s repick context); session_id names the bound session whose clip the frame is cut from; timestamp_ms is the scrub position (clamped into the clip server-side).

object
block_id
required

The phase block being corrected (phase-slider-1 / phase-breakdown-1).

  • phase-slider-1 - phase-slider-1
  • phase-breakdown-1 - phase-breakdown-1
string
Allowed values: phase-slider-1 phase-breakdown-1
phase_id
required

Analyzer phase name, e.g. take_off — the id of the phase inside the block payload.

string
>= 1 characters <= 100 characters
attempt_id

Per-trial payload id for multi-attempt reports (the block’s repick.attemptId); omit for single-attempt reports.

string
"" <= 64 characters
session_id
required

Bound session whose clip the frame is extracted from (the block’s repick.sessionId). Must be in the run’s bindings.

string format: uuid
timestamp_ms
required

Clip position to extract, in ms from clip start.

integer
Examples
ExampleRe-pickTheTake-offStill

Replace the running-gait Take-off frame at 2.44 s

{
"block_id": "phase-slider-1",
"phase_id": "take_off",
"attempt_id": "",
"session_id": "6f1d3a2e-8c4b-4f4e-9d2a-1b2c3d4e5f60",
"timestamp_ms": 2440
}
Media typeapplication/json

200 from the phase-frame pick — the stored override frame.

object
frame_image_url
required

Public URL of the extracted frame now shown for the phase.

string
Examples
ExampleOverrideStored

Override stored

{
"frame_image_url": "https://media.example.com/aik-media/teams/1/solutions/9a8b7c6d/phase-frames/0f9e8d7c6b5a.jpg"
}

Invalid body — unknown block_id, a session_id not in the run’s bindings, or a session with no clip to extract from.

Media typeapplication/json
object
detail
required

Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).

string
Examplegenerated
{
"detail": "example"
}
Media typeapplication/json
object
detail
required

Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).

string
Examplegenerated
{
"detail": "example"
}
Media typeapplication/json
object
detail
required

Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).

string
Examplegenerated
{
"detail": "example"
}

frame_extract_failed — ffmpeg could not produce a frame (unreachable clip, decode failure, timeout). Nothing is stored; the phase keeps its previous frame.

Media typeapplication/json
object
detail
required

Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).

string
Examplegenerated
{
"detail": "example"
}