Coletar a entrada do usuário com a ação Reconhecer

Este guia ajudará você a começar a reconhecer a entrada DTMF fornecida pelos participantes por meio do SDK de Automação de Chamadas dos Serviços de Comunicação do Azure.

Pré-requisitos

Para recursos de IA

Especificações técnicas

Os seguintes parâmetros estão disponíveis para personalizar a função Reconhecer:

Parâmetro Type Padrão (se não especificado) Description Obrigatório ou Opcional
Prompt

(para obter detalhes sobre a ação Jogar, consulte este guia de instruções)
FileSource, TextSource Não definido Esta é a mensagem que você deseja reproduzir antes de reconhecer a entrada. Opcional
InterToneTimeout TimeSpan 2 segundos

Mínimo: 1 segundo
Máx: 60 segundos
Limite em segundos que os Serviços de Comunicação do Azure aguardam que o chamador pressione outro dígito (tempo limite entre dígitos). Opcional
InitialSegmentationSilenceTimeoutInSeconds Número inteiro 0,5 segundo Quanto tempo a ação de reconhecimento aguarda a entrada antes de considerá-la um tempo limite. Leia mais aqui. Opcional
RecognizeInputsType Enumeração DTMF Tipo de entrada que é reconhecida. As opções são dtmf, choices, speech e speechordtmf. Necessário
InitialSilenceTimeout TimeSpan 5 segundos

Mínimo: 0 segundos
Máx: 300 segundos (DTMF)
Máx: 20 segundos (Opções)
Máx: 20 segundos (Fala)
O tempo limite de silêncio inicial ajusta a quantidade de áudio não falado permitida antes de uma frase antes que a tentativa de reconhecimento termine em um resultado "sem correspondência". Leia mais aqui. Opcional
MaxTonesToCollect Número inteiro Sem padrão

MÍN: 1
Número de dígitos que um desenvolvedor espera como entrada do participante. Necessário
StopTones IEnumeração<DtmfTone> Não definido Os participantes do dígito podem pressionar para escapar de um evento DTMF em lote. Opcional
InterruptPrompt Bool True Se o participante tiver a capacidade de interromper o playMessage pressionando um dígito. Opcional
InterruptCallMediaOperation Bool True Se esse sinalizador estiver definido, ele interromperá a operação de mídia de chamada atual. Por exemplo, se algum áudio estiver sendo reproduzido, ele interrompe essa operação e inicia o reconhecimento. Opcional
OperationContext String Não definido String que os desenvolvedores podem passar ação intermediária, útil para permitir que os desenvolvedores armazenem contexto sobre os eventos que recebem. Opcional
Frases String Não definido Lista de frases que se associam ao rótulo, se alguma delas for ouvida é considerada um reconhecimento bem-sucedido. Necessário
Tom String Não definido O tom a ser reconhecido se o usuário decidir pressionar um número em vez de usar a fala. Opcional
Etiqueta String Não definido O valor-chave para o reconhecimento. Necessário
Idioma String En-nos A linguagem usada para reconhecer a fala. Opcional
EndSilenceTimeout TimeSpan 0,5 segundo A pausa final do orador usada para detetar o resultado final que é gerado como fala. Opcional

Nota

Em situações em que o dtmf e a fala estão no recognizeInputsType, a ação reconhecer atuará no primeiro tipo de entrada recebido, ou seja, se o usuário pressionar um número de teclado primeiro, a ação de reconhecimento o considerará um evento dtmf e continuará ouvindo os tons dtmf. Se o usuário falar primeiro, a ação de reconhecimento considerará um reconhecimento de fala e ouvirá a entrada de voz.

Criar um novo aplicativo C#

Na janela do console do seu sistema operacional, use o dotnet comando para criar um novo aplicativo Web.

dotnet new web -n MyApplication

Instalar o pacote NuGet

O pacote NuGet pode ser obtido aqui, se você ainda não o fez.

Estabeleça uma chamada

A esta altura, você deve estar familiarizado com o início de chamadas, se precisar saber mais sobre como fazer uma chamada, siga nosso início rápido. Você também pode usar o trecho de código fornecido aqui para entender como atender uma chamada.

var callAutomationClient = new CallAutomationClient("<Azure Communication Services connection string>");

var answerCallOptions = new AnswerCallOptions("<Incoming call context once call is connected>", new Uri("<https://sample-callback-uri>"))  
{  
    CallIntelligenceOptions = new CallIntelligenceOptions() { CognitiveServicesEndpoint = new Uri("<Azure Cognitive Services Endpoint>") } 
};  

var answerCallResult = await callAutomationClient.AnswerCallAsync(answerCallOptions); 

Chamar a ação de reconhecimento

Quando seu aplicativo atende a chamada, você pode fornecer informações sobre como reconhecer a entrada do participante e reproduzir um prompt.

DTMF

var maxTonesToCollect = 3;
String textToPlay = "Welcome to Contoso, please enter 3 DTMF.";
var playSource = new TextSource(textToPlay, "en-US-ElizabethNeural");
var recognizeOptions = new CallMediaRecognizeDtmfOptions(targetParticipant, maxTonesToCollect) {
  InitialSilenceTimeout = TimeSpan.FromSeconds(30),
    Prompt = playSource,
    InterToneTimeout = TimeSpan.FromSeconds(5),
    InterruptPrompt = true,
    StopTones = new DtmfTone[] {
      DtmfTone.Pound
    },
};
var recognizeResult = await callAutomationClient.GetCallConnection(callConnectionId)
  .GetCallMedia()
  .StartRecognizingAsync(recognizeOptions);

Para fluxos de fala para texto, a ação de reconhecimento da Automação de Chamadas também suporta o uso de modelos de fala personalizados. Recursos como modelos de fala personalizados podem ser úteis quando você está criando um aplicativo que precisa ouvir palavras complexas que os modelos padrão de fala para texto podem não ser capazes de entender, um bom exemplo disso pode ser quando você está criando um aplicativo para o setor de telemedicina e seu agente virtual precisa ser capaz de reconhecer termos médicos. Você pode saber mais sobre como criar e implantar modelos de fala personalizados aqui.

Opções de fala para texto

var choices = new List < RecognitionChoice > {
  new RecognitionChoice("Confirm", new List < string > {
    "Confirm",
    "First",
    "One"
  }) {
    Tone = DtmfTone.One
  },
  new RecognitionChoice("Cancel", new List < string > {
    "Cancel",
    "Second",
    "Two"
  }) {
    Tone = DtmfTone.Two
  }
};
String textToPlay = "Hello, This is a reminder for your appointment at 2 PM, Say Confirm to confirm your appointment or Cancel to cancel the appointment. Thank you!";

var playSource = new TextSource(textToPlay, "en-US-ElizabethNeural");
var recognizeOptions = new CallMediaRecognizeChoiceOptions(targetParticipant, choices) {
  InterruptPrompt = true,
    InitialSilenceTimeout = TimeSpan.FromSeconds(30),
    Prompt = playSource,
    OperationContext = "AppointmentReminderMenu",
    //Only add the SpeechModelEndpointId if you have a custom speech model you would like to use
    SpeechModelEndpointId = "YourCustomSpeechModelEndpointId"
};
var recognizeResult = await callAutomationClient.GetCallConnection(callConnectionId)
  .GetCallMedia()
  .StartRecognizingAsync(recognizeOptions);

Conversão de Voz em Texto

String textToPlay = "Hi, how can I help you today?";
var playSource = new TextSource(textToPlay, "en-US-ElizabethNeural");
var recognizeOptions = new CallMediaRecognizeSpeechOptions(targetParticipant) {
  Prompt = playSource,
    EndSilenceTimeout = TimeSpan.FromMilliseconds(1000),
    OperationContext = "OpenQuestionSpeech",
    //Only add the SpeechModelEndpointId if you have a custom speech model you would like to use
    SpeechModelEndpointId = "YourCustomSpeechModelEndpointId"
};
var recognizeResult = await callAutomationClient.GetCallConnection(callConnectionId)
  .GetCallMedia()
  .StartRecognizingAsync(recognizeOptions);

Conversão de voz em texto ou DTMF

var maxTonesToCollect = 1; 
String textToPlay = "Hi, how can I help you today, you can press 0 to speak to an agent?"; 
var playSource = new TextSource(textToPlay, "en-US-ElizabethNeural"); 
var recognizeOptions = new CallMediaRecognizeSpeechOrDtmfOptions(targetParticipant, maxTonesToCollect) 
{ 
    Prompt = playSource, 
    EndSilenceTimeout = TimeSpan.FromMilliseconds(1000), 
    InitialSilenceTimeout = TimeSpan.FromSeconds(30), 
    InterruptPrompt = true, 
    OperationContext = "OpenQuestionSpeechOrDtmf",
    //Only add the SpeechModelEndpointId if you have a custom speech model you would like to use
    SpeechModelEndpointId = "YourCustomSpeechModelEndpointId" 
}; 
var recognizeResult = await callAutomationClient.GetCallConnection(callConnectionId) 
    .GetCallMedia() 
    .StartRecognizingAsync(recognizeOptions); 

Nota

Se os parâmetros não forem definidos, os padrões serão aplicados sempre que possível.

Receber atualizações de eventos de reconhecimento

Os desenvolvedores podem se inscrever nos eventos RecognizeCompleted e RecognizeFailed no retorno de chamada do webhook que registraram para a chamada para criar lógica de negócios em seu aplicativo para determinar as próximas etapas quando um dos eventos mencionados anteriormente ocorrer.

Exemplo de como você pode desserializar o evento RecognizeCompleted :

if (acsEvent is RecognizeCompleted recognizeCompleted) 
{ 
    switch (recognizeCompleted.RecognizeResult) 
    { 
        case DtmfResult dtmfResult: 
            //Take action for Recognition through DTMF 
            var tones = dtmfResult.Tones; 
            logger.LogInformation("Recognize completed succesfully, tones={tones}", tones); 
            break; 
        case ChoiceResult choiceResult: 
            // Take action for Recognition through Choices 
            var labelDetected = choiceResult.Label; 
            var phraseDetected = choiceResult.RecognizedPhrase; 
            // If choice is detected by phrase, choiceResult.RecognizedPhrase will have the phrase detected, 
            // If choice is detected using dtmf tone, phrase will be null 
            logger.LogInformation("Recognize completed succesfully, labelDetected={labelDetected}, phraseDetected={phraseDetected}", labelDetected, phraseDetected);
            break; 
        case SpeechResult speechResult: 
            // Take action for Recognition through Choices 
            var text = speechResult.Speech; 
            logger.LogInformation("Recognize completed succesfully, text={text}", text); 
            break; 
        default: 
            logger.LogInformation("Recognize completed succesfully, recognizeResult={recognizeResult}", recognizeCompleted.RecognizeResult); 
            break; 
    } 
} 

Exemplo de como você pode desserializar o evento RecognizeFailed :

if (acsEvent is RecognizeFailed recognizeFailed) 
{ 
    if (MediaEventReasonCode.RecognizeInitialSilenceTimedOut.Equals(recognizeFailed.ReasonCode)) 
    { 
        // Take action for time out 
        logger.LogInformation("Recognition failed: initial silencev time out"); 
    } 
    else if (MediaEventReasonCode.RecognizeSpeechOptionNotMatched.Equals(recognizeFailed.ReasonCode)) 
    { 
        // Take action for option not matched 
        logger.LogInformation("Recognition failed: speech option not matched"); 
    } 
    else if (MediaEventReasonCode.RecognizeIncorrectToneDetected.Equals(recognizeFailed.ReasonCode)) 
    { 
        // Take action for incorrect tone 
        logger.LogInformation("Recognition failed: incorrect tone detected"); 
    } 
    else 
    { 
        logger.LogInformation("Recognition failed, result={result}, context={context}", recognizeFailed.ResultInformation?.Message, recognizeFailed.OperationContext); 
    } 
} 

Exemplo de como você pode desserializar o evento RecognizeCanceled :

if (acsEvent is RecognizeCanceled { OperationContext: "AppointmentReminderMenu" })
        {
            logger.LogInformation($"RecognizeCanceled event received for call connection id: {@event.CallConnectionId}");
            //Take action on recognize canceled operation
           await callConnection.HangUpAsync(forEveryone: true);
        }

Pré-requisitos

Para recursos de IA

Especificações técnicas

Os seguintes parâmetros estão disponíveis para personalizar a função Reconhecer:

Parâmetro Type Padrão (se não especificado) Description Obrigatório ou Opcional
Prompt

(para obter detalhes sobre a ação Jogar, consulte este guia de instruções)
FileSource, TextSource Não definido Esta é a mensagem que você deseja reproduzir antes de reconhecer a entrada. Opcional
InterToneTimeout TimeSpan 2 segundos

Mínimo: 1 segundo
Máx: 60 segundos
Limite em segundos que os Serviços de Comunicação do Azure aguardam que o chamador pressione outro dígito (tempo limite entre dígitos). Opcional
InitialSegmentationSilenceTimeoutInSeconds Número inteiro 0,5 segundo Quanto tempo a ação de reconhecimento aguarda a entrada antes de considerá-la um tempo limite. Leia mais aqui. Opcional
RecognizeInputsType Enumeração DTMF Tipo de entrada que é reconhecida. As opções são dtmf, choices, speech e speechordtmf. Necessário
InitialSilenceTimeout TimeSpan 5 segundos

Mínimo: 0 segundos
Máx: 300 segundos (DTMF)
Máx: 20 segundos (Opções)
Máx: 20 segundos (Fala)
O tempo limite de silêncio inicial ajusta a quantidade de áudio não falado permitida antes de uma frase antes que a tentativa de reconhecimento termine em um resultado "sem correspondência". Leia mais aqui. Opcional
MaxTonesToCollect Número inteiro Sem padrão

MÍN: 1
Número de dígitos que um desenvolvedor espera como entrada do participante. Necessário
StopTones IEnumeração<DtmfTone> Não definido Os participantes do dígito podem pressionar para escapar de um evento DTMF em lote. Opcional
InterruptPrompt Bool True Se o participante tiver a capacidade de interromper o playMessage pressionando um dígito. Opcional
InterruptCallMediaOperation Bool True Se esse sinalizador estiver definido, ele interromperá a operação de mídia de chamada atual. Por exemplo, se algum áudio estiver sendo reproduzido, ele interrompe essa operação e inicia o reconhecimento. Opcional
OperationContext String Não definido String que os desenvolvedores podem passar ação intermediária, útil para permitir que os desenvolvedores armazenem contexto sobre os eventos que recebem. Opcional
Frases String Não definido Lista de frases que se associam ao rótulo, se alguma delas for ouvida é considerada um reconhecimento bem-sucedido. Necessário
Tom String Não definido O tom a ser reconhecido se o usuário decidir pressionar um número em vez de usar a fala. Opcional
Etiqueta String Não definido O valor-chave para o reconhecimento. Necessário
Idioma String En-nos A linguagem usada para reconhecer a fala. Opcional
EndSilenceTimeout TimeSpan 0,5 segundo A pausa final do orador usada para detetar o resultado final que é gerado como fala. Opcional

Nota

Em situações em que o dtmf e a fala estão no recognizeInputsType, a ação reconhecer atuará no primeiro tipo de entrada recebido, ou seja, se o usuário pressionar um número de teclado primeiro, a ação de reconhecimento o considerará um evento dtmf e continuará ouvindo os tons dtmf. Se o usuário falar primeiro, a ação de reconhecimento considerará um reconhecimento de fala e ouvirá a entrada de voz.

Criar uma nova aplicação Java

No seu terminal ou janela de comando, navegue até o diretório onde você gostaria de criar sua aplicação Java. Execute o mvn comando para gerar o projeto Java a partir do modelo maven-archetype-quickstart.

mvn archetype:generate -DgroupId=com.communication.quickstart -DartifactId=communication-quickstart -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false

O mvn comando cria um diretório com o mesmo nome artifactId do argumento. Neste diretório, src/main/java o diretório contém o código-fonte do projeto, src/test/java o diretório contém a fonte de teste.

Você percebe que a etapa 'gerar' criou um diretório com o mesmo nome que o artifactId. Neste diretório, src/main/java o diretório contém código-fonte, src/test/java o diretório contém testes e pom.xml o arquivo é o Project Object Model ou POM do projeto.

Atualize o arquivo POM de seus aplicativos para usar Java 8 ou superior.

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

Adicionar referências de pacote

No arquivo POM, adicione a seguinte referência para o projeto

azure-communication-callautomation

<dependency>
  <groupId>com.azure</groupId>
  <artifactId>azure-communication-callautomation</artifactId>
  <version>1.0.0</version>
</dependency>

Estabeleça uma chamada

A esta altura, você deve estar familiarizado com o início de chamadas, se precisar saber mais sobre como fazer uma chamada, siga nosso início rápido. Você também pode usar o trecho de código fornecido aqui para entender como atender uma chamada.

CallIntelligenceOptions callIntelligenceOptions = new CallIntelligenceOptions().setCognitiveServicesEndpoint("https://sample-cognitive-service-resource.cognitiveservices.azure.com/"); 
answerCallOptions = new AnswerCallOptions("<Incoming call context>", "<https://sample-callback-uri>").setCallIntelligenceOptions(callIntelligenceOptions); 
Response < AnswerCallResult > answerCallResult = callAutomationClient
  .answerCallWithResponse(answerCallOptions)
  .block();

Chamar a ação de reconhecimento

Quando seu aplicativo atende a chamada, você pode fornecer informações sobre como reconhecer a entrada do participante e reproduzir um prompt.

DTMF

var maxTonesToCollect = 3;
String textToPlay = "Welcome to Contoso, please enter 3 DTMF.";
var playSource = new TextSource() 
    .setText(textToPlay) 
    .setVoiceName("en-US-ElizabethNeural");

var recognizeOptions = new CallMediaRecognizeDtmfOptions(targetParticipant, maxTonesToCollect) 
    .setInitialSilenceTimeout(Duration.ofSeconds(30)) 
    .setPlayPrompt(playSource) 
    .setInterToneTimeout(Duration.ofSeconds(5)) 
    .setInterruptPrompt(true) 
    .setStopTones(Arrays.asList(DtmfTone.POUND));

var recognizeResponse = callAutomationClient.getCallConnectionAsync(callConnectionId) 
    .getCallMediaAsync() 
    .startRecognizingWithResponse(recognizeOptions) 
    .block(); 

log.info("Start recognizing result: " + recognizeResponse.getStatusCode()); 

Para fluxos de fala para texto, a ação de reconhecimento da Automação de Chamadas também suporta o uso de modelos de fala personalizados. Recursos como modelos de fala personalizados podem ser úteis quando você está criando um aplicativo que precisa ouvir palavras complexas que os modelos padrão de fala para texto podem não ser capazes de entender, um bom exemplo disso pode ser quando você está criando um aplicativo para o setor de telemedicina e seu agente virtual precisa ser capaz de reconhecer termos médicos. Você pode saber mais sobre como criar e implantar modelos de fala personalizados aqui.

Opções de fala para texto

var choices = Arrays.asList(
  new RecognitionChoice()
  .setLabel("Confirm")
  .setPhrases(Arrays.asList("Confirm", "First", "One"))
  .setTone(DtmfTone.ONE),
  new RecognitionChoice()
  .setLabel("Cancel")
  .setPhrases(Arrays.asList("Cancel", "Second", "Two"))
  .setTone(DtmfTone.TWO)
);

String textToPlay = "Hello, This is a reminder for your appointment at 2 PM, Say Confirm to confirm your appointment or Cancel to cancel the appointment. Thank you!";
var playSource = new TextSource()
  .setText(textToPlay)
  .setVoiceName("en-US-ElizabethNeural");
var recognizeOptions = new CallMediaRecognizeChoiceOptions(targetParticipant, choices)
  .setInterruptPrompt(true)
  .setInitialSilenceTimeout(Duration.ofSeconds(30))
  .setPlayPrompt(playSource)
  .setOperationContext("AppointmentReminderMenu")
  //Only add the SpeechRecognitionModelEndpointId if you have a custom speech model you would like to use
  .setSpeechRecognitionModelEndpointId("YourCustomSpeechModelEndpointID"); 
var recognizeResponse = callAutomationClient.getCallConnectionAsync(callConnectionId)
  .getCallMediaAsync()
  .startRecognizingWithResponse(recognizeOptions)
  .block();

Conversão de Voz em Texto

String textToPlay = "Hi, how can I help you today?"; 
var playSource = new TextSource() 
    .setText(textToPlay) 
    .setVoiceName("en-US-ElizabethNeural"); 
var recognizeOptions = new CallMediaRecognizeSpeechOptions(targetParticipant, Duration.ofMillis(1000)) 
    .setPlayPrompt(playSource) 
    .setOperationContext("OpenQuestionSpeech")
    //Only add the SpeechRecognitionModelEndpointId if you have a custom speech model you would like to use
    .setSpeechRecognitionModelEndpointId("YourCustomSpeechModelEndpointID");  
var recognizeResponse = callAutomationClient.getCallConnectionAsync(callConnectionId) 
    .getCallMediaAsync() 
    .startRecognizingWithResponse(recognizeOptions) 
    .block(); 

Conversão de voz em texto ou DTMF

var maxTonesToCollect = 1; 
String textToPlay = "Hi, how can I help you today, you can press 0 to speak to an agent?"; 
var playSource = new TextSource() 
    .setText(textToPlay) 
    .setVoiceName("en-US-ElizabethNeural"); 
var recognizeOptions = new CallMediaRecognizeSpeechOrDtmfOptions(targetParticipant, maxTonesToCollect, Duration.ofMillis(1000)) 
    .setPlayPrompt(playSource) 
    .setInitialSilenceTimeout(Duration.ofSeconds(30)) 
    .setInterruptPrompt(true) 
    .setOperationContext("OpenQuestionSpeechOrDtmf")
    //Only add the SpeechRecognitionModelEndpointId if you have a custom speech model you would like to use
    .setSpeechRecognitionModelEndpointId("YourCustomSpeechModelEndpointID");  
var recognizeResponse = callAutomationClient.getCallConnectionAsync(callConnectionId) 
    .getCallMediaAsync() 
    .startRecognizingWithResponse(recognizeOptions) 
    .block(); 

Nota

Se os parâmetros não forem definidos, os padrões serão aplicados sempre que possível.

Receber atualizações de eventos de reconhecimento

Os desenvolvedores podem se inscrever para os eventos RecognizeCompleted e RecognizeFailed no retorno de chamada do webhook registrado. Esse retorno de chamada pode ser usado com lógica de negócios em seu aplicativo para determinar as próximas etapas quando um dos eventos ocorrer.

Exemplo de como você pode desserializar o evento RecognizeCompleted :

if (acsEvent instanceof RecognizeCompleted) { 
    RecognizeCompleted event = (RecognizeCompleted) acsEvent; 
    RecognizeResult recognizeResult = event.getRecognizeResult().get(); 
    if (recognizeResult instanceof DtmfResult) { 
        // Take action on collect tones 
        DtmfResult dtmfResult = (DtmfResult) recognizeResult; 
        List<DtmfTone> tones = dtmfResult.getTones(); 
        log.info("Recognition completed, tones=" + tones + ", context=" + event.getOperationContext()); 
    } else if (recognizeResult instanceof ChoiceResult) { 
        ChoiceResult collectChoiceResult = (ChoiceResult) recognizeResult; 
        String labelDetected = collectChoiceResult.getLabel(); 
        String phraseDetected = collectChoiceResult.getRecognizedPhrase(); 
        log.info("Recognition completed, labelDetected=" + labelDetected + ", phraseDetected=" + phraseDetected + ", context=" + event.getOperationContext()); 
    } else if (recognizeResult instanceof SpeechResult) { 
        SpeechResult speechResult = (SpeechResult) recognizeResult; 
        String text = speechResult.getSpeech(); 
        log.info("Recognition completed, text=" + text + ", context=" + event.getOperationContext()); 
    } else { 
        log.info("Recognition completed, result=" + recognizeResult + ", context=" + event.getOperationContext()); 
    } 
} 

Exemplo de como você pode desserializar o evento RecognizeFailed :

if (acsEvent instanceof RecognizeFailed) { 
    RecognizeFailed event = (RecognizeFailed) acsEvent; 
    if (ReasonCode.Recognize.INITIAL_SILENCE_TIMEOUT.equals(event.getReasonCode())) { 
        // Take action for time out 
        log.info("Recognition failed: initial silence time out"); 
    } else if (ReasonCode.Recognize.SPEECH_OPTION_NOT_MATCHED.equals(event.getReasonCode())) { 
        // Take action for option not matched 
        log.info("Recognition failed: speech option not matched"); 
    } else if (ReasonCode.Recognize.DMTF_OPTION_MATCHED.equals(event.getReasonCode())) { 
        // Take action for incorrect tone 
        log.info("Recognition failed: incorrect tone detected"); 
    } else { 
        log.info("Recognition failed, result=" + event.getResultInformation().getMessage() + ", context=" + event.getOperationContext()); 
    } 
} 

Exemplo de como você pode desserializar o evento RecognizeCanceled :

if (acsEvent instanceof RecognizeCanceled) { 
    RecognizeCanceled event = (RecognizeCanceled) acsEvent; 
    log.info("Recognition canceled, context=" + event.getOperationContext()); 
}

Pré-requisitos

  • Conta do Azure com uma subscrição ativa, para obter detalhes, consulte Criar uma conta gratuitamente.
  • Recurso dos Serviços de Comunicação do Azure. Consulte Criar um recurso dos Serviços de Comunicação do Azure. Observe a cadeia de conexão para este recurso.
  • Crie um novo aplicativo de serviço Web usando o SDK de automação de chamadas.
  • Tem Node.js instalado, você pode instalá-lo a partir de seu site oficial.

Para recursos de IA

Especificações técnicas

Os seguintes parâmetros estão disponíveis para personalizar a função Reconhecer:

Parâmetro Type Padrão (se não especificado) Description Obrigatório ou Opcional
Prompt

(para obter detalhes sobre a ação Jogar, consulte este guia de instruções)
FileSource, TextSource Não definido Esta é a mensagem que você deseja reproduzir antes de reconhecer a entrada. Opcional
InterToneTimeout TimeSpan 2 segundos

Mínimo: 1 segundo
Máx: 60 segundos
Limite em segundos que os Serviços de Comunicação do Azure aguardam que o chamador pressione outro dígito (tempo limite entre dígitos). Opcional
InitialSegmentationSilenceTimeoutInSeconds Número inteiro 0,5 segundo Quanto tempo a ação de reconhecimento aguarda a entrada antes de considerá-la um tempo limite. Leia mais aqui. Opcional
RecognizeInputsType Enumeração DTMF Tipo de entrada que é reconhecida. As opções são dtmf, choices, speech e speechordtmf. Necessário
InitialSilenceTimeout TimeSpan 5 segundos

Mínimo: 0 segundos
Máx: 300 segundos (DTMF)
Máx: 20 segundos (Opções)
Máx: 20 segundos (Fala)
O tempo limite de silêncio inicial ajusta a quantidade de áudio não falado permitida antes de uma frase antes que a tentativa de reconhecimento termine em um resultado "sem correspondência". Leia mais aqui. Opcional
MaxTonesToCollect Número inteiro Sem padrão

MÍN: 1
Número de dígitos que um desenvolvedor espera como entrada do participante. Necessário
StopTones IEnumeração<DtmfTone> Não definido Os participantes do dígito podem pressionar para escapar de um evento DTMF em lote. Opcional
InterruptPrompt Bool True Se o participante tiver a capacidade de interromper o playMessage pressionando um dígito. Opcional
InterruptCallMediaOperation Bool True Se esse sinalizador estiver definido, ele interromperá a operação de mídia de chamada atual. Por exemplo, se algum áudio estiver sendo reproduzido, ele interrompe essa operação e inicia o reconhecimento. Opcional
OperationContext String Não definido String que os desenvolvedores podem passar ação intermediária, útil para permitir que os desenvolvedores armazenem contexto sobre os eventos que recebem. Opcional
Frases String Não definido Lista de frases que se associam ao rótulo, se alguma delas for ouvida é considerada um reconhecimento bem-sucedido. Necessário
Tom String Não definido O tom a ser reconhecido se o usuário decidir pressionar um número em vez de usar a fala. Opcional
Etiqueta String Não definido O valor-chave para o reconhecimento. Necessário
Idioma String En-nos A linguagem usada para reconhecer a fala. Opcional
EndSilenceTimeout TimeSpan 0,5 segundo A pausa final do orador usada para detetar o resultado final que é gerado como fala. Opcional

Nota

Em situações em que o dtmf e a fala estão no recognizeInputsType, a ação reconhecer atuará no primeiro tipo de entrada recebido, ou seja, se o usuário pressionar um número de teclado primeiro, a ação de reconhecimento o considerará um evento dtmf e continuará ouvindo os tons dtmf. Se o usuário falar primeiro, a ação de reconhecimento considerará um reconhecimento de fala e ouvirá a entrada de voz.

Criar um novo aplicativo JavaScript

Crie um novo aplicativo JavaScript no diretório do projeto. Inicialize um novo projeto Node.js com o seguinte comando. Isso cria um arquivo de package.json para seu projeto, que é usado para gerenciar as dependências do projeto.

npm init -y

Instalar o pacote de Automação de Chamadas dos Serviços de Comunicação do Azure

npm install @azure/communication-call-automation

Crie um novo arquivo JavaScript no diretório do projeto, por exemplo, nomeie-o app.js. Você escreve seu código JavaScript neste arquivo. Execute seu aplicativo usando o Node.js com o seguinte comando. Isso executa o código JavaScript que você escreveu.

node app.js

Estabeleça uma chamada

A esta altura, você deve estar familiarizado com o início de chamadas, se precisar saber mais sobre como fazer uma chamada, siga nosso início rápido. Neste início rápido, criamos uma chamada de saída.

Chamar a ação de reconhecimento

Quando seu aplicativo atende a chamada, você pode fornecer informações sobre como reconhecer a entrada do participante e reproduzir um prompt.

DTMF

const maxTonesToCollect = 3; 
const textToPlay = "Welcome to Contoso, please enter 3 DTMF."; 
const playSource: TextSource = { text: textToPlay, voiceName: "en-US-ElizabethNeural", kind: "textSource" }; 
const recognizeOptions: CallMediaRecognizeDtmfOptions = { 
    maxTonesToCollect: maxTonesToCollect, 
    initialSilenceTimeoutInSeconds: 30, 
    playPrompt: playSource, 
    interToneTimeoutInSeconds: 5, 
    interruptPrompt: true, 
    stopDtmfTones: [ DtmfTone.Pound ], 
    kind: "callMediaRecognizeDtmfOptions" 
}; 

await callAutomationClient.getCallConnection(callConnectionId) 
    .getCallMedia() 
    .startRecognizing(targetParticipant, recognizeOptions); 

Para fluxos de fala para texto, a ação de reconhecimento da Automação de Chamadas também suporta o uso de modelos de fala personalizados. Recursos como modelos de fala personalizados podem ser úteis quando você está criando um aplicativo que precisa ouvir palavras complexas que os modelos padrão de fala para texto podem não ser capazes de entender, um bom exemplo disso pode ser quando você está criando um aplicativo para o setor de telemedicina e seu agente virtual precisa ser capaz de reconhecer termos médicos. Você pode saber mais sobre como criar e implantar modelos de fala personalizados aqui.

Opções de fala para texto

const choices = [ 
    {  
        label: "Confirm", 
        phrases: [ "Confirm", "First", "One" ], 
        tone: DtmfTone.One 
    }, 
    { 
        label: "Cancel", 
        phrases: [ "Cancel", "Second", "Two" ], 
        tone: DtmfTone.Two 
    } 
]; 

const textToPlay = "Hello, This is a reminder for your appointment at 2 PM, Say Confirm to confirm your appointment or Cancel to cancel the appointment. Thank you!"; 
const playSource: TextSource = { text: textToPlay, voiceName: "en-US-ElizabethNeural", kind: "textSource" }; 
const recognizeOptions: CallMediaRecognizeChoiceOptions = { 
    choices: choices, 
    interruptPrompt: true, 
    initialSilenceTimeoutInSeconds: 30, 
    playPrompt: playSource, 
    operationContext: "AppointmentReminderMenu", 
    kind: "callMediaRecognizeChoiceOptions",
    //Only add the speechRecognitionModelEndpointId if you have a custom speech model you would like to use
    speechRecognitionModelEndpointId: "YourCustomSpeechEndpointId"
}; 

await callAutomationClient.getCallConnection(callConnectionId) 
    .getCallMedia() 
    .startRecognizing(targetParticipant, recognizeOptions); 

Conversão de Voz em Texto

const textToPlay = "Hi, how can I help you today?"; 
const playSource: TextSource = { text: textToPlay, voiceName: "en-US-ElizabethNeural", kind: "textSource" }; 
const recognizeOptions: CallMediaRecognizeSpeechOptions = { 
    endSilenceTimeoutInSeconds: 1, 
    playPrompt: playSource, 
    operationContext: "OpenQuestionSpeech", 
    kind: "callMediaRecognizeSpeechOptions",
    //Only add the speechRecognitionModelEndpointId if you have a custom speech model you would like to use
    speechRecognitionModelEndpointId: "YourCustomSpeechEndpointId"
}; 

await callAutomationClient.getCallConnection(callConnectionId) 
    .getCallMedia() 
    .startRecognizing(targetParticipant, recognizeOptions); 

Conversão de voz em texto ou DTMF

const maxTonesToCollect = 1; 
const textToPlay = "Hi, how can I help you today, you can press 0 to speak to an agent?"; 
const playSource: TextSource = { text: textToPlay, voiceName: "en-US-ElizabethNeural", kind: "textSource" }; 
const recognizeOptions: CallMediaRecognizeSpeechOrDtmfOptions = { 
    maxTonesToCollect: maxTonesToCollect, 
    endSilenceTimeoutInSeconds: 1, 
    playPrompt: playSource, 
    initialSilenceTimeoutInSeconds: 30, 
    interruptPrompt: true, 
    operationContext: "OpenQuestionSpeechOrDtmf", 
    kind: "callMediaRecognizeSpeechOrDtmfOptions",
    //Only add the speechRecognitionModelEndpointId if you have a custom speech model you would like to use
    speechRecognitionModelEndpointId: "YourCustomSpeechEndpointId"
}; 

await callAutomationClient.getCallConnection(callConnectionId) 
    .getCallMedia() 
    .startRecognizing(targetParticipant, recognizeOptions); 

Nota

Se os parâmetros não forem definidos, os padrões serão aplicados sempre que possível.

Receber atualizações de eventos de reconhecimento

Os desenvolvedores podem se inscrever nos eventos RecognizeCompleted e RecognizeFailed no retorno de chamada do webhook que registraram para a chamada para criar lógica de negócios em seu aplicativo para determinar as próximas etapas quando um dos eventos mencionados anteriormente ocorrer.

Exemplo de como você pode desserializar o evento RecognizeCompleted :

if (event.type === "Microsoft.Communication.RecognizeCompleted") { 
    if (eventData.recognitionType === "dtmf") { 
        const tones = eventData.dtmfResult.tones; 
        console.log("Recognition completed, tones=%s, context=%s", tones, eventData.operationContext); 
    } else if (eventData.recognitionType === "choices") { 
        const labelDetected = eventData.choiceResult.label; 
        const phraseDetected = eventData.choiceResult.recognizedPhrase; 
        console.log("Recognition completed, labelDetected=%s, phraseDetected=%s, context=%s", labelDetected, phraseDetected, eventData.operationContext); 
    } else if (eventData.recognitionType === "speech") { 
        const text = eventData.speechResult.speech; 
        console.log("Recognition completed, text=%s, context=%s", text, eventData.operationContext); 
    } else { 
        console.log("Recognition completed: data=%s", JSON.stringify(eventData, null, 2)); 
    } 
} 

Exemplo de como você pode desserializar o evento RecognizeFailed :

if (event.type === "Microsoft.Communication.RecognizeFailed") {
    console.log("Recognize failed: data=%s", JSON.stringify(eventData, null, 2));
}

Exemplo de como você pode desserializar o evento RecognizeCanceled :

if (event.type === "Microsoft.Communication.RecognizeCanceled") {
    console.log("Recognize canceled, context=%s", eventData.operationContext);
}

Pré-requisitos

  • Conta do Azure com uma subscrição ativa, para obter detalhes, consulte Criar uma conta gratuitamente.
  • Recurso dos Serviços de Comunicação do Azure. Consulte Criar um recurso dos Serviços de Comunicação do Azure. Observe a cadeia de conexão para este recurso.
  • Crie um novo aplicativo de serviço Web usando o SDK de automação de chamadas.
  • Tenha o Python instalado, você pode instalar a partir do site oficial.

Para recursos de IA

Especificações técnicas

Os seguintes parâmetros estão disponíveis para personalizar a função Reconhecer:

Parâmetro Type Padrão (se não especificado) Description Obrigatório ou Opcional
Prompt

(para obter detalhes sobre a ação Jogar, consulte este guia de instruções)
FileSource, TextSource Não definido Esta é a mensagem que você deseja reproduzir antes de reconhecer a entrada. Opcional
InterToneTimeout TimeSpan 2 segundos

Mínimo: 1 segundo
Máx: 60 segundos
Limite em segundos que os Serviços de Comunicação do Azure aguardam que o chamador pressione outro dígito (tempo limite entre dígitos). Opcional
InitialSegmentationSilenceTimeoutInSeconds Número inteiro 0,5 segundo Quanto tempo a ação de reconhecimento aguarda a entrada antes de considerá-la um tempo limite. Leia mais aqui. Opcional
RecognizeInputsType Enumeração DTMF Tipo de entrada que é reconhecida. As opções são dtmf, choices, speech e speechordtmf. Necessário
InitialSilenceTimeout TimeSpan 5 segundos

Mínimo: 0 segundos
Máx: 300 segundos (DTMF)
Máx: 20 segundos (Opções)
Máx: 20 segundos (Fala)
O tempo limite de silêncio inicial ajusta a quantidade de áudio não falado permitida antes de uma frase antes que a tentativa de reconhecimento termine em um resultado "sem correspondência". Leia mais aqui. Opcional
MaxTonesToCollect Número inteiro Sem padrão

MÍN: 1
Número de dígitos que um desenvolvedor espera como entrada do participante. Necessário
StopTones IEnumeração<DtmfTone> Não definido Os participantes do dígito podem pressionar para escapar de um evento DTMF em lote. Opcional
InterruptPrompt Bool True Se o participante tiver a capacidade de interromper o playMessage pressionando um dígito. Opcional
InterruptCallMediaOperation Bool True Se esse sinalizador estiver definido, ele interromperá a operação de mídia de chamada atual. Por exemplo, se algum áudio estiver sendo reproduzido, ele interrompe essa operação e inicia o reconhecimento. Opcional
OperationContext String Não definido String que os desenvolvedores podem passar ação intermediária, útil para permitir que os desenvolvedores armazenem contexto sobre os eventos que recebem. Opcional
Frases String Não definido Lista de frases que se associam ao rótulo, se alguma delas for ouvida é considerada um reconhecimento bem-sucedido. Necessário
Tom String Não definido O tom a ser reconhecido se o usuário decidir pressionar um número em vez de usar a fala. Opcional
Etiqueta String Não definido O valor-chave para o reconhecimento. Necessário
Idioma String En-nos A linguagem usada para reconhecer a fala. Opcional
EndSilenceTimeout TimeSpan 0,5 segundo A pausa final do orador usada para detetar o resultado final que é gerado como fala. Opcional

Nota

Em situações em que o dtmf e a fala estão no recognizeInputsType, a ação reconhecer atuará no primeiro tipo de entrada recebido, ou seja, se o usuário pressionar um número de teclado primeiro, a ação de reconhecimento o considerará um evento dtmf e continuará ouvindo os tons dtmf. Se o usuário falar primeiro, a ação de reconhecimento considerará um reconhecimento de fala e ouvirá a entrada de voz.

Criar uma aplicação Python nova

Configurar um ambiente virtual Python para o seu projeto

python -m venv play-audio-app

Ativar o ambiente virtual

No Windows, use o seguinte comando:

.\ play-audio-quickstart \Scripts\activate

No Unix, use o seguinte comando:

source play-audio-quickstart /bin/activate

Instalar o pacote de Automação de Chamadas dos Serviços de Comunicação do Azure

pip install azure-communication-callautomation

Crie seu arquivo de aplicativo no diretório do projeto, por exemplo, nomeie-o app.py. Você escreve seu código Python neste arquivo.

Execute seu aplicativo usando Python com o seguinte comando. Isso executa o código Python que você escreveu.

python app.py

Estabeleça uma chamada

A esta altura, você deve estar familiarizado com o início de chamadas, se precisar saber mais sobre como fazer uma chamada, siga nosso início rápido. Neste início rápido, criamos uma chamada de saída.

Chamar a ação de reconhecimento

Quando seu aplicativo atende a chamada, você pode fornecer informações sobre como reconhecer a entrada do participante e reproduzir um prompt.

DTMF

max_tones_to_collect = 3 
text_to_play = "Welcome to Contoso, please enter 3 DTMF." 
play_source = TextSource(text=text_to_play, voice_name="en-US-ElizabethNeural") 
call_automation_client.get_call_connection(call_connection_id).start_recognizing_media( 
    dtmf_max_tones_to_collect=max_tones_to_collect, 
    input_type=RecognizeInputType.DTMF, 
    target_participant=target_participant, 
    initial_silence_timeout=30, 
    play_prompt=play_source, 
    dtmf_inter_tone_timeout=5, 
    interrupt_prompt=True, 
    dtmf_stop_tones=[ DtmfTone.Pound ]) 

Para fluxos de fala para texto, a ação de reconhecimento da Automação de Chamadas também suporta o uso de modelos de fala personalizados. Recursos como modelos de fala personalizados podem ser úteis quando você está criando um aplicativo que precisa ouvir palavras complexas que os modelos padrão de fala para texto podem não ser capazes de entender, um bom exemplo disso pode ser quando você está criando um aplicativo para o setor de telemedicina e seu agente virtual precisa ser capaz de reconhecer termos médicos. Você pode saber mais sobre como criar e implantar modelos de fala personalizados aqui.

Opções de fala para texto

choices = [ 
    RecognitionChoice( 
        label="Confirm", 
        phrases=[ "Confirm", "First", "One" ], 
        tone=DtmfTone.ONE 
    ), 
    RecognitionChoice( 
        label="Cancel", 
        phrases=[ "Cancel", "Second", "Two" ], 
        tone=DtmfTone.TWO 
    ) 
] 
text_to_play = "Hello, This is a reminder for your appointment at 2 PM, Say Confirm to confirm your appointment or Cancel to cancel the appointment. Thank you!" 
play_source = TextSource(text=text_to_play, voice_name="en-US-ElizabethNeural") 
call_automation_client.get_call_connection(call_connection_id).start_recognizing_media( 
    input_type=RecognizeInputType.CHOICES, 
    target_participant=target_participant, 
    choices=choices, 
    interrupt_prompt=True, 
    initial_silence_timeout=30, 
    play_prompt=play_source, 
    operation_context="AppointmentReminderMenu",
    # Only add the speech_recognition_model_endpoint_id if you have a custom speech model you would like to use
    speech_recognition_model_endpoint_id="YourCustomSpeechModelEndpointId")  

Conversão de Voz em Texto

text_to_play = "Hi, how can I help you today?" 
play_source = TextSource(text=text_to_play, voice_name="en-US-ElizabethNeural") 
call_automation_client.get_call_connection(call_connection_id).start_recognizing_media( 
    input_type=RecognizeInputType.SPEECH, 
    target_participant=target_participant, 
    end_silence_timeout=1, 
    play_prompt=play_source, 
    operation_context="OpenQuestionSpeech",
    # Only add the speech_recognition_model_endpoint_id if you have a custom speech model you would like to use
    speech_recognition_model_endpoint_id="YourCustomSpeechModelEndpointId") 

Conversão de voz em texto ou DTMF

max_tones_to_collect = 1 
text_to_play = "Hi, how can I help you today, you can also press 0 to speak to an agent." 
play_source = TextSource(text=text_to_play, voice_name="en-US-ElizabethNeural") 
call_automation_client.get_call_connection(call_connection_id).start_recognizing_media( 
    dtmf_max_tones_to_collect=max_tones_to_collect, 
    input_type=RecognizeInputType.SPEECH_OR_DTMF, 
    target_participant=target_participant, 
    end_silence_timeout=1, 
    play_prompt=play_source, 
    initial_silence_timeout=30, 
    interrupt_prompt=True, 
    operation_context="OpenQuestionSpeechOrDtmf",
    # Only add the speech_recognition_model_endpoint_id if you have a custom speech model you would like to use
    speech_recognition_model_endpoint_id="YourCustomSpeechModelEndpointId")  
app.logger.info("Start recognizing") 

Nota

Se os parâmetros não forem definidos, os padrões serão aplicados sempre que possível.

Receber atualizações de eventos de reconhecimento

Os desenvolvedores podem se inscrever nos eventos RecognizeCompleted e RecognizeFailed no retorno de chamada do webhook que registraram para a chamada para criar lógica de negócios em seu aplicativo para determinar as próximas etapas quando um dos eventos mencionados anteriormente ocorrer.

Exemplo de como você pode desserializar o evento RecognizeCompleted :

if event.type == "Microsoft.Communication.RecognizeCompleted": 
    app.logger.info("Recognize completed: data=%s", event.data) 
    if event.data['recognitionType'] == "dtmf": 
        tones = event.data['dtmfResult']['tones'] 
        app.logger.info("Recognition completed, tones=%s, context=%s", tones, event.data.get('operationContext')) 
    elif event.data['recognitionType'] == "choices": 
        labelDetected = event.data['choiceResult']['label']; 
        phraseDetected = event.data['choiceResult']['recognizedPhrase']; 
        app.logger.info("Recognition completed, labelDetected=%s, phraseDetected=%s, context=%s", labelDetected, phraseDetected, event.data.get('operationContext')); 
    elif event.data['recognitionType'] == "speech": 
        text = event.data['speechResult']['speech']; 
        app.logger.info("Recognition completed, text=%s, context=%s", text, event.data.get('operationContext')); 
    else: 
        app.logger.info("Recognition completed: data=%s", event.data); 

Exemplo de como você pode desserializar o evento RecognizeFailed :

if event.type == "Microsoft.Communication.RecognizeFailed": 
    app.logger.info("Recognize failed: data=%s", event.data); 

Exemplo de como você pode desserializar o evento RecognizeCanceled :

if event.type == "Microsoft.Communication.RecognizeCanceled":
    # Handle the RecognizeCanceled event according to your application logic

Códigos de evento

Status Código Subcódigo Mensagem
ReconheçaConcluído 200 8531 Ação concluída, dígitos máximos recebidos.
ReconheçaConcluído 200 8514 Ação concluída quando o tom de parada foi detetado.
ReconheçaConcluído 400 8508 A ação falhou, a operação foi cancelada.
ReconheçaConcluído 400 8532 A ação falhou, o tempo limite de silêncio entre dígitos foi atingido.
RecognizeCanceled 400 8508 A ação falhou, a operação foi cancelada.
RecognizeFailed 400 8510 A ação falhou, o tempo limite de silêncio inicial foi atingido.
RecognizeFailed 500 8511 A ação falhou, encontrou falha ao tentar reproduzir o prompt.
RecognizeFailed 500 8512 Erro interno desconhecido do servidor.
RecognizeFailed 400 8510 A ação falhou, o tempo limite de silêncio inicial foi atingido
RecognizeFailed 400 8532 A ação falhou, o tempo limite de silêncio entre dígitos foi atingido.
RecognizeFailed 400 8565 Falha na ação, solicitação incorreta para serviços de IA do Azure. Verifique os parâmetros de entrada.
Reconhecer falha 400 8565 Falha na ação, solicitação incorreta para serviços de IA do Azure. Não é possível processar a carga útil fornecida, verifique a entrada da fonte de reprodução
RecognizeFailed 401 8565 Falha na ação, erro de autenticação dos serviços de IA do Azure.
RecognizeFailed 403 8565 Falha na ação, solicitação proibida para serviços de IA do Azure, assinatura gratuita usada pela solicitação ficou sem cota.
RecognizeFailed 429 8565 Falha na ação, as solicitações excederam o número de solicitações simultâneas permitidas para a assinatura de serviços do Azure AI.
RecognizeFailed 408 8565 Falha na ação, a solicitação aos serviços de IA do Azure expirou.
RecognizeFailed 500 8511 A ação falhou, encontrou falha ao tentar reproduzir o prompt.
RecognizeFailed 500 8512 Erro interno desconhecido do servidor.

Limitações conhecidas

  • DTMF em banda não é suportado, use RFC 2833 DTMF em vez disso.
  • Os prompts de texto de conversão de texto em fala suportam um máximo de 400 caracteres, se o prompt for maior do que isso, sugerimos usar SSML para ações de reprodução baseadas em conversão de texto em fala.
  • Para cenários em que você excede o limite de cota do serviço de Fala, você pode solicitar o aumento desse lilmit seguindo as etapas descritas aqui.

Clean up resources (Limpar recursos)

Se quiser limpar e remover uma assinatura dos Serviços de Comunicação, você pode excluir o recurso ou grupo de recursos. A exclusão do grupo de recursos também exclui quaisquer outros recursos associados a ele. Saiba mais sobre a limpeza de recursos.

Passos Seguintes