2017-05-26 13:40:55 ls0609 阅读数 5051

转载请注明CSDN地址:http://blog.csdn.net/ls0609/article/details/72765789

语音在线听书demo:http://blog.csdn.net/ls0609/article/details/71519203

前言

国内语音识别技术已有多家,而olami不仅在语音识别上准确率较高,更重要的是在语义理解上十分强大,本文用olami sdk做了一个记账demo(记账部分代码参考开源代码),这个demo可以语音添加不同消费记录,查询当天,当月消费情况,删除消费列表中的记录。让我们一起来感受下olami如何实现强大的语义理解。

1.demo支持的说法

demo中实现的说法主要有如下几种(同类说法可以很多,没有全部列举):

今天餐饮开销一百元
今日交通出行五十元
本月15号日常购物一百元
这个月水电煤气两百元
查询今天的账单
查看今日的消费情况
今天的账单
今日消费
查询这个月的消费情况
查看本月消费
本月的账单
删除第一条
删除第一个记录
删除第五条消费记录

2. demo实现的效果图

这里写图片描述

这里写图片描述

3.olami的初始化和回调用法

初始化部分参考源码MainActivity.java中init()函数

     public void init()
    {
        initHandler();
        mOlamiVoiceRecognizer = new OlamiVoiceRecognizer(MainActivity.this);
        TelephonyManager telephonyManager=(TelephonyManager)this.getSystemService
                                          (this.getBaseContext().TELEPHONY_SERVICE);
        String imei=telephonyManager.getDeviceId();
        mOlamiVoiceRecognizer.init(imei);//set null if you do not want to notify olami server.

        mOlamiVoiceRecognizer.setListener(mOlamiVoiceRecognizerListener);//设置识别结果回listener
        mOlamiVoiceRecognizer.setLocalization
        (OlamiVoiceRecognizer.LANGUAGE_SIMPLIFIED_CHINESE);//设置支持的语音类型,优先选择中文简体 
        mOlamiVoiceRecognizer.setAuthorization(
        "573031596fd746fca478e5cccf6ca9e2","asr","d5307ed38df64ab6a08e467c00c81d37","nli"); 
        //注册Appkey,在olami官网注册应用后生成的appkey
        //注册api,请直接填写“asr”,标识语音识别类型
        //注册secret,在olami官网注册应用后生成的secret
        //注册seq ,请填写“nli”       
        mOlamiVoiceRecognizer.setVADTailTimeout(2000);//录音时尾音结束时间,建议填//2000ms
        mOlamiVoiceRecognizer.setLatitudeAndLongitude(31.155364678184498,121.34882432933009);
        //设置经纬度信息,不愿上传位置信息,可以填0 
    }

注册一个回调,用于各种回调,可以更新界面和处理服务器返回数据。

private class OlamiVoiceRecognizerListener implements IOlamiVoiceRecognizerListener{

        @Override
        public void onError(int errCode) {//出错回调
            mHandler.sendMessage(mHandler.obtainMessage(
                                 MessageConst.CLIENT_ACTION_ON_ERROR,errCode,0));

        }

        @Override
        public void onEndOfSpeech() {//录音结束回调
            mHandler.sendEmptyMessage(MessageConst.CLIENT_ACTION_STOP_RECORED);         
        }

        @Override
        public void onBeginningOfSpeech() {//录音开始回调
            mHandler.sendEmptyMessage(MessageConst.CLIENT_ACTION_START_RECORED);            
        }

        @Override
        public void onResult(String result, int type) {//结果返回回调
            mHandler.sendMessage(mHandler.obtainMessage(
                           MessageConst.SERVER_ACTION_RETURN_RESULT, type, 0, result));
        }

        @Override
        public void onCancel() {//取消录音回调
            mHandler.sendEmptyMessage(MessageConst.CLIENT_ACTION_CANCEL_RECORED);

        }

        @Override
        public void onUpdateVolume(int volume) {//实时返回音量回调
            mHandler.sendMessage(mHandler.obtainMessage(
                           MessageConst.CLIENT_ACTION_UPDATA_VOLUME, volume, 0, null));
        }

    }

4.服务器返回结果及解析

本月15号日常购物200元,服务器返回数据如下:

[
  {
    "desc_obj": {
      "result": "正在为您添加",
      "status": 0
    },
    "semantic": [
      {
        "app": "account",
        "input": "本月15号日常购物200元",
        "slots": [
          {
            "num_detail": {
              "recommend_value": "200",
              "type": "number"
            },
            "name": "pay_number",
            "value": "200"
          },
          {
            "name": "pay_type",
            "value": "日常购物"
          },
          {
            "num_detail": {
              "recommend_value": "15",
              "type": "number"
            },
            "name": "day",
            "value": "15"
          }
        ],
        "modifier": [
          "pay"
        ],
        "customer": "58df512384ae11f0bb7b487e"
      }
    ],
    "type": "account"
  }
]

删除第一个记录, 服务器返回数据如下:

[
  {
    "desc_obj": {
      "result": "正在为您删除",
      "status": 0
    },
    "semantic": [
      {
        "app": "account",
        "input": "删除第一个记录",
        "slots": [
          {
            "num_detail": {
              "recommend_value": "1",
              "type": "number"
            },
            "name": "index",
            "value": "一"
          }
        ],
        "modifier": [
          "delete_today"
        ],
        "customer": "58df512384ae11f0bb7b487e"
      }
    ],
    "type": "account"
  }
]

来看一下代码是如何解析的:

private void processServerMessage(String message)
{
        try{
            String input = null;
            JSONObject jsonObject = new JSONObject(message);
            JSONArray jArrayNli = jsonObject.optJSONObject("data").optJSONArray("nli");
            JSONObject jObj = jArrayNli.optJSONObject(0);
            JSONArray jArraySemantic = null;
            if(message.contains("semantic"))
            {
              jArraySemantic = jObj.getJSONArray("semantic");
              input = jArraySemantic.optJSONObject(0).optString("input");
            }
            else{
                input = jsonObject.optJSONObject("data").
                                    optJSONObject("asr").optString("result");
            }
            JSONObject jObjSemantic;
            JSONArray jArraySlots;
            JSONArray jArrayModifier;
            String type = null;
            String pay_number = null;
            String pay_type = null;
            String day = null;
            if(jObj != null) {
                type = jObj.optString("type");
                if("account".equals(type))//应用的名称是account,代表记账应用
                {
                    jObjSemantic = jArraySemantic.optJSONObject(0);
                    input = jObjSemantic.optString("input");
                    jArraySlots = jObjSemantic.optJSONArray("slots");
                    jArrayModifier = jObjSemantic.optJSONArray("modifier");
                    String modifier = (String)jArrayModifier.opt(0);
                    if((jArrayModifier != null) && ("pay".equals(modifier)))
                    {//modifier为pay,代表行为是记账
                        if(jArraySlots != null)
                        {
                           for(int i=0,k=jArraySlots.length(); i<k; i++)
                           {
                               JSONObject obj = jArraySlots.getJSONObject(i);
                               String name = obj.optString("name");
                               if("pay_type".equals(name))
                                   pay_type = obj.optString("value");
                               else if("pay_number".equals(name))
                               {//找出记录的具体金额
                                   pay_number = obj.getJSONObject("num_detail").
                                                 getString("recommend_value");
                               }
                               else if("day".equals(name))
                               {//找出某日发生消费的金额
                                   day = obj.getJSONObject("num_detail").
                                                 getString("recommend_value");
                               }

                           }
                        }
                        String date = null;
                        Calendar localCalendar = Calendar.getInstance();
                        int i_year = localCalendar.get(Calendar.YEAR);
                        int i_month = localCalendar.get(Calendar.MONTH)+1;
                        int i_day = localCalendar.get(Calendar.DAY_OF_MONTH);
                         if(day == null)
                         {
                             date = i_year + "-" + i_month + "-" + i_day;
                         }
                         else
                         {
                             date = i_year + "-" + i_month + "-" + day;
                         }
                         consumeClass trade = new consumeClass(0, 
                                             Float.parseFloat("-"+pay_number), 
                                             date, "123", pay_type,  MainActivity.this);                       
                                             trade.trade_add();
                                             //添加到消费列表中
                    }
                    else if((jArrayModifier != null) && ("query_today".equals(modifier)))
                    {   
                        QueryByTodayActivity.refreshListView(
                                                 QueryByTodayActivity.QUERY_BY_DAY);
                       //查询当天的消费情况,并更新列表                          
                    }
                    else if((jArrayModifier != null) && ("query_month".equals(modifier)))
                    {   
                        QueryByTodayActivity.refreshListView(
                                                    QueryByTodayActivity.QUERY_BY_MONTH);
                         //查询当月的消费情况,并更新列表                                                      
                    }else if((jArrayModifier != null) && ("delete_today".equals(modifier)))
                    {//找出要删除的消费记录的索引,删除并更新界面
                        String index = null;
                        if(jArraySlots != null)
                        {                         
                           JSONObject obj = jArraySlots.getJSONObject(0);                            
                           index = obj.getJSONObject("num_detail").
                                          getString("recommend_value");                                                   
                        }
                        if(index != null && !"".equals(index))
                            QueryByTodayActivity. deleteTodayDataByIndex(
                                                      Integer.parseInt(index));                                                 

                    }
                }
            }
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }                   
    }

5.源码下载链接

语音记账demo下载

6.相关链接

语音在线听书博客:http://blog.csdn.net/ls0609/article/details/71519203

olami开放平台语法编写简介:http://blog.csdn.net/ls0609/article/details/71624340

olami开放平台语法官方介绍:https://cn.olami.ai/wiki/?mp=nli&content=nli2.html

2014-06-03 10:14:59 u011871750 阅读数 885

百度语义理解开放平台面向互联网开发者提供自然语言文本的解析服务,也就是可以根据文本的意图解析成相应的表示。

为了易于人阅读,同时也方便机器解析和生成,意图表示协议采用 json 语言进行描述,采用 gb18030 编码。 

json 语言的基本概念: 
1、属性名/属性值 
即键值对(key-value) 
2、数组 
在 json 中是“[]”括起来的内容,数据结构为 ["value1","value2",...],取值方式和所有语言中一样,使用索引获取,属性值的类型可以是数字、字符串、数组、对象。 
3、对象 
在 json 中表示为“{}”括起来的内容,数据结构为 {key1:value1,key2:value2,...}的键值对的结构。在面向对象的语言中,key 为对象的属性,value 为对应的属性值,所以很容易理解,取值方法为对象.key 获取属性值,这个属性值的类型可以是数字、字符串、数组、对象几种。 

自然语言文本(以下简称 query)。query 的意图表示由如下键值对和数组构成: 
1、raw_text:用户的原始输入文本 
2、parsed_text:经过分词,纠错,改写处理后的文本 
3、version:协议版本号 
4、results:意图表示数组 

从服务器中得到的json数据就是按照这样的几个部分组成的,例如 “北京天气”对应的json结构如下

[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. query:北京明天天气   
  2. {   
  3.  "raw_text":"北京明天天气",   
  4.  "parsed_text":"北京 明天 天气",   
  5.  "results":[   
  6.  {   
  7.  "domain":"weather",   
  8.  "intent":"query",   
  9.  "score":1,    
  10.  "object":{   
  11.  "date": "2013-09-25,2013-09-25",   
  12. "region":"北京"   
  13.  }   
  14.  }   
  15.  ]   
  16. }  
在“百度语义理解开放平台 意图表示协议”文档中有详细的介绍,这篇文章主要介绍如何通过代码对这样的语义模型结果进行解析,并对解析的结果进行相应的操作。

下面的代码就是对服务器返回的json数据结构进行解析的过程,开发者首先需要了解json数据是怎么的键值对,然后一层一层解析就可以,根据不同的语义,分发到不同的操作中。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private void handleResult(String result) {  
  2.         try {  
  3.             JSONObject r = new JSONObject(result);  
  4.             result = r.optString("json_res");  
  5.             r = new JSONObject(result);  
  6.             String query = r.optString("raw_text");  
  7.             if (!TextUtils.isEmpty(query)) {  
  8.                 mAdapter.add(new ChatItem(query));  
  9.                 mAdapter.notifyDataSetChanged();  
  10.             }  
  11.             JSONArray commands = r.optJSONArray("results");  
  12.             JSONObject command = null;  
  13.             String type = null;  
  14.             if (commands != null && commands.length() > 0) {  
  15.                 command = commands.optJSONObject(0);  
  16.                 type = command.optString("domain");  
  17.             } else {  
  18.                 commands = r.optJSONArray("commandlist");  
  19.                 if (commands != null && commands.length() > 0) {  
  20.                     command = commands.optJSONObject(0);  
  21.                     type = command.optString("commandtype");  
  22.   
  23.                 }  
  24.             }  
  25.             if (!TextUtils.isEmpty(type)) {  
  26.                 Log.i("TYPE", type);  
  27.                 new CommandProcessorTask().execute(mProcessors.getProcessor(type), command);  
  28.             }  
  29.         } catch (JSONException e) {  
  30.   
  31.             e.printStackTrace();  
  32.         }  
  33.     }  

结果是以String格式返回的,所以首先,将该字符串转为JSONObject,然后解析"json_res"对应的字符串,再生产JSONObject,之后解析"raw_text"对应的文本,然后一步步的把每个键值对应的数据提取出来,其中“domain”对应的是语义的领域,可以作为区分语意的type类型分发到不同操作。
没有更多推荐了,返回首页