项目简介
1.使用c++编写一个与智能机器人对话和语音命令执行的语音管理工具。
2.通过使用图灵机器人和百度语音识别和合成的第三方平台完成。
3.其中可执行命令支持配置。
项目技术点
1.c++STL
2.http第三方库
3.图灵机器人
4.百度语音识别和合成
5.Linux系统/网络编程
6.各种第三方库和第三方工具的安装和使用。
项目流程
1.程序启动后,加载命令配置文件,启动本地录音工具,开始录音。(录音)
2.程序识别后,将特定格式的录音推送到百度语音识别系统的平台进行识别,返回识别完毕后的的文字信息。(录音——语音识别——返回文字信息)
3.对比识别之后的文本,看是命令还是普通对话信息。(判断是否是命令)
4.如果是对话信息,推送给图灵机器人,图灵机器人会进行智能对话,得到图灵机器人相应的文本信息,调用百度的语音合成功能,在本地合成录音,然后程序启动播放器,播放语音信息,完成对话。(对话信息——图灵机器人——文本信息——语音合成——播放)
5.支持语音退出。
项目准备
1.注册图灵机器人
2.使用百度语音识别和合成的第三方平台。
3.准备第三方库(安装高版本gcc;下载百度语音识别SDK;安装jsoncpp;安装openssl;安装libcurl;准备好录音和播放工具)
开始编码
这部分可以分成以下几步来完成:
1.连接图灵机器人完成文本交流
2.完成录音后可以转成文本进行交流。
3.将文本转成语音进行交流。
1.连接图灵机器人
1.连接图灵机器人我们需要一个请求接口url,还有机器人自带的api_key,user_id,我们将这三项作为机器人类的成员变量。
2.需要考虑机器人需要完成哪些功能:1.将我们的文本信息转为机器人识别的语言;2.发起http请求,连接图灵机器人;3.将http响应回来的信息转为文本信息。
通过看官方的文档,我们可以发现使用的语言是Json,那么我们就需要了解一下Json.
Json是轻量级的文本数据交换格式;具有自我描述性,更易理解;采用完全独立于语言的文本格式:使用JavaScript语法来描述对象,但是Json任然独立于语言和平台。
文本转化为Json串
要将文本转化成Json串,需要进行序列化。
std::string MessageToJson(std::string& message)
{
Json::Value root;//可以看做是一个万能对象,什么类型的信息都可以存放在这个对象中,方便序列化
Json::StreamWriterBuilder wb;
std::ostringstream ss;
Json::Value item_;
item_["text"] = message;
Json::Value item;
item["inputText"] = item_;
//输入类型:0-文本(默认)、1-图片、2-音频
root["reqType"] = 0; //text
root["perception"] = item;
item.clear();
item["apiKey"] = api_key;
item["userId"] = user_id;
root["userInfo"] = item;
//将new好的资源交给智能指针管理,以免忘记释放导致内存泄漏
std::unique_ptr<Json::StreamWriter> sw(wb.newStreamWriter());
//创建好的对象调用Write接口将root中的信息写入ss中
sw->write(root,&ss);
std::string json_string = ss.str();
//std::cout << "debug: " << json_string << std::endl;
return json_string;
}
Json串转化成文本
std::string JsonToEchoMessage(std::string& str)
{
//std::cout << "JsonToEchoMessage: " << str << std::endl;
JSONCPP_STRING errs;
Json::Value root;
Json::CharReaderBuilder rb;
//将new好的资源交给智能指针管理,以免忘记释放导致内存泄漏
std::unique_ptr<Json::CharReader> const cr(rb.newCharReader());
//用创建好的cr对象调用parse接口解析response中的信息
bool res = cr->parse(str.data(),str.data()+str.size(),&root,&errs);
if(!res || !errs.empty()){//如果解析为空或是有错误
std::cerr << "http post parse error" << errs << std::endl;
return "";
}
int code = root["intent"]["code"].asInt();
if(!IsCodeLegal(code)){//返回码若是错误
std::cerr << "response code error" << std::endl;
return "";
}
Json::Value item = root["results"][0];
std::string msg = item["values"]["text"].asString();
return msg;
}
发起http请求
在这里我们使用的是post请求方法。
POST请求:向指定资源提交数据进行处理请求,数据被包含在请求体中。POST请求可能会导致新的资源的建立、已有资源的修改。(通常用来发送数据)。
//向图灵机器人,发起http post请求
//这里要使用开源jsoncpp进行序列化和反序列化
std::string PostRequest(std::string &request_json)
{
//http Post请求返回的结果
std::string response;
//用我们创建的httpclient对象调用百度内部的post请求接口
//其实我们也可以自己写post请求,使用socket套接字,但是为了简便我们直接使用百度提供的post接口
int status_code = client.post(url,nullptr,request_json,nullptr,&response);
if(status_code != CURLcode::CURLE_OK){//post请求失败,返回空
std::cerr << "http post request error!" << std::endl;
return "";
}
//std::cout << "debug:"<< response << std::endl;
return response;
}
2.语音识别
1.接入机器人Sosuke完成文本交流功能之后,我们接下来就可以借助百度ai平台的语音识别功能将我们录制好的语音识别成文本消息发送给图灵机器人,这里我们封装一个SpeechRec类来实现语音识别的功能
2.阅读百度语音识别C++SDK文档 通过阅读文档确定我们这个类需要的的成员变量。
bool ASR(std::string path,std::string &out)
{
std::map<std::string,std::string> options;
options["den_pid"]="1536";
std::string file_content;
aip::get_file_content(ASR_PATH,&file_content);
Json::Value result= client->recognize(file_content,"wav",16000,options);
//std::cout<<"debug: "<<result.toStyledString()<<std::endl;
int code=result["err_no"].asInt();
if(!IsCodeLegal(code)){
std::cout<<"recognize error"<<std::endl;
return false;
}
out=result["result"][0].asString();
return true;
}
3.做完这些之后我们再多实现一个功能,就是通过语音让wjk替我执行Linux下的命令,为了能够执行更多的命令,也为了不重复多次的修改代码,我们就直接创建一个命令配置文件,将我们想执行的命令对应说的话都写在配置文件中,然后在我们的代码中将配置文件加载进来即可.
bool LoadEtc(){
std::ifstream in(CMD_ETC);
if(!in.is_open()){
std::cerr<<"open error"<<std::endl;
return false;
}
std::string sep = ":";
char line[256];
while(in.getline(line,sizeof(line))){
std::string str=line;
std::size_t pos=str.find(sep);
if(std::string::npos==pos){
std::cerr<<"not find:"<<std::endl;
continue;
}
std::string k=str.substr(0,pos);
std::string v=str.substr(pos+sep.size());
k+="。";
commands.insert(std::make_pair(k,v));
//commands.insert({k,v});
}
std::cerr<<"Load command etc done ...success"<<std::endl;
in.close();
return true;
}
3.语音合成
bool TTS(std::string message){
bool ret;
std::ofstream ofile;
std::string ret_file;
std::map<std::string,std::string> options;
options["spd"]="5";//语速0-15
options["pit"]="7";//语调//0-15
options["vol"]="15";//风格0-15c
options["per"]="110";//1 0 3 4 110 111 103 106 5
options["aue"]="6";
ofile.open(TTS_PATH,std::ios::out|std::ios::binary);
Json::Value result =client->text2audio(message,options,ret_file);
if(!ret_file.empty()){
ofile<<ret_file;
ofile.close();
ret=true;
}
else{
std::cerr<<result.toStyledString()<<std::endl;
ret=false;
}
ofile.close();
return ret;
}
项目难点
对第三方文档的理解。
总体来说,这个项目主要是对第三方平台和文档的使用和连接,其他的就没有什么难度了。