ML NDJSON Stream API
HTTP streaming API and NDJSON events for the ML service.
ML HTTP Streaming API
The ML service exposes a bidirectional HTTP streaming endpoint. Core opens the connection on StartRecordingCommand and holds it open for the duration of the session.
POST /streaming/sessions
Creates a streaming session. The HTTP response body remains open.
| Auth | serviceAuth (Core → ML, mTLS service token) |
| Request Content-Type | application/json |
| Body | { meeting_id, transcription_id, audio_config } |
| Response | 201 Created — initial JSON { session_id } header line, then Content-Type: application/x-ndjson streaming body |
| Errors | 409 a session for this meeting_id already exists; 503 AssemblyAI unavailable |
POST /streaming/sessions/{session_id}/audio
Delivers a binary audio chunk to the active session.
| Auth | serviceAuth |
| Request Content-Type | application/octet-stream |
| Body | Raw binary audio chunk |
| Response | 204 No Content |
| Errors | 404 session not found; 410 session has been terminated |
DELETE /streaming/sessions/{session_id}
Terminates the session cleanly. ML drains the AssemblyAI buffer and closes the streaming response.
| Auth | serviceAuth |
| Response | 204 No Content |
| Errors | 404 session not found |
Streaming Response Envelope
ML writes NDJSON events to the open response stream. Each newline-terminated line is one event.
{ "type": "transcript_segment", "data": { "segment_id": "<uuid>", "speaker_label": "Speaker A", "text": "Hello world", "start_ms": 1200, "end_ms": 2400, "confidence": 0.96, "is_final": true } }
{ "type": "feature_vector", "data": { "segment_id": "<uuid>", "vector": [0.12, -0.34, 0.77] } }
{ "type": "speaker_match", "data": { "segment_id": "<uuid>", "person_id": "<uuid>", "score": 0.91 } }
{ "type": "talking_point", "data": { "id": "<uuid>", "content": "Discussed Q3 roadmap", "is_final": false, "segments": ["<uuid>"] } }
{ "type": "task", "data": { "id": "<uuid>", "content": "Follow up with design team", "source": "system" } }Core routes each event type to the appropriate handler:
| Event type | Core action |
|---|---|
transcript_segment | Broadcast TranscriptSegmentEvent on WS → async DB insert |
feature_vector | Async DB update on segment (no WS broadcast) |
speaker_match | Async DB update → broadcast EntityChanged { entity: transcript_segment } |
talking_point | Broadcast TalkingPointEvent on WS → async DB upsert |
task | Broadcast TaskEvent on WS → async DB insert |