feat(perception): publish immutable lab session instances

This commit is contained in:
DCCONSTRUCTIONS
2026-07-23 20:13:40 +03:00
parent f1f8e21b78
commit 10019a454a
16 changed files with 1970 additions and 30 deletions
+8 -19
View File
@@ -327,6 +327,7 @@ def build_session_router(
"modalities": list(item.modalities),
"duration_seconds": item.duration_seconds or 0.0,
"replayable": item.replayable,
**({"lab": item.lab.as_dict()} if item.lab is not None else {}),
**(
{
"preparation": _catalog_preparation_document(
@@ -410,9 +411,8 @@ def build_session_router(
detail="Запись сейчас открыта в интерфейсе. Закройте её и повторите удаление.",
)
if (
recording_preparation_manager is not None
and not recording_preparation_manager.discard(session_id)
if recording_preparation_manager is not None and not recording_preparation_manager.discard(
session_id
):
raise HTTPException(
status_code=409,
@@ -960,10 +960,7 @@ def build_session_router(
},
)
@router.get(
"/api/v1/observation-sessions/{session_id}/perception-media/"
"{result_id}/manifest"
)
@router.get("/api/v1/observation-sessions/{session_id}/perception-media/{result_id}/manifest")
def get_recorded_perception_media_manifest(
session_id: str,
result_id: str,
@@ -988,8 +985,7 @@ def build_session_router(
)
@router.api_route(
"/api/v1/observation-sessions/{session_id}/perception-media/"
"{result_id}/recording.mp4",
"/api/v1/observation-sessions/{session_id}/perception-media/{result_id}/recording.mp4",
methods=["GET", "HEAD"],
)
def stream_recorded_perception_media(
@@ -1593,10 +1589,7 @@ def _recorded_perception_manifest_document(
) -> dict[str, Any]:
encoded_session_id = quote(video.session_id, safe="")
encoded_result_id = quote(video.result_id, safe="")
base = (
f"/api/v1/observation-sessions/{encoded_session_id}/perception-media/"
f"{encoded_result_id}"
)
base = f"/api/v1/observation-sessions/{encoded_session_id}/perception-media/{encoded_result_id}"
return {
"schema_version": RECORDED_MEDIA_STREAM_MANIFEST_SCHEMA,
"source_id": video.public_source_id,
@@ -1835,9 +1828,7 @@ def _recorded_media_epoch_response(
if len(matches) != 1:
raise HTTPException(status_code=404, detail="Эпоха записанного медиаканала не найдена.")
epoch = matches[0]
byte_length = epoch.init_byte_length + sum(
segment.byte_length for segment in epoch.segments
)
byte_length = epoch.init_byte_length + sum(segment.byte_length for segment in epoch.segments)
start, end = (0, byte_length - 1)
status_code = 200
if range_header is not None:
@@ -1851,9 +1842,7 @@ def _recorded_media_epoch_response(
"ETag": etag,
"Content-Length": str(end - start + 1),
"X-Content-Type-Options": "nosniff",
"Content-Disposition": (
f'inline; filename="recorded-camera-{epoch.ordinal}.mp4"'
),
"Content-Disposition": (f'inline; filename="recorded-camera-{epoch.ordinal}.mp4"'),
}
if status_code == 206:
headers["Content-Range"] = f"bytes {start}-{end}/{byte_length}"