【Android App】实战项目之实现你问我答的智能语音机器人(超详细 附源码和演示视频)
需要全部代码请点赞关注收藏后评论区留言私信~~~
一、需求描述
想必大家都见过商场里的智能语音机器人,你对它提问时它可以自动回答你的问题,接下来我们也实现这样一个机器人,它依靠语音技术完成问询服务 基本功能如下
1:接收人们的对话语音 并从语音中识别问题文本
2:对问题文本进行语义分析 判断本次提问想问什么 对应的答案又是什么 至于提问与答案的对应关系 既能由系统自动关联 也可以由用户手动关联
3:把答案文本合成为语音数据,再播放这段音频
二、功能分析
机器人较少通过控件与用户交互,主要通过语音与用户交互,主要集成了以下技术
1:数据库框架Room
2:定位服务 机器人回答一些问题依赖于定位服务
3:网络通信框架 根据经纬度查询地址 根据城市名称获取城市代码天气等等
4:原始音频录制 机器人识别语音的时候,要不停的监听原始音频,再发给第三方语音平台处理
5:语音识别与语音合成 这里选用云知声第三方语音平台 它不但提供了语音识别与语音合成功能 而且集成比较方便
6:WebSocket接口
7:中文转拼音
下面介绍一下源码之间模块的关系
1:RobotActivity 机器人的交互界面 机器人在此聆听用户的提问并回答问题
2:QuestionEditActivity 自定义问答的编辑页面 既支持增加新问答 也支持编辑现有问答 还能切换到问答详情的浏览页面
3:QuestionListActivity 自定义问答的列表页面
4:getAddressTask 获得详细地址的异步任务
5:getCityCodeTask 获取城市代码的异步任务
6:getWeatherTask 获取城市天气的异步任务
业务逻辑中主要步骤如下
1:首次运行时加载初始问答
2:侦听用户的提问并作答
3:判断用户的提问要怎么回答
三、效果展示
使用机器人前确保手机已经联网,并且开启了定位功能,为了方便观察语音问答的交互结果,机器人会把识别到的问题文本显示在界面上方,把合成后的答案文本显示在界面下方
演示视频如下 也可前往主页观看
Android你问我答机器人
开始界面如下 机器人欢迎你的到来
接着询问今天的天气和住址,机器人高德地图获取当前城市的天气
同样你可以考察一下机器人的计算水平,对于一些简单的计算它能很快给出正确答案
机器人同样可以背诵一部分唐诗宋词
你可以自己对加入问题与回答存入后台数据库,这样下次你问的时候就有了对应得答案
上面添加的问题保存后可以使用
四、代码
部分源码如下 按照上面源码之间对应关系的顺序排列
代码太多此处省略部分 需要全部源码请点赞关注收藏后评论区留言私信~~~
1:主界面类
package com.example.voice;import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;import com.example.voice.bean.CityInfo;
import com.example.voice.constant.RobotConstant;
import com.example.voice.constant.SoundConstant;
import com.example.voice.dao.QuestionDao;
import com.example.voice.entity.PoemInfo;
import com.example.voice.entity.QuestionInfo;
import com.example.voice.task.AsrClientEndpoint;
import com.example.voice.task.GetAddressTask;
import com.example.voice.task.GetCityCodeTask;
import com.example.voice.task.GetWeatherTask;
import com.example.voice.task.TtsClientEndpoint;
import com.example.voice.task.VoiceRecognizeTask;
import com.example.voice.util.SoundUtil;
import com.example.voice.util.SwitchUtil;import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;public class RobotActivity extends AppCompatActivity {private final static String TAG = "RobotActivity";private TextView tv_question; // 声明一个文本视图对象private TextView tv_answer; // 声明一个文本视图对象private String mInitQuestion, mInitAnswer; // 初始的问题,初始的答案private MediaPlayer mMediaPlayer = new MediaPlayer(); // 媒体播放器private LocationManager mLocationMgr; // 声明一个定位管理器对象private boolean isLocated = false; // 是否已经定位private CityInfo mCityInfo; // 城市信息private Map<String, QuestionInfo> mQuestionSystemMap = new HashMap<>(); // 系统自带的问答映射private Map<String, QuestionInfo> mQuestionCustomMap = new HashMap<>(); // 用户添加的问答映射private List<PoemInfo> mPoemList = new ArrayList<>();private QuestionDao questionDao; // 声明一个问答的持久化对象private VoiceRecognizeTask mRecognizeTask; // 声明一个原始音频识别线程对象private boolean isPlaying = false; // 是否正在播放private boolean isComposing = false; // 是否正在合成private long mBeginTime; // 语音识别的开始时间private Timer mTimer = new Timer(); // 语音识别计时器private TimerTask mTimerTask; // 计时任务private Handler mHandler = new Handler(Looper.myLooper()); // 声明一个处理器对象@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_robot);getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // 保持屏幕常亮findViewById(R.id.iv_back).setOnClickListener(v -> finish());TextView tv_title = findViewById(R.id.tv_title);tv_title.setText("小小机器人");tv_question = findViewById(R.id.tv_question);tv_answer = findViewById(R.id.tv_answer);mInitQuestion = tv_question.getText().toString();mInitAnswer = tv_answer.getText().toString();findViewById(R.id.btn_question_list).setOnClickListener(v -> {Intent intent = new Intent(this, QuestionListActivity.class);startActivity(intent);});findViewById(R.id.btn_question_edit).setOnClickListener(v -> {Intent intent = new Intent(this, QuestionEditActivity.class);startActivity(intent);});SwitchUtil.checkLocationIsOpen(this, "需要打开定位功能才能查看定位信息");// 从App实例中获取唯一的问答持久化对象new Thread(() -> {RobotConstant.copySampleFiles(this);runOnUiThread(() -> playVoice(RobotConstant.SAMPLE_PATHS[0])); // 播放欢迎语音}).start(); // 启动线程把资产目录下的欢迎音频文件复制到存储卡new Thread(() -> loadAllPoem()).start(); // 启动线程加载所有诗歌}@Overrideprotected void onRestart() {super.onRestart();tv_question.setText(mInitQuestion);tv_answer.setText(mInitAnswer);playVoice(RobotConstant.SAMPLE_PATHS[0]); // 播放欢迎语音}@Overrideprotected void onStart() {super.onStart();new Thread(() -> loadAllQuestion()).start(); // 启动线程加载所有问答}@Overrideprotected void onStop() {super.onStop();releaseRobot(); // 释放机器人资源}// 释放机器人资源private void releaseRobot() {if (mRecognizeTask != null) {new Thread(() -> mRecognizeTask.cancel()).start(); // 启动取消识别语音的线程}isPlaying = false;if (mMediaPlayer.isPlaying()) { // 如果正在播放mMediaPlayer.stop(); // 停止播放}mTimer.cancel(); // 取消计时器if (mTimerTask != null) {mTimerTask.cancel(); // 取消计时任务}}// 加载所有问答private void loadAllQuestion() {RobotConstant.initSystemQuestion(this, questionDao); // 初始化系统设定的问题List<QuestionInfo> questionList = questionDao.queryAllQuestion(); // 加载所有问答信息for (QuestionInfo item : questionList) {if (item.getType() == 0) { // 系统问答mQuestionSystemMap.put(item.getQuestion(), item);} else { // 用户问答mQuestionCustomMap.put(item.getQuestion(), item);}}Log.d(TAG, "SystemMap.size()="+mQuestionSystemMap.size()+",CustomMap.size()="+mQuestionCustomMap.size());}// 加载所有诗歌private void loadAllPoem() {RobotConstant.initPoetryData(this, questionDao); // 初始化古诗数据mPoemList = questionDao.queryAllPoem(); // 加载所有诗歌信息Log.d(TAG, "mPoemList.size()="+mPoemList.size());}// 播放语音private void playVoice(String audioPath) {Log.d(TAG, "playVoice audioPath="+audioPath);if (mTimerTask != null) {mTimerTask.cancel(); // 取消计时任务}if (isPlaying) {return;}isPlaying = true;findViewById(R.id.iv_robot).setOnClickListener(null);mMediaPlayer.reset(); // 重置媒体播放器// 设置媒体播放器的完成监听器mMediaPlayer.setOnCompletionListener(mp -> new Thread(() -> onlineRecognize()).start());mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); // 设置音频流的类型为音乐try {mMediaPlayer.setDataSource(audioPath); // 设置媒体数据的文件路径mMediaPlayer.prepare(); // 媒体播放器准备就绪mMediaPlayer.start(); // 媒体播放器开始播放} catch (Exception e) {e.printStackTrace();}}// 在线识别实时语音private void onlineRecognize() {// 创建语音识别任务,并指定语音监听器AsrClientEndpoint asrTask = new AsrClientEndpoint(this, "",arg -> checkRecognize((boolean)arg[0], arg[2].toString()));SoundUtil.startSoundTask(SoundConstant.URL_ASR, asrTask); // 启动语音识别任务// 创建一个原始音频识别线程mRecognizeTask = new VoiceRecognizeTask(this, asrTask);mRecognizeTask.start(); // 启动原始音频识别线程isPlaying = false;findViewById(R.id.iv_robot).setOnClickListener(v -> {new Thread(() -> mRecognizeTask.cancel()).start(); // 启动取消识别语音的线程playVoice(RobotConstant.SAMPLE_PATHS[2]); // 播放样本音频});mBeginTime = System.currentTimeMillis();mTimer = new Timer(); // 创建一个录音计时器// 创建一个录音计时任务mTimerTask = new TimerTask() {@Overridepublic void run() {long now = System.currentTimeMillis();Log.d(TAG, "interval="+(now - mBeginTime));if (now - mBeginTime > 10 * 1000) { // 超过10秒,则停止本次识别,重新开始识别mTimer.cancel(); // 取消计时器new Thread(() -> mRecognizeTask.cancel()).start(); // 启动取消识别语音的线程runOnUiThread(() -> tv_answer.setText("我的回答是:"+RobotConstant.SYSTEM_ANSWERS[6]));playVoice(RobotConstant.SAMPLE_PATHS[6]); // 播放样本音频}}};mTimer.schedule(mTimerTask, 0, 1000); // 计时器每隔一秒就检查识别语音是否超时了}// 检查已识别的文本是否为已设定的问题private void checkRecognize(boolean isEnd, String text) {tv_question.setText("您的问题是:"+text);for (Map.Entry<String, QuestionInfo> item : mQuestionCustomMap.entrySet()) {if (text.contains(item.getKey())) { // 匹配用户添加的问题if (!isEnd) { // 尚未结束识别new Thread(() -> mRecognizeTask.cancel()).start(); // 启动取消识别语音的线程} else { // 已经结束识别answerCustomQuestion(item.getValue()); // 回答用户问题}return;}}for (Map.Entry<String, QuestionInfo> item : mQuestionSystemMap.entrySet()) {if (text.matches(item.getKey())) { // 匹配系统自带的问题if (!isEnd) { // 尚未结束识别new Thread(() -> mRecognizeTask.cancel()).start(); // 启动取消识别语音的线程} else { // 已经结束识别answerSystemQuestion(text, item.getValue()); // 回答系统问题}return;}}if (text.matches(RobotConstant.RECITE_PATTERN)) { // 匹配诗歌背诵String[] recites = text.split(RobotConstant.RECITE_PART);if (recites.length < 2) {return;}Log.d(TAG, "content="+recites[1]);if (isEnd) { // 已经结束识别if (mPoemPos == -1) {mPoemPos = RobotConstant.searchPoemPos(recites[1], mPoemPos, mPoemList);}if (mPoemPos != -1) {readPoem(mPoemList.get(mPoemPos)); // // 朗读诗歌}return;}// 查找该诗在列表中的位置int poemPos = RobotConstant.searchPoemPos(recites[1], mPoemPos, mPoemList);if (poemPos > mPoemPos) {mTimerTask.cancel(); // 取消计时任务if (mPoemPos == -1) {mHandler.postDelayed(mHasFindPoem, 2000);}mPoemPos = poemPos;}}}private int mPoemPos = -1; // 诗歌在列表中的位置private Runnable mHasFindPoem = () -> {new Thread(() -> mRecognizeTask.cancel()).start(); // 启动取消识别语音的线程};// 朗读诗歌private void readPoem(PoemInfo poem) {mTimerTask.cancel(); // 取消计时任务mPoemPos = -1;String poemContent = poem.getContent().replace("\\n", "\n");String showText = String.format("%s\n%s\n%s", poem.getTitle(), poem.getAuthor(), poemContent);String answer = String.format("%s,%s。%s", poem.getTitle(), poem.getAuthor(), poemContent);Log.d(TAG, "answerCustomQuestion answer=" + answer);new Thread(() -> mRecognizeTask.cancel()).start(); // 启动取消识别语音的线程runOnUiThread(() -> tv_answer.setText(showText));// 启动在线合成语音的线程new Thread(() -> onlineCompose(poem.getAuthor()+"_"+poem.getTitle(), -1, answer, "")).start();}// 回答系统问题private void answerSystemQuestion(String question, QuestionInfo questionInfo) {mTimerTask.cancel(); // 取消计时任务String answer = questionInfo.getAnswer();Log.d(TAG, "answerSystemQuestion answer="+answer);new Thread(() -> mRecognizeTask.cancel()).start(); // 启动取消识别语音的线程Object[] resultArray = RobotConstant.judgeAnswerResult(question, answer, mCityInfo);int voiceSeq = (int) resultArray[0];String tempText = (String) resultArray[1];String answerText = TextUtils.isEmpty(tempText) ? RobotConstant.SYSTEM_ANSWERS[voiceSeq] : tempText;runOnUiThread(() -> tv_answer.setText("我的回答是:"+answerText));String voicePath = voiceSeq==-1 ? "" : RobotConstant.SAMPLE_PATHS[voiceSeq];Log.d(TAG, "voiceSeq="+voiceSeq+",answerText="+answerText+",voicePath="+voicePath);// 启动在线合成语音的线程new Thread(() -> onlineCompose(answer, voiceSeq, answerText, voicePath)).start();}// 回答用户问题private void answerCustomQuestion(QuestionInfo questionInfo) {mTimerTask.cancel(); // 取消计时任务String answer = questionInfo.getAnswer();Log.d(TAG, "answerCustomQuestion answer=" + answer);new Thread(() -> mRecognizeTask.cancel()).start(); // 启动取消识别语音的线程runOnUiThread(() -> tv_answer.setText("我的回答是:"+answer));// 启动在线合成语音的线程new Thread(() -> onlineCompose(""+questionInfo.getId(), -1, answer, "")).start();}// 在线合成语音private void onlineCompose(String function, int seq, String text, String path) {Log.d(TAG, "onlineCompose function="+function+",text="+text);String voicePath = !TextUtils.isEmpty(path) ? path : String.format("%s/robot/%s.mp3",getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(), function);File file = new File(voicePath);if (file.exists() && seq==-1) { // 不是样本音频,如果已经存在语音文件,就要删除文件,这样才能重新生成新的语音文件file.delete();}if (file.exists()) {playVoice(voicePath); // 播放语音} else if (!isComposing) {isComposing = true;// 创建语音合成任务,并指定语音监听器TtsClientEndpoint task = new TtsClientEndpoint(this, voicePath, text, arg -> {if (Boolean.TRUE.equals(arg[0])) {playVoice(voicePath); // 播放语音isComposing = false;}});SoundUtil.startSoundTask(SoundConstant.URL_TTS, task); // 启动语音合成任务}}@Overrideprotected void onResume() {super.onResume();if (mCityInfo == null) {initLocation(); // 初始化定位服务}}// 初始化定位服务private void initLocation() {Log.d(TAG, "initLocation");// 从系统服务中获取定位管理器mLocationMgr = (LocationManager) getSystemService(Context.LOCATION_SERVICE);Criteria criteria = new Criteria(); // 创建一个定位准则对象// 设置定位精确度。Criteria.ACCURACY_COARSE表示粗略,Criteria.ACCURACY_FIN表示精细criteria.setAccuracy(Criteria.ACCURACY_FINE);criteria.setAltitudeRequired(true); // 设置是否需要海拔信息criteria.setBearingRequired(true); // 设置是否需要方位信息criteria.setCostAllowed(true); // 设置是否允许运营商收费criteria.setPowerRequirement(Criteria.POWER_LOW); // 设置对电源的需求// 获取定位管理器的最佳定位提供者String bestProvider = mLocationMgr.getBestProvider(criteria, true);if (mLocationMgr.isProviderEnabled(bestProvider)) { // 定位提供者当前可用beginLocation(bestProvider); // 开始定位}Log.d(TAG, "isProviderEnabled="+mLocationMgr.isProviderEnabled(bestProvider));}// 开始定位private void beginLocation(String method) {// 检查当前设备是否已经开启了定位功能if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)!= PackageManager.PERMISSION_GRANTED) {Toast.makeText(this, "请授予定位权限并开启定位功能", Toast.LENGTH_SHORT).show();return;}// 设置定位管理器的位置变更监听器mLocationMgr.requestLocationUpdates(method, 300, 0, mLocationListener);// 获取最后一次成功定位的位置信息Location location = mLocationMgr.getLastKnownLocation(method);getAddress(location); // 获取详细地址}// 获取详细地址private void getAddress(Location location) {if (location != null) {// 创建一个根据经纬度查询详细地址的任务GetAddressTask task = new GetAddressTask(this, location, cityInfo -> getCityCode(cityInfo));task.start(); // 启动地址查询任务}}// 获取城市代码private void getCityCode(CityInfo cityInfo) {isLocated = true;mCityInfo = cityInfo;// 创建一个查询城市编码的任务GetCityCodeTask task = new GetCityCodeTask(this, cityInfo, cityCode -> getWeather(cityCode));task.start(); // 启动城市编码查询任务}// 获取天气信息private void getWeather(String city_code) {mCityInfo.city_code = city_code;// 创建一个查询城市天气的任务GetWeatherTask task = new GetWeatherTask(this, city_code, weatherInfo -> {mCityInfo.weather_info = weatherInfo;});task.start(); // 启动城市天气查询任务}// 定义一个位置变更监听器private LocationListener mLocationListener = new LocationListener() {@Overridepublic void onLocationChanged(Location location) {if (!isLocated) {getAddress(location); // 获取详细地址}}@Overridepublic void onProviderDisabled(String arg0) {}@Overridepublic void onProviderEnabled(String arg0) {}@Overridepublic void onStatusChanged(String arg0, int arg1, Bundle arg2) {}};@Overrideprotected void onDestroy() {super.onDestroy();if (mLocationMgr != null) {mLocationMgr.removeUpdates(mLocationListener); // 移除定位管理器的位置变更监听器}releaseRobot(); // 释放机器人资源mMediaPlayer.release(); // 释放媒体播放器}}
2:问题类
package com.example.voice;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;import com.example.voice.dao.QuestionDao;
import com.example.voice.entity.QuestionInfo;import java.io.File;public class QuestionEditActivity extends AppCompatActivity {private final static String TAG = "QuestionEditActivity";private TextView tv_option; // 声明一个文本视图对象private EditText et_question; // 声明一个编辑框对象private EditText et_answer; // 声明一个编辑框对象private LinearLayout ll_view; // 声明一个线性视图对象private TextView tv_question; // 声明一个文本视图对象private TextView tv_answer; // 声明一个文本视图对象private int mQuestionId; // 问答编号private boolean isEditing = false; // 是否为编辑状态private QuestionDao questionDao; // 声明一个问答的持久化对象private QuestionInfo mQuestionInfo; // 问答信息@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_question_edit);mQuestionId = getIntent().getIntExtra("id", -1);findViewById(R.id.iv_back).setOnClickListener(v -> finish());TextView tv_title = findViewById(R.id.tv_title);tv_option = findViewById(R.id.tv_option);et_question = findViewById(R.id.et_question);et_answer = findViewById(R.id.et_answer);ll_view = findViewById(R.id.ll_view);tv_question = findViewById(R.id.tv_question);tv_answer = findViewById(R.id.tv_answer);tv_option.setOnClickListener(v -> {if (mQuestionId==-1 || isEditing) { // 添加或者修改saveQuestion(); // 保存问答信息} else { // 查看详情tv_option.setText("保存");ll_view.setVisibility(View.GONE);}isEditing = !isEditing;});// 从App实例中获取唯一的问答持久化对象questionDao = MainApplication.getInstance().getQuestionDB().questionDao();if (mQuestionId == -1) { // 添加新问答tv_title.setText("添加问答");tv_option.setText("保存");} else { // 查看问答详情tv_title.setText("问答详情");tv_option.setText("编辑");showQuestion(); // 显示问答详情}}// 显示问答详情private void showQuestion() {// 根据编号加载问答信息mQuestionInfo = questionDao.queryQuestionById(mQuestionId);et_question.setText(mQuestionInfo.getQuestion());et_answer.setText(mQuestionInfo.getAnswer());tv_question.setText(mQuestionInfo.getQuestion());tv_answer.setText(mQuestionInfo.getAnswer());ll_view.setVisibility(View.VISIBLE);}// 保存问答信息private void saveQuestion() {String question = et_question.getText().toString();String answer = et_answer.getText().toString();if (TextUtils.isEmpty(question)) {Toast.makeText(this, "请先输入问题描述", Toast.LENGTH_SHORT).show();return;}if (TextUtils.isEmpty(answer)) {Toast.makeText(this, "请先输入回答内容", Toast.LENGTH_SHORT).show();return;}if (mQuestionId == -1) { // 添加来源mQuestionInfo = new QuestionInfo(question, answer, 1);questionDao.insertOneQuestion(mQuestionInfo); // 插入一条问答信息} else { // 查看来源mQuestionInfo.setQuestion(question);mQuestionInfo.setAnswer(answer);questionDao.updateQuestion(mQuestionInfo); // 更新问答信息String voicePath = String.format("%s/robot/%s.mp3",getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(),mQuestionInfo.getId()+"");File voiceFile = new File(voicePath);if (voiceFile.exists()) { // 如果已经存在该问答的语音文件,就要删除原文件,这样下次才会重新合成新的语音文件voiceFile.delete();}}Toast.makeText(this, "成功保存问答信息", Toast.LENGTH_SHORT).show();finish(); // 关闭当前页面}
}
创作不易 觉得有帮助请点赞关注收藏~~~
【Android App】实战项目之实现你问我答的智能语音机器人(超详细 附源码和演示视频)相关推荐
- 【Android App】实现在线语音合成功能(使用云知声平台和WebSocket 超详细 附源码)
需要源码和Jar包请点赞关注收藏后评论区留下QQ~~~ 一.在线语音合成 虽然国产智能机大多集成了中文语音引擎,但是系统自带的语音工具无法满足商用要求,功能单一,所以势必引入第三方的语音引擎,依靠第三 ...
- Android App开发实战项目之仿喜马拉雅的听说书App实现(超详细 附源码和演示视频)
需要全部源码请点赞关注收藏后评论区留下QQ~~~ 一.需求分析 用户不仅能在平台上收听音频,还能成为内容创作者,总之长音频分享平台需要满足两种角色的使用:一种是作为内容创作者发布自己的音频,另一种是作 ...
- 【Android +Tensroflow Lite】实现从基于机器学习语音中识别指令讲解及实战(超详细 附源码和演示视频)
需要源码和配置文件请点赞关注收藏后评论区留言~~~ 一.基于机器学习的语音推断 Tensorflow基于分层和模块化的设计思想,整个框架以C语言的编程接口为界,分为前端和后端两大部分 Tensorfl ...
- 【Android App】在线语音识别功能实现(使用云知声平台与WebSocket 超详细 附源码)
需要源码和相关资源请点赞关注收藏后评论区留下QQ~~~ 一.在线语音识别 云知声的语音识别同样采用WebSocket接口,待识别的音频流支持MP3和PCM两种格式,对于在线语音识别来说,云知声使用JS ...
- 【Android App】实战项目之虚拟现实(VR)的全景相册(附源码和演示视频 可用于学习和大作业)
需要源码请点赞关注收藏后评论区留言私信~~~ 不管是绘画还是摄影,都是把三维的物体投影到平面上,其实仍旧呈现二维的模拟画面. 随着科技的发展,传统的成像手段越来越凸显出局限性,缘由在于人们需要一种更逼 ...
- Android App开发实战项目之模仿美图秀秀的抠图工具(附源码和演示视频 简单易懂 可直接使用)
需要图片集和源码请点赞关注收藏后评论区留言~~~ 所谓抠图神器,就是从一副图片中扣出用户想要的某块区域 一.需求描述 美图的修图功能如此强大,离不开专业的图片加工技术,抠图便是其中重要的一项功能.在A ...
- Android App开发实战项目之仿手机QQ动感影集动画播放(附源码和演示视频 可直接使用)
需要图片集和源码请点赞关注收藏后评论区留言~~~ 动感影集就是只要用户添加一张图片,动感影集就能给每张图片渲染不同的动画效果,让原本静止的图片变得活泼起来,辅以各种精致的动画特效,营造一种赏心悦目的感 ...
- 【Android App】实战项目之仿微信的私信和群聊App(附源码和演示视频 超详细必看)
需要全部代码请点赞关注收藏后评论区留言私信~~~ 手机最开始用于通话,后来增加了短信功能,初步满足了人与人之间的沟通需求.然而短信只能发文字,于是出现了能够发图片的彩信,但不管短信还是彩信,资费都太贵 ...
- Android App开发语音处理之系统自带的语音引擎、文字转语音、语音识别的讲解及实战(超详细 附源码)
需要源码请点赞关注收藏后评论区留下QQ~~~ 一.系统自带的语音引擎 语音播报的本质是将书面文字转换成自然语言的音频流,这个转换操作被称作语音合成,又称TTS(从文本到语音)在转换过程中,为了避免机械 ...
最新文章
- Lnmp安装与配置笔记
- 基于CNN的图像缺陷分类
- Android NDK环境搭建
- anaconda pycharm 动手学深度学习环境配置
- 集合还有这么优雅的运算法?
- C++ 标准库 vector list map使用方法
- mongoose如何发送html页面,Mongoose/Express/Nodejs尝试从服务器到html传递变量
- bootstrap项目实例_精选开源SpringBoot项目:涵盖权限、搜索、秒杀、支付!
- iot开源_Android ROM开源,新的IoT应用程序以及更多新闻
- oracle财务软件报表,甲骨文推出Oracle 财务管理分析软件
- 七天学完Vue之第四天学习笔记(ref获取dom元素和组件以及路由的讲解)
- 小型电商平台的项目估算
- 系统分析与设计之用例图
- 关系数据模型的三个组成部分(关系数据模型的三个组成部分)
- 擎天哥as3教程系列第四回——设计模式运用自如
- 5G、LPWAN、SDN、NFV、TSN…一文带你看懂物联网“网”的本质
- Linux中ifconfig command not found
- angular基础学习
- 如何提取出word里的图片
- word2016如何加载endnote x7,如何连接word和endnote