资源行业动态AI智能语音机器人

AI智能语音机器人

2020-02-20 | |  234 |   0

原标题:AI智能语音机器人 

来源:CSDN博客       链接:https://blog.csdn.net/C15191504149/article/details/100062953


项目简介

使用C++编写一个智能AI对话和语音命令执行的语音管理工具

其中可执行命令支持配置


项目技术点

C++ STL

http第三方库

图灵机器人

百度语音识别和语音合成

Linux系统/网络编程

各种第三方库和第三方工具的安装与使用


项目演示

程序启动之后,加载命令配置文件,启动本地录音工具,开始录音

程序准备识别, 将特定格式的录音推送到百度语音识别平台进行识别,返回识别完毕之后的文字信息

对比识别之后的输入文本,辨别是命令还是普通对话信息

如果是命令,进入系统命令执行模块,执行完毕,看到执行结果,一次交互完成

如果是对话信息,推送给图灵机器人,图灵机器人会智能相应对话,得到图灵机器人响应的文本,调用百

度语音合成,在本地合成语音,然后程序启动播放器,播放语音信息,完成对话信息

支持语言退出

演示项目效果


1. 使用图灵机器人

注册图灵机器人,官网:http://www.turingapi.com/


注册完毕时候,需要身份认证,安装提示来就行【图灵平台在2019-6-5号开始,需要个人进行身份认证】登录之后,就可以看看图灵官网的参考手册,也可以点击链接:https://www.kancloud.cn/turing/www-tuling123-com/718227


根据官网手册可以看出,请求是依赖http协议,请求和相应的数据都是json格式,所以,我们必须的1. 能够发起http的POST请求 2. 能够使用json进行数据序列号和反序列化


http我们不在单独写了,使用第三方库,可以选择httplib,但是后面的百度语音识别自带了httpclient,我们后面可以使用。


json进行数据序列号和反序列化功能需要我们完成,我们选择一个开源的C++库:jsoncpp


2. 使用百度语音识别

注册百度语音识别,上官网:http://ai.baidu.com/


应用的创建,全部默认即可

技术文档我们选择C++SDK


3. 准备需要的第三方库和sdk

因后续开发需要,需要先安装高版本cmake,gcc


cmake更新: https://blog.csdn.net/fancyler/article/details/78009812


安装高版本gcc:

# sudo yum install centos-release-scl

# sudo yum install devtoolset-6

# scl enable devtoolset-6 bash


a. 下载百度C++语音识别SDK

在http://ai.baidu.com/sdk下载,识别、合成 RESTful API C++ SDK,后面的工具,基本都要支持C++11以上


b. 安装jsoncpp,要求:>1.6.2版本,0.x版本将不被支持

json官网:http://www.json.org/json-zh.html


注意,推荐使用https://github.com/open-source-parsers/jsoncpp/releases 1.8.3版本,其他最新版本可能会有中文编码的问题


下载好安装包,解压

# cd jsoncpp-1.8.3

# make build

# cd build

# cmake ..

# make

# sudo make install


c. 安装openssl

openssl轻易不要卸载,之间更新开发包即可,如果不行,需要结合实际情况进行安装

# sudo yum install openssl-devel


d. 安装libcurl(需要支持https)

官网:<https://curl.haxx.se/download.html


下载curl-7.64.1.tar.gz版本

# tar xzf curl-7.64.1.tar.gz

# cd curl-7.64.1

# ./configure

# make

# sudo make install


4. 准备Centos 7录音和播放工具

语音录制与播放


采用arecord进行语音录制,使用vlc/cvlc进行播放


arecord系统默认自带,可以直接输入arecord看看你的平台有没有安装,如果没有,就会告诉你“bash:XXX: command not found...”,网上查阅进行安装即可,参考链接:https://blog.csdn.net/outstanding_yzq/article/details/8126350


使用arecord进行录音


语音采样样例:


# arecord -t wav -c 1 -r 16000 -d 5 -f S16_LE demo.wav


// -t: 设置文件类型,我们采用wav格式


// -c: 设置通道号


// -r: 设置频率


// -d: 设置持续时间,单位为秒


// -f: 设置采样格式.格式包括:S8 U8 S16_LE(S16_LE: little endian signed 16 bits)


//                                           S16_BE U16_LE U16_BE S24_LE S24_BE U24_LE U24_BE S32_LE S32_BE


//                                           U32_LE U32_BE FLOAT_LE FLOAT_BE FLOAT64_LE FLOAT64_BE


// IEC958_SUBFRAME_LE IEC958_SUBFRAME_BE MU_LAW A_LAW IMA_ADPCM MPEG GSM


//我们为何这样采用,主要是因为百度语音识别的要求,具体可以参照百度语音识别文档


运行上面的命令,会在当前目录下录制demo.wav格式的语音,测试播放可以使用自带的


# aplay demo.wav


播放你录制的音频.


安装vlc/cvlc播放器


我们在语音合成之后,直接使用aplay播放会有一定问题,我们采用第三方工具vlc/cvlc实现MP3文件播放


# sudo rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm


# sudo yum install vlc -y


代码如下:

1、项目目录:

build.sh //构建项目的shell脚本,简单实现

command.etc //语音命令配置文件 

Jarvis.cc //Jarvis 源文件 

Jarvis.hpp //Jarvis 核心代码 

Makefile 

speech //引入百度语音识别SDK 

temp_file //保存临时语音文件目录


2、Jarvis.hpp

#ifndef _Jarvis_HPP_

#define _Jarvis_HPP_

 

#include<iostream>

#include<cstdio>

#include<string>

#include<map>

#include<unordered_map>

#include<memory>

#include<sstream>

#include<unistd.h>

#include<pthread.h>

#include<json/json.h>

#include"base/http.h"

#include"speech.h"

using namespace std;

 

#define PLAY_FILE "temp_file/play.mp3"

#define VOICE_FILE "temp_file/voice.wav"

#define CMD_ETC "command.etc"

 

class Util{

private:

static pthread_t tid;

public:

//在Linux中执行指定命令,以及是否需要打印出命令

static bool Exec(string command, bool is_print){

if(!is_print){

//不打印

command += ">/dev/null 2>&1";

}

FILE* fp = popen(command.c_str(), "r");

if(NULL == fp){

cerr << "popen error" << endl;

return false;

}

if(is_print){

char c;

cout << "--------start--------" << endl;

while(fread(&c, 1, 1, fp) > 0){

cout << c;

}

cout << endl;

cout << "---------end---------" << endl;

}

pclose(fp);

return true;

}

//让等待的过程动态化

static void* Move(void* arg){

string message = (char*)arg;

const char* lable = "......";

const char* blank = "      ";

int i = 5;

int j = 0;

while(1){

cout << message << lable+i << "r";

fflush(stdout);

i--;

j++;

if(i < 0){

i = 5;

cout << message << blank << "r";

}

usleep(500000);

}

}

 

//开始展示消息

static void BeginShowMessage(string message){

pthread_create(&tid, NULL, Move, (void*)message.c_str());

}

 

//结束展示

static void EndShowMessage(){

pthread_cancel(tid);

}

};

pthread_t Util::tid;

 

 

class SpeechRec{

private:

static string app_id;

static string api_key;

static string secret_key;

aip::Speech *client;//SDK对应的语音识别客户端

public:

//语音识别

SpeechRec()

{

client = new aip::Speech(app_id, api_key, secret_key);

}

 

//语音识别

string ASR(const string &voice_bin){

Util::BeginShowMessage("正在识别");

map<string, string> options;//以中文显示

options["dev_pid"]= "1536";

 

string file_content;

aip::get_file_content(voice_bin.c_str(), &file_content);//获取语音文件

 

Json::Value result = client->recognize(file_content, "wav", 16000, options);//开始识别,需要语音文件,格式是"wav",频率是16k

Util::EndShowMessage();

 

int code = result["err_no"][0].asInt();

if(code != 0){

cerr << "code: " << code << "err_msg: " << result["err_msg"].asString() << endl;

return "";

}

return result["result"][0].asString();

}

 

//语音合成,文本转语音

void TTS(string &text, string voice_tts){

ofstream ofile;

string ret;

map<string, string> options;

options["spd"] = "5";

options["per"] = "4";

options["vol"] = "15";

Util::BeginShowMessage("正在合成");

ofile.open(voice_tts, ios::out | ios::binary);

//语音合成,文本转语音,放到指定目录,形成指定文件

Json::Value result = client->text2audio(text, options, ret);

if(ret.empty()){

cerr << result.toStyledString() << endl;

}

else{

ofile << ret;

}

ofile.close();

Util::EndShowMessage();

}

 

~SpeechRec()

{

delete client;

client = nullptr;

}

};

string SpeechRec::app_id = "16685272";

string SpeechRec::api_key = "PHf8eAYFmVGkOGkcaETg6QgG";

string SpeechRec::secret_key = "62V1w1U36y5WkfC742woxOwZGhQpCUX9";

 

class Robot{

private:

string url = "openapi.tuling123.com/openapi/api/v2";

string api_key = "efe2cac8a7104897a01ef250bccdcc50";

string user_id = "1";//用户ID,可以随意指定

aip::HttpClient client;//使用百度语音识别自带的HttpClient发起相关请求

public:

Robot()

{}

 

//获取Json串,序列化,多转一

string MakeJsonString(const string &message){

Json::Value root;

Json::Value item;

Json::Value item1;

Json::Value item2;

item["apiKey"] = api_key;

item["userId"] = user_id;

root["reqType"] = 0;

root["userInfo"] = item;

 

item1["text"] = message;

item2["inputText"] = item1;

root["perception"] = item2;

Json::StreamWriterBuilder wb;

ostringstream os;

unique_ptr<Json::StreamWriter> jw(wb.newStreamWriter());

jw->write(root, &os);

return os.str();

}

 

//利用HttpClient自带的http协议发起post请求

string PostRequest(string &body){

string response;

int code = client.post(url, nullptr, body, nullptr, &response);

if(code != CURLcode::CURLE_OK){

return "";

}

 

return response;

}

 

//反序列化,一转多

string ParseJson(string &response){

JSONCPP_STRING errs;

Json::Value root;

Json::CharReaderBuilder rb;

unique_ptr<Json::CharReader> const rp(rb.newCharReader());

bool res = rp->parse(response.data(), response.data()+response.size(), &root, &errs);

if(!res || !errs.empty()){

cerr << "Jsonparse error" << errs << endl;

return "";

}

Json::Value item = root["result"][0];

Json::Value item1 = item["values"];

return item1["text"].asString();

}

 

//文本交流,传入一个字符串,经过序列化与反序列化后,返回一个字符串

string Talk(string &message, string &result){

string body = MakeJsonString(message);

string response = PostRequest(body);

result = ParseJson(response);

}

 

~Robot()

{}

};

 

class Jarvis{

private:

SpeechRec sr;

Robot rt;

unordered_map<string, string> cmd_map;

public:

//使用arecord工具进行录音,语音转文本

bool RecordVoice(){

Util::BeginShowMessage("正在录音");

bool ret = true;

string command = "arecord -t wav -c 1 -r 16000 -d 5 -f S16_LE ";

command += VOICE_FILE;

 

if(!Util::Exec(command, false)){

cerr << "Record error" << endl;

ret = false;

}

Util::EndShowMessage();

return ret;

}

public:

Jarvis()

{

//加载命令执行配置文件command.etc

ifstream in(CMD_ETC);

if(!in.is_open()){

cerr << "open error" << endl;

exit(1);

}

char buffer[128];

string sep = ":";

while(in.getline(buffer, sizeof(buffer))){

string str = buffer;

size_t pos = str.find(sep);

if(string::npos == pos){

cerr << "Load Etc Error" << endl;

exit(2);

}

string k = str.substr(0, pos);

string v = str.substr(pos + sep.size());

k += "。";

cmd_map.insert(make_pair(k, v));

in.close();

}

}

 

//判断一条消息是否是命令,如果是命令,就执行,不需要交给机器人进行对话

bool IsCommand(const string &text, string &out_command){

auto iter = cmd_map.find(text);

if(iter != cmd_map.end()){

out_command = iter->second;

return true;

}

out_command = "";

return false;

}

//使用百度语音合成接口,文本转语音,再使用cvlc进行本地播放

void PlayVoice(string voice_file){

string cmd = "cvlc --play-and-exit ";//播放完毕

cmd += voice_file;

Util::Exec(cmd, false);//执行播放

}

 

void Run(){

string voice_bin = VOICE_FILE;

volatile bool is_quit = false;

string cmd;

while(!is_quit){

cmd = "";

if(RecordVoice()){

string text = sr.ASR(voice_bin);//进行录音

cout << "Me# "<< text << endl;

if(IsCommand(text, cmd)){//判定是否是命令

cout << "[luvky@bogon Jarvis]$ " << cmd << endl;

Util::Exec(cmd, true);

}

else{

string message;

if(text == "退下吧。"){

message = "臣告辞";

is_quit = true;

}

else{//不是命令就交给机器人

rt.Talk(text, message);

cout << "Robot# " << message << endl;

}

string voice_tts;

sr.TTS(message, PLAY_FILE);//使用百度语音合成

PlayVoice(PLAY_FILE);//播放语音

}

 

}

}

}

~Jarvis()

{}

};

 

#endif

3、Jarvis.cc


#include"Jarvis.hpp"                                                               

 

using namespace std;

 

int main(){

  Jarvis js;

  js.Run();

  return 0;

}

4、command.etc


查看内存:free

退出:exit

显示当前文件:ls -al

查看硬盘:df -h

关闭防火墙:systemctl stop firewalld

打开防火墙:systemctl start firewalld

查看进程:ps aux

5、Makefile


Jarvis:Jarvis.cc

g++ -std=c++11 -o Jarvis Jarvis.cc -Ispeech -ljsoncpp -lcurl -lcrypto -lpthread

.PHONY:clean

clean:

rm -f Jarvis

6、build.sh


#!/bin/bash

 

make clean

make

项目总结:

整体来讲,这个项目的难度不大,核心点在于对各个工具,平台的收悉程度,我们主要从这个项目中吸收的东西是: 学会使用第三方平台,第三方工具,就能完成很有意思的功能

————————————————

版权声明:本文为CSDN博主「C15191504149」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/C15191504149/article/details/100062953

THE END

免责声明:本文来自互联网新闻客户端自媒体,不代表本网的观点和立场。

合作及投稿邮箱:E-mail:editor@tusaishared.com

上一篇:语音识别框架

下一篇: 2020年河南省将推广应用3万台工业机器人

用户评价
全部评价

热门资源

  • 国内人才报告:机...

    近日,BOSS 直聘职业科学实验室 &BOSS 直聘研究院...

  • AI使物联网更智能...

    看到微软对物联网和人工智能的结合感兴趣是一个明...

  • 推荐一批学习自然...

    这里推荐一批学习自然语言处理相关的书籍,当然,...

  • 安防智能化大势下...

    大部分传统安防设备不仅拍摄视野有限,而且无法事...

  • 20亿创业基金、10...

    近日,杭州举办了建设国家新一代人工智能创新发展...