65.9K
CodeProject 正在变化。 阅读更多。
Home

AISpeech API ASDK 教程 – 一个口语英语评估应用

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2012年4月10日

CPOL

6分钟阅读

viewsIcon

16816

在本教程中,我们将学习如何使用 AISpeech API 及其 ASSDK (ActionScript SDK) 创建一个英语口语评估 Flex 应用程序。

引言

在本教程中,我们将学习如何使用 AISpeech API 及其 ASSDK (ActionScript SDK) 创建一个英语口语评估 Flex 应用程序。此演示的源代码位于 github

背景

Ask AI Speech Ltd (发邮件至 api@aispeech.com) 申请一个开发者帐户、应用程序 ID、密钥和 AISpeech API ASSDK (AISpeechLib.swc) 的发布版本。

请注意,此 ASSDK 仅支持 ActionScript 3.0。ActionScript 2.0 版本也可用,但需另行申请。

此演示应用程序需要耳机或麦克风。

目标

我们正在构建一个英语口语评估应用程序。它是一个 Flex 应用程序。该应用程序允许用户阅读一个英语句子。然后它会录制用户的语音,并分别显示每个单词的得分。分数越高,用户的发音越好。

分数图表面板

更新:Flex BarChart 视图组件拒绝显示其垂直轴上重复项的值。例如,如果参考文本是“I have done what I have to do”,则此分数图表将不会显示第二个“I”和“have”的得分。感谢 Little Bridge 的 James 报告了这个问题。我正在考虑为这个演示使用另一个更好的视图组件。

我们从一个分数图表面板开始,它看起来像下面这样:

图 1 分数图表面板

使用 FlexBuilder。新建一个 Flex 项目。分数面板的源代码如下所示:

<!– score panel –>
<s:Panel title=’Scores’ width=’600' height=’100%’ color="0×000000" borderAlpha="0.15">
    <s:layout>
        <s:HorizontalLayout paddingLeft="10" paddingRight="10" paddingTop="10" paddingBottom="10"/>
    </s:layout>
    <mx:BarChart id="scoreBar" height="100%" color="0×323232" showDataTips="true" dataProvider="{_scores}">
        <mx:verticalAxis>
            <mx:CategoryAxis categoryField="Word" />
        </mx:verticalAxis>
        <mx:horizontalAxis>
            <mx:LinearAxis maximum="100" minimum="0" />
        </mx:horizontalAxis>
        <mx:series>
            <mx:BarSeries yField="Word" xField="Score" displayName="Score" />
        </mx:series>
    </mx:BarChart>
</s:Panel> 

分数面板使用 Flex BarChart 组件。其数据提供程序(_scores)定义如下(在 <fx:script> 部分):

<fx:Script>
    <![CDATA[
        import mx.collections.ArrayCollection; 
        // parsed score results to show in the result chart 
        // each item is like {Word: 'I', Score: '80'} 
        [Bindable] private var _scores:ArrayCollection = new ArrayCollection(); 
        private function init():void
        {
            _scores.addItem({Word:'piano', Score:'67'});
            _scores.addItem({Word:'play', Score:'34'});
            _scores.addItem({Word:'to', Score:'90'});
            _scores.addItem({Word:'want', Score:'30'});
            _scores.addItem({Word:'I', Score:'80'});
        }
    ]]>
</fx:Script> 

将应用程序的 creationComplete 回调设置为 init() 方法,我们在其中硬编码了一些分数项。应用程序现在应该显示如图 1 所示的分数图表。

其他控件

然后我们添加两个按钮(开始和停止)和一个文本区域字段(ID 为 txtRefText)。使用 HGroupVGroup 来布局组件。最终的应用程序布局将如下所示:

图 2 应用程序布局

导入 AISpeech API SDK

AISpeechLib.swc 添加到项目的构建路径。(在 Flash Builder 中,项目 -> 属性 -> Flex 构建路径 -> 库路径 -> 添加 SWC...)

<fx:script> 部分,添加以下变量:

private static const RECORDERLIB_PARAMS:Object = {
    appKey:"your application ID",
    secretKey:"your secret key",
    serverList:["rtmp://demo.aispeech.com:443/v2.0/aistream"]  // release 2.0 
};
private var _coreRequesterParams:Object = {
    refText:"past", // this to be updated for each core request 
    scoreType:100,  // ask score in grade 100 
    rank:100,
    coreType:"en.sent.score",  // request the English-Senetence core 
    userId:"xxxxxx",
    applicationId:"your application ID"  // application ID again 
};
private var _recorderLib:RecorderLib; // the recorder. 

请注意,RecorderLib 属于 com.aispeech.RecorderLib。如果 IDE 没有为您自动导入此命名空间,请导入它。

更新上述 init() 方法以初始化 RecorderLib 实例。(我们已经从 init() 方法中删除了那些设置示例分数项的代码)

private function init():void
{
    // init RecorderLib instance 
    _recorderLib = new RecorderLib();
    _recorderLib.init(RECORDERLIB_PARAMS);
} 

运行项目。应用程序将弹出一个对话框,请求用户允许应用程序访问麦克风设备,如下所示:

图 3 请求用户权限的对话框

点击“允许”单选按钮并勾选“记住”是安全的。如果您已勾选“记住”,下次运行应用程序时将不会再次显示此提示。您可以选择不勾选“记住”,因为此提示是一个很好的指示,表明 RecorderLib 实例已成功加载。

录制用户语音

录制用户语音就像调用 RecorderLibstartRecord() 方法一样简单。此方法需要一个参数,如以下代码所示:

private function startRecord():void
{
    _coreRequesterParams.refText = txtRefText.text;
    var recorderParams:Object =
        {
            serverParam:_coreRequesterParams,
            recordLength:5000 // ms 
        };
    _recorderLib.startRecord(recorderParams);
} 
 
Blocks of code should be set as style "Formatted"
		like this: 

开始录音时,我们首先根据用户输入(txtRefText.text)更新 _coreRequesterParamsrefText 值。然后我们设置一个 recorderParams 变量,其中包含两个属性:serverParam 是更新后的 _coreRequestParams,而 recordLength 设置为 5000 毫秒。录音将在 5 秒后自动停止。

将“开始”按钮的点击回调设置为 startRecord() 方法。运行项目。点击“开始”按钮。如果您听到“叮”声,则表示录音现在工作正常。

以下代码手动停止录音。将其添加到“停止”按钮的点击回调中以使其工作。

_recorderLib.stopRecord();

到目前为止,录制用户语音时似乎什么也没发生。在我们深入研究捕获和解析 API 响应之前,我们首先回放我们的录音。

添加另一个标记为“开始回放”的按钮(我现在已将另外两个按钮分别重命名为“开始录音”和“停止录音”)。将其点击回调设置为:

_recorderLib.startReplay({});  

RecorderLib:startReplay() 方法需要一个参数。我们传入一个空对象,要求回放最近的录音。

运行程序。首先点击“开始录音”按钮。听到“叮”声后,对着麦克风说话约 5 秒。然后点击“开始回放”按钮以听到回放。我希望到目前为止一切正常。

捕获 API 响应

是时候了解 AISpeech API 的工作流程了。SDK 将用户语音的音频数据增量发送到 API 的一个节点。API 分析音频数据并返回分数给 SDK。应用程序监听 RecorderLib 的特定事件以捕获这些响应。SDK 和 API 在录制用户语音时交换多个信号和数据。但在此演示中,我们只捕获和解析最终分数结果(通常在录音停止后捕获)。

为了捕获 API 返回的最终分数结果,我们需要监听 RecorderLibCoreRequesterEvent.RESULT。在 init() 方法中,在调用 RecorderLib::init() 方法之前,我们添加以下行:

_recorderLib.addEventListener(CoreRequesterEvent.RESULT, coreRequesterEventHandler);

如果 IDE 没有为您导入 com.aispeech.events.CoreRequesterEvent,请导入它。

然后我们实现 coreRequesterEventHandler 方法如下:

private function coreRequesterEventHandler(event:CoreRequesterEvent):void 
{
    var strResult:String = new JSONEncoder(event.data).getString();
    Alert.show(strResult);
}

如果 IDE 没有为您导入 com.adobe.serialization.json.JSONEncodermx.controls.Alert,请导入它们。

很明显,API 在 event.data 中返回结果,它反过来是一个键值格式的 ActionScript 对象。为了显示目的,我们将其转换为 JSON 字符串,并使用 Alert.show 方法显示。它看起来像下图:

图 4 显示所有 API 返回

它显示了大量信息,这意味着 API 返回了相当丰富的评估结果。API 返回的数据结构定义良好,但截至本文撰写时,在线文档只有中文版本。对于此演示,我们将仅解析每个单词的分数以进行演示。

解析每个单词的分数

coreRequesterEventHandler 方法中设置一个断点,我们将使用 Flash Builder 调试器查看 API 返回。

如图 5 所示,event.data 对象有一个“result”字段,其中有一个“details”数组对象。 “details”数组的每个元素对应于参考文本中的一个单词,在本例中是“I want to play piano.”。因此,我们看到“details”数组包含五个元素(五个单词)。

Figure 5 Data structure of the API return 

图 5 API 返回的数据结构

details”数组的每个元素都有一个 char 字段和一个 score 字段,如图 6 所示。我们对这两个字段感兴趣。

图 6 “details”数组元素的数据结构

所以逻辑很简单:我们从“details”数组的每个元素中提取 charscore,然后将这些结果添加到我们定义的 ArrayCollection _scores 中。由于 _scores 绑定到分数图表,因此图表将在收到 API 结果后自动更新。

两个实现细节:首先,我们希望在添加新结果之前清除 _scores;其次,我们以相反的顺序添加结果,以便使单词沿图表的垂直轴从上到下排列。

代码如下:

private function coreRequesterEventHandler(event:CoreRequesterEvent):void
{
    _scores.removeAll();
    var details:Array = event.data.result.details;
    var len:int = details.length;
    for (var i:int = len - 1; i >=0; i --)
    {
        _scores.addItem({Word:details[i].char, Score:details[i].score});
    }
} 

完成后的应用程序将如下所示:

图 7 完成后的应用程序

结论  

此演示到此结束。

但是使用 AISpeech API ASSDK 还有更多细节,例如处理异常和使用其他语音核心(例如语音识别)。请注意,此演示完全不涉及异常处理。因此,在遵循本教程时,如果您遇到任何问题,请随时发表评论。

我正在向 AI Speech Ltd 申请英文在线文档。

此演示的源代码位于 github

有关 AISpeech API 的更多信息,请访问 blog.aispeech.com

感谢阅读。

历史 

这是本文的第一版。

© . All rights reserved.