Partilhar via


Adicione transcrição em tempo real à sua aplicação

Este guia ajuda você a entender melhor as diferentes maneiras de usar a oferta dos Serviços de Comunicação do Azure de transcrição em tempo real por meio de SDKs de Automação de Chamadas.

Pré-requisitos

Configurar um servidor WebSocket

Os Serviços de Comunicação do Azure exigem que seu aplicativo de servidor configure um servidor WebSocket para transmitir transcrição em tempo real. WebSocket é um protocolo padronizado que fornece um canal de comunicação full-duplex através de uma única conexão TCP. Opcionalmente, você pode usar os serviços do Azure Azure WebApps que permitem criar um aplicativo para receber transcrições em uma conexão websocket. Siga este guia de início rápido.

Estabeleça uma chamada

Neste guia de início rápido, assumimos que você já está familiarizado com o início de chamadas. Se precisar de saber mais sobre como iniciar e estabelecer chamadas, pode seguir o nosso guia de início rápido. Para os fins deste início rápido, estamos passando pelo processo de iniciar a transcrição para chamadas de entrada e de saída.

Ao trabalhar com transcrição em tempo real, você tem algumas opções sobre quando e como iniciar a transcrição:

Opção 1 - Começar no momento de atender ou criar uma chamada

Opção 2 - Iniciar a transcrição durante uma chamada em curso

Opção 3 - Iniciar a transcrição ao conectar-se a uma chamada das Salas dos Serviços de Comunicação do Azure

Neste tutorial, estamos demonstrando as opções 2 e 3, iniciando a transcrição durante uma chamada em andamento ou ao se conectar a uma chamada de salas. Por padrão, o 'startTranscription' é definido como false no momento de atender ou criar uma chamada.

Crie uma chamada e forneça os detalhes da transcrição

Defina as TranscriptionOptions para ACS para especificar quando iniciar a transcrição, especifique a localidade para transcrição e a conexão de soquete da Web para enviar a transcrição.

var createCallOptions = new CreateCallOptions(callInvite, callbackUri)
{
    CallIntelligenceOptions = new CallIntelligenceOptions() { CognitiveServicesEndpoint = new Uri(cognitiveServiceEndpoint) },
    TranscriptionOptions = new TranscriptionOptions(new Uri(""), "en-US", false, TranscriptionTransport.Websocket)
};
CreateCallResult createCallResult = await callAutomationClient.CreateCallAsync(createCallOptions);

Conecte-se a uma chamada de salas e forneça detalhes de transcrição

Se você estiver se conectando a uma sala ACS e quiser usar a transcrição, configure as opções de transcrição da seguinte maneira:

var transcriptionOptions = new TranscriptionOptions(
    transportUri: new Uri(""),
    locale: "en-US", 
    startTranscription: false,
    transcriptionTransport: TranscriptionTransport.Websocket,
    //Only add the SpeechRecognitionModelEndpointId if you have a custom speech model you would like to use
    SpeechRecognitionModelEndpointId = "YourCustomSpeechRecognitionModelEndpointId"
);

var connectCallOptions = new ConnectCallOptions(new RoomCallLocator("roomId"), callbackUri)
{
    CallIntelligenceOptions = new CallIntelligenceOptions() 
    { 
        CognitiveServicesEndpoint = new Uri(cognitiveServiceEndpoint) 
    },
    TranscriptionOptions = transcriptionOptions
};

var connectResult = await client.ConnectCallAsync(connectCallOptions);

Iniciar transcrição

Quando estiver pronto para iniciar a transcrição, você pode fazer uma chamada explícita para o Call Automation para começar a transcrever a chamada.

// Start transcription with options
StartTranscriptionOptions options = new StartTranscriptionOptions()
{
    OperationContext = "startMediaStreamingContext",
    //Locale = "en-US",
    //Only add the SpeechRecognitionModelEndpointId if you have a custom speech model you would like to use
    SpeechRecognitionModelEndpointId = "YourCustomSpeechRecognitionModelEndpointId"
};

await callMedia.StartTranscriptionAsync(options);

// Alternative: Start transcription without options
// await callMedia.StartTranscriptionAsync();

Cabeçalhos adicionais:

A ID de Correlação e a ID de Conexão de Chamada agora estão incluídas nos cabeçalhos WebSocket para melhor rastreabilidade x-ms-call-correlation-id e x-ms-call-connection-id.

Recebendo fluxo de transcrição

Quando a transcrição é iniciada, seu websocket recebe a carga útil de metadados de transcrição como o primeiro pacote.

{
    "kind": "TranscriptionMetadata",
    "transcriptionMetadata": {
        "subscriptionId": "aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e",
        "locale": "en-us",
        "callConnectionId": "65c57654=f12c-4975-92a4-21668e61dd98",
        "correlationId": "65c57654=f12c-4975-92a4-21668e61dd98"
    }
}

Receber dados de transcrição

Após os metadados, os próximos pacotes que seu soquete da Web receberá serão TranscriptionData para o áudio transcrito.

{
    "kind": "TranscriptionData",
    "transcriptionData": {
        "text": "Testing transcription.",
        "format": "display",
        "confidence": 0.695223331451416,
        "offset": 2516998782481234400,
        "words": [
            {
                "text": "testing",
                "offset": 2516998782481234400
            },
            {
                "text": "testing",
                "offset": 2516998782481234400
            }
        ],
        "participantRawID": "8:acs:",
        "resultStatus": "Final"
    }
}

Manipulando o fluxo de transcrição no servidor de soquete da Web

using WebServerApi;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();
app.UseWebSockets();
app.Map("/ws", async context =>
{
    if (context.WebSockets.IsWebSocketRequest)
    {
        using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
        await HandleWebSocket.Echo(webSocket);
    }
    else
    {
        context.Response.StatusCode = StatusCodes.Status400BadRequest;
    }
});

app.Run();

Atualizações do código para o manipulador websocket

using Azure.Communication.CallAutomation;
using System.Net.WebSockets;
using System.Text;

namespace WebServerApi
{
    public class HandleWebSocket
    {
        public static async Task Echo(WebSocket webSocket)
        {
            var buffer = new byte[1024 * 4];
            var receiveResult = await webSocket.ReceiveAsync(
                new ArraySegment(buffer), CancellationToken.None);

            while (!receiveResult.CloseStatus.HasValue)
            {
                string msg = Encoding.UTF8.GetString(buffer, 0, receiveResult.Count);
                var response = StreamingDataParser.Parse(msg);

                if (response != null)
                {
                    if (response is AudioMetadata audioMetadata)
                    {
                        Console.WriteLine("***************************************************************************************");
                        Console.WriteLine("MEDIA SUBSCRIPTION ID-->"+audioMetadata.MediaSubscriptionId);
                        Console.WriteLine("ENCODING-->"+audioMetadata.Encoding);
                        Console.WriteLine("SAMPLE RATE-->"+audioMetadata.SampleRate);
                        Console.WriteLine("CHANNELS-->"+audioMetadata.Channels);
                        Console.WriteLine("LENGTH-->"+audioMetadata.Length);
                        Console.WriteLine("***************************************************************************************");
                    }
                    if (response is AudioData audioData)
                    {
                        Console.WriteLine("***************************************************************************************");
                        Console.WriteLine("DATA-->"+audioData.Data);
                        Console.WriteLine("TIMESTAMP-->"+audioData.Timestamp);
                        Console.WriteLine("IS SILENT-->"+audioData.IsSilent);
                        Console.WriteLine("***************************************************************************************");
                    }

                    if (response is TranscriptionMetadata transcriptionMetadata)
                    {
                        Console.WriteLine("***************************************************************************************");
                        Console.WriteLine("TRANSCRIPTION SUBSCRIPTION ID-->"+transcriptionMetadata.TranscriptionSubscriptionId);
                        Console.WriteLine("LOCALE-->"+transcriptionMetadata.Locale);
                        Console.WriteLine("CALL CONNECTION ID--?"+transcriptionMetadata.CallConnectionId);
                        Console.WriteLine("CORRELATION ID-->"+transcriptionMetadata.CorrelationId);
                        Console.WriteLine("***************************************************************************************");
                    }
                    if (response is TranscriptionData transcriptionData)
                    {
                        Console.WriteLine("***************************************************************************************");
                        Console.WriteLine("TEXT-->"+transcriptionData.Text);
                        Console.WriteLine("FORMAT-->"+transcriptionData.Format);
                        Console.WriteLine("OFFSET-->"+transcriptionData.Offset);
                        Console.WriteLine("DURATION-->"+transcriptionData.Duration);
                        Console.WriteLine("PARTICIPANT-->"+transcriptionData.Participant.RawId);
                        Console.WriteLine("CONFIDENCE-->"+transcriptionData.Confidence);

                        foreach (var word in transcriptionData.Words)
                        {
                            Console.WriteLine("TEXT-->"+word.Text);
                            Console.WriteLine("OFFSET-->"+word.Offset);
                            Console.WriteLine("DURATION-->"+word.Duration);
                        }
                        Console.WriteLine("***************************************************************************************");
                    }
                }

                await webSocket.SendAsync(
                    new ArraySegment(buffer, 0, receiveResult.Count),
                    receiveResult.MessageType,
                    receiveResult.EndOfMessage,
                    CancellationToken.None);

                receiveResult = await webSocket.ReceiveAsync(
                    new ArraySegment(buffer), CancellationToken.None);
            }

            await webSocket.CloseAsync(
                receiveResult.CloseStatus.Value,
                receiveResult.CloseStatusDescription,
                CancellationToken.None);
        }
    }
}

Atualizar transcrição

Para situações em que seu aplicativo permite que os usuários selecionem seu idioma preferido, você também pode querer capturar a transcrição nesse idioma. Para fazer isso, o Call Automation SDK permite que você atualize a localidade de transcrição.

UpdateTranscriptionOptions updateTranscriptionOptions = new UpdateTranscriptionOptions(locale)
{
OperationContext = "UpdateTranscriptionContext",
//Only add the SpeechRecognitionModelEndpointId if you have a custom speech model you would like to use
SpeechRecognitionModelEndpointId = "YourCustomSpeechRecognitionModelEndpointId"
};

await client.GetCallConnection(callConnectionId).GetCallMedia().UpdateTranscriptionAsync(updateTranscriptionOptions);

Parar transcrição

Quando seu aplicativo precisar parar de ouvir a transcrição, você poderá usar a solicitação StopTranscription para informar a Automação de Chamadas para parar de enviar dados de transcrição para seu soquete da Web.

StopTranscriptionOptions stopOptions = new StopTranscriptionOptions()
{
    OperationContext = "stopTranscription"
};

await callMedia.StopTranscriptionAsync(stopOptions);

Crie uma chamada e forneça os detalhes da transcrição

Defina as TranscriptionOptions para ACS para especificar quando iniciar a transcrição, a localidade para transcrição e a conexão de soquete da Web para enviar a transcrição.

CallInvite callInvite = new CallInvite(target, caller); 

CallIntelligenceOptions callIntelligenceOptions = new CallIntelligenceOptions()
    .setCognitiveServicesEndpoint(appConfig.getCognitiveServiceEndpoint()); 

TranscriptionOptions transcriptionOptions = new TranscriptionOptions(
    appConfig.getWebSocketUrl(), 
    TranscriptionTransport.WEBSOCKET, 
    "en-US", 
    false,
    "your-endpoint-id-here" // speechRecognitionEndpointId
); 

CreateCallOptions createCallOptions = new CreateCallOptions(callInvite, appConfig.getCallBackUri());
createCallOptions.setCallIntelligenceOptions(callIntelligenceOptions); 
createCallOptions.setTranscriptionOptions(transcriptionOptions); 

Response result = client.createCallWithResponse(createCallOptions, Context.NONE); 
return result.getValue().getCallConnectionProperties().getCallConnectionId(); 

Conecte-se a uma chamada de salas e forneça detalhes de transcrição

Se você estiver se conectando a uma sala ACS e quiser usar a transcrição, configure as opções de transcrição da seguinte maneira:

TranscriptionOptions transcriptionOptions = new TranscriptionOptions(
    appConfig.getWebSocketUrl(), 
    TranscriptionTransport.WEBSOCKET, 
    "en-US", 
    false,
    "your-endpoint-id-here" // speechRecognitionEndpointId
);

ConnectCallOptions connectCallOptions = new ConnectCallOptions(new RoomCallLocator("roomId"), appConfig.getCallBackUri())
    .setCallIntelligenceOptions(
        new CallIntelligenceOptions()
            .setCognitiveServicesEndpoint(appConfig.getCognitiveServiceEndpoint())
    )
    .setTranscriptionOptions(transcriptionOptions);

ConnectCallResult connectCallResult = Objects.requireNonNull(client
    .connectCallWithResponse(connectCallOptions)
    .block())
    .getValue();

Iniciar transcrição

Quando estiver pronto para iniciar a transcrição, você pode fazer uma chamada explícita para o Call Automation para começar a transcrever a chamada.

//Option 1: Start transcription with options
StartTranscriptionOptions transcriptionOptions = new StartTranscriptionOptions()
    .setOperationContext("startMediaStreamingContext"); 

client.getCallConnection(callConnectionId)
    .getCallMedia()
    .startTranscriptionWithResponse(transcriptionOptions, Context.NONE); 

// Alternative: Start transcription without options
// client.getCallConnection(callConnectionId)
//     .getCallMedia()
//     .startTranscription();

Cabeçalhos adicionais:

A ID de Correlação e a ID de Conexão de Chamada agora estão incluídas nos cabeçalhos WebSocket para melhor rastreabilidade x-ms-call-correlation-id e x-ms-call-connection-id.

Recebendo fluxo de transcrição

Quando a transcrição é iniciada, seu websocket recebe a carga útil de metadados de transcrição como o primeiro pacote.

{
    "kind": "TranscriptionMetadata",
    "transcriptionMetadata": {
        "subscriptionId": "aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e",
        "locale": "en-us",
        "callConnectionId": "65c57654=f12c-4975-92a4-21668e61dd98",
        "correlationId": "65c57654=f12c-4975-92a4-21668e61dd98"
    }
}

Receber dados de transcrição

Após os metadados, os próximos pacotes que seu soquete da Web receberá serão TranscriptionData para o áudio transcrito.

{
    "kind": "TranscriptionData",
    "transcriptionData": {
        "text": "Testing transcription.",
        "format": "display",
        "confidence": 0.695223331451416,
        "offset": 2516998782481234400,
        "words": [
            {
                "text": "testing",
                "offset": 2516998782481234400
            },
            {
                "text": "testing",
                "offset": 2516998782481234400
            }
        ],
        "participantRawID": "8:acs:",
        "resultStatus": "Final"
    }
}

Manipulando o fluxo de transcrição no servidor de soquete da Web

package com.example;

import org.glassfish.tyrus.server.Server;

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class App {
    public static void main(String[] args) {
        Server server = new Server("localhost", 8081, "/ws", null, WebSocketServer.class);

        try {
            server.start();
            System.out.println("Web socket running on port 8081...");
            System.out.println("wss://localhost:8081/ws/server");
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            reader.readLine();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            server.stop();
        }
    }
}

Atualizações do código para o manipulador websocket

package com.example;

import javax.websocket.OnMessage;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import com.azure.communication.callautomation.models.streaming.StreamingData;
import com.azure.communication.callautomation.models.streaming.StreamingDataParser;
import com.azure.communication.callautomation.models.streaming.media.AudioData;
import com.azure.communication.callautomation.models.streaming.media.AudioMetadata;
import com.azure.communication.callautomation.models.streaming.transcription.TranscriptionData;
import com.azure.communication.callautomation.models.streaming.transcription.TranscriptionMetadata;
import com.azure.communication.callautomation.models.streaming.transcription.Word;

@ServerEndpoint("/server")
public class WebSocketServer {
    @OnMessage
    public void onMessage(String message, Session session) {
        StreamingData data = StreamingDataParser.parse(message);

        if (data instanceof AudioMetadata) {
            AudioMetadata audioMetaData = (AudioMetadata) data;
            System.out.println("----------------------------------------------------------------");
            System.out.println("SUBSCRIPTION ID: --> " + audioMetaData.getMediaSubscriptionId());
            System.out.println("ENCODING: --> " + audioMetaData.getEncoding());
            System.out.println("SAMPLE RATE: --> " + audioMetaData.getSampleRate());
            System.out.println("CHANNELS: --> " + audioMetaData.getChannels());
            System.out.println("LENGTH: --> " + audioMetaData.getLength());
            System.out.println("----------------------------------------------------------------");
        }

        if (data instanceof AudioData) {
            AudioData audioData = (AudioData) data;
            System.out.println("----------------------------------------------------------------");
            System.out.println("DATA: --> " + audioData.getData());
            System.out.println("TIMESTAMP: --> " + audioData.getTimestamp());
            System.out.println("IS SILENT: --> " + audioData.isSilent());
            System.out.println("----------------------------------------------------------------");
        }

        if (data instanceof TranscriptionMetadata) {
            TranscriptionMetadata transcriptionMetadata = (TranscriptionMetadata) data;
            System.out.println("----------------------------------------------------------------");
            System.out.println("TRANSCRIPTION SUBSCRIPTION ID: --> " + transcriptionMetadata.getTranscriptionSubscriptionId());
            System.out.println("IS SILENT: --> " + transcriptionMetadata.getLocale());
            System.out.println("CALL CONNECTION ID: --> " + transcriptionMetadata.getCallConnectionId());
            System.out.println("CORRELATION ID: --> " + transcriptionMetadata.getCorrelationId());
            System.out.println("----------------------------------------------------------------");
        }

        if (data instanceof TranscriptionData) {
            TranscriptionData transcriptionData = (TranscriptionData) data;
            System.out.println("----------------------------------------------------------------");
            System.out.println("TEXT: --> " + transcriptionData.getText());
            System.out.println("FORMAT: --> " + transcriptionData.getFormat());
            System.out.println("CONFIDENCE: --> " + transcriptionData.getConfidence());
            System.out.println("OFFSET: --> " + transcriptionData.getOffset());
            System.out.println("DURATION: --> " + transcriptionData.getDuration());
            System.out.println("RESULT STATUS: --> " + transcriptionData.getResultStatus());
            for (Word word : transcriptionData.getWords()) {
                System.out.println("Text: --> " + word.getText());
                System.out.println("Offset: --> " + word.getOffset());
                System.out.println("Duration: --> " + word.getDuration());
            }
            System.out.println("----------------------------------------------------------------");
        }
    }
}

Atualizar transcrição

Para situações em que seu aplicativo permite que os usuários selecionem seu idioma preferido, você também pode querer capturar a transcrição nesse idioma. Para fazer isso, o Call Automation SDK permite que você atualize a localidade de transcrição.

UpdateTranscriptionOptions transcriptionOptions = new UpdateTranscriptionOptions()
    .setLocale(newLocale)
    .setOperationContext("transcriptionContext")
    .setSpeechRecognitionEndpointId("your-endpoint-id-here");

client.getCallConnection(callConnectionId)
    .getCallMedia()
    .updateTranscriptionWithResponse(transcriptionOptions, Context.NONE);

Parar transcrição

Quando seu aplicativo precisar parar de ouvir a transcrição, você poderá usar a solicitação StopTranscription para informar a Automação de Chamadas para parar de enviar dados de transcrição para seu soquete da Web.

// Option 1: Stop transcription with options
StopTranscriptionOptions stopTranscriptionOptions = new StopTranscriptionOptions()
    .setOperationContext("stopTranscription");

client.getCallConnection(callConnectionId)
    .getCallMedia()
    .stopTranscriptionWithResponse(stopTranscriptionOptions, Context.NONE);

// Alternative: Stop transcription without options
// client.getCallConnection(callConnectionId)
//     .getCallMedia()
//     .stopTranscription();

Crie uma chamada e forneça os detalhes da transcrição

Defina as TranscriptionOptions para ACS para especificar quando iniciar a transcrição, a localidade para transcrição e a conexão de soquete da Web para enviar a transcrição.

const transcriptionOptions = {
    transportUrl: "",
    transportType: "websocket",
    locale: "en-US",
    startTranscription: false,
    speechRecognitionModelEndpointId: "YOUR_CUSTOM_SPEECH_RECOGNITION_MODEL_ID"
};

const options = {
    callIntelligenceOptions: {
        cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT
    },
    transcriptionOptions: transcriptionOptions
};

console.log("Placing outbound call...");
acsClient.createCall(callInvite, process.env.CALLBACK_URI + "/api/callbacks", options);

Conecte-se a uma chamada de salas e forneça detalhes de transcrição

Se você estiver se conectando a uma sala ACS e quiser usar a transcrição, configure as opções de transcrição da seguinte maneira:

const transcriptionOptions = {
    transportUri: "",
    locale: "en-US",
    transcriptionTransport: "websocket",
    startTranscription: false,
    speechRecognitionModelEndpointId: "YOUR_CUSTOM_SPEECH_RECOGNITION_MODEL_ID"
};

const callIntelligenceOptions = {
    cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT
};

const connectCallOptions = {
    callIntelligenceOptions: callIntelligenceOptions,
    transcriptionOptions: transcriptionOptions
};

const callLocator = {
    id: roomId,
    kind: "roomCallLocator"
};

const connectResult = await client.connectCall(callLocator, callBackUri, connectCallOptions);

Iniciar transcrição

Quando estiver pronto para iniciar a transcrição, você pode fazer uma chamada explícita para o Call Automation para começar a transcrever a chamada.

const startTranscriptionOptions = {
    locale: "en-AU",
    operationContext: "startTranscriptionContext"
};

// Start transcription with options
await callMedia.startTranscription(startTranscriptionOptions);

// Alternative: Start transcription without options
// await callMedia.startTranscription();

Cabeçalhos adicionais:

A ID de Correlação e a ID de Conexão de Chamada agora estão incluídas nos cabeçalhos WebSocket para melhor rastreabilidade x-ms-call-correlation-id e x-ms-call-connection-id.

Recebendo fluxo de transcrição

Quando a transcrição é iniciada, seu websocket recebe a carga útil de metadados de transcrição como o primeiro pacote.

{
    "kind": "TranscriptionMetadata",
    "transcriptionMetadata": {
        "subscriptionId": "aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e",
        "locale": "en-us",
        "callConnectionId": "65c57654=f12c-4975-92a4-21668e61dd98",
        "correlationId": "65c57654=f12c-4975-92a4-21668e61dd98"
    }
}

Receção de dados de transcrição

Após os metadados, os próximos pacotes que seu soquete da Web receberá serão TranscriptionData para o áudio transcrito.

{
    "kind": "TranscriptionData",
    "transcriptionData": {
        "text": "Testing transcription.",
        "format": "display",
        "confidence": 0.695223331451416,
        "offset": 2516998782481234400,
        "words": [
            {
                "text": "testing",
                "offset": 2516998782481234400
            },
            {
                "text": "testing",
                "offset": 2516998782481234400
            }
        ],
        "participantRawID": "8:acs:",
        "resultStatus": "Final"
    }
}

Manipulando o fluxo de transcrição no servidor de soquete da Web

import WebSocket from 'ws';
import { streamingData } from '@azure/communication-call-automation/src/util/streamingDataParser';

const wss = new WebSocket.Server({ port: 8081 });

wss.on('connection', (ws) => {
    console.log('Client connected');

    ws.on('message', (packetData) => {
        const decoder = new TextDecoder();
        const stringJson = decoder.decode(packetData);
        console.log("STRING JSON => " + stringJson);

        const response = streamingData(packetData);
        
        if ('locale' in response) {
            console.log("Transcription Metadata");
            console.log(response.callConnectionId);
            console.log(response.correlationId);
            console.log(response.locale);
            console.log(response.subscriptionId);
        }
        
        if ('text' in response) {
            console.log("Transcription Data");
            console.log(response.text);
            console.log(response.format);
            console.log(response.confidence);
            console.log(response.offset);
            console.log(response.duration);
            console.log(response.resultStatus);

            if ('phoneNumber' in response.participant) {
                console.log(response.participant.phoneNumber);
            }

            response.words.forEach((word) => {
                console.log(word.text);
                console.log(word.duration);
                console.log(word.offset);
            });
        }
    });

    ws.on('close', () => {
        console.log('Client disconnected');
    });
});

console.log('WebSocket server running on port 8081');

Atualizar transcrição

Para situações em que seu aplicativo permite que os usuários selecionem seu idioma preferido, você também pode querer capturar a transcrição nesse idioma. Para fazer essa tarefa, o SDK de automação de chamadas permite que você atualize a localidade de transcrição.

async function updateTranscriptionAsync() {
  const options: UpdateTranscriptionOptions = {
operationContext: "updateTranscriptionContext",
speechRecognitionModelEndpointId: "YOUR_CUSTOM_SPEECH_RECOGNITION_MODEL_ID"
  };
  await acsClient
.getCallConnection(callConnectionId)
.getCallMedia()
.updateTranscription("en-au", options);
}

Parar transcrição

Quando seu aplicativo precisar parar de ouvir a transcrição, você poderá usar a solicitação StopTranscription para informar a Automação de Chamadas para parar de enviar dados de transcrição para seu soquete da Web.

const stopTranscriptionOptions = {
    operationContext: "stopTranscriptionContext"
};

// Stop transcription with options
await callMedia.stopTranscription(stopTranscriptionOptions);

// Alternative: Stop transcription without options
// await callMedia.stopTranscription();

Crie uma chamada e forneça os detalhes da transcrição

Defina as TranscriptionOptions para ACS para especificar quando iniciar a transcrição, a localidade para transcrição e a conexão de soquete da Web para enviar a transcrição.

transcription_options = TranscriptionOptions(
    transport_url="WEBSOCKET_URI_HOST",
    transport_type=TranscriptionTransportType.WEBSOCKET,
    locale="en-US",
    start_transcription=False,
    #Only add the SpeechRecognitionModelEndpointId if you have a custom speech model you would like to use
    speech_recognition_model_endpoint_id = "YourCustomSpeechRecognitionModelEndpointId"
);
)

call_connection_properties = call_automation_client.create_call(
    target_participant,
    CALLBACK_EVENTS_URI,
    cognitive_services_endpoint=COGNITIVE_SERVICES_ENDPOINT,
    source_caller_id_number=source_caller,
    transcription=transcription_options
)

Conecte-se a uma chamada de salas e forneça detalhes de transcrição

Se você estiver se conectando a uma sala ACS e quiser usar a transcrição, configure as opções de transcrição da seguinte maneira:

transcription_options = TranscriptionOptions(
    transport_url="",
    transport_type=TranscriptionTransportType.WEBSOCKET,
    locale="en-US",
    start_transcription=False,
    #Only add the SpeechRecognitionModelEndpointId if you have a custom speech model you would like to use
    speech_recognition_model_endpoint_id = "YourCustomSpeechRecognitionModelEndpointId"
)

connect_result = client.connect_call(
    room_id="roomid",
    CALLBACK_EVENTS_URI,
    cognitive_services_endpoint=COGNITIVE_SERVICES_ENDPOINT,
    operation_context="connectCallContext",
    transcription=transcription_options
)

Iniciar transcrição

Quando estiver pronto para iniciar a transcrição, você pode fazer uma chamada explícita para o Call Automation para começar a transcrever a chamada.

# Start transcription without options
call_connection_client.start_transcription()

# Option 1: Start transcription with locale and operation context
# call_connection_client.start_transcription(locale="en-AU", operation_context="startTranscriptionContext")

# Option 2: Start transcription with operation context
# call_connection_client.start_transcription(operation_context="startTranscriptionContext")

Cabeçalhos adicionais:

A ID de Correlação e a ID de Conexão de Chamada agora estão incluídas nos cabeçalhos WebSocket para melhor rastreabilidade x-ms-call-correlation-id e x-ms-call-connection-id.

Recebendo fluxo de transcrição

Quando a transcrição é iniciada, seu websocket recebe a carga útil de metadados de transcrição como o primeiro pacote.

{
    "kind": "TranscriptionMetadata",
    "transcriptionMetadata": {
        "subscriptionId": "aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e",
        "locale": "en-us",
        "callConnectionId": "65c57654=f12c-4975-92a4-21668e61dd98",
        "correlationId": "65c57654=f12c-4975-92a4-21668e61dd98"
    }
}

Receção de dados de transcrição

Após os metadados, os próximos pacotes que seu websocket receberá serão TranscriptionData para o áudio transcrito.

{
    "kind": "TranscriptionData",
    "transcriptionData": {
        "text": "Testing transcription.",
        "format": "display",
        "confidence": 0.695223331451416,
        "offset": 2516998782481234400,
        "words": [
            {
                "text": "testing",
                "offset": 2516998782481234400
            },
            {
                "text": "testing",
                "offset": 2516998782481234400
            }
        ],
        "participantRawID": "8:acs:",
        "resultStatus": "Final"
    }
}

Manipulando o fluxo de transcrição no servidor de soquete da Web

import asyncio
import json
import websockets
from azure.communication.callautomation._shared.models import identifier_from_raw_id

async def handle_client(websocket, path):
    print("Client connected")
    try:
        async for message in websocket:
            json_object = json.loads(message)
            kind = json_object['kind']
            if kind == 'TranscriptionMetadata':
                print("Transcription metadata")
                print("-------------------------")
                print("Subscription ID:", json_object['transcriptionMetadata']['subscriptionId'])
                print("Locale:", json_object['transcriptionMetadata']['locale'])
                print("Call Connection ID:", json_object['transcriptionMetadata']['callConnectionId'])
                print("Correlation ID:", json_object['transcriptionMetadata']['correlationId'])
            if kind == 'TranscriptionData':
                participant = identifier_from_raw_id(json_object['transcriptionData']['participantRawID'])
                word_data_list = json_object['transcriptionData']['words']
                print("Transcription data")
                print("-------------------------")
                print("Text:", json_object['transcriptionData']['text'])
                print("Format:", json_object['transcriptionData']['format'])
                print("Confidence:", json_object['transcriptionData']['confidence'])
                print("Offset:", json_object['transcriptionData']['offset'])
                print("Duration:", json_object['transcriptionData']['duration'])
                print("Participant:", participant.raw_id)
                print("Result Status:", json_object['transcriptionData']['resultStatus'])
                for word in word_data_list:
                    print("Word:", word['text'])
                    print("Offset:", word['offset'])
                    print("Duration:", word['duration'])
            
    except websockets.exceptions.ConnectionClosedOK:
        print("Client disconnected")
    except websockets.exceptions.ConnectionClosedError as e:
        print("Connection closed with error: %s", e)
    except Exception as e:
        print("Unexpected error: %s", e)

start_server = websockets.serve(handle_client, "localhost", 8081)

print('WebSocket server running on port 8081')

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

Atualizar transcrição

Para situações em que seu aplicativo permite que os usuários selecionem seu idioma preferido, você também pode querer capturar a transcrição nesse idioma. Para fazer essa tarefa, o SDK de automação de chamadas permite que você atualize a localidade de transcrição.

await call_automation_client.get_call_connection(
    call_connection_id=call_connection_id
).update_transcription(
    operation_context="UpdateTranscriptionContext",
    locale="en-au",
    #Only add the SpeechRecognitionModelEndpointId if you have a custom speech model you would like to use
    speech_recognition_model_endpoint_id = "YourCustomSpeechRecognitionModelEndpointId"
)

Parar transcrição

Quando seu aplicativo precisar parar de ouvir a transcrição, você poderá usar a solicitação StopTranscription para informar a Automação de Chamadas para parar de enviar dados de transcrição para seu soquete da Web.

# Stop transcription without options
call_connection_client.stop_transcription()

# Alternative: Stop transcription with operation context
# call_connection_client.stop_transcription(operation_context="stopTranscriptionContext")

Códigos de evento

Evento código subcódigo Mensagem
Transcrição Iniciada 200 0 Ação concluída com êxito.
Transcrição Interrompida 200 0 Ação concluída com êxito.
Transcrição Atualizada 200 0 Ação concluída com êxito.
Transcrição Falhou 400 8581 Falha na ação, StreamUrl não é válido.
Transcrição Falhou 400 8565 A ação falhou devido a um mau pedido aos Serviços Cognitivos. Verifique os parâmetros de entrada.
Transcrição Falhou 400 8565 A ação falhou devido a um pedido aos Serviços Cognitivos de tempo limite. Tente novamente mais tarde ou verifique se há problemas com o serviço.
Transcrição Falhou 400 8605 Não há suporte para o modelo de reconhecimento de fala personalizado para transcrição.
Transcrição Falhou 400 8523 Solicitação inválida, localidade em falta.
Transcrição Falhou 400 8523 Solicitação inválida, somente localidades que contêm informações de região são suportadas.
Transcrição Falhou 405 8520 A funcionalidade de transcrição não é suportada no momento.
Transcrição Falhou 405 8520 UpdateTranscription não é suportado para conexão criada com a interface Connect.
Transcrição Falhou 400 8528 A ação é inválida, a chamada já foi encerrada.
Transcrição Falhou 405 8520 A funcionalidade de transcrição de atualização não é suportada no momento.
Transcrição Falhou 405 8522 Solicitação não permitida quando a URL de transcrição não estiver definida durante a configuração da chamada.
Transcrição Falhou 405 8522 Solicitação não permitida quando a Configuração do Serviço Cognitivo não estiver definida durante a configuração da chamada.
Transcrição Falhou 400 8501 A ação é inválida quando a chamada não está no estado Estabelecido.
Transcrição Falhou 401 8565 A ação falhou devido a um erro de autenticação dos Serviços Cognitivos. Verifique a sua entrada de autorização e certifique-se de que está correta.
Transcrição Falhou 403 8565 A ação falhou devido a um pedido proibido aos Serviços Cognitivos. Verifique o estado da sua subscrição e certifique-se de que está ativa.
Transcrição Falhou 429 8565 A ação falhou, as solicitações excederam o número de solicitações simultâneas permitidas para a assinatura de serviços cognitivos.
Transcrição Falhou 500 8578 Falha na ação, não é possível estabelecer a conexão WebSocket.
Transcrição Falhou 500 8580 A ação falhou, o serviço de transcrição foi encerrado.
Transcrição Falhou 500 8579 A ação falhou, a transcrição foi cancelada.
Transcrição Falhou 500 9999 Erro interno desconhecido do servidor.

Problemas conhecidos

  • Para chamadas 1:1 com usuários do ACS usando SDKs de cliente, startTranscription = True não é suportado no momento.