你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

使用 Recognize 操作收集用户输入

本指南将帮助你了解如何通过通过 Azure 通信服务通话自动化 SDK 来识别参与者提供的 DTMF 输入。

先决条件

对于 AI 功能

技术规范

以下参数可用于自定义 Recognize 函数:

参数 类型 默认值(如果未指定) 说明 必需还是可选
Prompt

(有关播放操作的详细信息,请参阅此操作指南
FileSource、TextSource 未设置 这是你希望在识别输入之前播放的消息。 可选
InterToneTimeout TimeSpan 2 秒

最小值:1 秒
最大值:60 秒
Azure 通信服务等待呼叫者按另一个数字的秒数限制(数字间超时)。 可选
InitialSegmentationSilenceTimeoutInSeconds Integer 0.5 秒 识别操作在考虑超时之前将等待输入多长时间。 在此处阅读详细信息。 可选
RecognizeInputsType Enum dtmf 识别的输入的类型。 选项包括 dtmf、choices、speech 和 speechordtmf。 必须
InitialSilenceTimeout TimeSpan 5 秒

最小值:0 秒
最大值:300 秒 (DTMF)
最大值:20 秒 (Choices)
最大值:20 秒 (Speech)
初始静音超时调整在识别尝试以“不匹配”结果结束之前,在一个短语之前允许的非语音音频量。 在此处阅读详细信息。 可选
MaxTonesToCollect Integer 无默认值

最小值:1
开发人员期望参与者输入的位数。 必须
StopTones IEnumeration<DtmfTone> 未设置 数字参与者可以按压以退出批量 DTMF 事件。 可选
InterruptPrompt Bool True 如果参与者能够通过按一个数字来中断 playMessage。 可选
InterruptCallMediaOperation Bool True 如果设置此标记,则会中断当前的调用媒体操作。 例如,如果正在播放任何音频,它会中断该操作并启动识别。 可选
OperationContext 字符串 未设置 开发人员可以传递 mid 操作的字符串,用于允许开发人员存储有关他们收到的事件的上下文。 可选
短语 字符串 未设置 与标签关联的短语列表,如果听到其中任何一个短语,则将被视为一次成功的识别。 必须
语气 字符串 未设置 用户决定按下数字而不是使用语音时,要识别的音调。 可选
标签 字符串 未设置 用于识别的关键值。 必须
语言 字符串 En-us 用于识别语音的语言。 可选
EndSilenceTimeout TimeSpan 0.5 秒 用于检测生成为语音的最终结果的说话人的最后一次暂停。 可选

注意

在 dtmf 和语音都位于 recognizeInputsType 的情况下,识别操作将处理收到的第一个输入类型,即如果用户先按键盘号码,则识别操作会将其视为 dtmf 事件并继续侦听 dtmf 音调。 如果用户先说话,则识别操作会将其视为语音识别并侦听语音输入。

新建 C# 应用程序

在操作系统的控制台窗口中,使用 dotnet 命令创建新的 Web 应用程序。

dotnet new web -n MyApplication

安装 NuGet 包

可以从此处获取 NuGet 包(如果尚未获取)。

建立呼叫

至此,你应该熟悉开始呼叫,如需了解有关拨打电话的详细信息,请遵循我们的快速入门。 还可以使用此处提供的代码片段来了解如何应答呼叫。

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); 

调用识别动作

在你的应用程序应答呼叫时,你可以提供有关识别参与者输入和播放提示的信息。

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);

对于语音转文本流,呼叫自动化识别操作还支持使用自定义语音模型。 构建需要侦听默认语音转文本模型可能无法理解的复杂字词的应用程序时,自定义语音模型等功能非常有用,例如,在为远程医疗行业构建应用程序,并且虚拟代理需要能够识别医疗术语时。 请参阅此处详细了解如何创建和部署自定义语音模型。

语音转文本选择

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);

语音转文本

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);

语音转文本或 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); 

注意

如果未设置参数,将尽可能应用默认值。

接收识别事件更新

开发人员可以订阅他们为调用注册的 webhook 回调上的 RecognizeCompletedRecognizeFailed 事件,以在其应用程序中创建业务逻辑,以便在发生上述任一事件时确定下一步操作。

如何反序列化 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; 
    } 
} 

如何反序列化 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); 
    } 
} 

如何反序列化 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);
        }

先决条件

对于 AI 功能

技术规范

以下参数可用于自定义 Recognize 函数:

参数 类型 默认值(如果未指定) 说明 必需还是可选
Prompt

(有关播放操作的详细信息,请参阅此操作指南
FileSource、TextSource 未设置 这是你希望在识别输入之前播放的消息。 可选
InterToneTimeout TimeSpan 2 秒

最小值:1 秒
最大值:60 秒
Azure 通信服务等待呼叫者按另一个数字的秒数限制(数字间超时)。 可选
InitialSegmentationSilenceTimeoutInSeconds Integer 0.5 秒 识别操作在考虑超时之前将等待输入多长时间。 在此处阅读详细信息。 可选
RecognizeInputsType Enum dtmf 识别的输入的类型。 选项包括 dtmf、choices、speech 和 speechordtmf。 必须
InitialSilenceTimeout TimeSpan 5 秒

最小值:0 秒
最大值:300 秒 (DTMF)
最大值:20 秒 (Choices)
最大值:20 秒 (Speech)
初始静音超时调整在识别尝试以“不匹配”结果结束之前,在一个短语之前允许的非语音音频量。 在此处阅读详细信息。 可选
MaxTonesToCollect Integer 无默认值

最小值:1
开发人员期望参与者输入的位数。 必须
StopTones IEnumeration<DtmfTone> 未设置 数字参与者可以按压以退出批量 DTMF 事件。 可选
InterruptPrompt Bool True 如果参与者能够通过按一个数字来中断 playMessage。 可选
InterruptCallMediaOperation Bool True 如果设置此标记,则会中断当前的调用媒体操作。 例如,如果正在播放任何音频,它会中断该操作并启动识别。 可选
OperationContext 字符串 未设置 开发人员可以传递 mid 操作的字符串,用于允许开发人员存储有关他们收到的事件的上下文。 可选
短语 字符串 未设置 与标签关联的短语列表,如果听到其中任何一个短语,则将被视为一次成功的识别。 必须
语气 字符串 未设置 用户决定按下数字而不是使用语音时,要识别的音调。 可选
标签 字符串 未设置 用于识别的关键值。 必须
语言 字符串 En-us 用于识别语音的语言。 可选
EndSilenceTimeout TimeSpan 0.5 秒 用于检测生成为语音的最终结果的说话人的最后一次暂停。 可选

注意

在 dtmf 和语音都位于 recognizeInputsType 的情况下,识别操作将处理收到的第一个输入类型,即如果用户先按键盘号码,则识别操作会将其视为 dtmf 事件并继续侦听 dtmf 音调。 如果用户先说话,则识别操作会将其视为语音识别并侦听语音输入。

创建新的 Java 应用程序

在终端或命令窗口中,导航到要在其中创建 Java 应用程序的目录。 运行 mvn 命令以从 maven-archetype-quickstart 模板生成 Java 项目。

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

artifactId 命令将创建一个与 mvn 参数同名的目录。 在此目录下,src/main/java 目录包含项目源代码,src/test/java 目录包含测试源。

你会注意到,“生成”步骤创建了与 artifactId 同名的目录。 在此目录下,src/main/java 目录包含源代码,src/test/java 目录包含测试,pom.xml 文件是项目的项目对象模型 (POM)。

将应用程序的 POM 文件更新为使用 Java 8 或更高版本。

<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>

添加包引用

在 POM 文件中,为项目添加以下引用

azure-communication-callautomation

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

建立呼叫

至此,你应该熟悉开始呼叫,如需了解有关拨打电话的详细信息,请遵循我们的快速入门。 还可以使用此处提供的代码片段来了解如何应答呼叫。

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();

调用识别动作

在你的应用程序应答呼叫时,你可以提供有关识别参与者输入和播放提示的信息。

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()); 

对于语音转文本流,呼叫自动化识别操作还支持使用自定义语音模型。 构建需要侦听默认语音转文本模型可能无法理解的复杂字词的应用程序时,自定义语音模型等功能非常有用,例如,在为远程医疗行业构建应用程序,并且虚拟代理需要能够识别医疗术语时。 请参阅此处详细了解如何创建和部署自定义语音模型。

语音转文本选择

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();

语音转文本

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(); 

语音转文本或 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(); 

注意

如果未设置参数,将尽可能应用默认值。

接收识别事件更新

开发人员可以在已注册的 Webhook 回调上订阅 RecognizeCompletedRecognizeFailed 事件。 此回调可用于应用程序中的业务逻辑,以确定发生其中任一事件时执行的后续步骤。

如何反序列化 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()); 
    } 
} 

如何反序列化 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()); 
    } 
} 

如何反序列化 RecognizeCanceled 事件的示例:

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

先决条件

对于 AI 功能

技术规范

以下参数可用于自定义 Recognize 函数:

参数 类型 默认值(如果未指定) 说明 必需还是可选
Prompt

(有关播放操作的详细信息,请参阅此操作指南
FileSource、TextSource 未设置 这是你希望在识别输入之前播放的消息。 可选
InterToneTimeout TimeSpan 2 秒

最小值:1 秒
最大值:60 秒
Azure 通信服务等待呼叫者按另一个数字的秒数限制(数字间超时)。 可选
InitialSegmentationSilenceTimeoutInSeconds Integer 0.5 秒 识别操作在考虑超时之前将等待输入多长时间。 在此处阅读详细信息。 可选
RecognizeInputsType Enum dtmf 识别的输入的类型。 选项包括 dtmf、choices、speech 和 speechordtmf。 必须
InitialSilenceTimeout TimeSpan 5 秒

最小值:0 秒
最大值:300 秒 (DTMF)
最大值:20 秒 (Choices)
最大值:20 秒 (Speech)
初始静音超时调整在识别尝试以“不匹配”结果结束之前,在一个短语之前允许的非语音音频量。 在此处阅读详细信息。 可选
MaxTonesToCollect Integer 无默认值

最小值:1
开发人员期望参与者输入的位数。 必须
StopTones IEnumeration<DtmfTone> 未设置 数字参与者可以按压以退出批量 DTMF 事件。 可选
InterruptPrompt Bool True 如果参与者能够通过按一个数字来中断 playMessage。 可选
InterruptCallMediaOperation Bool True 如果设置此标记,则会中断当前的调用媒体操作。 例如,如果正在播放任何音频,它会中断该操作并启动识别。 可选
OperationContext 字符串 未设置 开发人员可以传递 mid 操作的字符串,用于允许开发人员存储有关他们收到的事件的上下文。 可选
短语 字符串 未设置 与标签关联的短语列表,如果听到其中任何一个短语,则将被视为一次成功的识别。 必须
语气 字符串 未设置 用户决定按下数字而不是使用语音时,要识别的音调。 可选
标签 字符串 未设置 用于识别的关键值。 必须
语言 字符串 En-us 用于识别语音的语言。 可选
EndSilenceTimeout TimeSpan 0.5 秒 用于检测生成为语音的最终结果的说话人的最后一次暂停。 可选

注意

在 dtmf 和语音都位于 recognizeInputsType 的情况下,识别操作将处理收到的第一个输入类型,即如果用户先按键盘号码,则识别操作会将其视为 dtmf 事件并继续侦听 dtmf 音调。 如果用户先说话,则识别操作会将其视为语音识别并侦听语音输入。

创建新的 JavaScript 应用程序

在项目目录中创建新的 JavaScript 应用程序。 使用以下命令,初始化新的 Node.js 项目。 这会为项目创建一个 package.json 文件,该文件用于管理项目的依赖项。

npm init -y

安装 Azure 通信服务呼叫自动化包

npm install @azure/communication-call-automation

例如,在项目目录中创建新的 JavaScript 文件,将其命名为 app.js。 在此文件中编写 JavaScript 代码。 通过以下命令,使用 Node.js 运行你的应用程序。 此命令执行已编写的 JavaScript 代码。

node app.js

建立呼叫

至此,你应该熟悉开始呼叫,如需了解有关拨打电话的详细信息,请遵循我们的快速入门。 在本快速入门中,我们将创建出站呼叫。

调用识别动作

在你的应用程序应答呼叫时,你可以提供有关识别参与者输入和播放提示的信息。

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); 

对于语音转文本流,呼叫自动化识别操作还支持使用自定义语音模型。 构建需要侦听默认语音转文本模型可能无法理解的复杂字词的应用程序时,自定义语音模型等功能非常有用,例如,在为远程医疗行业构建应用程序,并且虚拟代理需要能够识别医疗术语时。 请参阅此处详细了解如何创建和部署自定义语音模型。

语音转文本选择

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); 

语音转文本

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); 

语音转文本或 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); 

注意

如果未设置参数,将尽可能应用默认值。

接收识别事件更新

开发人员可以订阅他们为调用注册的 webhook 回调上的 RecognizeCompletedRecognizeFailed 事件,以在其应用程序中创建业务逻辑,以便在发生上述任一事件时确定下一步操作。

如何反序列化 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)); 
    } 
} 

如何反序列化 RecognizeFailed 事件的示例:

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

如何反序列化 RecognizeCanceled 事件的示例:

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

先决条件

对于 AI 功能

技术规范

以下参数可用于自定义 Recognize 函数:

参数 类型 默认值(如果未指定) 说明 必需还是可选
Prompt

(有关播放操作的详细信息,请参阅此操作指南
FileSource、TextSource 未设置 这是你希望在识别输入之前播放的消息。 可选
InterToneTimeout TimeSpan 2 秒

最小值:1 秒
最大值:60 秒
Azure 通信服务等待呼叫者按另一个数字的秒数限制(数字间超时)。 可选
InitialSegmentationSilenceTimeoutInSeconds Integer 0.5 秒 识别操作在考虑超时之前将等待输入多长时间。 在此处阅读详细信息。 可选
RecognizeInputsType Enum dtmf 识别的输入的类型。 选项包括 dtmf、choices、speech 和 speechordtmf。 必须
InitialSilenceTimeout TimeSpan 5 秒

最小值:0 秒
最大值:300 秒 (DTMF)
最大值:20 秒 (Choices)
最大值:20 秒 (Speech)
初始静音超时调整在识别尝试以“不匹配”结果结束之前,在一个短语之前允许的非语音音频量。 在此处阅读详细信息。 可选
MaxTonesToCollect Integer 无默认值

最小值:1
开发人员期望参与者输入的位数。 必须
StopTones IEnumeration<DtmfTone> 未设置 数字参与者可以按压以退出批量 DTMF 事件。 可选
InterruptPrompt Bool True 如果参与者能够通过按一个数字来中断 playMessage。 可选
InterruptCallMediaOperation Bool True 如果设置此标记,则会中断当前的调用媒体操作。 例如,如果正在播放任何音频,它会中断该操作并启动识别。 可选
OperationContext 字符串 未设置 开发人员可以传递 mid 操作的字符串,用于允许开发人员存储有关他们收到的事件的上下文。 可选
短语 字符串 未设置 与标签关联的短语列表,如果听到其中任何一个短语,则将被视为一次成功的识别。 必须
语气 字符串 未设置 用户决定按下数字而不是使用语音时,要识别的音调。 可选
标签 字符串 未设置 用于识别的关键值。 必须
语言 字符串 En-us 用于识别语音的语言。 可选
EndSilenceTimeout TimeSpan 0.5 秒 用于检测生成为语音的最终结果的说话人的最后一次暂停。 可选

注意

在 dtmf 和语音都位于 recognizeInputsType 的情况下,识别操作将处理收到的第一个输入类型,即如果用户先按键盘号码,则识别操作会将其视为 dtmf 事件并继续侦听 dtmf 音调。 如果用户先说话,则识别操作会将其视为语音识别并侦听语音输入。

创建新的 Python 应用程序

为你的项目设置 Python 虚拟环境

python -m venv play-audio-app

激活虚拟环境

在 Windows 上,使用以下命令:

.\ play-audio-quickstart \Scripts\activate

在 Unix 上,使用以下命令:

source play-audio-quickstart /bin/activate

安装 Azure 通信服务呼叫自动化包

pip install azure-communication-callautomation

例如,在项目目录中创建应用程序文件,将其命名为 app.js。 在此文件中编写 Python 代码。

通过以下命令,使用 Python 运行你的应用程序。 此命令执行已编写的 Python 代码。

python app.py

建立呼叫

至此,你应该熟悉开始呼叫,如需了解有关拨打电话的详细信息,请遵循我们的快速入门。 在本快速入门中,我们将创建出站呼叫。

调用识别动作

在你的应用程序应答呼叫时,你可以提供有关识别参与者输入和播放提示的信息。

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 ]) 

对于语音转文本流,呼叫自动化识别操作还支持使用自定义语音模型。 构建需要侦听默认语音转文本模型可能无法理解的复杂字词的应用程序时,自定义语音模型等功能非常有用,例如,在为远程医疗行业构建应用程序,并且虚拟代理需要能够识别医疗术语时。 请参阅此处详细了解如何创建和部署自定义语音模型。

语音转文本选择

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")  

语音转文本

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") 

语音转文本或 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") 

注意

如果未设置参数,将尽可能应用默认值。

接收识别事件更新

开发人员可以订阅他们为调用注册的 webhook 回调上的 RecognizeCompletedRecognizeFailed 事件,以在其应用程序中创建业务逻辑,以便在发生上述任一事件时确定下一步操作。

如何反序列化 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); 

如何反序列化 RecognizeFailed 事件的示例:

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

如何反序列化 RecognizeCanceled 事件的示例:

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

事件代码

Status 代码 子代码 Message
RecognizeCompleted 200 8531 操作已完成,接收的最大位数。
RecognizeCompleted 200 8514 检测到停止音调时完成的操作。
RecognizeCompleted 400 8508 操作失败,操作已取消。
RecognizeCompleted 400 8532 操作失败,已达到数字间静音超时。
RecognizeCanceled 400 8508 操作失败,操作已取消。
RecognizeFailed 400 8510 操作失败,已达到初始静音超时。
RecognizeFailed 500 8511 操作失败,尝试播放提示时遇到失败。
RecognizeFailed 500 8512 未知的内部服务器错误。
RecognizeFailed 400 8510 操作失败,已达到初始静音超时
RecognizeFailed 400 8532 操作失败,已达到数字间静音超时。
RecognizeFailed 400 8565 操作失败,对 Azure AI 服务的请求不正确。 检查输入参数。
识别失败 400 8565 操作失败,对 Azure AI 服务的请求不正确。 无法处理提供的有效负载,请检查播放源输入
RecognizeFailed 401 8565 操作失败,Azure AI 服务身份验证错误。
RecognizeFailed 403 8565 操作失败,禁止请求 Azure AI 服务,请求使用的免费订阅已用完配额。
RecognizeFailed 429 8565 操作失败,请求超出了 Azure AI 服务订阅允许的并发请求数。
RecognizeFailed 408 8565 操作失败,对 Azure AI 服务的请求已超时。
RecognizeFailed 500 8511 操作失败,尝试播放提示时遇到失败。
RecognizeFailed 500 8512 未知的内部服务器错误。

已知限制

  • 不支持带内 DTMF,请转而使用 RFC 2833 DTMF。
  • 文本转语音文本提示最多支持 400 个字符,如果你的提示超过此长度限制,建议对基于文本转语音的播放操作使用 SSML。
  • 对于超出语音服务配额限制的场景,可按照此处概述的步骤请求调高此限制。

清理资源

如果想要清理并删除通信服务订阅,可以删除资源或资源组。 删除资源组同时也会删除与之相关联的任何其他资源。 了解有关清理资源的详细信息。

后续步骤