Replace a phase still with a coach-picked frame
const url = 'http://localhost:8000/api/solutions/runs/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/phase-frame/';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"block_id":"phase-slider-1","phase_id":"take_off","attempt_id":"","session_id":"6f1d3a2e-8c4b-4f4e-9d2a-1b2c3d4e5f60","timestamp_ms":2440}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}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.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Request Bodyrequired
Section titled “Request Bodyrequired”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
The phase block being corrected (phase-slider-1 / phase-breakdown-1).
phase-slider-1- phase-slider-1phase-breakdown-1- phase-breakdown-1
Analyzer phase name, e.g. take_off — the id of the phase inside the block payload.
Per-trial payload id for multi-attempt reports (the block’s repick.attemptId); omit for single-attempt reports.
Bound session whose clip the frame is extracted from (the block’s repick.sessionId). Must be in the run’s bindings.
Clip position to extract, in ms from clip start.
Examples
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}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
The phase block being corrected (phase-slider-1 / phase-breakdown-1).
phase-slider-1- phase-slider-1phase-breakdown-1- phase-breakdown-1
Analyzer phase name, e.g. take_off — the id of the phase inside the block payload.
Per-trial payload id for multi-attempt reports (the block’s repick.attemptId); omit for single-attempt reports.
Bound session whose clip the frame is extracted from (the block’s repick.sessionId). Must be in the run’s bindings.
Clip position to extract, in ms from clip start.
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
The phase block being corrected (phase-slider-1 / phase-breakdown-1).
phase-slider-1- phase-slider-1phase-breakdown-1- phase-breakdown-1
Analyzer phase name, e.g. take_off — the id of the phase inside the block payload.
Per-trial payload id for multi-attempt reports (the block’s repick.attemptId); omit for single-attempt reports.
Bound session whose clip the frame is extracted from (the block’s repick.sessionId). Must be in the run’s bindings.
Clip position to extract, in ms from clip start.
Responses
Section titled “Responses”200 from the phase-frame pick — the stored override frame.
object
Public URL of the extracted frame now shown for the phase.
Examples
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.
object
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).
Examplegenerated
{ "detail": "example"}object
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).
Examplegenerated
{ "detail": "example"}object
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).
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.
object
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).
Examplegenerated
{ "detail": "example"}