2018-02-02 00:00:00 Z1Y492Vn3ZYD9et3B06 阅读数 271

作者:欧应刚  | 小编:小葱



在人工智能领域,场景应用、平台建设是并行的,如何打通多项AI能力,提供融合的智能服务,对国内AI企业提出了挑战。捷通华声作为国内人工智能产业的开拓者与领导者,早在2011年就推出了全球首个全方位人工智能平台——灵云(AIcloud.com)。


该平台融合智能语音、智能图像、生物特征识别、智能语义等12项人工智能技术,并面向产业全面开放。为此,作为中国软件网策划的“2018中国AI应用、平台与生态”系列专访第二期,我们采访了捷通华声总经理武卫东,跟他聊一聊人智能应用和人工智能开放平台的发展逻辑,以及捷通华声的一些实践经验。

 

深化应用、构建平台,是人工智能厂商的未来


根据中国软件网《2018中国人工智能应用与生态研究报告》中调研数据显示,38%的人认为我国人工智能产业目前处于应用扩展、平台建设阶段;33%的人认为我国人工智能产业已经进入平台竞争、生态建设阶段。可见,大部分人都认为我国正在进行AI平台和生态建设。


值得提出的是,应用落地和平台、生态建设是同步并举,人工智能厂商之间的竞争将在多个维度同时进行。要建成完善的AI平台和生态,预计还有5~10年时间。


武卫东认为,通过构建人工智能开放平台的方式,深化行业应用、聚集合作伙伴,进而构建人工智能产业生态是捷通华声重要的战略布局。捷通华声在这方面很早就进行了积极的探索,2011年,捷通华声的灵云平台就面向产业全面开放,并以“云 + 端”方式,为产业界提供语音合成(TTS)、语音识别(ASR)、麦克风阵列(SMA)、语音唤醒(VW)、手写识别(HWR)、光学字符识别(OCR)、人脸识别(AFR)、声纹识别(VPR)、指纹识别(FPR)、自然语言理解(NLU)、数据挖掘(DM)、机器翻译(MT)等全方位人工智能能力。通过将其积累的人工智能技术开放出来,捷通华声积累了众多的合作伙伴,并服务大量的行业客户。


融合多项智能应用,打通整个智能产业链条


武卫东指出,目前人工智能厂商大多提供单一的智能服务,比如语音识别、图像识别等,多项智能应用的融合度不高。但是就市场需求来看,用户想要的往往是多项智能服务,并且这些不同领域的智能应用要很好的融合,形成完善的解决方案。


捷通华声作为在智能语音领域领先的厂商,其能力不仅局限于语音领域,已经扩展到智能图像、智能语义、生物特征识别等领域。具体来看,捷通华声提供的智能服务包括:


智能语音领域,捷通华声能具备正确率为97%以上的语音识别能力,并能实现21种语言的语音合成服务,以及语义理解能力。另外,捷通华声还提供独具特色的声纹识别应用,可以根据说话人的语音特征,提供声纹鉴别和声纹确认,并作为生物特征识别的重要手段;


智能图像领域,捷通华声提供的OCR服务,除了支持识别汉语、英语之外,还支持维语、蒙语、藏语、朝鲜语、哈萨克、彝族等多种少数民族语言的识别。更进一步的,捷通华声具备手写识别能力,能将手写字迹转化成文本,识别准确率在99.9%以上。此外,捷通华声还支持人脸识别和指纹识别应用。



值得提出的是,捷通华声通过灵云平台来提供这些智能应用,致力于实现不同种类智能服务的融合,而不是简单的产品堆砌。在武卫东看来,单项智能的局限性较大,未来必然是多项智能的高度融合。为此,捷通华声突出全方位人工智能的能力建设,并以灵云平台为载体,向开发者、合作伙伴开放出来,共同赋能整个智能生态的发展。


融合生物特征识别,提供个性化智能服务 


构建人工智能平台,不是单纯的将各项AI能力放上去就可以,要发挥作用必然要理顺内部的业务逻辑。在与武总的交流中,给我启发比较大的是捷通华声基于生物特征识别打通智能服务链条的构想和实践。


在捷通华声看来,人工智能应用的一个重要价值,就是对不同用户提供高度符合其需求的相关服务。在以前,针对特定个体提供定制化服务只在很有限的范围内实现,比如对VIP客户的服务。现在,由于数据的积累和智能化技术的发展,基于数据分析的用户画像和定制化服务,无论从技术难度还是经济效益上来说,都具备了实现的可能。而要实现对不同个体的定制化服务,关键的第一步就是对实现特定个体的识别。在互联网时代,人们大多通过各类账户来实现用户识别;在智能时代,基于生物特征的用户识别将成为常态,比较典型的就是人脸识别和指纹识别。另外,捷通华声还提供独具特色的声纹识别服务,可以根据一个人声音特点来进行身份识别和验证。


通过人脸、声纹、指纹等生物特征识别技术,加上数据分析和用户画像,就可以打通整个智能服务链条,给用户带来实时、智能的服务体验。为此,他描述了这样一个场景:一个银行用户进入银行,通过人脸识别、声纹识别技术,系统可以根据对用户面部和声音的识别知道他的身份,再通过对系统内该用户记录和用户画像的分析,推测出该用户的需求,并提供不同的服务。比如根据系统分析,如果一个用户属于风险厌恶型的,在推荐理财产品时就会选取低风险产品;如果分析出该用户是激进型的,则推荐高风险、高收益的理财产品。这样,可以大大提升用户体验,提升用户粘性。这样一套系统充分体现了人工智能相对于人的优越性,在上述场景中,银行大堂经理是不可能对进入银行的每个用户都能全面了解的。通过人工智能与大数据技术,以及多项AI能力的融合,构建的这套系统能实现基于身份认证的个性化智能服务,这也是灵云平台的优势所在。


携手合作伙伴,共铸智能生态


作为成立于2000年并一直全面发展人工智能云服务的高新技术企业,捷通华声不仅提供智能语音、智能图像、生物特征识别、智能语义等全方位人工智能技术研究与应用,也与众多伙伴一起,推展更丰富的应用领域,搭建互利共赢得智能生态。



基于灵云平台,捷通华声致力于用AI技术促进产品产业升级,巩固合作伙伴行业地位,帮助合作伙伴落地AI业务场景,共同构建AI全链条的行业生态。为了最大化支持合作伙伴,捷通华声可提供公有云、私有云服务及综合智能解决方案,并针对不同产品灵活变换合作模式。此外还提供全套的技术培训支持,包括灵云AI产品课程培训、业务分享沙龙、在线视频技术学习等,并在联合推广营销方面给予合作伙伴大量的支持。


在人工智能的各个领域,平台化、生态化趋势日益明显,其平台和生态建设路径一般是:通过AI技术赋能各个行业,找到一些适合AI应用的领域快速商业化和规模化;加快应用领域拓展、行业深耕和客户资源的积累;搭建人工智能平台,实现生态化发展。总体来看,捷通华声也基本遵循了这一发展路径,在发展出众多AI能力之后,构建人工智能平台,携手合作伙伴共建智能生态,未来必将取得更大的成绩。

 



了解中国软件网

移动办公、CRM、HR服务

趋势洞察报告研究文章及报告获取路径

请在公众号后来回复【报告】



 中国软件网 

专注有深度的

互联网软件趋势分析

 作者 

欧应刚

人工智能、大数据、云计算和AR领域


致力于做一个有态度、有洞见、有策略的产业观察者

微信:微信oyg0001

邮箱:oyg@soft6.com


 AI系列专访 


扫描二维码,关注我们吧


2016-08-15 16:31:15 q4878802 阅读数 2631

源码

GitHub

在线语音识别

SDK下载

灵云SDK下载

SDK集成

下载SDK以后,将jar和so导入工程

权限

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

封装

灵云配置类

package kong.qingwei.kqwhcidemo;

/**
 * Created by kqw on 2016/8/12.
 * 灵云配置信息
 */
public final class ConfigUtil {

    /**
     * 灵云APP_KEY
     */
    public static final String APP_KEY = "3d5d5466";

    /**
     * 开发者密钥
     */
    public static final String DEVELOPER_KEY = "eca643ff7b3c758745d7cf516e808d34";

    /**
     * 灵云云服务的接口地址
     */
    public static final String CLOUD_URL = "test.api.hcicloud.com:8888";

    /**
     * 需要运行的灵云能力
     */
    public static final String CAP_KEY = "tts.local.synth";
    //    public static final String CAP_KEY = "tts.cloud.wangjing";
    public static final String CAP_KEY_NUL = "nlu.cloud";
}

初始化灵云语音能力的工具类

package kong.qingwei.kqwhcidemo;

import android.app.Activity;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;

import com.sinovoice.hcicloudsdk.api.HciCloudSys;
import com.sinovoice.hcicloudsdk.common.AuthExpireTime;
import com.sinovoice.hcicloudsdk.common.HciErrorCode;
import com.sinovoice.hcicloudsdk.common.InitParam;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
 * Created by kqw on 2016/8/12.
 * 初始化灵云语音
 */
public class HciUtil {

    private static final String TAG = "HciUtil";
    private Activity mActivity;
    private final String mConfigStr;

    public HciUtil(Activity activity) {
        mActivity = activity;

        // 加载信息,返回InitParam, 获得配置参数的字符串
        InitParam initParam = getInitParam();
        mConfigStr = initParam.getStringConfig();
    }

    public boolean initHci() {
        // 初始化
        int errCode = HciCloudSys.hciInit(mConfigStr, mActivity);
        if (errCode != HciErrorCode.HCI_ERR_NONE && errCode != HciErrorCode.HCI_ERR_SYS_ALREADY_INIT) {
            Toast.makeText(mActivity, "hciInit error: " + HciCloudSys.hciGetErrorInfo(errCode), Toast.LENGTH_SHORT).show();
            return false;
        }

        // 获取授权/更新授权文件 :
        errCode = checkAuthAndUpdateAuth();
        if (errCode != HciErrorCode.HCI_ERR_NONE) {
            // 由于系统已经初始化成功,在结束前需要调用方法hciRelease()进行系统的反初始化
            Toast.makeText(mActivity, "CheckAuthAndUpdateAuth error: " + HciCloudSys.hciGetErrorInfo(errCode), Toast.LENGTH_SHORT).show();
            HciCloudSys.hciRelease();
            return false;
        }
        return true;
    }

    /**
     * 释放
     */
    public void hciRelease(){
        HciCloudSys.hciRelease();
    }

    /**
     * 加载初始化信息
     *
     * @return 系统初始化参数
     */
    private InitParam getInitParam() {
        String authDirPath = mActivity.getFilesDir().getAbsolutePath();
        // 前置条件:无
        InitParam initparam = new InitParam();
        // 授权文件所在路径,此项必填
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_AUTH_PATH, authDirPath);
        // 是否自动访问云授权,详见 获取授权/更新授权文件处注释
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_AUTO_CLOUD_AUTH, "no");
        // 灵云云服务的接口地址,此项必填
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_CLOUD_URL, ConfigUtil.CLOUD_URL);
        // 开发者Key,此项必填,由捷通华声提供
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_DEVELOPER_KEY, ConfigUtil.DEVELOPER_KEY);
        // 应用Key,此项必填,由捷通华声提供
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_APP_KEY, ConfigUtil.APP_KEY);
        // 配置日志参数
        String sdcardState = Environment.getExternalStorageState();
        if (Environment.MEDIA_MOUNTED.equals(sdcardState)) {
            String sdPath = Environment.getExternalStorageDirectory().getAbsolutePath();
            String packageName = mActivity.getPackageName();
            String logPath = sdPath + File.separator + "sinovoice" + File.separator + packageName + File.separator + "log" + File.separator;
            // 日志文件地址
            File fileDir = new File(logPath);
            if (!fileDir.exists()) {
                fileDir.mkdirs();
            }
            // 日志的路径,可选,如果不传或者为空则不生成日志
            initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_PATH, logPath);
            // 日志数目,默认保留多少个日志文件,超过则覆盖最旧的日志
            initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_COUNT, "5");
            // 日志大小,默认一个日志文件写多大,单位为K
            initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_SIZE, "1024");
            // 日志等级,0=无,1=错误,2=警告,3=信息,4=细节,5=调试,SDK将输出小于等于logLevel的日志信息
            initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_LEVEL, "5");
        }
        return initparam;
    }

    /**
     * 获取授权
     *
     * @return 授权结果
     */
    private int checkAuthAndUpdateAuth() {
        // 获取系统授权到期时间
        int initResult;
        AuthExpireTime objExpireTime = new AuthExpireTime();
        initResult = HciCloudSys.hciGetAuthExpireTime(objExpireTime);
        if (initResult == HciErrorCode.HCI_ERR_NONE) {
            // 显示授权日期,如用户不需要关注该值,此处代码可忽略
            Date date = new Date(objExpireTime.getExpireTime() * 1000);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
            Log.i(TAG, "expire time: " + sdf.format(date));
            if (objExpireTime.getExpireTime() * 1000 > System.currentTimeMillis()) {
                // 已经成功获取了授权,并且距离授权到期有充足的时间(>7天)
                Log.i(TAG, "checkAuth success");
                return initResult;
            }
        }
        // 获取过期时间失败或者已经过期
        initResult = HciCloudSys.hciCheckAuth();
        if (initResult == HciErrorCode.HCI_ERR_NONE) {
            Log.i(TAG, "checkAuth success");
            return initResult;
        } else {
            Log.e(TAG, "checkAuth failed: " + initResult);
            return initResult;
        }
    }
}

语音识别的类

package kong.qingwei.kqwhcidemo;

import android.app.Activity;
import android.util.Log;

import com.sinovoice.hcicloudsdk.android.asr.recorder.ASRRecorder;
import com.sinovoice.hcicloudsdk.common.asr.AsrConfig;
import com.sinovoice.hcicloudsdk.common.asr.AsrInitParam;
import com.sinovoice.hcicloudsdk.common.asr.AsrRecogResult;
import com.sinovoice.hcicloudsdk.recorder.ASRRecorderListener;
import com.sinovoice.hcicloudsdk.recorder.RecorderEvent;


/**
 * Created by kqw on 2016/8/15.
 * 语音识别类
 */
public class AsrUtil {

    private static final String TAG = "AsrUtil";
    private Activity mActivity;
    private ASRRecorder mAsrRecorder;
    private AsrConfig asrConfig;
    private OnAsrRecogListener mOnAsrRecogListener;

    public AsrUtil(Activity activity) {
        mActivity = activity;
        initAsr();
    }

    private void initAsr() {
        Log.i(TAG, "initAsr: ");
        // 初始化录音机
        mAsrRecorder = new ASRRecorder();

        // 配置初始化参数
        AsrInitParam asrInitParam = new AsrInitParam();
        String dataPath = mActivity.getFilesDir().getPath().replace("files", "lib");
        asrInitParam.addParam(AsrInitParam.PARAM_KEY_INIT_CAP_KEYS, ConfigUtil.CAP_KEY_ASR_CLOUD_FREETALK);
        asrInitParam.addParam(AsrInitParam.PARAM_KEY_DATA_PATH, dataPath);
        asrInitParam.addParam(AsrInitParam.PARAM_KEY_FILE_FLAG, AsrInitParam.VALUE_OF_PARAM_FILE_FLAG_ANDROID_SO);
        Log.v(TAG, "init parameters:" + asrInitParam.getStringConfig());

        // 设置初始化参数
        mAsrRecorder.init(asrInitParam.getStringConfig(), new ASRResultProcess());

        // 配置识别参数
        asrConfig = new AsrConfig();
        // PARAM_KEY_CAP_KEY 设置使用的能力
        asrConfig.addParam(AsrConfig.SessionConfig.PARAM_KEY_CAP_KEY, ConfigUtil.CAP_KEY_ASR_CLOUD_FREETALK);
        // PARAM_KEY_AUDIO_FORMAT 音频格式根据不同的能力使用不用的音频格式
        asrConfig.addParam(AsrConfig.AudioConfig.PARAM_KEY_AUDIO_FORMAT, AsrConfig.AudioConfig.VALUE_OF_PARAM_AUDIO_FORMAT_PCM_16K16BIT);
        // PARAM_KEY_ENCODE 音频编码压缩格式,使用OPUS可以有效减小数据流量
        asrConfig.addParam(AsrConfig.AudioConfig.PARAM_KEY_ENCODE, AsrConfig.AudioConfig.VALUE_OF_PARAM_ENCODE_SPEEX);
        // 其他配置,此处可以全部选取缺省值

        asrConfig.addParam("intention", "weather");
    }

    /**
     * 开始语音识别
     */
    public void start(OnAsrRecogListener listener) {
        mOnAsrRecogListener = listener;
        if (mAsrRecorder.getRecorderState() == ASRRecorder.RECORDER_STATE_IDLE) {
            asrConfig.addParam(AsrConfig.SessionConfig.PARAM_KEY_REALTIME, "no");
            mAsrRecorder.start(asrConfig.getStringConfig(), null);
        } else {
            Log.i(TAG, "start: 录音机未处于空闲状态,请稍等");
        }
    }

    private class ASRResultProcess implements ASRRecorderListener {
        @Override
        public void onRecorderEventError(RecorderEvent event, int errorCode) {
            Log.i(TAG, "onRecorderEventError: errorCode = " + errorCode);
            if (null != mOnAsrRecogListener) {

                mOnAsrRecogListener.onError(errorCode);
            }
        }

        @Override
        public void onRecorderEventRecogFinsh(RecorderEvent recorderEvent, final AsrRecogResult arg1) {
            if (recorderEvent == RecorderEvent.RECORDER_EVENT_RECOGNIZE_COMPLETE) {
                Log.i(TAG, "onRecorderEventRecogFinsh: 识别结束");
            }
            if (null != mOnAsrRecogListener) {
                mActivity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mOnAsrRecogListener.onAsrRecogResult(arg1);
                    }
                });
            }
        }

        @Override
        public void onRecorderEventStateChange(RecorderEvent recorderEvent) {
            if (recorderEvent == RecorderEvent.RECORDER_EVENT_BEGIN_RECORD) {
                Log.i(TAG, "onRecorderEventStateChange: 开始录音");
            } else if (recorderEvent == RecorderEvent.RECORDER_EVENT_BEGIN_RECOGNIZE) {
                Log.i(TAG, "onRecorderEventStateChange: 开始识别");
            } else if (recorderEvent == RecorderEvent.RECORDER_EVENT_NO_VOICE_INPUT) {
                Log.i(TAG, "onRecorderEventStateChange: 无音频输入");
            } else {
                Log.i(TAG, "onRecorderEventStateChange: recorderEvent = " + recorderEvent);
            }
        }

        @Override
        public void onRecorderRecording(byte[] volumedata, int volume) {
            if (null != mOnAsrRecogListener) {
                mOnAsrRecogListener.onVolume(volume);
            }
        }

        @Override
        public void onRecorderEventRecogProcess(RecorderEvent recorderEvent, AsrRecogResult arg1) {
            if (recorderEvent == RecorderEvent.RECORDER_EVENT_RECOGNIZE_PROCESS) {
                Log.i(TAG, "onRecorderEventRecogProcess: 识别中间反馈");
            }
            if (arg1 != null) {
                if (arg1.getRecogItemList().size() > 0) {
                    Log.i(TAG, "onRecorderEventRecogProcess: 识别中间结果结果为:" + arg1.getRecogItemList().get(0).getRecogResult());
                } else {
                    Log.i(TAG, "onRecorderEventRecogProcess: 未能正确识别,请重新输入");
                }
            }
        }
    }

    /**
     * 语音识别的回调接口
     */
    public interface OnAsrRecogListener {
        // 识别结果
        void onAsrRecogResult(AsrRecogResult asrRecogResult);

        // 识别错误码
        void onError(int errorCode);

        // 录音音量
        void onVolume(int volume);
    }
}

使用

初始化灵云的语音能力和语音识别

// 灵云语音工具类
mInitTts = new HciUtil(this);
// 初始化灵云语音
boolean isInitHci = mInitTts.initHci();
if (isInitHci) { // 初始化成功
    ……
    // 语音识别
    mAsrUtil = new AsrUtil(this);
}

语音识别

/**
 * 语音识别(语音转文字)
 *
 * @param view view
 */
public void asr(View view) {
    mAsrUtil.start(new AsrUtil.OnAsrRecogListener() {
        @Override
        public void onAsrRecogResult(AsrRecogResult asrRecogResult) {
            StringBuilder stringBuffer = new StringBuilder();
            ArrayList<AsrRecogItem> asrRecogItemArrayList = asrRecogResult.getRecogItemList();
            for (AsrRecogItem asrRecogItem : asrRecogItemArrayList) {
                String result = asrRecogItem.getRecogResult();
                Log.i(TAG, "onAsrRecogResult: " + result);
                stringBuffer.append(result).append("\n");
            }
            showDialog("识别结果", stringBuffer.toString());
        }

        @Override
        public void onError(int errorCode) {
            Log.i(TAG, "onError: " + errorCode);
        }

        @Override
        public void onVolume(int volume) {
            Log.i(TAG, "onVolume: " + volume);
        }
    });
}

离线语音识别

离线命令词和在线很类似,只需要更改CapKey,导入离线资源包即可,我们先下载离线资源

下载完解压

解压后的源文件png

将里面所有的文件重命名,前面加lib,后面加.so,然后导入工程

重命名

修改CapKey为asr.local.freetalk

注意,灵云的离线语音功能第一次使用需要联网激活,激活以后才可以使用离线功能。

在线语音识别 + 语义理解

直接在在线语音识别的基础上实现语义理解更加简单,只要将CapKey换成asr.cloud.dialog即可

但是需要注意一点的是,想要使用哪个场景,必须开通以后,在参数里加上对应的场景,才是识别出来。

类似这样

asrConfig.addParam("intention", "weather");
2016-08-15 12:08:29 q4878802 阅读数 1674

效果图

效果图

源码

GitHub

SDK下载

灵云SDK下载

SDK集成

下载SDK以后,将jar和so导入工程

导入SDK

权限

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

封装

灵云配置类

package kong.qingwei.kqwhcidemo;

/**
 * Created by kqw on 2016/8/12.
 * 灵云配置信息
 */
public final class ConfigUtil {

    /**
     * 灵云APP_KEY
     */
    public static final String APP_KEY = "3d5d5466";

    /**
     * 开发者密钥
     */
    public static final String DEVELOPER_KEY = "eca643ff7b3c758745d7cf516e808d34";

    /**
     * 灵云云服务的接口地址
     */
    public static final String CLOUD_URL = "test.api.hcicloud.com:8888";

    /**
     * 需要运行的灵云能力
     */
    public static final String CAP_KEY = "tts.local.synth";
    //    public static final String CAP_KEY = "tts.cloud.wangjing";
    public static final String CAP_KEY_NUL = "nlu.cloud";
}

初始化灵云语音能力的工具类

package kong.qingwei.kqwhcidemo;

import android.app.Activity;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;

import com.sinovoice.hcicloudsdk.api.HciCloudSys;
import com.sinovoice.hcicloudsdk.common.AuthExpireTime;
import com.sinovoice.hcicloudsdk.common.HciErrorCode;
import com.sinovoice.hcicloudsdk.common.InitParam;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
 * Created by kqw on 2016/8/12.
 * 初始化灵云语音
 */
public class HciUtil {

    private static final String TAG = "HciUtil";
    private Activity mActivity;
    private final String mConfigStr;

    public HciUtil(Activity activity) {
        mActivity = activity;

        // 加载信息,返回InitParam, 获得配置参数的字符串
        InitParam initParam = getInitParam();
        mConfigStr = initParam.getStringConfig();
    }

    public boolean initHci() {
        // 初始化
        int errCode = HciCloudSys.hciInit(mConfigStr, mActivity);
        if (errCode != HciErrorCode.HCI_ERR_NONE && errCode != HciErrorCode.HCI_ERR_SYS_ALREADY_INIT) {
            Toast.makeText(mActivity, "hciInit error: " + HciCloudSys.hciGetErrorInfo(errCode), Toast.LENGTH_SHORT).show();
            return false;
        }

        // 获取授权/更新授权文件 :
        errCode = checkAuthAndUpdateAuth();
        if (errCode != HciErrorCode.HCI_ERR_NONE) {
            // 由于系统已经初始化成功,在结束前需要调用方法hciRelease()进行系统的反初始化
            Toast.makeText(mActivity, "CheckAuthAndUpdateAuth error: " + HciCloudSys.hciGetErrorInfo(errCode), Toast.LENGTH_SHORT).show();
            HciCloudSys.hciRelease();
            return false;
        }
        return true;
    }

    /**
     * 释放
     */
    public void hciRelease(){
        HciCloudSys.hciRelease();
    }

    /**
     * 加载初始化信息
     *
     * @return 系统初始化参数
     */
    private InitParam getInitParam() {
        String authDirPath = mActivity.getFilesDir().getAbsolutePath();
        // 前置条件:无
        InitParam initparam = new InitParam();
        // 授权文件所在路径,此项必填
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_AUTH_PATH, authDirPath);
        // 是否自动访问云授权,详见 获取授权/更新授权文件处注释
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_AUTO_CLOUD_AUTH, "no");
        // 灵云云服务的接口地址,此项必填
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_CLOUD_URL, ConfigUtil.CLOUD_URL);
        // 开发者Key,此项必填,由捷通华声提供
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_DEVELOPER_KEY, ConfigUtil.DEVELOPER_KEY);
        // 应用Key,此项必填,由捷通华声提供
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_APP_KEY, ConfigUtil.APP_KEY);
        // 配置日志参数
        String sdcardState = Environment.getExternalStorageState();
        if (Environment.MEDIA_MOUNTED.equals(sdcardState)) {
            String sdPath = Environment.getExternalStorageDirectory().getAbsolutePath();
            String packageName = mActivity.getPackageName();
            String logPath = sdPath + File.separator + "sinovoice" + File.separator + packageName + File.separator + "log" + File.separator;
            // 日志文件地址
            File fileDir = new File(logPath);
            if (!fileDir.exists()) {
                fileDir.mkdirs();
            }
            // 日志的路径,可选,如果不传或者为空则不生成日志
            initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_PATH, logPath);
            // 日志数目,默认保留多少个日志文件,超过则覆盖最旧的日志
            initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_COUNT, "5");
            // 日志大小,默认一个日志文件写多大,单位为K
            initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_SIZE, "1024");
            // 日志等级,0=无,1=错误,2=警告,3=信息,4=细节,5=调试,SDK将输出小于等于logLevel的日志信息
            initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_LEVEL, "5");
        }
        return initparam;
    }

    /**
     * 获取授权
     *
     * @return 授权结果
     */
    private int checkAuthAndUpdateAuth() {
        // 获取系统授权到期时间
        int initResult;
        AuthExpireTime objExpireTime = new AuthExpireTime();
        initResult = HciCloudSys.hciGetAuthExpireTime(objExpireTime);
        if (initResult == HciErrorCode.HCI_ERR_NONE) {
            // 显示授权日期,如用户不需要关注该值,此处代码可忽略
            Date date = new Date(objExpireTime.getExpireTime() * 1000);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
            Log.i(TAG, "expire time: " + sdf.format(date));
            if (objExpireTime.getExpireTime() * 1000 > System.currentTimeMillis()) {
                // 已经成功获取了授权,并且距离授权到期有充足的时间(>7天)
                Log.i(TAG, "checkAuth success");
                return initResult;
            }
        }
        // 获取过期时间失败或者已经过期
        initResult = HciCloudSys.hciCheckAuth();
        if (initResult == HciErrorCode.HCI_ERR_NONE) {
            Log.i(TAG, "checkAuth success");
            return initResult;
        } else {
            Log.e(TAG, "checkAuth failed: " + initResult);
            return initResult;
        }
    }
}

语义理解的类

package kong.qingwei.kqwhcidemo;

import android.app.Activity;
import android.util.Log;

import com.sinovoice.hcicloudsdk.api.nlu.HciCloudNlu;
import com.sinovoice.hcicloudsdk.common.HciErrorCode;
import com.sinovoice.hcicloudsdk.common.Session;
import com.sinovoice.hcicloudsdk.common.nlu.NluConfig;
import com.sinovoice.hcicloudsdk.common.nlu.NluInitParam;
import com.sinovoice.hcicloudsdk.common.nlu.NluRecogResult;

/**
 * Created by kqw on 2016/8/12.
 * 语义理解类
 */
public class NluUtil {

    private static final String TAG = "NluUtil";
    private Activity mActivity;

    public NluUtil(Activity activity) {
        mActivity = activity;
    }

    public boolean initNul() {
        //构造Asr初始化的帮助类的实例
        NluInitParam initParam = new NluInitParam();
        // 获取App应用中的lib的路径,放置能力所需资源文件。如果使用/data/data/packagename/lib目录,需要添加android_so的标记
        String dataPath = mActivity.getFilesDir().getAbsolutePath().replace("files", "lib");
        initParam.addParam(NluInitParam.PARAM_KEY_DATA_PATH, dataPath);
        initParam.addParam(NluInitParam.PARAM_KEY_FILE_FLAG, NluInitParam.VALUE_OF_PARAM_FILE_FLAG_ANDROID_SO);
        initParam.addParam(NluInitParam.PARAM_KEY_INIT_CAP_KEYS, ConfigUtil.CAP_KEY_NUL);
        int errCode = HciCloudNlu.hciNluInit(initParam.getStringConfig());
        Log.i(TAG, "initNul: errCode = " + errCode);
        return errCode == HciErrorCode.HCI_ERR_NONE || errCode == HciErrorCode.HCI_ERR_NLU_ALREADY_INIT;
    }

    public void recog(String text, OnNluRecogListener onNluRecogListener) {
        // 初始化配置参数
        NluConfig nluConfig = initConfig();

        // 创建会话
        Session session = new Session();
        // 开始会话
        int errCode = HciCloudNlu.hciNluSessionStart(nluConfig.getStringConfig(), session);
        if (errCode == HciErrorCode.HCI_ERR_NONE) {
            // 开始翻译
            // 调用HciCloudMt.hciMtTrans() 方法进行合成
            NluRecogResult nluResult = new NluRecogResult();
            errCode = HciCloudNlu.hciNluRecog(session, text, nluConfig.getStringConfig(), nluResult);
            if (errCode == HciErrorCode.HCI_ERR_NONE) {
                onNluRecogListener.onNluResult(nluResult);
            } else {
                onNluRecogListener.onError(errCode);
            }

            // 结束会话
            errCode = HciCloudNlu.hciNluSessionStop(session);
            if (errCode != HciErrorCode.HCI_ERR_NONE) {
                onNluRecogListener.onError(errCode);
            }
        } else {
            onNluRecogListener.onError(errCode);
        }
    }

    private NluConfig initConfig() {
        NluConfig nluConfig = new NluConfig();
        nluConfig.addParam(NluConfig.SessionConfig.PARAM_KEY_CAP_KEY, ConfigUtil.CAP_KEY_NUL);
        nluConfig.addParam("intention", "weather");
        return nluConfig;
    }

    public interface OnNluRecogListener {
        void onNluResult(NluRecogResult nluRecogResult);

        void onError(int errorCode);
    }
}

使用

初始化灵云的语音能力和语义理解

// 灵云语音工具类
mInitTts = new HciUtil(this);
// 初始化灵云语音
boolean isInitHci = mInitTts.initHci();
if (isInitHci) { // 初始化成功
    ……
    // 语义理解
    mNluUtil = new NluUtil(this);
    boolean isInitNul = mNluUtil.initNul();
    if (isInitNul) {
        Toast.makeText(this, "语义理解 初始化成功", Toast.LENGTH_SHORT).show();
    } else {
        Toast.makeText(this, "语义理解 初始化失败", Toast.LENGTH_SHORT).show();
    }
}

语义理解

/**
 * 语义理解
 *
 * @param view
 */
public void recog(View view) {
    final String text = mEditText2.getText().toString();
    if (TextUtils.isEmpty(text)) {
        Toast.makeText(this, "理解句子内容为空", Toast.LENGTH_SHORT).show();
        return;
    }
    mNluUtil.recog(text, new NluUtil.OnNluRecogListener() {
        @Override
        public void onNluResult(NluRecogResult nluRecogResult) {
            StringBuilder stringBuffer = new StringBuilder();
            ArrayList<NluRecogResultItem> nluRecogResultItems = nluRecogResult.getRecogResultItemList();
            for (NluRecogResultItem nluRecogResultItem : nluRecogResultItems) {
                String result = nluRecogResultItem.getResult();
                stringBuffer.append(result).append("\n");
                Log.i(TAG, "onNluResult: " + result);
            }
            showDialog(text, stringBuffer.toString());
        }

        @Override
        public void onError(int errorCode) {
            Log.i(TAG, "onError: errorCode = " + errorCode);
        }
    });

}

Dialog

/**
 * 显示Dialog
 *
 * @param title   title
 * @param message message
 */
private void showDialog(String title, String message) {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle(title);
    builder.setMessage(message);
    builder.setPositiveButton("确认", null);
    builder.create().show();
}

注意

灵云的语义,想要识别哪个场景,必须要先开通对应场景,然后做配置以后才可以使用,类似这样

nluConfig.addParam("intention", "weather");

这里的天气,对应的参数是weather,了解更多场景和对应场景参数可以查看捷通华声灵云公有云能力平台NLU结果开发手册.pdf

2016-08-16 14:28:24 q4878802 阅读数 1363

灵云语音唤醒

严格来讲,灵云没有语音唤醒功能,但是通过命令词的方式可以实现

实现方式

用命令词的方式实现唤醒,用唤醒词做命令词,做好标识,然后循环开启命令词识别,当识别到唤醒的命令词的时候,视为被唤醒了。

我个人认为这种方式实现唤醒意义不大,所以没有做demo,原因如下:

  1. 录音都有前置端点时间1和后置端点时间2,这样一来,即使我们准确的说出唤醒词,也要在说完唤醒词以后,保证在后端点时间内不再有声音录入,才能提高被唤醒的几率。
  2. 唤醒不是即时的,即使我们准确的说出唤醒词,并保持不再有声音录入,也要至少等待后端点时间过去,录音结束以后,才会识别(被唤醒)。
  3. 这种方式的唤醒其实就是在进行语音识别,如果一直开启唤醒,消耗性能,耗电。

  1. 在前置端点时间内没有有效的声音录入,表示此次录音无效,结束录音.
  2. 录音结束以后,在后置端点时间内没有再录入有效声音,表示录音完成,结束录音。
2016-08-12 14:36:39 q4878802 阅读数 2568

注册

官网

注册比较简单,就不做过多介绍了,注册万应用以后,在后台创建自己的应用,创建完应用以后需要给应用开通对应的语音能力。

开通语音能力

集成

下载灵云SDK

如果使用在线功能,下载对应的SDK,里面有jar包和so,就可以满足需求了。如果要使用离线的语音功能,还需要下载灵云资源文件

源码

GitHub

灵云在线语音合成

权限

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

配置类

package kong.qingwei.kqwhcittsdemo;

/**
 * Created by kqw on 2016/8/12.
 * 灵云配置信息
 */
public final class ConfigUtil {

    /**
     * 灵云APP_KEY
     */
    public static final String APP_KEY = "填入自己的APP KEY";

    /**
     * 开发者密钥
     */
    public static final String DEVELOPER_KEY = "填入自己的DEVELOPER KEY";

    /**
     * 灵云云服务的接口地址
     */
    public static final String CLOUD_URL = "test.api.hcicloud.com:8888";

    /**
     * 需要运行的灵云能力
     */
    // public static final String CAP_KEY = "tts.local.synth";
    public static final String CAP_KEY = "tts.cloud.wangjing";
}

封装灵云语音的初始化

package kong.qingwei.kqwhcittsdemo;

import android.app.Activity;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;

import com.sinovoice.hcicloudsdk.api.HciCloudSys;
import com.sinovoice.hcicloudsdk.common.AuthExpireTime;
import com.sinovoice.hcicloudsdk.common.HciErrorCode;
import com.sinovoice.hcicloudsdk.common.InitParam;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
 * Created by kqw on 2016/8/12.
 * 初始化灵云语音
 */
public class HciUtil {

    private static final String TAG = "HciUtil";
    private Activity mActivity;
    private final String mConfigStr;

    public HciUtil(Activity activity) {
        mActivity = activity;

        // 加载信息,返回InitParam, 获得配置参数的字符串
        InitParam initParam = getInitParam();
        mConfigStr = initParam.getStringConfig();
    }

    public boolean initHci() {
        // 初始化
        int errCode = HciCloudSys.hciInit(mConfigStr, mActivity);
        if (errCode != HciErrorCode.HCI_ERR_NONE && errCode != HciErrorCode.HCI_ERR_SYS_ALREADY_INIT) {
            Toast.makeText(mActivity, "hciInit error: " + HciCloudSys.hciGetErrorInfo(errCode), Toast.LENGTH_SHORT).show();
            return false;
        }

        // 获取授权/更新授权文件 :
        errCode = checkAuthAndUpdateAuth();
        if (errCode != HciErrorCode.HCI_ERR_NONE) {
            // 由于系统已经初始化成功,在结束前需要调用方法hciRelease()进行系统的反初始化
            Toast.makeText(mActivity, "CheckAuthAndUpdateAuth error: " + HciCloudSys.hciGetErrorInfo(errCode), Toast.LENGTH_SHORT).show();
            HciCloudSys.hciRelease();
            return false;
        }
        return true;
    }

    /**
     * 加载初始化信息
     *
     * @return 系统初始化参数
     */
    private InitParam getInitParam() {
        String authDirPath = mActivity.getFilesDir().getAbsolutePath();
        // 前置条件:无
        InitParam initparam = new InitParam();
        // 授权文件所在路径,此项必填
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_AUTH_PATH, authDirPath);
        // 是否自动访问云授权,详见 获取授权/更新授权文件处注释
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_AUTO_CLOUD_AUTH, "no");
        // 灵云云服务的接口地址,此项必填
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_CLOUD_URL, ConfigUtil.CLOUD_URL);
        // 开发者Key,此项必填,由捷通华声提供
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_DEVELOPER_KEY, ConfigUtil.DEVELOPER_KEY);
        // 应用Key,此项必填,由捷通华声提供
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_APP_KEY, ConfigUtil.APP_KEY);
        // 配置日志参数
        String sdcardState = Environment.getExternalStorageState();
        if (Environment.MEDIA_MOUNTED.equals(sdcardState)) {
            String sdPath = Environment.getExternalStorageDirectory().getAbsolutePath();
            String packageName = mActivity.getPackageName();
            String logPath = sdPath + File.separator + "sinovoice" + File.separator + packageName + File.separator + "log" + File.separator;
            // 日志文件地址
            File fileDir = new File(logPath);
            if (!fileDir.exists()) {
                fileDir.mkdirs();
            }
            // 日志的路径,可选,如果不传或者为空则不生成日志
            initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_PATH, logPath);
            // 日志数目,默认保留多少个日志文件,超过则覆盖最旧的日志
            initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_COUNT, "5");
            // 日志大小,默认一个日志文件写多大,单位为K
            initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_SIZE, "1024");
            // 日志等级,0=无,1=错误,2=警告,3=信息,4=细节,5=调试,SDK将输出小于等于logLevel的日志信息
            initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_LEVEL, "5");
        }
        return initparam;
    }

    /**
     * 获取授权
     *
     * @return 授权结果
     */
    private int checkAuthAndUpdateAuth() {
        // 获取系统授权到期时间
        int initResult;
        AuthExpireTime objExpireTime = new AuthExpireTime();
        initResult = HciCloudSys.hciGetAuthExpireTime(objExpireTime);
        if (initResult == HciErrorCode.HCI_ERR_NONE) {
            // 显示授权日期,如用户不需要关注该值,此处代码可忽略
            Date date = new Date(objExpireTime.getExpireTime() * 1000);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
            Log.i(TAG, "expire time: " + sdf.format(date));
            if (objExpireTime.getExpireTime() * 1000 > System.currentTimeMillis()) {
                // 已经成功获取了授权,并且距离授权到期有充足的时间(>7天)
                Log.i(TAG, "checkAuth success");
                return initResult;
            }
        }
        // 获取过期时间失败或者已经过期
        initResult = HciCloudSys.hciCheckAuth();
        if (initResult == HciErrorCode.HCI_ERR_NONE) {
            Log.i(TAG, "checkAuth success");
            return initResult;
        } else {
            Log.e(TAG, "checkAuth failed: " + initResult);
            return initResult;
        }
    }
}

封装灵云语音合成能

package kong.qingwei.kqwhcittsdemo;

import android.app.Activity;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;

import com.sinovoice.hcicloudsdk.api.HciCloudSys;
import com.sinovoice.hcicloudsdk.common.AuthExpireTime;
import com.sinovoice.hcicloudsdk.common.HciErrorCode;
import com.sinovoice.hcicloudsdk.common.InitParam;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
 * Created by kqw on 2016/8/12.
 * 初始化灵云语音
 */
public class HciUtil {

    private static final String TAG = "HciUtil";
    private Activity mActivity;
    private final String mConfigStr;

    public HciUtil(Activity activity) {
        mActivity = activity;

        // 加载信息,返回InitParam, 获得配置参数的字符串
        InitParam initParam = getInitParam();
        mConfigStr = initParam.getStringConfig();
    }

    public boolean initHci() {
        // 初始化
        int errCode = HciCloudSys.hciInit(mConfigStr, mActivity);
        if (errCode != HciErrorCode.HCI_ERR_NONE && errCode != HciErrorCode.HCI_ERR_SYS_ALREADY_INIT) {
            Toast.makeText(mActivity, "hciInit error: " + HciCloudSys.hciGetErrorInfo(errCode), Toast.LENGTH_SHORT).show();
            return false;
        }

        // 获取授权/更新授权文件 :
        errCode = checkAuthAndUpdateAuth();
        if (errCode != HciErrorCode.HCI_ERR_NONE) {
            // 由于系统已经初始化成功,在结束前需要调用方法hciRelease()进行系统的反初始化
            Toast.makeText(mActivity, "CheckAuthAndUpdateAuth error: " + HciCloudSys.hciGetErrorInfo(errCode), Toast.LENGTH_SHORT).show();
            HciCloudSys.hciRelease();
            return false;
        }
        return true;
    }

    /**
     * 加载初始化信息
     *
     * @return 系统初始化参数
     */
    private InitParam getInitParam() {
        String authDirPath = mActivity.getFilesDir().getAbsolutePath();
        // 前置条件:无
        InitParam initparam = new InitParam();
        // 授权文件所在路径,此项必填
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_AUTH_PATH, authDirPath);
        // 是否自动访问云授权,详见 获取授权/更新授权文件处注释
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_AUTO_CLOUD_AUTH, "no");
        // 灵云云服务的接口地址,此项必填
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_CLOUD_URL, ConfigUtil.CLOUD_URL);
        // 开发者Key,此项必填,由捷通华声提供
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_DEVELOPER_KEY, ConfigUtil.DEVELOPER_KEY);
        // 应用Key,此项必填,由捷通华声提供
        initparam.addParam(InitParam.AuthParam.PARAM_KEY_APP_KEY, ConfigUtil.APP_KEY);
        // 配置日志参数
        String sdcardState = Environment.getExternalStorageState();
        if (Environment.MEDIA_MOUNTED.equals(sdcardState)) {
            String sdPath = Environment.getExternalStorageDirectory().getAbsolutePath();
            String packageName = mActivity.getPackageName();
            String logPath = sdPath + File.separator + "sinovoice" + File.separator + packageName + File.separator + "log" + File.separator;
            // 日志文件地址
            File fileDir = new File(logPath);
            if (!fileDir.exists()) {
                fileDir.mkdirs();
            }
            // 日志的路径,可选,如果不传或者为空则不生成日志
            initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_PATH, logPath);
            // 日志数目,默认保留多少个日志文件,超过则覆盖最旧的日志
            initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_COUNT, "5");
            // 日志大小,默认一个日志文件写多大,单位为K
            initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_SIZE, "1024");
            // 日志等级,0=无,1=错误,2=警告,3=信息,4=细节,5=调试,SDK将输出小于等于logLevel的日志信息
            initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_LEVEL, "5");
        }
        return initparam;
    }

    /**
     * 获取授权
     *
     * @return 授权结果
     */
    private int checkAuthAndUpdateAuth() {
        // 获取系统授权到期时间
        int initResult;
        AuthExpireTime objExpireTime = new AuthExpireTime();
        initResult = HciCloudSys.hciGetAuthExpireTime(objExpireTime);
        if (initResult == HciErrorCode.HCI_ERR_NONE) {
            // 显示授权日期,如用户不需要关注该值,此处代码可忽略
            Date date = new Date(objExpireTime.getExpireTime() * 1000);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
            Log.i(TAG, "expire time: " + sdf.format(date));
            if (objExpireTime.getExpireTime() * 1000 > System.currentTimeMillis()) {
                // 已经成功获取了授权,并且距离授权到期有充足的时间(>7天)
                Log.i(TAG, "checkAuth success");
                return initResult;
            }
        }
        // 获取过期时间失败或者已经过期
        initResult = HciCloudSys.hciCheckAuth();
        if (initResult == HciErrorCode.HCI_ERR_NONE) {
            Log.i(TAG, "checkAuth success");
            return initResult;
        } else {
            Log.e(TAG, "checkAuth failed: " + initResult);
            return initResult;
        }
    }
}

使用

初始化

// 灵云语音工具类
HciUtil mInitTts = new HciUtil(this);
// 初始化灵云语音
boolean isInitHci = mInitTts.initHci();
if (isInitHci) { // 初始化成功
    // 语音合成能力工具类
    mTtsUtil = new TtsUtil(this);
    // 初始化语音合成
    isInitPlayer = mTtsUtil.initPlayer(this);
}

语音合成

/**
 * 开始合成
 *
 * @param view v
 */
public void synth(View view) {
    if (!isInitPlayer) {
        Toast.makeText(this, "初始化失败", Toast.LENGTH_SHORT).show();
        return;
    }
    String text = mEditText.getText().toString();
    if (TextUtils.isEmpty(text)) {
        Toast.makeText(this, "合成内容为空", Toast.LENGTH_SHORT).show();
        return;
    }
    mTtsUtil.synth(text);
}

语音合成回调

// 语音合成的回调
@Override
public void onPlayerEventStateChange(TTSCommonPlayer.PlayerEvent playerEvent) {

}

@Override
public void onPlayerEventProgressChange(TTSCommonPlayer.PlayerEvent playerEvent, int i, int i1) {

}

@Override
public void onPlayerEventPlayerError(TTSCommonPlayer.PlayerEvent playerEvent, int i) {

}

灵云离线语音合成

离线语音合成相对也比较简单,首先要下载离线资源,下载完以后是一个zip包,解压缩里面有类似这样的几个文件

下载离线资源文件

给每个文件重命名,前面加lib,后面加后缀.so,然后导入工程

重命名

导入资源文件以后,修改capKey为离线语音合成

public static final String CAP_KEY = "tts.local.synth";

注:灵云的离线语音能力,第一次使用的时候也是需要有一个联网授权的过程,授权成功以后,即可在授权期内使用离线语音能力。

没有更多推荐了,返回首页