Modulate · AsyncAPI Specification

Modulate Velma-2 Streaming Server

Version 0.0.0

Streaming velma-2 over WebSocket. Transcribes and analyzes a live audio stream against a client-supplied analysis configuration, emitting JSON events that describe clips and analysis results as they are produced, plus aggregate results (topics, sentiments, summary) and a final `done` event.

View Spec View on GitHub CompanyAiVoice AISpeech to TextTranscriptionDeepfake DetectionContent ModerationTrust and SafetyAudioMachine LearningPII RedactionVoice IntelligenceAsyncAPIWebhooksEvents

Channels

listPresets
HTTP `GET` endpoint that returns the catalog of behavior presets that can be referenced from the `behaviors` array in a BatchConfig using the `preset:` syntax. Each entry includes the preset `identifier`, `name`, `short_description`, and `detailed_description`. Requires the `X-API-Key` header. The key is validated for model access before the presets are returned, but calling this endpoint does not consume any usage. Returns HTTP `403` if the request is not permitted, HTTP `429` if the account has insufficient credits, or HTTP `502` if the usage check is temporarily unavailable.
velma2Streaming
WebSocket channel for streaming velma-2. ## Connection Flow 1. Connect with `api_key` and optional audio-format query parameters. 2. Connection is accepted if authentication succeeds and limits are not exceeded. 3. Send one text frame: either the literal string `default` or a JSON-encoded `BatchConfig`. 4. Stream audio data as binary WebSocket frames. 5. Send an empty text frame ("") to signal end of audio. 6. Receive streaming events as JSON messages. 7. Receive a final `done` event with total audio duration. 8. Connection closes automatically after completion. ## Error Handling If an error occurs, the server sends an `error` event and closes the connection. Connection rejections during handshake use WebSocket close codes. ## WebSocket Close Codes - `1000`: Normal closure after the `done` message, or after the connection completes. - `1003`: Protocol error (invalid or incomplete config, audio before config, unsupported audio format / sample rate / channel count). An `error` message is sent before the close. - `4003`: The request could not be validated, or the request is not permitted. An `error` message is sent before the close. - `4029`: The request could not be completed due to insufficient credits. An `error` message is sent before the close.

Messages

ListPresetsResponse
List Presets Response
JSON body returned by `GET /api/velma-2-streaming/list-presets`.
StreamConfig
Stream Configuration
First text frame: either the literal string `default` (to use the built-in default configuration) or a JSON-encoded BatchConfig object.
AudioChunk
Audio Data Chunk
Raw audio data chunk.
EndOfStream
End of Audio Stream
Empty text frame signalling end of audio stream.
ClipEvent
Clip
A transcribed clip with metadata.
PartialClipEvent
Partial Clip
An in-progress clip streamed while an utterance is still being spoken, before it finalizes. Multiple partials may be emitted for the same `clip_uuid` as the utterance grows; the eventual `clip` event for that utterance reuses the same `clip_uuid`, so a run of partials can be correlated with its final clip.
ClipUpdateEvent
Clip Update
Refined values for a previously finalized clip; `clip_update.clip_uuid` matches the `clip_uuid` of an earlier `clip` event. A finalized clip may receive any number of `clip_update` events (including none), each emitted after that clip's `clip` event (possibly interleaved with events for other clips) and always before the `done` event on clean completion. For each field present, the latest received value supersedes the value on the `clip` event and on any earlier `clip_update` for that clip.
ConversationTypeEvent
Conversation Type Pick
Inferred or default conversation-type pick for the session.
ParticipantRoleEvent
Participant Role Pick
Inferred or default participant-role pick for a speaker.
BehaviorDetectionEvent
Behavior Detection
Per-behavior detection result.
TopicsEvent
Topics
Aggregated list of conversation topics. May be emitted more than once as the stream progresses; each event fully replaces the previous `topics` event, so always treat the latest as authoritative and never merge with earlier ones.
TopicSentimentEvent
Topic Sentiment
Per-speaker sentiment for an aggregated topic, keyed by topic and speaker. May be emitted more than once as the stream progresses; a later event supersedes an earlier one for the same topic and speaker.
SummaryEvent
Summary
Free-form summary of the conversation. May be emitted more than once as the stream progresses; each event fully replaces the previous `summary` event, so always treat the latest as authoritative.
ErrorEvent
Error
An error occurred during processing.
DoneEvent
Done
Streaming completed.

Servers

wss
production
Modulate Velma-2 Streaming Server

AsyncAPI Specification

Raw ↑
asyncapi: 3.0.0
info:
  title: Modulate Velma-2 Streaming Server
  version: 0.0.0
  description: >
    Streaming velma-2 over WebSocket. Transcribes and analyzes a live audio

    stream against a client-supplied analysis configuration, emitting JSON
    events

    that describe clips and analysis results as they are produced, plus
    aggregate

    results (topics, sentiments, summary) and a final `done` event.
servers:
  production:
    host: platform.modulate.ai
    protocol: wss
    description: Modulate Velma-2 Streaming Server
channels:
  listPresets:
    address: /api/velma-2-streaming/list-presets
    description: |
      HTTP `GET` endpoint that returns the catalog of behavior presets
      that can be referenced from the `behaviors` array in a BatchConfig
      using the `preset:<identifier>` syntax. Each entry includes the
      preset `identifier`, `name`, `short_description`, and
      `detailed_description`.

      Requires the `X-API-Key` header. The key is validated for
      model access before the presets are returned, but calling this
      endpoint does not consume any usage. Returns HTTP `403` if the
      request is not permitted, HTTP `429` if the account has
      insufficient credits, or HTTP `502` if the usage check is
      temporarily unavailable.
    messages:
      listPresetsResponse:
        $ref: '#/components/messages/ListPresetsResponse'
  velma2Streaming:
    address: /api/velma-2-streaming
    description: >
      WebSocket channel for streaming velma-2.


      ## Connection Flow

      1. Connect with `api_key` and optional audio-format query parameters.

      2. Connection is accepted if authentication succeeds and limits are not
      exceeded.

      3. Send one text frame: either the literal string `default` or a
         JSON-encoded `BatchConfig`.
      4. Stream audio data as binary WebSocket frames.

      5. Send an empty text frame ("") to signal end of audio.

      6. Receive streaming events as JSON messages.

      7. Receive a final `done` event with total audio duration.

      8. Connection closes automatically after completion.


      ## Error Handling

      If an error occurs, the server sends an `error` event and closes the

      connection. Connection rejections during handshake use WebSocket close

      codes.


      ## WebSocket Close Codes

      - `1000`: Normal closure after the `done` message, or after the
        connection completes.
      - `1003`: Protocol error (invalid or incomplete config, audio before
        config, unsupported audio format / sample rate / channel count). An
        `error` message is sent before the close.
      - `4003`: The request could not be validated, or the request is not
        permitted. An `error` message is sent before the close.
      - `4029`: The request could not be completed due to insufficient credits.
        An `error` message is sent before the close.
    bindings:
      ws:
        query:
          type: object
          required:
            - api_key
          properties:
            api_key:
              type: string
              description: |
                Your API key for authentication. Required. Must be provided as a
                query parameter when establishing the WebSocket connection; the
                connection is rejected during the handshake if it is missing.
            audio_format:
              type: string
              description: |
                Audio encoding format. Self-describing formats (AAC, AIFF, FLAC,
                MP3, OGG, WAV, WebM) are auto-detected when omitted.
                Raw/headerless formats (PCM, mu-law, A-law) require this
                parameter plus `sample_rate` and `num_channels`.
              enum:
                - s8
                - s16le
                - s16be
                - s24le
                - s24be
                - s32le
                - s32be
                - u8
                - u16le
                - u16be
                - u24le
                - u24be
                - u32le
                - u32be
                - f32le
                - f32be
                - f64le
                - f64be
                - mulaw
                - alaw
                - wav
                - mp3
                - ogg
                - flac
                - webm
                - aac
                - aiff
            sample_rate:
              type: integer
              description: |
                Audio sample rate in Hz. Required when `audio_format` is a
                raw/headerless format. Cannot be specified without
                `audio_format`.
              enum:
                - 8000
                - 11025
                - 16000
                - 22050
                - 32000
                - 44100
                - 48000
                - 96000
            num_channels:
              type: integer
              minimum: 1
              maximum: 8
              description: |
                Number of audio channels (1-8). Required when `audio_format` is
                a raw/headerless format. Cannot be specified without
                `audio_format`.
    messages:
      streamConfig:
        $ref: '#/components/messages/StreamConfig'
      audioChunk:
        $ref: '#/components/messages/AudioChunk'
      endOfStream:
        $ref: '#/components/messages/EndOfStream'
      clipEvent:
        $ref: '#/components/messages/ClipEvent'
      partialClipEvent:
        $ref: '#/components/messages/PartialClipEvent'
      clipUpdateEvent:
        $ref: '#/components/messages/ClipUpdateEvent'
      conversationTypeEvent:
        $ref: '#/components/messages/ConversationTypeEvent'
      participantRoleEvent:
        $ref: '#/components/messages/ParticipantRoleEvent'
      behaviorDetectionEvent:
        $ref: '#/components/messages/BehaviorDetectionEvent'
      topicsEvent:
        $ref: '#/components/messages/TopicsEvent'
      topicSentimentEvent:
        $ref: '#/components/messages/TopicSentimentEvent'
      summaryEvent:
        $ref: '#/components/messages/SummaryEvent'
      errorEvent:
        $ref: '#/components/messages/ErrorEvent'
      doneEvent:
        $ref: '#/components/messages/DoneEvent'
operations:
  receiveListPresets:
    action: receive
    summary: HTTP GET - list available behavior presets.
    channel:
      $ref: '#/channels/listPresets'
    messages:
      - $ref: '#/channels/listPresets/messages/listPresetsResponse'
  sendStreamConfig:
    action: send
    summary: First text frame - `default` or JSON-encoded BatchConfig.
    channel:
      $ref: '#/channels/velma2Streaming'
    messages:
      - $ref: '#/channels/velma2Streaming/messages/streamConfig'
  sendAudioChunk:
    action: send
    summary: Binary audio frame.
    channel:
      $ref: '#/channels/velma2Streaming'
    messages:
      - $ref: '#/channels/velma2Streaming/messages/audioChunk'
  sendEndOfStream:
    action: send
    summary: Empty text frame signaling end of audio.
    channel:
      $ref: '#/channels/velma2Streaming'
    messages:
      - $ref: '#/channels/velma2Streaming/messages/endOfStream'
  receiveStreamingEvents:
    action: receive
    summary: Server-emitted events. Discriminated by the `type` field.
    channel:
      $ref: '#/channels/velma2Streaming'
    messages:
      - $ref: '#/channels/velma2Streaming/messages/clipEvent'
      - $ref: '#/channels/velma2Streaming/messages/partialClipEvent'
      - $ref: '#/channels/velma2Streaming/messages/clipUpdateEvent'
      - $ref: '#/channels/velma2Streaming/messages/conversationTypeEvent'
      - $ref: '#/channels/velma2Streaming/messages/participantRoleEvent'
      - $ref: '#/channels/velma2Streaming/messages/behaviorDetectionEvent'
      - $ref: '#/channels/velma2Streaming/messages/topicsEvent'
      - $ref: '#/channels/velma2Streaming/messages/topicSentimentEvent'
      - $ref: '#/channels/velma2Streaming/messages/summaryEvent'
      - $ref: '#/channels/velma2Streaming/messages/errorEvent'
      - $ref: '#/channels/velma2Streaming/messages/doneEvent'
components:
  messages:
    ListPresetsResponse:
      name: listPresetsResponse
      title: List Presets Response
      summary: JSON body returned by `GET /api/velma-2-streaming/list-presets`.
      contentType: application/json
      payload:
        $ref: '#/components/schemas/ListPresetsResponse'
    StreamConfig:
      name: streamConfig
      title: Stream Configuration
      summary: |
        First text frame: either the literal string `default` (to use
        the built-in default configuration) or a JSON-encoded
        BatchConfig object.
      contentType: application/json
      payload:
        oneOf:
          - $ref: '#/components/schemas/BatchConfig'
          - type: string
            const: default
    AudioChunk:
      name: audioChunk
      title: Audio Data Chunk
      summary: Raw audio data chunk.
      contentType: application/octet-stream
      payload:
        type: string
        format: binary
    EndOfStream:
      name: endOfStream
      title: End of Audio Stream
      summary: Empty text frame signalling end of audio stream.
      contentType: text/plain
      payload:
        type: string
        const: ''
    ClipEvent:
      name: clipEvent
      title: Clip
      summary: A transcribed clip with metadata.
      contentType: application/json
      payload:
        type: object
        required:
          - type
          - clip
        properties:
          type:
            type: string
            const: clip
          clip:
            $ref: '#/components/schemas/Clip'
    PartialClipEvent:
      name: partialClipEvent
      title: Partial Clip
      summary: |
        An in-progress clip streamed while an utterance is still being spoken,
        before it finalizes. Multiple partials may be emitted for the same
        `clip_uuid` as the utterance grows; the eventual `clip` event for that
        utterance reuses the same `clip_uuid`, so a run of partials can be
        correlated with its final clip.
      contentType: application/json
      payload:
        type: object
        required:
          - type
          - partial_clip
        properties:
          type:
            type: string
            const: partial_clip
          partial_clip:
            $ref: '#/components/schemas/PartialClip'
    ClipUpdateEvent:
      name: clipUpdateEvent
      title: Clip Update
      summary: |
        Refined values for a previously finalized clip;
        `clip_update.clip_uuid` matches the `clip_uuid` of an earlier `clip`
        event. A finalized clip may receive any number of `clip_update`
        events (including none), each emitted after that clip's `clip` event
        (possibly interleaved with events for other clips) and always before
        the `done` event on clean completion. For each field present, the
        latest received value supersedes the value on the `clip` event and on
        any earlier `clip_update` for that clip.
      contentType: application/json
      payload:
        type: object
        required:
          - type
          - clip_update
        properties:
          type:
            type: string
            const: clip_update
          clip_update:
            $ref: '#/components/schemas/ClipUpdate'
    ConversationTypeEvent:
      name: conversationTypeEvent
      title: Conversation Type Pick
      summary: Inferred or default conversation-type pick for the session.
      contentType: application/json
      payload:
        type: object
        required:
          - type
          - pick
        properties:
          type:
            type: string
            const: conversation_type
          pick:
            $ref: '#/components/schemas/ConversationTypePick'
    ParticipantRoleEvent:
      name: participantRoleEvent
      title: Participant Role Pick
      summary: Inferred or default participant-role pick for a speaker.
      contentType: application/json
      payload:
        type: object
        required:
          - type
          - pick
        properties:
          type:
            type: string
            const: participant_role
          pick:
            $ref: '#/components/schemas/ParticipantRolePick'
    BehaviorDetectionEvent:
      name: behaviorDetectionEvent
      title: Behavior Detection
      summary: Per-behavior detection result.
      contentType: application/json
      payload:
        type: object
        required:
          - type
          - detection
        properties:
          type:
            type: string
            const: behavior_detection
          detection:
            $ref: '#/components/schemas/BehaviorDetection'
    TopicsEvent:
      name: topicsEvent
      title: Topics
      summary: |
        Aggregated list of conversation topics. May be emitted more than once as
        the stream progresses; each event fully replaces the previous `topics`
        event, so always treat the latest as authoritative and never merge with
        earlier ones.
      contentType: application/json
      payload:
        type: object
        required:
          - type
          - topics
        properties:
          type:
            type: string
            const: topics
          topics:
            type: array
            items:
              type: string
    TopicSentimentEvent:
      name: topicSentimentEvent
      title: Topic Sentiment
      summary: |
        Per-speaker sentiment for an aggregated topic, keyed by topic and
        speaker. May be emitted more than once as the stream progresses; a later
        event supersedes an earlier one for the same topic and speaker.
      contentType: application/json
      payload:
        type: object
        required:
          - type
          - topic_sentiment
        properties:
          type:
            type: string
            const: topic_sentiment
          topic_sentiment:
            $ref: '#/components/schemas/TopicSentiment'
    SummaryEvent:
      name: summaryEvent
      title: Summary
      summary: |
        Free-form summary of the conversation. May be emitted more than once as
        the stream progresses; each event fully replaces the previous `summary`
        event, so always treat the latest as authoritative.
      contentType: application/json
      payload:
        type: object
        required:
          - type
          - text
        properties:
          type:
            type: string
            const: summary
          text:
            type: string
    ErrorEvent:
      name: errorEvent
      title: Error
      summary: An error occurred during processing.
      contentType: application/json
      payload:
        type: object
        required:
          - type
          - error
        properties:
          type:
            type: string
            const: error
          error:
            type: string
            description: Human-readable error message
      examples:
        - name: internalError
          payload:
            type: error
            error: Internal server error
        - name: invalidInputAudio
          payload:
            type: error
            error: Invalid input audio
        - name: invalidConfig
          payload:
            type: error
            error: Invalid configuration.
        - name: notPermitted
          payload:
            type: error
            error: This request is not permitted.
        - name: insufficientCredits
          payload:
            type: error
            error: Insufficient credits.
        - name: validationUnavailable
          payload:
            type: error
            error: Unable to validate request. Please try again.
        - name: invalidAudioFormat
          payload:
            type: error
            error: >-
              Invalid audio_format='mp4'. Valid values: ['aac', 'aiff', 'alaw',
              'f32be', 'f32le', 'f64be', 'f64le', 'flac', 'mp3', 'mulaw', 'ogg',
              's16be', 's16le', 's24be', 's24le', 's32be', 's32le', 's8',
              'u16be', 'u16le', 'u24be', 'u24le', 'u32be', 'u32le', 'u8', 'wav',
              'webm']
        - name: rawFormatMissingParams
          payload:
            type: error
            error: >-
              Raw audio formats require sample_rate and num_channels query
              parameters
        - name: paramsWithoutFormat
          payload:
            type: error
            error: sample_rate and num_channels require audio_format to be specified
        - name: invalidSampleRate
          payload:
            type: error
            error: >-
              Invalid sample_rate=50000. Valid values: [8000, 11025, 16000,
              22050, 32000, 44100, 48000, 96000]
        - name: invalidNumChannels
          payload:
            type: error
            error: Invalid num_channels=12. Must be between 1 and 8
    DoneEvent:
      name: doneEvent
      title: Done
      summary: Streaming completed.
      contentType: application/json
      payload:
        type: object
        required:
          - type
          - duration_ms
        properties:
          type:
            type: string
            const: done
          duration_ms:
            type: integer
            minimum: 0
      examples:
        - name: completionExample
          payload:
            type: done
            duration_ms: 45000
  schemas:
    ConversationTypeDef:
      type: object
      required:
        - conversation_type_uuid
        - name
        - short_description
        - detailed_description
      properties:
        conversation_type_uuid:
          type: string
          format: uuid
        name:
          type: string
          minLength: 1
        short_description:
          type: string
        detailed_description:
          type: string
    ParticipantRoleDef:
      type: object
      required:
        - participant_role_uuid
        - name
        - short_description
        - detailed_description
      properties:
        participant_role_uuid:
          type: string
          format: uuid
        name:
          type: string
          minLength: 1
        short_description:
          type: string
        detailed_description:
          type: string
        applies_to_conversation_type_uuids:
          description: Null/missing means applies to all conversation types.
          oneOf:
            - type: array
              items:
                type: string
                format: uuid
            - type: 'null'
    BehaviorDef:
      type: object
      required:
        - behavior_uuid
        - name
        - short_description
        - detailed_description
      properties:
        behavior_uuid:
          type: string
          format: uuid
        name:
          type: string
          minLength: 1
        short_description:
          type: string
        detailed_description:
          type: string
        applies_to_conversation_type_uuids:
          oneOf:
            - type: array
              items:
                type: string
                format: uuid
            - type: 'null'
        applies_to_participant_role_uuids:
          oneOf:
            - type: array
              items:
                type: string
                format: uuid
            - type: 'null'
    BehaviorPresetListing:
      type: object
      required:
        - identifier
        - name
        - short_description
        - detailed_description
      properties:
        identifier:
          type: string
          description: |
            The preset identifier to use in a `preset:<identifier>`
            behavior reference.
        name:
          type: string
        short_description:
          type: string
        detailed_description:
          type: string
    ListPresetsResponse:
      type: object
      required:
        - presets
      properties:
        presets:
          type: array
          items:
            $ref: '#/components/schemas/BehaviorPresetListing'
    STTOptions:
      type: object
      properties:
        speaker_diarization:
          type: boolean
          default: true
        emotion_signal:
          type: boolean
          default: false
        accent_signal:
          type: boolean
          default: false
        deepfake_signal:
          type: boolean
          default: false
        pii_phi_tagging:
          type: boolean
          default: false
        language:
          description: |
            Optional language hint as a case-insensitive ISO 639-1 code (e.g.
            "en", "fr"). BCP 47 region/script subtags (e.g. "en-US") are
            accepted; only the primary language subtag is used. When omitted or
            null, the language is detected automatically for each clip.
          oneOf:
            - type: string
              pattern: ^[A-Za-z]{2,3}([-_][A-Za-z0-9]+)*$
            - type: 'null'
        custom_terms:
          description: >-
            Optional custom vocabulary to bias transcription toward domain terms
            and names. Each entry is either a plain string (the term) or a
            CustomTerm object. Blank terms and blank pronunciations are dropped.
            At most 1000 entries, and the term strings serialized together as
            JSON must total under 8000 characters. Null or omitted means no
            biasing.
          oneOf:
            - type: 'null'
            - type: array
              maxItems: 1000
              items:
                oneOf:
                  - type: string
                  - $ref: '#/components/schemas/CustomTerm'
    CustomTerm:
      type: object
      required:
        - term
      properties:
        term:
          type: string
          minLength: 1
          description: The vocabulary term to bias transcription toward.
        definition:
          type: string
          maxLength: 256
          description: Optional short definition of the term.
        pronunciations:
          type: array
          maxItems: 16
          items:
            type: string
            maxLength: 128
          description: >-
            Optional pronunciation hints, as X-SAMPA notation or
            hyphen-separated ASCII respelling with the stressed syllable in
            capitals (e.g. GOO-guhl). Printable ASCII only.
    BatchConfig:
      type: object
      properties:
        conversation_types:
          description: |
            Candidate conversation types. If this key is omitted, the
            built-in default conversation types are used; pass an empty
            array to provide no candidates.
          type: array
          items:
            $ref: '#/components/schemas/ConversationTypeDef'
        participant_roles:
          description: |
            Candidate participant roles. If this key is omitted, the
            built-in default participant roles are used; pass an empty
            array to provide no candidates.
          type: array
          items:
            $ref: '#/components/schemas/ParticipantRoleDef'
        behaviors:
          description: |
            Each entry is either a full BehaviorDef object or a preset
            reference string matching `preset:<identifier>` (e.g.
            `preset:complaints`). Preset references are expanded into
            full BehaviorDef objects before processing. Use the
            list-presets endpoint to discover available identifiers.
            If this key is omitted, no behaviors are evaluated.
          type: array
          items:
            oneOf:
              - $ref: '#/components/schemas/BehaviorDef'
              - type: string
                pattern: ^preset:.+$
        stt:
          $ref: '#/components/schemas/STTOptions'
        produce_topics:
          type: boolean
          default: true
        produce_topic_sentiments:
          type: boolean
          default: true
        produce_summary:
          type: boolean
          default: true
        default_conversation_type:
          description: |
            Fallback conversation type used when no candidate
            conversation type applies. If this key is omitted, a
            built-in fallback is supplied automatically; set it to null
            to disable the fallback.
          oneOf:
            - $ref: '#/components/schemas/ConversationTypeDef'
            - type: 'null'
        default_participant_role:
          description: |
            Fallback participant role used when no candidate participant
            role applies to a speaker. If this key is omitted, a
            built-in fallback is supplied automatically; set it to null
            to disable the fallback.
          oneOf:
            - $ref: '#/components/schemas/ParticipantRoleDef'
            - type: 'null'
    SelectionSource:
      type: string
      enum:
        - inferred
        - auto_selected_single_option
        - default
    ConversationTypePick:
      type: object
      required:
        - conversation_type_uuid
        - name
        - confidence
        - selection_source
        - detail
      properties:
        conversation_type_uuid:
          type: string
          format: uuid
        name:
          type: string
        confidence:
          type: number
          format: double
          minimum: 0
          maximum: 1
        selection_source:
          $ref: '#/components/schemas/SelectionSource'
        detail:
          type: string
        reasoning:
          oneOf:
            - type: string
            - type: 'null'
    ParticipantRolePick:
      type: object
      required:
        - speaker_label
        - participant_role_uuid
        - name
        - confidence
        - selection_source
        - detail
      properties:
        speaker_label:
          type: string
        participant_role_uuid:
          type: string
          format: uuid
        name:
          type: string
        confidence:
          type: number
          format: double
          minimum: 0
          maximum: 1
        selection_source:
          $ref: '#/components/schemas/SelectionSource'
        detail:
          type: string
        reasoning:
          oneOf:
            - type: string
            - type: 'null'
    Clip:
      type: object
      required:
        - clip_uuid
        - text
        - start_ms
        - duration_ms
        - speaker_label
        - language
      properties:
        clip_uuid:
          type: string
          format: uuid
        text:
          type: string
        start_ms:
          type: integer
          minimum: 0
        duration_ms:
          type: integer
          minimum: 0
        speaker_label:
          type: string
        language:
          type: string
        emotion:
          description: >-
            Predicted emotion label for the clip, or null when no emotion label
            is available.
          oneOf:
            - type: string
            - type: 'null'
        accent:
          description: >-
            Predicted accent label for the clip, or null when no accent label is
            available.
          oneOf:
            - type: string
            - type: 'null'
        deepfake_score:
          oneOf:
            - type: number
              format: double
              minimum: 0
              maximum: 1
            - type: 'null'
    PartialClip:
      type: object
      required:
        - clip_uuid
        - text
        - start_ms
      properties:
        clip_uuid:
          type: string
          format: uuid
          description: >-
            Stable identifier shared across a clip's lifetime. The eventual
            finalized `clip` event for the same utterance reuses this value.
        text:
          type: string
        start_ms:
          type: integer
          minimum: 0
        end_ms:
          description: >-
            Current end of the in-progress utterance; grows as the utterance
            extends. Null until available. The finalized clip reports
            `duration_ms` instead of `end_ms`.
          oneOf:
            - type: integer
              minimum: 0
            - type: 'null'
        speaker_label:
          description: Null until diarization resolves the speaker.
          oneOf:
            - type: string
            - type: 'null'
        emotion:
          description: >-
            Latest in-progress emotion label, or null when no value is available
            yet.
          oneOf:
            - type: string
            - type: 'null'
        accent:
          description: >-
            Latest in-progress accent label, or null when no value is available
            yet.
          oneOf:
            - type: string
            - type: 'null'
        deepfake_score:
          description: >-
            Latest in-progress deepfake score, or null when no value is
            available yet.
          oneOf:
            - type: number
              format: double
              minimum: 0
              maximum: 1
            - type: 'null'
    ClipUpdate:
      type: object
      required:
        - clip_uuid
      properties:
        clip_uuid:
          type: string
          format: uuid
          description: Matches the `clip_uuid` of a previously emitted `clip` event.
        emotion:
          description: >-
            Refined emotion label for the clip, or null when no emotion label is
            available.
          oneOf:
            - type: string
            - type: 'null'
        accent:
          description: >-
            Refined accent label for the clip, or null when no accent label is
            available.
          oneOf:
            - type: string
            - type: 'null'
    BehaviorDetection:
      type: object
      required:
        - behavior_uuid
        - behavior_name
        - speaker_label
        - detected
      properties:
        behavior_uuid:
          type: string
          format: uuid
        behavior_name:
          type: string
        speaker_label:
          oneOf:
            - type: string
            - type: 'null'
        detected:
          type: boolean
        confidence:
          oneOf:
            - type: number
              format: double
              minimum: 0
              maximum: 1
            - type: 'null'
        evidence_clip_uuids:
          type: array
          items:
            type: string
            format: uuid
        definitive_clip_uuid:
          oneOf:
            - type: string
              format: uuid
            - type: 'null'
        reasoning:
          oneOf:
            - type: string
            - type: 'null'
    TopicSentiment:
      type: object
      required:
        - topic
        - speaker_label
        - sentiment_score
        - sentiment_label
      properties:
        topic:
          type: string
        speaker_label:
          type: string
        sentiment_score:
          type: number
          format: double
          minimum: -1
          maximum: 1
        sentiment_label:
          type: string