给浏览器加了一个语音搜索功能【玩转华为云】

DS小龙哥 发表于 2022/01/07 00:06:56 2022/01/07
【摘要】 华为云提供的语音服务支持实时语音识别、录音文件识别、短语音转文字等,提供了HTTP接口的支持,使用起来非常方便;短语音转文字,实时语音转文字用的场景非常多,比如: 会议上的智能笔记本,可以自动识别会场讲话,将语音转为文本保存下来;本篇文章就采用华为云提供的在线语音识别服务给浏览器设计一个语音自动搜索的功能,体验语音转文字接口的效果,编程语言采用C++,软件框架采用QT设计。

1. 前言

随着物联网的发展,语音识别技术受到越来越多的关注,语音识别技术正积极推动信息通信领域的革命,语音拨号,语音邮件,语音输入,语音操控等以语音识别为基础的人机交互日益普及;尽管生物识别方式不断增多,语音识别方式任然是主流方式,与其他生物识别技术相比,语音识别技术不仅具有非接触,非侵入性,使用方便,不会遗失和忘记,不需记忆等特点。

华为云提供的语音服务支持实时语音识别、录音文件识别、短语音转文字等,提供了HTTP接口的支持,使用起来非常方便;短语音转文字,实时语音转文字用的场景非常多,比如: 会议上的智能笔记本,可以自动识别会场讲话,将语音转为文本保存下来;游戏里可以通过短语音转文本快速聊天,不用打字;导航地图可以通过语音操作导航到指定的目的地;智能家居里,通过语音可以控制家电等等,都是语音识别常见的场景。

本篇文章就采用华为云提供的在线语音识别服务给浏览器设计一个语音自动搜索的功能,体验语音转文字接口的效果,编程语言采用C++,软件框架采用QT设计,浏览器内核采用QWebEngineView,在QT5.7以后,QT里就不支持webkit了,目前自带的浏览器内核是QWebEngineView,只能使用MSVC编译编译,mingw要使用浏览器可以单独下载webkit的库,或者使用COM组件调用IE浏览器,当前文章里使用的浏览器是QWebEngineView,编译器采用VS2017,32bit。

语音采集功能使用QT的QAudioInput类来实现,采集声卡的PCM数据,保存起来,通过华为云的语音识别HTTP接口完成文字识别,得到文字后再通过浏览器进行搜索文字相关内容。

实现效果如下:

image-20220106190739135

点击界面上的 ”开始语音采集“按钮,就可以说话,说完点击停止采集,然后调用华为云的语音识别接口进行语音识别,在下面的显示框上显示识别到的文字,然后再完成浏览器自动搜索。

image-20220106190855680

image-20220106193216974

2. 创建语音服务器

2.1 使用语音服务

登录华为云官网: https://www.huaweicloud.com/

选择产品-人工智能-语音交互服务-一句话识别。

image-20220106164835826

短语音识别地址: https://www.huaweicloud.com/product/asr.html

短语音识别是将口述音频转换为文本,通过API调用识别不超过一分钟的不同音频源发来的音频流或音频文件。适用于语音搜索、人机交互等语音交互识别场景。 支持免费试用。

image-20220106165023581

免费试用每日500次,期限是一年,对于测试而言完全足够了。

image-20220106165205406

image-20220106165217533

image-20220106165234937

image-20220106165403583

image-20220106170045851

2.2 HTTP接口使用介绍

文档地址: https://support.huaweicloud.com/api-sis/sis_03_0094.html

image-20220106170707976

在线调试接口地址: https://apiexplorer.developer.huaweicloud.com/apiexplorer/doc?product=SIS&api=RecognizeShortAudio

在线调试功能非常方便,可以找一段语音进行测试,特别是文档有些参数或者格式不清楚的,推荐直接使用在线调试接口,可以了解到那些参数必填,那些可以选填,数据格式是怎么样等等,都很清楚。

几个重要的参数:

本地音频采集的频率、通道数都得与参数匹配。

image-20220106191232190

image-20220106191250256

2.3 接口地址总结

请求地址: "https://{endpoint}/v1/{project_id}/asr/short-audio"

请求数据:
{
    "config": {
        "audio_format": "ulaw8k8bit",
        "property": "chinese_8k_common",
        "add_punc": "yes",
        "digit_norm": "yes",
        "need_word_info": "yes"
    },
    "data": "/+MgxAAUeHpMAUkQAANhuRAC..."
}

请求头里要带: X-Auth-Token 参数

请求数据里的参数在前面截图里介绍了,data就是音频文件的base64编码数据。

请求地址里的endpoint字段、project_id字段、还有X-Auth-Token字段只要是访问华为云的任何API接口都需要填,获取方法看这里: https://bbs.huaweicloud.com/blogs/317759 翻到2.3小节。

image-20220106192419443

识别成功返回的数据:

{
  "trace_id": "567e8537-a89c-13c3-a882-826321939651",
  "result": {
    "text": "欢迎使用语音云服务。",
    "score": 0.9,
    "word_info": [
      {
        "start_time": 150,
        "end_time": 570,
        "word": "欢迎"
      },
      {
        "start_time": 570,
        "end_time": 990,
        "word": "使用"
      },
      {
        "start_time": 990,
        "end_time": 1380,
        "word": "语音"
      },
      {
        "start_time": 1380,
        "end_time": 1590,
        "word": "云"
      },
      {
        "start_time": 1590,
        "end_time": 2070,
        "word": "服务"
      }
    ]
  }
}

其中的text字段就是识别的文本数据。

3. 项目代码示例

下面列出核心的代码,主要是就是字符串拼接格式,拼接完发送http请求即可。

3.1 语音转文字请求代码

//语音转文本
void Widget::audio_to_text(QByteArray data)
{
    function_select=0;

    QString requestUrl;
    QNetworkRequest request;

    //存放文件的BASE64编码
    QString base64_Data;

    //设置请求地址
    QUrl url;

    //一句话识别的请求地址
    requestUrl = QString("https://sis-ext.%1.myhuaweicloud.com/v1/%2/asr/short-audio")
            .arg(SERVER_ID)
            .arg(PROJECT_ID);
    qDebug()<<"requestUrl:"<<requestUrl;
    
    //设置数据提交格式
    request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));

    //将图片进行Base64编码
    base64_Data = QString(data.toBase64());

    //设置token
    request.setRawHeader("X-Auth-Token",Token);

    //构造请求
    url.setUrl(requestUrl);
    request.setUrl(url);

   //设置采样率
   QString post_param=QString
              ("{"
                   "\"config\": {"
                       "\"audio_format\": \"%1\","
                       "\"property\": \"%2\","
                       "\"add_punc\": \"yes\","
                       "\"digit_norm\": \"yes\","
                       "\"need_word_info\": \"yes\""
                   "},"
                   "\"data\": \"%3\""
               "}").arg("pcm16k16bit").arg("chinese_16k_common").arg(base64_Data);

/*
chinese_16k_common  支持采样率为16k的中文普通话语音识别。
pcm16k16bit  16k16bit单通道录音数据。
*/
    //发送请求
    manager->post(request, post_param.toUtf8());
}

3.2 更新token代码

/*
功能: 获取token
*/
void Widget::GetToken()
{
    //表示获取token
    function_select=3;

    QString requestUrl;
    QNetworkRequest request;

    //设置请求地址
    QUrl url;

    //获取token请求地址
    requestUrl = QString("https://iam.%1.myhuaweicloud.com/v3/auth/tokens")
                 .arg(SERVER_ID);

    //自己创建的TCP服务器,测试用
    //requestUrl="http://10.0.0.6:8080";

    //设置数据提交格式
    request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json;charset=UTF-8"));

    //构造请求
    url.setUrl(requestUrl);

    request.setUrl(url);

    QString text =QString("{\"auth\":{\"identity\":{\"methods\":[\"password\"],\"password\":"
    "{\"user\":{\"domain\": {"
    "\"name\":\"%1\"},\"name\": \"%2\",\"password\": \"%3\"}}},"
    "\"scope\":{\"project\":{\"name\":\"%4\"}}}}")
            .arg(MAIN_USER)
            .arg(IAM_USER)
            .arg(IAM_PASSWORD)
            .arg(SERVER_ID);

    //发送请求
    manager->post(request, text.toUtf8());
}

3.3 华为云返回的结果处理

//解析反馈结果
void Widget::replyFinished(QNetworkReply *reply)
{
    QString displayInfo;
    int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();

    //读取所有数据
    QByteArray replyData = reply->readAll();

    qDebug()<<"状态码:"<<statusCode;
    qDebug()<<"反馈的数据:"<<QString(replyData);

    //更新token
    if(function_select==3)
    {
        displayInfo="token 更新失败.";
        //读取HTTP响应头的数据
        QList<QNetworkReply::RawHeaderPair> RawHeader=reply->rawHeaderPairs();
        qDebug()<<"HTTP响应头数量:"<<RawHeader.size();
        for(int i=0;i<RawHeader.size();i++)
        {
            QString first=RawHeader.at(i).first;
            QString second=RawHeader.at(i).second;
            if(first=="X-Subject-Token")
            {
                Token=second.toUtf8();
                displayInfo="token 更新成功.";

                //保存到文件
                SaveDataToFile(Token);
                break;
            }
        }
        qDebug()<<displayInfo;
        return;
    }

    //判断状态码
    if(200 != statusCode)
    {
        //解析数据
        QJsonParseError json_error;
        QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error);
        if(json_error.error == QJsonParseError::NoError)
        {
            //判断是否是对象,然后开始解析数据
            if(document.isObject())
            {
                QString error_str="";
                QJsonObject obj = document.object();
                QString error_code;
                //解析错误代码
                if(obj.contains("error_code"))
                {
                    error_code=obj.take("error_code").toString();
                    error_str+="错误代码:";
                    error_str+=error_code;
                    error_str+="\n";
                }
                if(obj.contains("error_msg"))
                {
                    error_str+="错误消息:";
                    error_str+=obj.take("error_msg").toString();
                    error_str+="\n";
                }
                //显示错误代码
                qDebug()<<error_str;
            }
         }
        return;
    }

    //语音识别
    if(function_select==0)
    {
        //解析数据
        QJsonParseError json_error;
        QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error);
        if(json_error.error == QJsonParseError::NoError)
        {
            //判断是否是对象,然后开始解析数据
            if(document.isObject())
            {
                QString error_str="";
                QJsonObject obj = document.object();
                QString error_code;

                if(obj.contains("result"))
                {
                    QJsonObject obj2=obj.take("result").toObject();
                    if(obj2.contains("text"))
                    {
                        QString text=obj2.take("text").toString();
                        qDebug()<<"识别的文本:"<<text;
                        ui->lineEdit_text_display->setText(text);

                        //浏览器搜索
                        QString url="https://www.baidu.com/s?ie=UTF-8&wd="+text;

                        m_webView->load(QUrl(url));

                    }
                }
                //显示错误代码
                qDebug()<<error_str;
            }
         }
    }
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:cloudbbs@huaweicloud.com进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。