REST实战——调用百度语音的云服务

RESTful

REST(REpresentation State Transfer)描述了一个架构样式的网络系统,比如说web应用程序。它首次出现在2000年Roy Thomas Fielding的博士论文中,他是 HTTP 规范的主要编写者之一。REST指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计,即具有REST风格就是RESTful。在REST中,以资源为核心,任何事物,只要具有被引用的必要,就是一个资源。每个资源必须至少有一个统一资源标识符,即URI,URI既是资源的名称也是资源的地址。URI和资源之间的关系是多对一的,也就是说一个URI仅标识一个资源,但是一个资源可以有多余一个URI。REST中的资源是数据和表现形式的组合,以资源为核心的设计思想是REST的核心所在。资源是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈现出来的形式,叫做它的表现层(Representation)。如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"(State
Transfer)。而这种转化是建立在表现层之上的,所以就是"表现层状态转化"。客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。REST规范包括:客户-服务器,无状态,缓存,统一接口,分层系统和按需代码。这些架构约束是从Fielding的博士论文中直译过来的,所以极力推荐阅读Roy Thomas
Fielding的博士论文,可以对REST有一个更深刻的理解。

目前,基于RESTful的Web Service在一些领域得到了较好的利用,一些大公司已经提供了基于REST的网络服务。比如说的国外的谷歌、亚马逊等,国内的百度等公司。下面就以一个比较有意思的语音识别云服务为例,该服务是百度http://yuyin.baidu.com/提供的。

百度语音云服务

百度的语音识别服务通过RESTAPI的方式给开发者提供了一个通用的HTTP接口。这么做的一个好处就是轻量级。这里的轻量级的意思是,不需要在开发的应用中集成任何SDK,也不需要在测试机中添加任何的识别引擎。开发者只需要了解HTTP网络请求以及百度语音REST API的使用规则,就可以在自己的应用中实现语音识别功能。

当然,在使用百度的语音云服务之前,肯定是要进行开发者注册申请的,申请完以后百度会给开发者提供一个API Key和Secret Key,在后期跟百度的服务器通信时会用到两个Key。在使用百度的语音识别 REST API之前,需要获取一个Access Token。这个Access Token 是用户身份验证和授权的凭证。百度的语音识别采用的是Client Credentials(http://developer.baidu.com/wiki/index.php?title=docs/oauth/client)授权方式,即采用应用公钥、密钥的方式来获取Access
Token,适用于任何带server类型应用,通过此授权方式获取的Access Token仅可访问平台授权类的接口,也就是说,通过它所获取的Access Token只能用于访问与用户无关的Open API。获取Access Token的方法也很简单。开发者按照百度的要求,给百度的服务器发送特定格式的请求数据包,百度的服务器就会返回一个响应数据包,这个响应数据包里面就有Json格式的数据,其中的一个字段就是access_token。

获取Access Token需要应用给百度POST一个OAuth2.0授权服务的请求,POST到的地址为https://openapi.baidu.com/oauth/2.0/token,还需要带上以下的参数:grant_type:必须参数,固定为“client_credentials”;client_id:必须参数,也就是开发者申请时百度给开发者提供的API
Key;client_secret:必须参数,也就是开发者申请时百度给开发者提供的Secret Key;scope:非必须参数,是一个以空格分隔的权限列表。比如说一个标准的POST请求数据包的格式如下:

https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id=Va5yQRHlA4Fq4eR3LT0vuXV4&client_secret= 0rDSjzQ20XUj5itV7WRtznPQSzr5pVw2

在请求参数无误的情况下,百度的服务器会返回一段Json格式的文本,具有以下字段:access_token:要获取的Access Token;expires_in:Access Token的有效期,以秒为单位;refresh_token:用于刷新Access Token 的Refresh Token,所有应用都会返回该参数;scope:Access Token最终的访问范围,即用户实际授予的权限列表(用户在授权页面时,有可能会取消掉某些请求的权限),关于权限的具体信息参考“权限列表”一节;session_key:基于http调用Open
API时所需要的Session Key,其有效期与Access Token一致;session_secret:基于http调用Open API时计算参数签名用的签名密钥。例如,百度服务器返回的一个响应数据包如下:

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store

{
"access_token": "1.a6b7dbd428f731035f771b8d15063f61.86400.1292922000-2346678-124328",
    "expires_in": 86400,
"refresh_token": "2.385d55f8615fdfd9edb7c4b5ebdc3e39.604800.1293440400-2346678-124328",
    "scope": "public",
    "session_key": "ANXxSNjwQDugf8615OnqeikRMu2bKaXCdlLxn",
    "session_secret": "248APxvxjCZ0VEC43EYrvxqaK4oZExMB",
}

若请求错误,百度的服务器也会返回一段Json格式的文本,包含以下参数:error:错误码,即错误类型的代码;error_description:错误描述信息,用来帮助理解和解决发生的错误。比如说如下的请求响应数据包:

HTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-store

{
    "error": "invalid_grant",
"error_description":"Invalid authorization code: ANXxSNjwQDugOnqeikRMu2bKaXCdlLxn"
}

想利用C或者C++语言来完成上述工作时,有一个很强大的工具:curl。curl是利用URL语法在命令行方式下工作的开源文件传输工具。它被广泛应用在Unix、多种Linux发行版中,并且有DOS和Win32、Win64下的移植版本。在C/C++中也有对应的开发库函数——libcurl,该库为开发者提供了丰富的库函数用于给服务器通信。比如说想利用curl获取百度的Access Token,方法也很简单,利用curl –s命令给百度的服务器POST一个请求就可以实现,我在自己的机器上实验如下图:

通过上图,可以看出响应的结果就是一段Json格式的数据包。其中 “access_token” 字段即为请求REST API 所需的令牌,默认情况下,Access Token的有效期是一个月,开发者需要对Access Token的有效性进行判断,如果Access Token过期可以重新获取。

想利用百度的语音识别服务来识别本地的一段语音也很简单,直接给百度的服务器POST自己的语音数据,对方的服务器就会返回一段Json格式的文本,相应的字段就是识别的结果,将这个结果解析出来就可以利用识别的结果了。

百度语音的云服务支持POST的方式来上传语音数据;目前百度语音的REST API仅支持整段语音识别的模式,即需要上传整段语音进行识别。语音数据的压缩格式有以下几种:pcm(不压缩)、wav、opus、speex、amr、x-flac这几种。

语音数据的上传方式有两种:隐示发送和显示发送。所谓的隐式发送就是就是将语音数据格式化成标准的Json格式数据,通过POST上传,这里的Json格式规定了相应的字段,当然,在格式化之前需要将语音数据进行Base64编码。所谓的显示发送顾名思义就是将语音数据直接放在HTTP-BODY中,控制REST参数以及相关的统计信息就可以通过REST API进行传递。对于上面的两种上传方式,百度的服务器都会返回统一的结果,都采用Json格式封装。如果识别成功,识别结果放在 JSON的“result”字段中,统一采用 utf-8
方式编码。

对于上面的所有HTTP动作,在liburl库中都有相应的库函数,所以用起来非常得方便。下面给出一个例子。利用百度的语音识别服务来POST一段本地pcm格式的语音数据给百度的服务器,语音数据的内容是“百度语音提供技术支持”。源码也很简单,主要就是base64编码、Json格式数据解析和利用libcurl库函数来进行POST、GET操作。环境是在Ubuntu下进行的,当然在使用之前需要先安装jsoncpp库和libcurl库,安装方法也很简单,网上有一大堆。这里直接贴上源码:

#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include "curl/curl.h"

#include "curl/easy.h"
#include "json/json.h"
#define MAX_BUFFER_SIZE 512
#define MAX_BODY_SIZE 1000000
using namespace std;

static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(unsigned char c)
{
	return (isalnum(c) || (c == '+') || (c == '/'));
}

string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len)
{
	std::string ret;
	int i = 0;
	int j = 0;
	unsigned char char_array_3[3];
	unsigned char char_array_4[4];

	while (in_len--)
	{
		char_array_3[i++] = *(bytes_to_encode++);
		if (i == 3)
		{
			char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
			char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
			char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
			char_array_4[3] = char_array_3[2] & 0x3f;

			for (i = 0; (i <4); i++)
				ret += base64_chars[char_array_4[i]];
			i = 0;
		}
	}

	if (i)
	{
		for (j = i; j < 3; j++)
			char_array_3[j] = '\0';

		char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
		char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
		char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
		char_array_4[3] = char_array_3[2] & 0x3f;

		for (j = 0; (j < i + 1); j++)
			ret += base64_chars[char_array_4[j]];

		while ((i++ < 3))
			ret += '=';
	}
	return ret;
}

string base64_decode(std::string const& encoded_string)
{
	int in_len = encoded_string.size();
	int i = 0;
	int j = 0;
	int in_ = 0;
	unsigned char char_array_4[4], char_array_3[3];
	std::string ret;

	while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_]))
	{
		char_array_4[i++] = encoded_string[in_]; in_++;
		if (i == 4)
		{
			for (i = 0; i <4; i++)
				char_array_4[i] = base64_chars.find(char_array_4[i]);

			char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
			char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
			char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

			for (i = 0; (i < 3); i++)
				ret += char_array_3[i];
			i = 0;
		}
	}

	if (i)
	{
		for (j = i; j <4; j++)
			char_array_4[j] = 0;

		for (j = 0; j <4; j++)
			char_array_4[j] = base64_chars.find(char_array_4[j]);

		char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
		char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
		char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

		for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
	}
	return ret;
}

//回调函数
static size_t writefunc(void *ptr, size_t size, size_t nmemb, char **result)
{
	size_t result_len = size * nmemb;
	*result = (char *)realloc(*result, result_len + 1);
	if (*result == NULL)
	{
		printf("realloc failure!\n");
		return 1;
	}
	memcpy(*result, ptr, result_len);
	(*result)[result_len] = '\0';
	cout<<百度服务器返回的json数据:"<<*result<<endl;
	/*Json::Reader reader;
	Json::Value root;
	if(reader.parse(result,root))
	{
		string res = root["result"].asString();
		cout <<"解析的结果: "<< res << endl;
	}*/
	return result_len;
}

int main()
{
	freopen("out.txt", "w", stdout);
	int json_file_size;
	FILE *pFile = NULL;
	char *audio_data;
	pFile = fopen("test.pcm", "r");
	if (pFile == NULL)
	{
		perror("Open file error!\n");
	}
	else
	{
		fseek(pFile, 0, SEEK_END);
		int file_size = ftell(pFile);
		cout << "file size: " << file_size << " bytes" << endl;
		fseek(pFile, 0, SEEK_SET);
		audio_data = (char *)malloc(sizeof(char)*file_size);
		fread(audio_data, file_size, sizeof(char), pFile);

		//机器的mac地址
		char *cuid = "56:84:7a:fe:97:99";
		char *api_key = "6yFhYifMjXc8QmubiICXBQgi";
		char *secret_key = "nZn45o3X0LGx42qovumYy2mjpOiOup2E";

		char host[MAX_BUFFER_SIZE];
		snprintf(host, sizeof(host),
			"https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id=%s&client_secret=%s",
			api_key, secret_key);
		cout << "curl -s命令的host: " << host << endl;

		FILE *p = NULL;
		char cmd[MAX_BUFFER_SIZE];
		//curl -s命令的返回结果
		char *result = (char*)malloc(MAX_BUFFER_SIZE);
		char *curl_cmd = "curl -s ";
		char *yinhao = "\"";

		strcpy(cmd, curl_cmd);
		strcat(cmd, yinhao);
		strcat(cmd, host);
		strcat(cmd, yinhao);

		p = popen(cmd, "r");
		fgets(result, MAX_BUFFER_SIZE, p);
		cout << "curl -s 响应结果: " << result << endl;
		pclose(p);

		string access_token;
		//解析服务器返回的Json数据,获取access_token
		if (result != NULL)
		{
			Json::Reader reader;
			Json::Value root;
			if (reader.parse(result, root, false))
			{
				access_token = root.get("access_token", "").asString();
			}
			cout << "access_token: " << access_token << endl;
		}

		//采取隐式发送的方式给服务器发送json格式的数据
		char body[MAX_BODY_SIZE];
		memset(body, 0, sizeof(body));
		string decode_data = base64_encode((const unsigned char *)audio_data, file_size);
		if (0 == decode_data.length())
		{
			cout << "Error!base64 encoded data is empty!";
			return 1;
		}
		else
		{
			Json::Value buffer;
			Json::FastWriter buf_writer;
			buffer["format"] = "pcm";
			buffer["rate"] = 8000;
			buffer["channel"] = 1;
			buffer["token"] = access_token.c_str();
			buffer["cuid"] = cuid;
			buffer["speech"] = decode_data;
			buffer["len"] = file_size;
			//实际json格式数据的长度
			json_file_size = buf_writer.write(buffer).length();
			cout << "Json file size:" << json_file_size << " bytes" << endl;
			memcpy(body, buf_writer.write(buffer).c_str(), json_file_size);

			CURL *curl;
			CURLcode res;//服务器的响应结果
			char *result_buffer = NULL;
			struct curl_slist *http_header = NULL;
			char temp[MAX_BUFFER_SIZE];
			memset(temp, 0, sizeof(temp));
			snprintf(temp, sizeof(temp), "%s", "Content-Type: application/json; charset=utf-8");
			http_header = curl_slist_append(http_header, temp);
			snprintf(temp, sizeof(temp), "Content-Length: %d", json_file_size);
			http_header = curl_slist_append(http_header, temp);

			memset(host, 0, sizeof(host));
			snprintf(host, sizeof(host), "%s", "http://vop.baidu.com/server_api");
			cout << "server host: " << host << endl;
			curl = curl_easy_init();
			curl_easy_setopt(curl, CURLOPT_URL, host);//设置访问的URL
			curl_easy_setopt(curl, CURLOPT_POST, 1);//1表示常规的http post请求
			curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30);//设置延时
			curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_header);
			curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body);
			curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, json_file_size);
			curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);//设置回调函数
			curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result_buffer);
			res = curl_easy_perform(curl);
			if (res != CURLE_OK)
			{
				printf("perform curl error:%d.\n", res);
				return 1;
			}
			curl_slist_free_all(http_header);
			curl_easy_cleanup(curl);

			free(audio_data);
		}
	}

	fclose(pFile);
	return 0;

}

因为利用了额外的库函数,所以在编译时需要加上链接参数,编译命令如下:

g++-o bdvoice BaiduVR.cpp -L . -l json_linux-gcc-4.8_libmt -l curl

注:这里将jsoncpp库的头文件在json文件夹下和libcurl库的头文件在curl文件夹下,以及相应的.a和.so库跟代码文件放在一个目录下。运行可执行文件,源码中将标准输出写入到out.txt,out.txt的内容如下:

时间: 2024-07-30 15:41:43

REST实战——调用百度语音的云服务的相关文章

QT调用百度语音REST API实现语音合成

QT调用百度语音REST API实现语音合成 1.首先点击点击链接http://yuyin.baidu.com/docs/tts 点击access_token,获取access_token,里面有详细步骤,不再赘述 记下链接,等会在QT程序中会用到,tex后面跟要转换成语音的文字,tok后面是刚获得的access_token 2.打开Qt Creator,新建一个QWidget应用程序,绘制界面如下 3.获取语音按钮槽函数如下 void Widget::on_pushButton_clicked

调用百度语音AI实现语音的识别和合成

#coding:utf-8 ## 先去ffmpeg官网下载(https://ffmpeg.zeranoe.com/builds/),好了之后解压缩,配一下环境变量 ## 打开cmd,运行命令,安装如下的包 ## pip install baidu-aip ## pip install pydub ## pip install PyAudio ## pip install Wave """ 调用百度语音api """ from aip import

python调用百度语音(语音识别-斗地主语音记牌器)

一.概述 本篇简要介绍百度语音语音识别的基本使用(其实是斗地主时想弄个记牌器又没money,抓包什么的又不会,只好搞语音识别的了) 二.创建应用 打开百度语音官网,产品与使用->语音识别->立即使用->创建应用 出现如下页面 依照提示依次填写,最终结果 (ps:我就想弄个记牌的,就起了个计数器的名) 点右方的 ‘查看key’ 记下App ID,API Key,Secret Key.接下来要用到 需要安装模块 pip install baidu-aip pip install pyaudi

百度AI开放平台- API实战调用

百度AI开放平台- API实战调用 一.      前言 首先说一下项目需求. 两个用户,分别上传了两段不同的文字,要计算两段文字相似度有多少,匹配数据库中的符合条件的数据,初步估计列出来会有60-100条左右,不会更多,只会更少.最终的需求是:从这些匹配结果中找到相似度较高的那些条目. 自己编写算法来实现是一个很大的工程,涉及到自然语言处理的一些方面,比较复杂.于是上网搜了搜,发现百度开放平台的自然语言处理可以免费调用,而且每天有10W的调用次数,对我的小项目来说正好满足.但是,在往下翻的时候

Android 通过调用系统,如接口 谷歌语音、百度语音、科大讯飞语音等语音识别方法对话框

现在app在发展过程中会集成一些语音识别功能,不具有其自己的显影剂一般正在开发的语音识别引擎,所以在大多数情况下,它是选择一个成熟的语音识别引擎SDK集成到他们的app在. 平时,这种整合被分成两个,一种是直接调用SDK开发商设计了弹出框.互界面:另一种是开发人员仅仅利用SDK提供的语音识别服务,自己开发一个属于自己的交互设计. 本文介绍最简单直接调起弹出框的方法. 首先.測试机须要安装如谷歌语音.百度语音.讯飞语音等产品的语音软件,这时能够在系统设置界面的语言与输入处找到相关的语音识别功能列表

Android 通过调用系统接口使用如 谷歌语音、百度语音、讯飞语音等语音识别对话框的方法

现在app的开发进程会集成一些语音识别功能,而一般开发者是不具备自己开发一套语音识别引擎的,因此大多数情况是选择一个已经成熟的语音识别引擎SDK集成到自己的app中. 通常情况下,这种集成分两种,一种是直接调用SDK为开发者设计好的弹出框,开发者不需要开发识别交互界面:还有一种是开发者只利用SDK提供的语音识别服务,自己开发一个属于自己的交互设计. 本文介绍最简单直接调起弹出框的方法. 首先,测试机需要安装如谷歌语音.百度语音.讯飞语音等产品的语音软件,这时可以在系统设置界面的语言与输入处找到相

APP搜索附近功能的一种解决方案-基于百度LBS云服务

为了在APP中根据定位实现搜索附近(POI)的功能,采用百度LBS云服务,将所有POI数据上传后,可以实现该功能. LBS数据管理地址:在这里标记信息后(支持批量上传)即可开始使用搜索功能. http://lbsyun.baidu.com/datamanager/datamanage 搜索附近接口地址: http://api.map.baidu.com/geosearch/v3/nearby 请求方式: GET 参数: { ak:'540b088ff0f926b7d0b6d5a641******

【实战+视频】在龙芯CPU和中标麒麟系统上装品高云,实现EC2,EIP,VPC等云服务

本文详细描述了,如何在国产CPU,龙芯3B(MIPS架构)+中标麒麟OS的运行情况下,如何安装部署品高云(BingoCloudOS),并实现弹性服务器(EC2).弹性IP(EIP)和虚拟私有云(VPC)等云服务. 至此实现了全国产化(国产CPU+国产OS+国产云操作系统)组团的云操作系统架构,为军队.涉密单位乃至未来的国家整体国产化云平台奠定了坚实基础. 先用一个视频,展示下最终成果 环境信息与思路 版本信息 组件 版本 龙芯CPU 3B(MIPS架构) 中标麒麟(类RHEL) 版本:6.0_U

Node.js调用百度地图Web服务API的Geocoding接口进行点位反地理信息编码

(从我的新浪博客上搬来的,做了一些修改.) 最近迷上了node.js以及JavaScript.现在接到一个活,要解析一个出租车点位数据的地理信息.于是就想到使用Node.js调用百度地图API进行解析. 使用的库主要就是有fs.request. // 请求包 var fs = require('fs');var request = require('request'); // 设置百度API的参数var baiduApiKey = "cQV9U4QhamoOjg6rjdOTAQSiUMxxxxx