最近在做Android语音播报功能(TTS),现总结如下:(ps:demo代码地址:https://github.com/giserlong/TTS_DEMO

一.Android原生接口

用Android原生接口TextToSpeech,简单易用,但是一般情况下不支持中文,需自己下载讯飞语音+ 等中文引擎,并设置为系统默认tts,方可正常播报中文,关键代码如下:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_native);
//初始化TTS
tts = new TextToSpeech(this, this);
//获取控件
speechText = (EditText)findViewById(R.id.speechTextView); speechButton = (Button)findViewById(R.id.speechButton);
//为button添加监听
speechButton.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v){
// TODO Auto-generated method stub
tts.speak(speechText.getText().toString(), TextToSpeech.QUEUE_FLUSH, null);
}
});
} @Override
public void onInit(int status){
// 判断是否转化成功
if (status == TextToSpeech.SUCCESS){
//tts.getCurrentEngine();
//默认设定语言为中文,原生的android貌似不支持中文。
int result = tts.setLanguage(Locale.CHINA);
if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED){
tts.setLanguage(Locale.US);
Toast.makeText(this,"不支持中文,已自动设置为英文",Toast.LENGTH_SHORT).show();
Log.d("ss","");
}else{
Toast.makeText(this,"已自动设置为中文",Toast.LENGTH_SHORT).show();
Log.d("ss","");
}
}
}

  二.百度离在线融合SDK

注册百度智能云开发者账号后,添加语音合成应用,填写包名等相关信息后,生成key及APPID等信息:

激活SDK需此关键信息,还需下载对应SDK,并添加至项目中,引用相关jar包,添加对应so库至asset

关键代码如下:

package com.yupont.www.myapplication;

import android.content.Context;
import android.os.Environment; import com.baidu.tts.client.SpeechSynthesizer;
import com.baidu.tts.client.SpeechSynthesizerListener;
import com.baidu.tts.client.TtsMode; import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream; /**
* <p>文件描述:<p>
* <p>作者:Mark<p>
* <p>创建时间:2019/5/23<p>
* <p>更改时间:2019/5/23<p>
* <p>版本号:1<p>
*/
public class BaiDuSpeechUtil {
private final String TAG = this.getClass().getSimpleName();
private SpeechSynthesizer mSpeechSynthesizer;
private String mSampleDirPath;
private static final String SAMPLE_DIR_NAME = "baiduTTS";
//-------以下全是在assets下的文件,使用离线时必须全部copy到手机中方可使用----start--
private static final String SPEECH_FEMALE_MODEL_NAME = "bd_etts_common_speech_f7_mand_eng_high_am-mix_v3.0.0_20170512.dat";
private static final String SPEECH_MALE_MODEL_NAME = "bd_etts_common_speech_m15_mand_eng_high_am-mix_v3.0.0_20170505.dat";
private static final String TEXT_MODEL_NAME = "bd_etts_text.dat";
private static final String ENGLISH_SPEECH_FEMALE_MODEL_NAME = "bd_etts_speech_female_en.dat";
private static final String ENGLISH_SPEECH_MALE_MODEL_NAME = "bd_etts_speech_male_en.dat";
private static final String ENGLISH_TEXT_MODEL_NAME = "bd_etts_text_en.dat"; //--------end------------------------------------------------------------- private static BaiDuSpeechUtil baiDuSpeechUtil = null;
public static BaiDuSpeechUtil getInstance(){
if(baiDuSpeechUtil == null) {
synchronized (BaiDuSpeechUtil.class) {
if(baiDuSpeechUtil == null) {
baiDuSpeechUtil = new BaiDuSpeechUtil();
}
}
}
return baiDuSpeechUtil;
} /**
* 初始化百度语音资源
* @param context
*/
public void setInitialEnv(Context context) {
initialEnv(context);
}
/**
* 初始化百度语音播报相关
* @param context
*/
public void setInitialTts(Context context, SpeechSynthesizerListener speechSynthesizerListener){
initialTts(context,speechSynthesizerListener);
} private void initialEnv(Context context) {
// long start_time= System.currentTimeMillis();
if (mSampleDirPath == null) {
String sdcardPath = Environment.getExternalStorageDirectory().toString();
mSampleDirPath = sdcardPath + "/" + SAMPLE_DIR_NAME;
}
makeDir(mSampleDirPath);
copyFromAssetsToSdcard(context,false, SPEECH_FEMALE_MODEL_NAME, mSampleDirPath + "/" + SPEECH_FEMALE_MODEL_NAME);
copyFromAssetsToSdcard(context,false, SPEECH_MALE_MODEL_NAME, mSampleDirPath + "/" + SPEECH_MALE_MODEL_NAME);
copyFromAssetsToSdcard(context,false, TEXT_MODEL_NAME, mSampleDirPath + "/" + TEXT_MODEL_NAME);
copyFromAssetsToSdcard(context,false, "english/" + ENGLISH_SPEECH_FEMALE_MODEL_NAME, mSampleDirPath + "/"
+ ENGLISH_SPEECH_FEMALE_MODEL_NAME);
copyFromAssetsToSdcard(context,false, "english/" + ENGLISH_SPEECH_MALE_MODEL_NAME, mSampleDirPath + "/"
+ ENGLISH_SPEECH_MALE_MODEL_NAME);
copyFromAssetsToSdcard(context,false, "english/" + ENGLISH_TEXT_MODEL_NAME, mSampleDirPath + "/"
+ ENGLISH_TEXT_MODEL_NAME); // Log.d(TAG,"initialEnv cost:"+ (System.currentTimeMillis()-start_time));
} private void makeDir(String dirPath) {
File file = new File(dirPath);
if (!file.exists()) {
file.mkdirs();
}
} /**
* 将sample工程需要的资源文件拷贝到SD卡中使用(授权文件为临时授权文件,请注册正式授权)
* 主要是在离线时候用到,只需执行一次即可,这里写的不严谨,应该去判断一下离线用的那些文件,sd卡是否存在,如果不存在,则copy,如果存在则无需在copy,可在子线程操作
* @param isCover 是否覆盖已存在的目标文件
* @param source
* @param dest
*/
private void copyFromAssetsToSdcard(Context context, boolean isCover, String source, String dest) {
File file = new File(dest);
if (isCover || (!isCover && !file.exists())) {
InputStream is = null;
FileOutputStream fos = null;
try {
is = context.getAssets().open(source);
String path = dest;
fos = new FileOutputStream(path);
byte[] buffer = new byte[1024];
int size = 0;
while ((size = is.read(buffer, 0, 1024)) != -1) {
fos.write(buffer, 0, size);
}
fos.flush(); } catch (Exception e) {
e.printStackTrace();
} finally { if (is != null) {
try {
is.close();
} catch (Exception e) {
e.printStackTrace();
} }
if (fos != null) {
try {
is.close();
} catch (Exception e) {
e.printStackTrace();
}
} }
} }
//此方法可在子线程中操作,由于这个初始化过程比较费时,大概在1s左右,看项目需求而定,如果是进入界面就必须播放(伴随UI改变的)的,在UI线程,如无其他特殊要求,放在子线程中即可
private void initialTts(Context context,SpeechSynthesizerListener speechSynthesizerListener) {
// long start_time= System.currentTimeMillis();
mSpeechSynthesizer = SpeechSynthesizer.getInstance();
mSpeechSynthesizer.setContext(context);
mSpeechSynthesizer.setSpeechSynthesizerListener(speechSynthesizerListener);
mSpeechSynthesizer.setApiKey(Config.appKey_baidu, Config.secret_baidu);
mSpeechSynthesizer.setAppId(Config.appID_baidu); // 文本模型文件路径 (离线引擎使用)
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, mSampleDirPath + "/"
+ TEXT_MODEL_NAME);
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, mSampleDirPath + "/"
+ SPEECH_FEMALE_MODEL_NAME);
// 本地授权文件路径,如未设置将使用默认路径.设置临时授权文件路径,LICENCE_FILE_NAME请替换成临时授权文件的实际路径,仅在使用临时license文件时需要进行设置,如果在[应用管理]中开通了正式离线授权,不需要设置该参数,建议将该行代码删除(离线引擎)
// 如果合成结果出现临时授权文件将要到期的提示,说明使用了临时授权文件,请删除临时授权即可。 // 发音人(在线引擎),可用参数为0,1,2,3。。。(服务器端会动态增加,各值含义参考文档,以文档说明为准。0--普通女声,1--普通男声,2--特别男声,3--情感男声。。。)
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, "0");
// 设置Mix模式的合成策略, //mix模式下,wifi使用在线合成,非wifi使用离线合成)
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_MIX_MODE, SpeechSynthesizer.MIX_MODE_HIGH_SPEED_SYNTHESIZE_WIFI);
// if(SystemUtil.isNetWorkConnected(getCurrentActivity())) {
// // AuthInfo接口用于测试开发者是否成功申请了在线或者离线授权,如果测试授权成功了,可以删除AuthInfo部分的代码(该接口首次验证时比较耗时),不会影响正常使用(合成使用时
// AuthInfo authInfo=this.mSpeechSynthesizer.auth(TtsMode.MIX);
//
// if (authInfo.isSuccess()){
// toPrint("auth success");
// }else{
// String errorMsg=authInfo.getTtsError().getDetailMessage();
// toPrint("auth failed errorMsg=" + errorMsg);
// }
// } // 初始化tts
mSpeechSynthesizer.initTts(TtsMode.MIX);
// 加载离线英文资源(提供离线英文合成功能)
//int result = mSpeechSynthesizer.loadEnglishModel(mSampleDirPath + "/" + ENGLISH_TEXT_MODEL_NAME, mSampleDirPath + mSampleDirPath + "/" + ENGLISH_SPEECH_FEMALE_MODEL_NAME);
// Log.d(TAG,"initialTts cost:"+ (System.currentTimeMillis()-start_time));
int result = mSpeechSynthesizer.loadModel(mSampleDirPath + "/" + TEXT_MODEL_NAME, mSampleDirPath + mSampleDirPath + "/" + SPEECH_FEMALE_MODEL_NAME);
if(result<0){
result++;
}
} /**
* 播报的文字
* @param content
*/
public void speakText(String content) {
try{
if(mSpeechSynthesizer != null) {
int result = mSpeechSynthesizer.speak(content);
if (result < 0) {
// Log.d(TAG,"error,please look up error code in doc or URL:http://yuyin.baidu.com/docs/tts/122 ");
}
}
}catch (Exception e) {
e.printStackTrace();
} } /**
* 暂停
*/
public void pauseSpeechSynthesizer(){
if(mSpeechSynthesizer != null) {
mSpeechSynthesizer.pause();
}
} /**
* 停止播放
*/
public void stopSpeechSynthesizer(){
if(mSpeechSynthesizer != null) {
mSpeechSynthesizer.stop();
}
} /**
* 接着停止后的地方播放
*/ public void resumeSpeechSynthesizer(){
if(mSpeechSynthesizer != null) {
mSpeechSynthesizer.resume();
}
} /**
* 释放mSpeechSynthesizer,在使用完之后必须调用,确保下个界面使用的时候资源已经释放掉了,否则下个界面将无法正常播放
*/
public void releaseSpeechSynthesizer(){
if(mSpeechSynthesizer != null) {
mSpeechSynthesizer.release();
}
} public void setSpeechSynthesizerNull(){
if(mSpeechSynthesizer != null) {
mSpeechSynthesizer = null;
}
} public void endSpeechSynthesizer(){
pauseSpeechSynthesizer();
stopSpeechSynthesizer();
releaseSpeechSynthesizer();
setSpeechSynthesizerNull();
} }

首次需联网,自动下载授权文件,以后离线也能用

三.云知声离线SDK

同百度,注册账号后,下载sdk,做好引用与配置

gradle中配置:

sourceSets {

main {

jniLibs.srcDirs = ['libs']

}

}

关键代码:

package com.yupont.www.myapplication;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream; import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast; import com.unisound.client.SpeechConstants;
import com.unisound.client.SpeechSynthesizer;
import com.unisound.client.SpeechSynthesizerListener; public class yzsTTSOfflineActivity extends Activity { private static boolean TTS_PLAY_FLAGE = false; private EditText mTTSText;
private TextView mTextViewTip;
private TextView mTextViewStatus;
private Button mTTSPlayBtn;
private SpeechSynthesizer mTTSPlayer;
private final String mFrontendModel= Environment.getExternalStorageDirectory().toString()+"/Yupont/UAV/OfflineTTSModels/frontend_model";
private final String mBackendModel = Environment.getExternalStorageDirectory().toString()+"/Yupont/UAV/OfflineTTSModels/backend_lzl";
// private final String mFrontendModel= getClass().getClassLoader().getResource("assets/OfflineTTSModels/frontend_model").getPath().substring(5);
// private final String mBackendModel = getClass().getClassLoader().getResource("assets/OfflineTTSModels/backend_lzl").getPath();
//
@Override
public void onCreate(Bundle savedInstanceState) {
// requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_yzs_offline_tts);
copyFilesFassets(this,"OfflineTTSModels", Environment.getExternalStorageDirectory().toString()+"/Yupont/UAV/OfflineTTSModels"); //getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.status_bar_main); mTTSText = (EditText) findViewById(R.id.textViewResult);
//mTextViewStatus = (TextView) findViewById(R.id.textViewStatus);
//mTextViewTip = (TextView) findViewById(R.id.textViewTip);
mTTSPlayBtn = (Button) findViewById(R.id.recognizer_btn);
mTTSPlayBtn.setEnabled(false);
mTTSPlayBtn.setOnClickListener(new OnClickListener() { @Override
public void onClick(View arg0) {
TTSPlay();
}
}); // 初始化本地TTS播报
initTts();
} /**
* 从assets目录中复制整个文件夹内容
* @param context Context 使用CopyFiles类的Activity
* @param oldPath String 原文件路径 如:/aa
* @param newPath String 复制后路径 如:xx:/bb/cc
*/
public void copyFilesFassets(Context context, String oldPath, String newPath) {
try {
String fileNames[] = context.getAssets().list(oldPath);//获取assets目录下的所有文件及目录名
if (fileNames.length > 0) {//如果是目录
File file = new File(newPath);
file.mkdirs();//如果文件夹不存在,则递归
for (String fileName : fileNames) {
copyFilesFassets(context,oldPath + "/" + fileName,newPath+"/"+fileName);
}
} else {//如果是文件
if(new File(newPath).exists()){
return;
}
InputStream is = context.getAssets().open(oldPath);
FileOutputStream fos = new FileOutputStream(new File(newPath));
byte[] buffer = new byte[1024];
int byteCount=0;
while((byteCount=is.read(buffer))!=-1) {//循环从输入流读取 buffer字节
fos.write(buffer, 0, byteCount);//将读取的输入流写入到输出流
}
fos.flush();//刷新缓冲区
is.close();
fos.close();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
//如果捕捉到错误则通知UI线程
//MainActivity.handler.sendEmptyMessage(COPY_FALSE);
}
} /**
* 初始化本地离线TTS
*/
private void initTts() { // 初始化语音合成对象
try {
mTTSPlayer = new SpeechSynthesizer(this, Config.appKey, Config.secret); // 设置本地合成
mTTSPlayer.setOption(SpeechConstants.TTS_SERVICE_MODE, SpeechConstants.TTS_SERVICE_MODE_LOCAL);
File _FrontendModelFile = new File(mFrontendModel);
if (!_FrontendModelFile.exists()) {
toastMessage("文件:" + mFrontendModel + "不存在,请将assets下相关文件拷贝到SD卡指定目录!");
}
File _BackendModelFile = new File(mBackendModel);
if (!_BackendModelFile.exists()) {
toastMessage("文件:" + mBackendModel + "不存在,请将assets下相关文件拷贝到SD卡指定目录!");
}
// 设置前端模型
mTTSPlayer.setOption(SpeechConstants.TTS_KEY_FRONTEND_MODEL_PATH, mFrontendModel);
// 设置后端模型
mTTSPlayer.setOption(SpeechConstants.TTS_KEY_BACKEND_MODEL_PATH, mBackendModel);
// 设置回调监听
mTTSPlayer.setTTSListener(new SpeechSynthesizerListener() { @Override
public void onEvent(int type) {
switch (type) {
case SpeechConstants.TTS_EVENT_INIT:
// 初始化成功回调
log_i("onInitFinish");
mTTSPlayBtn.setEnabled(true);
break;
case SpeechConstants.TTS_EVENT_SYNTHESIZER_START:
// 开始合成回调
log_i("beginSynthesizer");
break;
case SpeechConstants.TTS_EVENT_SYNTHESIZER_END:
// 合成结束回调
log_i("endSynthesizer");
break;
case SpeechConstants.TTS_EVENT_BUFFER_BEGIN:
// 开始缓存回调
log_i("beginBuffer");
break;
case SpeechConstants.TTS_EVENT_BUFFER_READY:
// 缓存完毕回调
log_i("bufferReady");
break;
case SpeechConstants.TTS_EVENT_PLAYING_START:
// 开始播放回调
log_i("onPlayBegin");
break;
case SpeechConstants.TTS_EVENT_PLAYING_END:
// 播放完成回调
log_i("onPlayEnd");
setTTSButtonReady();
break;
case SpeechConstants.TTS_EVENT_PAUSE:
// 暂停回调
log_i("pause");
break;
case SpeechConstants.TTS_EVENT_RESUME:
// 恢复回调
log_i("resume");
break;
case SpeechConstants.TTS_EVENT_STOP:
// 停止回调
log_i("stop");
break;
case SpeechConstants.TTS_EVENT_RELEASE:
// 释放资源回调
log_i("release");
break;
default:
break;
} } @Override
public void onError(int type, String errorMSG) {
// 语音合成错误回调
log_i("onError");
toastMessage(errorMSG);
setTTSButtonReady();
}
});
// 初始化合成引擎
mTTSPlayer.init("");
} catch (Exception e) {
e.printStackTrace();
}
} private void TTSPlay() {
if (!TTS_PLAY_FLAGE) {
mTTSPlayer.playText(mTTSText.getText().toString());
setTTSButtonStop();
} else {
mTTSPlayer.stop();
setTTSButtonReady();
} } private void setTTSButtonStop() {
TTS_PLAY_FLAGE = true;
mTTSPlayBtn.setText(R.string.stop_tts);
} private void setTTSButtonReady() {
mTTSPlayBtn.setText(R.string.start_tts);
TTS_PLAY_FLAGE = false;
} protected void setTipText(String tip) { mTextViewTip.setText(tip);
} protected void setStatusText(String status) { mTextViewStatus.setText(getString(R.string.lable_status) + "(" + status + ")");
} @Override
public void onPause() {
super.onPause();
// 主动停止识别
if (mTTSPlayer != null) {
mTTSPlayer.stop();
}
} private void log_i(String log) {
Log.i("demo", log);
} @Override
protected void onDestroy() {
// 主动释放离线引擎
if (mTTSPlayer != null) {
mTTSPlayer.release(SpeechConstants.TTS_RELEASE_ENGINE, null);
}
super.onDestroy();
} private void toastMessage(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
}

  

Android,百度,云知声tts总结的更多相关文章

  1. Android 百度云推送

    http://developer.baidu.com/wiki/index.php?title=docs/cplat/push/sdk/clientsdk. public class DemoAppl ...

  2. Android 百度云媒体 等播放器播放4:3等多种比例的视频 大小配置的问题

    视频播放宽度大小各不一样,就需要根据视频的尺寸去适应屏幕的宽度和高度进行缩放. 思路是在onPrepared方法中,或者切换屏幕后,获取video的高度和宽度.以及屏幕展示区域的高度的宽度.并对比二者 ...

  3. Android 高仿微信实时聊天 基于百度云推送

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38799363 ,本文出自:[张鸿洋的博客] 一直在仿微信界面,今天终于有幸利用百 ...

  4. Android 高仿微信即时聊天 百度云为基础的推

    转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/38799363 ,本文出自:[张鸿洋的博客] 一直在仿微信界面,今天最终有幸利用百 ...

  5. Android推送 百度云推送 入门篇

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/27231237 现在app基本都有推送的功能,于是看了下百度云的推送,官方文档和D ...

  6. 消息推送之百度云推送Android集成与使用方法

    这两天由于项目需要,研究了一下百度云推送,本来这事没什么多大工作量的,但注册百度开发者账户创建应用令我蛋疼菊紧了好一阵,这些东西做了对技术没啥提升,不做又不行,必经之路.好在我耗费了N多个毫毫秒秒后稀 ...

  7. android开发(25) - 推送的实现,使用百度云推送

    什么叫推送? 中文名称:推送 英文名称:push 定义:描述因特网内容提供者和因特网用户之间工作方式的术语.“推送”指因特网内容提供者定期向预订用户“提供”数据. 项目中有可能会用到推送.如果自己写一 ...

  8. 消息推送之百度云推送Android集成与用法

    这两天因为项目须要.研究了一下百度云推送,本来这事没什么多大工作量的,但注冊百度开发人员账户创建应用令我蛋疼菊紧了好一阵,这些东西做了对技术没啥提升,不做又不行,必经之路. 好在我耗费了N多个毫毫秒秒 ...

  9. Android推送服务——百度云推送

    一.推送服务简介 消息推送,顾名思义,是由一方主动发起,而另一方与发起方以某一种方式建立连接并接收消息.在Android开发中,这里的发起方我们把它叫做推送服务器(Push Server),接收方叫做 ...

随机推荐

  1. linux中vi和vim操作

    一.简单介绍 vi 和 vim 类似于windows的文本编辑器 所有的Linux系统都会内置vi文本编辑器 vim可以看做是vi增强版,具有程序编辑能力,支持语法高亮,代码补全,编译及错误跳转等功能 ...

  2. 【C++常用函数】头文件<algorithm>中的常用函数(绝对值,交换,比较)

    swap(a,b) 用于交换a,b两个变量的值: max(a,b) 返回a,b中的最大值: min(a,b) 返回a,b中的最小值: abs(x) 返回x的绝对值,x必须是整数:

  3. Vue-easyui中如何给ComboGrid添加过滤器

    1,给ComboGrid绑定监听事件,将事件对象传入.文档:http://www.jeasyui.net/vue/653.html @filterChange="example($event ...

  4. CSS绘制三角形和箭头,不用再用图片了

    前言 还在用图片制作箭头,三角形,那就太lou了.css可以轻松搞定这一切,而且颜色大小想怎么变就怎么变,还不用担心失真等问题. 先来看看这段代码: /**css*/.d1{ width: 0; he ...

  5. pjd-fstest The test suite checks POSIX compliance - 测试文件系统posix 接口兼容性

    pjd-fstest: 参考网址:https://www.tuxera.com/community/posix-test-suite/ fstest是一套简化版的文件系统POSIX兼容性测试套件,它可 ...

  6. [日常] win10开启和安装ubuntu子系统

    在控制面板的程序与功能里启用和关闭windows功能打开,适用于linux的windows子系统 在微软商店里搜索ubuntu,直接点击安装就可以了 安装完成后的windows与linux的磁盘映射见 ...

  7. STL 中 map 的使用

    涉及:vector,pair 基本结构 map 从本质上来说是一颗二叉排序树,树上的节点类型为pair.pair类型中有两个重要的成员变量,其中 first 存储了 key ,second 存储了 v ...

  8. May 19th, 2019. Week 21st, Sunday

    Fight for what matters to you. 为自己珍视的东西奋斗吧! We all want to make our life goals true, and we all expe ...

  9. Redux使用

    思想 应用中所有的state都以一个对象树的形式储存在一个单一的store中.唯一能改变state的办法是触发action,一个描述发生什么的对象.为了描述action如何改变state树,需要编写r ...

  10. networkx生成网络

    ER随机网络,WS小世界网络,BA无标度网络的生成 import networkx as nx import matplotlib.pyplot as plt #ER随机网络 #10个节点,连接概率为 ...