需要全部代码请点赞关注收藏后评论区留言私信~~~

一、需求描述

想必大家都见过商场里的智能语音机器人,你对它提问时它可以自动回答你的问题,接下来我们也实现这样一个机器人,它依靠语音技术完成问询服务 基本功能如下

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】实战项目之实现你问我答的智能语音机器人(超详细 附源码和演示视频)相关推荐

  1. 【Android App】实现在线语音合成功能(使用云知声平台和WebSocket 超详细 附源码)

    需要源码和Jar包请点赞关注收藏后评论区留下QQ~~~ 一.在线语音合成 虽然国产智能机大多集成了中文语音引擎,但是系统自带的语音工具无法满足商用要求,功能单一,所以势必引入第三方的语音引擎,依靠第三 ...

  2. Android App开发实战项目之仿喜马拉雅的听说书App实现(超详细 附源码和演示视频)

    需要全部源码请点赞关注收藏后评论区留下QQ~~~ 一.需求分析 用户不仅能在平台上收听音频,还能成为内容创作者,总之长音频分享平台需要满足两种角色的使用:一种是作为内容创作者发布自己的音频,另一种是作 ...

  3. 【Android +Tensroflow Lite】实现从基于机器学习语音中识别指令讲解及实战(超详细 附源码和演示视频)

    需要源码和配置文件请点赞关注收藏后评论区留言~~~ 一.基于机器学习的语音推断 Tensorflow基于分层和模块化的设计思想,整个框架以C语言的编程接口为界,分为前端和后端两大部分 Tensorfl ...

  4. 【Android App】在线语音识别功能实现(使用云知声平台与WebSocket 超详细 附源码)

    需要源码和相关资源请点赞关注收藏后评论区留下QQ~~~ 一.在线语音识别 云知声的语音识别同样采用WebSocket接口,待识别的音频流支持MP3和PCM两种格式,对于在线语音识别来说,云知声使用JS ...

  5. 【Android App】实战项目之虚拟现实(VR)的全景相册(附源码和演示视频 可用于学习和大作业)

    需要源码请点赞关注收藏后评论区留言私信~~~ 不管是绘画还是摄影,都是把三维的物体投影到平面上,其实仍旧呈现二维的模拟画面. 随着科技的发展,传统的成像手段越来越凸显出局限性,缘由在于人们需要一种更逼 ...

  6. Android App开发实战项目之模仿美图秀秀的抠图工具(附源码和演示视频 简单易懂 可直接使用)

    需要图片集和源码请点赞关注收藏后评论区留言~~~ 所谓抠图神器,就是从一副图片中扣出用户想要的某块区域 一.需求描述 美图的修图功能如此强大,离不开专业的图片加工技术,抠图便是其中重要的一项功能.在A ...

  7. Android App开发实战项目之仿手机QQ动感影集动画播放(附源码和演示视频 可直接使用)

    需要图片集和源码请点赞关注收藏后评论区留言~~~ 动感影集就是只要用户添加一张图片,动感影集就能给每张图片渲染不同的动画效果,让原本静止的图片变得活泼起来,辅以各种精致的动画特效,营造一种赏心悦目的感 ...

  8. 【Android App】实战项目之仿微信的私信和群聊App(附源码和演示视频 超详细必看)

    需要全部代码请点赞关注收藏后评论区留言私信~~~ 手机最开始用于通话,后来增加了短信功能,初步满足了人与人之间的沟通需求.然而短信只能发文字,于是出现了能够发图片的彩信,但不管短信还是彩信,资费都太贵 ...

  9. Android App开发语音处理之系统自带的语音引擎、文字转语音、语音识别的讲解及实战(超详细 附源码)

    需要源码请点赞关注收藏后评论区留下QQ~~~ 一.系统自带的语音引擎 语音播报的本质是将书面文字转换成自然语言的音频流,这个转换操作被称作语音合成,又称TTS(从文本到语音)在转换过程中,为了避免机械 ...

最新文章

  1. Lnmp安装与配置笔记
  2. 基于CNN的图像缺陷分类
  3. Android NDK环境搭建
  4. anaconda pycharm 动手学深度学习环境配置
  5. 集合还有这么优雅的运算法?
  6. C++ 标准库 vector list map使用方法
  7. mongoose如何发送html页面,Mongoose/Express/Nodejs尝试从服务器到html传递变量
  8. bootstrap项目实例_精选开源SpringBoot项目:涵盖权限、搜索、秒杀、支付!
  9. iot开源_Android ROM开源,新的IoT应用程序以及更多新闻
  10. oracle财务软件报表,甲骨文推出Oracle 财务管理分析软件
  11. 七天学完Vue之第四天学习笔记(ref获取dom元素和组件以及路由的讲解)
  12. 小型电商平台的项目估算
  13. 系统分析与设计之用例图
  14. 关系数据模型的三个组成部分(关系数据模型的三个组成部分)
  15. 擎天哥as3教程系列第四回——设计模式运用自如
  16. 5G、LPWAN、SDN、NFV、TSN…一文带你看懂物联网“网”的本质
  17. Linux中ifconfig command not found
  18. angular基础学习
  19. 如何提取出word里的图片
  20. word2016如何加载endnote x7,如何连接word和endnote

热门文章

  1. 贝壳后台开发面经(22 届春招)
  2. 【istioctl】multicluster mesh 管理源码走读
  3. 微软Windows CEO梅尔森跟全体员工告别
  4. 华为RS3 封层模型及以太网帧结构
  5. java封神OL_MobaXterm:远程终端登录软件封神选手
  6. 3月份,计算机保研er应该做好哪些准备?
  7. 数学类笔试题(四分位数、数据规约和协方差)
  8. 数据集成平台,多数据统一存储和管理
  9. Cocos Creator | 挤水果小游戏实现 ( 二 )
  10. Android日历只显示年月,只显示年