失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 智能语音生活助手实现(QT)

智能语音生活助手实现(QT)

时间:2019-09-27 08:18:08

相关推荐

智能语音生活助手实现(QT)

智能语音生活助手实现(QT)

一、功能介绍二、实现步骤2.1 语音识别模块2.1.1 录音2.1.2 点击释放按钮槽函数2.1.3 申请百度AI开发平台语音识别应用2.1.4 HTTP请求类实现2.1.5 发送请求2.1.6 MainWindow类调用函数2.1.7 语音控制设备联动2.2 智慧生活模块2.2.1 创建API应用2.2.2 Get方法获取API的JSON数据2.2.3 解析JSON数据2.3 出行地图模块2.3.1 申请百度地图API秘钥2.3.2 新建map.html2.3.3 在map.html文件添加方法2.3.4 QT端实现2.4 智能闹钟模块2.4.1 开启线程,检测时间2.4.2 提交闹钟时间总结

一、功能介绍


1、 调用百度 AI 开发平台 API 进行语音识别,进行语音控制传感器的联

动,实现智能语音识别平台的功能。

2、 调用天气生活指数 API,获取不同城市每天的运动指数、 舒适度指数、

化妆指数等等。

3、 调用百度地图 api,显示不同城市的地图。

4、 实现智能闹钟,定时提醒。

二、实现步骤

2.1 语音识别模块

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

2.1.1 录音

在 pro 文件添加

QT += networkQT += multimedia

在 mainwindow.h 头文件添加下面定义

void RecorderStart(QString fileName);//开始录音void RecorderEnd();//结束录音并转换格式QFile *outFile;//录音时的变量QAudioInput *my_audio;//录音时的变量QAudioFormat audioFormat;//录音时的变量

Mainwindow.cpp 录音函数实现:

void MainWindow::RecorderStart(QString fileName){QAudioDeviceInfo device = QAudioDeviceInfo::defaultInputDevice();if(device.isNull()){QMessageBox::warning(NULL,"QAudioDeviceInfo","录音设备不存在");return;}// 设置通道数audioFormat.setChannelCount(1);// 设置编码audioFormat.setCodec("audio/pcm");// 设置采样频率audioFormat.setSampleRate(16000);// 设置位深audioFormat.setSampleSize(16);// 判断设备是否支持该格式if(!device.isFormatSupported(audioFormat)){//当前使用设备是否支持audioFormat = device.nearestFormat(audioFormat); //转换为最接近格式}// 创建录音对象my_audio = new QAudioInput(audioFormat,this);outFile = new QFile;outFile->setFileName(fileName); //语音原始文件outFile->open(QIODevice::WriteOnly);//开始录音my_audio->start(outFile);}

结束录音函数实现

/*********************** 结束录音并转换格式**********************/void MainWindow::RecorderEnd(){// 结束录音my_audio->stop();outFile->close();delete outFile;outFile =NULL;delete my_audio;my_audio = NULL;}

2.1.2 点击释放按钮槽函数

2.1.3 申请百度AI开发平台语音识别应用

语音识别是利用百度的 API 在线识别。所以需要申请项目 ID。进入百度AI开放平台

在产品服务下选择语音识别:

点击立即使用:

申请账号点击登录:

点击创建应用:

输入应用名称、应用描述,点击立即创建:

点击返回应用列表:

获取 AppID、API Key 和 Secret Key:

我们记住其中的API Key 和 Secret Key,下面会用到。

2.1.4 HTTP请求类实现

我们录好的音频文件需要通过HTTPS协议上传到百度AI开发平台进行语音识别,之后AI平台会返回给我们识别的结果。

http类只需要封装一个方法

bool post_sync(QString url,QMap<QString,QString>header,QByteArray requestData,QByteArray &replyData);

使用这个方法去URL发送请求会收到URL的返回值。

http.h

#ifndef HTTP_H#define HTTP_H#include <QObject>#include <QMap>#include <QNetworkAccessManager>#include <QNetworkRequest>#include <QNetworkReply>#include <QEventLoop>#include <QDebug>class Http : public QObject{Q_OBJECTpublic:explicit Http(QObject *parent = nullptr);bool post_sync(QString url,QMap<QString,QString>header,QByteArray requestData,QByteArray &replyData);};#endif // HTTP_H

http.cpp

这个方法的第一个参数是 post方法发送请求的URL,第二个参数是请求的方法头,第三个参数是请求的数据,第四个参数是返回的数据。

这里要说的是必须要设置openssl签名配置,否则在ARM上会报错。

bool Http::post_sync(QString url,QMap<QString,QString>header,QByteArray requestData,QByteArray &replyData){// 发送请求的对象QNetworkAccessManager manager;// 请求 对象QNetworkRequest request;request.setUrl(url);QMapIterator<QString,QString> it(header);while (it.hasNext()) {it.next();request.setRawHeader(it.key().toLatin1() ,it.value().toLatin1());}//设置openssl签名配置,否则在ARM上会报错QSslConfiguration conf = request.sslConfiguration();conf.setPeerVerifyMode(QSslSocket::VerifyNone);#if (QT_VERSION > QT_VERSION_CHECK(5,0,0))conf.setProtocol(QSsl::TlsV1_0);#elseconf.setProtocol(QSsl::TlsV1);#endifrequest.setSslConfiguration(conf);QNetworkReply *reply = manager.post(request,requestData);QEventLoop l;//一旦服务器返回,reply会发出信号connect(reply,&QNetworkReply::finished,&l,&QEventLoop::quit);l.exec();if(reply != nullptr && reply->error() == QNetworkReply::NoError){replyData = reply->readAll();return true;}else{qDebug()<<"request error!";return false;}}

2.1.5 发送请求

这里需要向两个URL发送两个请求,第一个请求是把我们4.2.3创建应用得到的API Key 和 Secret Key组合成一个URL获取access_token,第二个请求是把音频文件发送请求到语音识别的URL才能返回语音识别的结果。

我们新建一个类Speech

Speech.h

这里我们把API Key和Secret Key作为参数传到const QString baiduTokenUrl里面去。把主机名和获取的access_token做为参数传入const QString baiduSpeechUrl。

#include <QObject>#include <QJsonDocument>#include <QJsonParseError>#include <QJsonObject>#include <QJsonValue>#include <QJsonArray>#include <QFile>#include "http.h"#include <QHostInfo>// 获取Access Tokenconst QString baiduTokenUrl = "/oauth/2.0/token?grant_type=client_credentials&client_id=%1&client_secret=%2&";const QString client_id = "我们创建应用的API Key";const QString client_secret = "我们创建应用的Secret Key";// 语音识别urlconst QString baiduSpeechUrl = "/server_api?dev_pid=1537&cuid=%1&token=%2";class Speech:public QObject{Q_OBJECTpublic:Speech();QString speechIdentify(QString fileName);private:QString getJsonValue(QByteArray ba,QString key);};#endif // SPEECH_HSpeech.cppQString Speech::speechIdentify(QString fileName){// 获取Access TokenQString tokenUrl =QString(baiduTokenUrl).arg(client_id).arg(client_secret);Http my_http;QMap<QString,QString>header;header.insert(QString("Content-Type"),QString("audio/pcm;rate=16000"));QByteArray requestData;//请求内容QByteArray replyData;//url返回内容qDebug()<<tokenUrl;bool result = my_http.post_sync(tokenUrl,header,requestData,replyData);if(result) {QString key = "access_token";QString accessToken =getJsonValue(replyData,key);qDebug()<<accessToken;// 语音识别QString speechUrl = QString(baiduSpeechUrl).arg(QHostInfo::localHostName()).arg(accessToken);QFile file;file.setFileName(fileName);file.open(QIODevice::ReadOnly);requestData = file.readAll();file.close();replyData.clear();// 再次发起请求result = my_http.post_sync(speechUrl,header,requestData,replyData);if(result) {QString key = "result";QString retText =getJsonValue(replyData,key);qDebug()<<retText;return retText;}else{return NULL;}}else {return "error";}}

解析返回的数据

返回的数据是这种Json类型的,我们只需要获取里边result的值就能得到我们想要的结果了。

{"err_no":0,"err_msg":"success.","corpus_no":"15984125203285346378","sn":"481D633F-73BA-726F-49EF-8659ACCC2F3D","result":["北京天气"]}

QString Speech::getJsonValue(QByteArray ba,QString key){QJsonParseError parseError;QJsonDocument jsondocument = QJsonDocument::fromJson(ba,&parseError);if(parseError.error ==QJsonParseError::NoError){if(jsondocument.isObject()){QJsonObject jsonObject = jsondocument.object();if(jsonObject.contains(key)){QJsonValue jsonvalue = jsonObject.value(key);if(jsonvalue.isString())return jsonvalue.toString();else if(jsonvalue.isArray()){QJsonArray arr = jsonvalue.toArray();QJsonValue val =arr.at(0);return val.toString();}}}}return "";}

2.1.6 MainWindow类调用函数

我们在释放按钮的槽函数里添加以下代码。

void MainWindow::on_pushButton_video_released(){ui->pushButton_video->setText("按住说话");RecorderEnd();Speech my_speech;QString text =my_speech.speechIdentify("./1.pcm");ui->textEdit->append(text);audioCtrl(text);

2.1.7 语音控制设备联动

void MainWindow::audioCtrl(QString text){if(text == "开灯。"){system("echo 1 >/sys/class/leds/user1/brightness");system("echo 1 >/sys/class/leds/user2/brightness");system("echo 1 >/sys/class/leds/user3/brightness");ui->textEdit_2->setText("灯已打开");}else if(text == "关灯。"){system("echo 0 >/sys/class/leds/user1/brightness");system("echo 0 >/sys/class/leds/user2/brightness");system("echo 0 >/sys/class/leds/user3/brightness");ui->textEdit_2->setText("灯已关闭");}else if(text == "报警。"){int fd;struct input_event event;struct timeval time;fd = open("/dev/input/by-path/platform-beeper-event", O_RDWR);event.type = EV_SND;event.code = SND_TONE;event.value = 1000;time.tv_sec = 1;time.tv_usec = 0;event.time = time;write(fd, &event, sizeof(struct input_event));ui->textEdit_2->setText("蜂鸣器已报警");}else if(text == "关闭。"){int fd;struct input_event event;struct timeval time;fd = open("/dev/input/by-path/platform-beeper-event", O_RDWR);event.type = EV_SND;event.code = SND_TONE;event.value = 0;time.tv_sec = 0;time.tv_usec = 0;event.time = time;write(fd, &event, sizeof(struct input_event));ui->textEdit_2->setText("蜂鸣器报警已关闭");}else if(text == "关风扇。"){unsigned char arg;Ioctl(EXIT_FAN,&arg);ui->textEdit_2->setText("风扇已关闭");}else if(text == "开风扇。"){unsigned char arg;Ioctl(EXIT_FAN,&arg);Ioctl(INIT_FAN,&arg);Ioctl(FAN_UP,&arg);ui->textEdit_2->setText("风扇已打开");}else if(text == "温度。"){QString tem = temCollect();ui->textEdit_2->setText(QString("此时温度为:").append(tem).append("'C"));}else if(text == "湿度。"){QString hum = humCollect();ui->textEdit_2->setText(QString("此时湿度为:").append(hum).append("%"));}}

2.2 智慧生活模块

2.2.1 创建API应用

浏览器进入和风天气官网,注册账号并登陆,点击进入控制台。

进入控制台后,点击应用管理。

点击创建应用,选择免费开发板

填写天气数据应用名称后选择WebAPI,自定义天气数据应用名称。

完成上述操作后,把key复制下来,后边代码需要用到。

2.2.2 Get方法获取API的JSON数据

我们将key填写到下面的URL里面,使用get方法就能从API爬下JSON数据来了。

/v7/indices/1d?type=1,2&location=101010100&key=你的KEY

其中请求参数

Location:需要查询地区的LocationID或以英文逗号分隔的经度,纬度坐标(十进制),LocationID可通过城市搜索服务获取。例如 location=101010100

Key:用户认证key,即上面获取到的key。

Type:生活指数的类型ID,包括洗车指数、穿衣指数、钓鱼指数等。可以一次性获取多个类型的生活指数,多个类型用英文,分割。例如type=3,5。具体生活指数的ID和等级参考生活指数常量。各项生活指数并非适用于所有城市。

所以我们以参数的形式将城市的LocationID填入URL就能获取不同城市的生活指标。

具体代码参考下面:

//get方法获取信息void LifeWidget::sendQuest(QString cityStr){QString key = "您申请的key";QString quest_url = "/v7/indices/1d?type=0&location=%1&key=%2";quest_url = quest_url.arg(cityStr).arg(key);QNetworkRequest quest;quest.setUrl(QUrl(quest_url));//设置openssl签名配置,否则在ARM上会报错QSslConfiguration conf = quest.sslConfiguration();conf.setPeerVerifyMode(QSslSocket::VerifyNone);#if (QT_VERSION > QT_VERSION_CHECK(5,0,0))conf.setProtocol(QSsl::TlsV1_0);#elseconf.setProtocol(QSsl::TlsV1);#endifquest.setSslConfiguration(conf);manager->get(quest); /*发送get网络请求*/}//数据接收槽函数void LifeWidget::replyFinished(QNetworkReply *reply){replyall = reply->readAll();reply->deleteLater(); //销毁请求对象}void LifeWidget::init_networt_life(){manager = new QNetworkAccessManager(this); connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));//关联信号和槽}

2.2.3 解析JSON数据

{"code": "200","updateTime": "-02-06T16:36+08:00","fxLink": "http://hfx.link/2ax2","daily": [{"date": "-02-06","type": "2","name": "洗车指数","level": "2","category": "较适宜","text": "较适宜洗车,未来一天无雨,风力较小,擦洗一新的汽车至少能保持一天。"},{"date": "-02-06","type": "1","name": "运动指数","level": "3","category": "较不宜","text": "天气较好,但考虑天气寒冷,推荐您进行室内运动,户外运动时请注意保暖并做好准备活动。"}],"refer": {"sources": ["Weather China"],"license": ["commercial license"]}}

我们通过get方法获取到的JOSN数据如上所示。只需要解析key为daily的值即可。其中daily的值是一个数组类型的数据,只需要取出我们需要的即可。

void DetaInfo::setInfo(QString info,int type){qDebug()<<"setINfo";QJsonParseError err;QJsonDocument json_recv = QJsonDocument::fromJson(info.toUtf8(), &err);//解析json对象if (!json_recv.isNull()){QJsonObject object = json_recv.object();if (object.contains("daily")){QJsonValue value = object.value("daily"); // 获取指定 key 对应的 valueif (value.isArray()){QJsonObject today_life = value.toArray().at(type).toObject();QString category = today_life.value("category").toString();QString text = today_life.value("text").toString();ui->label_category->setText(category);ui->label_text->setText(text);}}}}

2.3 出行地图模块

2.3.1 申请百度地图API秘钥

进入百度地图官网

点击进入控制台。

这里需要登录百度账号,扫码或者输入用户名密码登录即可。

登录成功后点击应用管理下的我的应用。

点击创建应用

自定义应用名称后,应用类型选择浏览器端,在白名单输入框输入*。

这里就是我们需要的AK秘钥。

2.3.2 新建map.html

复制百度地图API源码。

新建map.html

将上面API的源码复制到吗map.html

将代码里面的红框里的您的秘钥替换刚才申请的AK即可。

2.3.3 在map.html文件添加方法

添加函数,通过QT程序传参来改变地图路线的起点,途经点,终点。

2.3.4 QT端实现

这里使用了webkit模块,在pro文件中添加

QT += webkit webkitwidgets

具体代码如下

void MainWindow::mapinit(){QWebSettings *settings = QWebSettings::globalSettings();settings->setAttribute(QWebSettings::PluginsEnabled, true);//允许插件settings->setAttribute(QWebSettings::JavascriptEnabled, true);//JavaScriptsettings->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);//settings->setAttribute(QWebSettings::JavascriptCanOpenWindows, true);settings->setFontFamily(QWebSettings::FixedFont,"幼圆");ui->webView->setStyle(new CustomStyle());ui->webView->load(QUrl("qrc:/map.html"));connect(ui->webView->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(populateJavaScriptWindowObject()));}void MainWindow::populateJavaScriptWindowObject(){ui->webView->page()->mainFrame()->addToJavaScriptWindowObject("Mywebkit", this);}void MainWindow::onBtnCallJSClicked(){QString strVal = QString("callfromqt(要传的参数);"));ui->webView->page()->mainFrame()->evaluateJavaScript(strVal);}

2.4 智能闹钟模块

2.4.1 开启线程,检测时间

这里设置了四个闹钟,即在线程类里边设置了四个全局变量(闹钟时间)。当前时间戳等于设置的时间戳后设置蜂鸣器响起。

void TimeAlarmClock::run(){while (1) {QDateTime time = QDateTime::currentDateTime(); //获取当前时间uint timeT = time.toTime_t(); //将当前时间转为时间戳// qDebug()<<timeT<<alarm_clocktime1;if(alarm_clocktime1==timeT){beep_on();// qDebug()<<"open";}else{}if(alarm_clocktime2==timeT){beep_on();}else{}if(alarm_clocktime3==timeT){beep_on();}else{}if(alarm_clocktime4==timeT){beep_on();}else{}}}void TimeAlarmClock::beep_on(){int fd;struct input_event event;struct timeval time;fd = open("/dev/input/by-path/platform-beeper-event", O_RDWR);event.type = EV_SND;event.code = SND_TONE;event.value = 1000;time.tv_sec = 1;time.tv_usec = 0;event.time = time;write(fd, &event, sizeof(struct input_event));close(fd);}

2.4.2 提交闹钟时间

使用QdateTimeEdit设置闹钟时间,点击按钮后,将闹钟时间设置到线程中的全局变量中。void MainWindow::on_time_btn1_clicked(){if(ui->time_btn1->text()==" "){ui->time_btn1->setText("\n");timeAlarmClock.alarm_clocktime1 = ui->dateTimeEdit_1->dateTime().toTime_t();}else{ui->time_btn1->setText(" ");timeAlarmClock.alarm_clocktime1 = 0;}}

总结

此项目可在ubuntu下运行,也可通过交叉编译在ARM平台上运行。源码请私信

如果觉得《智能语音生活助手实现(QT)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。