API de streaming

O protocolo de streaming da API de STT é baseado na biblioteca socket.io, com as seguintes mensagens:

Mensagens do Servidor

broad

O servidor envia uma mensagem. Usado para debug.

speechData

O servidor envia os dados da transcrição, seguindo o seguinte formato:

{
    "results": [
        {
            "text": "a abertura de novos grupos foi suspensa",
            "score": -21.840528
        },
        {
            "text": "a abertura de novos grupos foi suspensa",
            "score": -31.796457
        },
        {
            "text": "a a abertura de novos grupos foi suspensa",
            "score": -39.00835
        }
    ]
}

Note que a partir de cada mensagem de cliente de startStream (que será definido à seguir), iniciamos uma sessão de transcrição e todo o conteúdo da transcrição até o momento é retornado nas mensagems de speechData, até que a sessão seja finalizada com uma mensagem de endStream.

Mensagens dos Client

join

Iniciar uma conexão com o servidor.

messages

O cliente enviar uma mensagem. Usado para debug.

startStream

Inicia uma sessão de streaming.

endStream

Finaliza a sessão de streaming atual.

setModel

Define um modelo para a sessão de streaming atual.

binary

Envia um frame em WAV.

'use strict'

let endpoint = "wss://staging-api.alabiabot.com/";

const socket = io.connect(endpoint, {
    transports: ['websocket']
});

//================= CONFIG =================
// Stream Audio
let bufferSize = 2048 * 8,
    AudioContext,
    context,
    processor,
    input,
    globalStream,
    model = "default";

//vars
let isStreaming = false;


//audioStream constraints
const constraints = {
    audio: true,
    video: false
};

//================= RECORDING =================
function startRecording() {
    navigator.mediaDevices.getUserMedia(constraints)
        .then(function (stream) {
            console.log("recording...");
            socket.emit('startStream', '');
            socket.emit('setModel', model);
            isStreaming = true;
            AudioContext = window.AudioContext || window.webkitAudioContext;
            context = new AudioContext({
                latencyHint: 'interactive',
                sampleRate: 16000,
            });
            processor = context.createScriptProcessor(bufferSize, 1, 1);
            processor.onaudioprocess = function (event) {
                let left16 = toIntArray(event.inputBuffer.getChannelData(0));
                socket.emit('binary', left16);
            };
            processor.connect(context.destination);
            context.resume();

            globalStream = stream;
            input = context.createMediaStreamSource(stream);
            input.connect(processor);
        });
}

function stopRecording() {
    console.log("stop recording");
    isStreaming = false;
    socket.emit('endStream', '');

    let track = globalStream.getTracks()[0];
    track.stop();

    input.disconnect(processor);
    processor.disconnect(context.destination);
    context.close().then(function () {
        input = null;
        processor = null;
        context = null;
        AudioContext = null;
        startButton.disabled = false;
    });
}

//================= SOCKET IO =================
socket.on('connect', function (data) {
    socket.emit('join', 'Server Connected to Client');
});


socket.on('broad', function (data) {
    console.log(data);
});


socket.on('speechData', function (data) {
    console.log(data);
    displayResult(addTimeSettingsFinal(data))
});


function addTimeSettingsFinal(speechData) {
    return speechData.results[0].text;
}

window.onbeforeunload = function () {
    if (isStreaming) { socket.emit('endStream', ''); }
};

function toIntArray(buffer) {
    let array = new Int16Array(buffer.length);
    for (let i = 0; i < buffer.length; i++) {
        array[i] = Math.min(1, buffer[i]) * 0x7FFF;
    }
    return array.buffer;
}

Teste ao Vivo

...