开发一个会叫自己“爷爷”的“孙子”,是一种什么样的体验?

独居的生活很是无聊,如果有什么成精的东西和我聊聊天就好了…

“独居的生活很是无聊,如果有什么成精的东西和我聊聊天就好了”,基于这个独特的想法,我,决定让某一样东西成精,赋予它阅读指定文字的能力。

目前市面上有两款产品可以较好的实现语音相关的功能,分别是百度语音识别与科大讯飞语音识别,在这两个中我选科大讯飞。如果Python、Node.js、C#、C++、PHP作为你的开发语言,百度语音识别可以找到相关文档。如果开发的语音识别是搭载着HarmonyOS系统上,可以选科大讯飞。二者各有所长、各有所短。

在操作前需要先前往官网下载语音相关的demo,demo里面有我们集成语音技术必要的资源。

开发一个会叫自己“爷爷”的“孙子”,是一种什么样的体验?
下载后,将assets、libs文件夹拷贝至自己的项目,在 AndroidManifest.xml静态声明部分权限。

<uses-permission android:name="android.permission.INTERNET"/>

<uses-permission android:name="android.permission.RECORD_AUDIO"/>

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

<uses-permission android:name="android.permission.WRITE_SETTINGS"/>

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

接着动态申请危险权限:


private void initPermission() {
   String permissions[] = {Manifest.permission.RECORD_AUDIO,
           Manifest.permission.WRITE_EXTERNAL_STORAGE
   };
   ArrayList<String> toApplyList = new ArrayList<String>();

   for (String perm : permissions) {
       if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(this,
               perm)) {
           toApplyList.add(perm);
       }
   }
   String tmpList[] = new String[toApplyList.size()];
   if (!toApplyList.isEmpty()) {
       ActivityCompat.requestPermissions(this, toApplyList.toArray(tmpList), 123);
   }
}

使用科大讯飞语音识别需要初始化,初始化即创建语音配置对象,只有初始化后才可以使用MSC的各项服务。建议将初始化放在程序入口处(如Application、Activity的onCreate方法)。


SpeechUtility.createUtility(this, "appid=" + getString(R.string.app_id));

实现语音识别监听


private RecognizerDialogListener mRecognizerDialogListener = new RecognizerDialogListener() {
    public void onResult(RecognizerResult results, boolean isLast) {
        if (!isLast) {

        }
    }

    public void onError(SpeechError error) {
        Toast.makeText(MainActivity.this, error.getPlainDescription(true),
                Toast.LENGTH_SHORT).show();
    }
};

接着就是 call 孙子啦

public void call() {

    mIat = SpeechRecognizer.createRecognizer(this, mInitListener);
    if (null == mIat) {

        Toast.makeText(this, "创建对象失败,请确认 libmsc.so 放置正确,且有调用 createUtility 进行初始化",
                Toast.LENGTH_SHORT).show();
        return;
    }

    mIatResults.clear();

    mIat.setParameter(SpeechConstant.PARAMS, null);

    mIat.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);

    mIat.setParameter(SpeechConstant.RESULT_TYPE, "json");

    if (language.equals("zh_cn")) {
        String lag = mSharedPreferences.getString("iat_language_preference",
                "mandarin");

        mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");

        mIat.setParameter(SpeechConstant.ACCENT, lag);
    } else {
        mIat.setParameter(SpeechConstant.LANGUAGE, language);
    }

    mIat.setParameter("view_tips_plain", "false");

    mIat.setParameter(SpeechConstant.VAD_BOS, mSharedPreferences.getString(
            "iat_vadbos_preference", "4000"));

    mIat.setParameter(SpeechConstant.VAD_EOS, mSharedPreferences.getString(
            "iat_vadeos_preference", "1000"));

    mIat.setParameter(SpeechConstant.ASR_PTT, mSharedPreferences.getString(
            "iat_punc_preference", "1"));

    mIat.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
    mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH,
            Environment.getExternalStorageDirectory() + "/msc/iat.wav");
    mIatDialog.setListener(mRecognizerDialogListener);
    mIatDialog.show();
}

看到 show()方法没?随着 show()方法的执行,语音识别功能也就完成了喔

开发一个会叫自己“爷爷”的“孙子”,是一种什么样的体验?
爷爷问,这时孙子无法回答爷爷的话,对于爷爷的问候,只能默默地看着爷爷,像个木头人一样不知所措。
[En]

Grandpa asked, at this time the grandson can not reply to Grandpa’s words, for Grandpa’s greeting, can only silently look at Grandpa, like a wooden man like at a loss.

当孙子说话时,你需要使用语音合成。语音合成与语音听写相反,是将一段文字转换成语音,可以根据需要合成不同音色、速度和语调的声音,使机器说话像人一样。不仅如此,还可以根据个人需要,更换孙辈,高大上的孙辈可以经常认国语,多语种哦。

[En]

When Sun Tzu speaks, you need to use speech synthesis. Speech synthesis, contrary to speech dictation, converts a section of text into speech, which can synthesize sounds with different timbre, speed and intonation according to needs, making the machine speak like a human. Not only that, but also according to personal needs, change grandchildren, high-end grandchildren can often recognize national languages, multi-language oh.

孙子怎么知道该回复什么信息呢?

[En]

How does Sun Tzu know what message to reply to?

回复消息是我们预先设置的,语音不同,回复内容也不一样。语音识别和命令词识别是有区别的。命令词识别是通过文本输出识别语音并提取预设关键字。另一方面,语音识别将一系列语音翻译成文本并直接输出。

[En]

The reply message is we preset in advance, the speech is different, the reply content is not the same. There is a difference between speech recognition and command word recognition. Command word recognition is to recognize speech and extract preset keywords through text output. On the other hand, speech recognition translates a series of speech into text and outputs them directly.

我把爷爷发言与孙子的答复提前插入 Sqlite,待语音识别到的文本与存储在 Sqlite里爷爷的发言一致时,取对应的答案,通过语音输出,孙子也就不再是一个哑巴了。

那么,让我们来实现孙子的声音回复。

[En]

So, let’s realize Sun Tzu’s voice reply.


private void grandsonAnswer(String answer) {

    cloudVoicersEntries = getResources().getStringArray(R.array.voicer_cloud_entries);
    cloudVoicersValue = getResources().getStringArray(R.array.voicer_cloud_values);

    mTts = SpeechSynthesizer.createSynthesizer(this, mInitListener);

    mTts.setParameter(SpeechConstant.PARAMS, null);

    mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);

    mTts.setParameter(SpeechConstant.VOICE_NAME, voicerCloud);

    mTts.setParameter(SpeechConstant.SPEED, "50");

    mTts.setParameter(SpeechConstant.PITCH, "50");

    mTts.setParameter(SpeechConstant.VOLUME, "50");

    mTts.setParameter(SpeechConstant.STREAM_TYPE, "3");

    mTts.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "true");

    mTts.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");

    mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH,
            Environment.getExternalStorageDirectory() + "/msc/tts.wav");
    int code = mTts.startSpeaking(answer, mTtsListener);
    if (code != ErrorCode.SUCCESS) {
        Toast.makeText(this, "语音合成失败,错误码: " + code + ",请点击网址https://www.xfyun" +
                ".cn/document/error-code查询解决方案", Toast.LENGTH_SHORT).show();
    }
}

代码copy一下运行起来便是这样的结果了 ↓

开发一个会叫自己“爷爷”的“孙子”,是一种什么样的体验?
如果您希望听到您的孙子调用Gardpa,只需在调用该方法时传递一个Gardpa参数即可。
[En]

If you want to hear your grandson call Grandpa, just pass a Grandpa parameter when you call the method.

public void callGrandpa(View view) {
    grandsonAnswer("爷爷~");
}

开发一个会叫自己“爷爷”的“孙子”,是一种什么样的体验?
我厌倦了听我孙子的声音,我可以把它换成我孙女的声音。
[En]

I’m tired of hearing my grandson’s voice, and I can switch it to my granddaughter’s voice.


public void update(View view) {
   new AlertDialog.Builder(this).setTitle("更换孙子或孙女")
           .setSingleChoiceItems(cloudVoicersEntries,
                   selectedNumCloud,
                   new DialogInterface.OnClickListener() {
                       public void onClick(DialogInterface dialog,
                                           int which) {
                           voicerCloud = cloudVoicersValue[which];
                           selectedNumCloud = which;
                           dialog.dismiss();
                       }
                   }).show();
}

可切换的孙子、孙女


 <string-array name="voicer_cloud_entries">
     <item>小燕item>
     <item>小宇item>
     <item>凯瑟琳item>
     <item>亨利item>
     <item>玛丽item>
     <item>小研item>
     <item>小琪item>
     <item>小峰item>
     <item>小梅item>
     <item>小莉item>
     <item>小蓉item>
     <item>小芸item>
     <item>小坤item>
     <item>小强 item>
     <item>小莹item>
     <item>小新item>
     <item>楠楠item>
     <item>老孙item>
 string-array>
 <string-array name="voicer_cloud_values">
     <item>xiaoyanitem>
     <item>xiaoyuitem>
     <item>catherineitem>
     <item>henryitem>
     <item>vimaryitem>
     <item>vixyitem>
     <item>xiaoqiitem>
     <item>vixfitem>
     <item>xiaomeiitem>
     <item>xiaolinitem>
     <item>xiaorongitem>
     <item>xiaoqianitem>
     <item>xiaokunitem>
     <item>xiaoqiangitem>
     <item>vixyingitem>
     <item>xiaoxinitem>
     <item>nannanitem>
     <item>vilsitem>
 string-array>

到这里,能想到的功能也就都完成了,附上demo运行GIF

开发一个会叫自己“爷爷”的“孙子”,是一种什么样的体验?
最后,不要忘记,当接口被破坏时,相应的变量应该释放内存。
[En]

Finally, don’t forget that when the interface is destroyed, the corresponding variables should release memory.

@Override
protected void onDestroy() {
    super.onDestroy();
    if( null != mIat ){

        mIat.cancel();
        mIat.destroy();
    }
    if( null != mTts ){
        mTts.stopSpeaking();

        mTts.destroy();
    }
}

本文代码已上传至:开发一个会叫自己”爷爷”的”孙子”,是一种什么样的体验?

参考文献:
1、Android 科大讯飞语音识别(详细步骤+源码)
2、科大讯飞在线语音听写 Android SDK 文档
3、科大讯飞在线语音合成 Android SDK 文档

Original: https://blog.csdn.net/baidu_41616022/article/details/119580034
Author: 宾有为
Title: 开发一个会叫自己“爷爷”的“孙子”,是一种什么样的体验?

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/512717/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球