Noesis / Integrations

Stream a Plivo call to Noesis with the Stream XML element and a stream token, and receive the answers through a relay.

Plivo's <Stream> element sends a call's audio to a WebSocket. Noesis reads Plivo's media messages as they are. Plivo cannot send an Authorization header to Noesis, so put a stream token in the URL.

1. Stream the call to Noesis

Ask Plivo for μ-law at 8 kHz and set the same format on the URL. In XML, write each & in the URL as &amp;:

XML
<Response>
  <Stream bidirectional="false" audioTrack="inbound" contentType="audio/x-mulaw;rate=8000">wss://api.noesis.detectif.ai/v1/detect/stream?token=ntk_...&amp;encoding=mulaw&amp;sample_rate=8000</Stream>
  <!-- your existing call flow continues here -->
</Response>

Create the token in your answer webhook, right before you return the XML, as in the Twilio guide. To not record the call, add &amp;record=false to the URL.

2. Receive the answers during the call

Plivo does not pass messages from the stream back to you. To act on the answers, point the stream at a relay on your server, which forwards Plivo's messages to Noesis unchanged and receives the answers:

XML
<Response>
  <Stream bidirectional="false" audioTrack="inbound" contentType="audio/x-mulaw;rate=8000">wss://relay.example.com/plivo</Stream>
  <!-- your existing call flow continues here -->
</Response>

The relay uses noesis_relay.py from the relay helper:

Python
# plivo_relay.py: Plivo Stream -> your server -> Noesis
import asyncio

import websockets

from noesis_relay import NoesisCall

async def on_answer(event):
    if event["type"] == "classification":
        print(event["call_id"], event["label"])     # your own logic; call_id is Plivo's call ID

async def handle(plivo):
    call = NoesisCall(on_answer, encoding="mulaw", sample_rate=8000)
    await call.open()
    try:
        async for message in plivo:                 # Plivo's JSON messages, unchanged
            await call.send(message)
    except websockets.ConnectionClosed:
        pass
    await call.close()

async def main():
    async with websockets.serve(handle, "0.0.0.0", 8080):
        await asyncio.Future()                      # run until stopped

asyncio.run(main())

If you choose 16-bit PCM in contentType (audio/x-l16;rate=8000 or audio/x-l16;rate=16000), set encoding="pcm_s16le" and the same sample_rate.