2019-08-15 11:18:50 minthemir 阅读数 1338
  • 微信h5支付开发-php开发微信h5支付demo

    会员免费看,http://edu.csdn.net/lecturer/842右侧可办理会员卡。微信h5支付开发是子恒老师《子恒说微信开发》视频教程的第17部。详细讲解了微信H5支付开发,内容包含开通H5支付,实现微信h5支付,订单查询,关闭订单等等。欢迎反馈,微信号:QQ68183131

    8517 人正在学习 去看看 秦子恒
最近在学习如何应用API来实现语言交互系统的功能,所以打算写一篇文章来整理和记录自己了解API使用的过程。
有很多平台提供语音识别等功能的API,文章使用的是科大讯飞开发的API。

讯飞开放平台简介

本文所使用的资料和基础代码均来自科大讯飞的 讯飞开放平台开放平台论坛社区讯飞开放平台上提供了很多产品和项目解决方案,一些SDK以及基础使用方法。你只需注册一个账号(或进一步实名制来申请更多资源)就可获取一个APPID,就可以在一定的每日免费使用量下完成本文的demo。

讯飞开放平台
讯飞开放平台–论坛社区

SDK的下载

实际上讯飞开放平台提供的SDK会根据你的选中的功能自动生成一个包含你APPID的压缩包,里面会有已经实现你选中功能的例程sample的整个工程:
如果使用语音唤醒需要提前在控制台的页面内设置唤醒词,然后再下载SDK
在这里插入图片描述
平台已经提供了相关的文档来支持你跑动所有你可以下载到的例程,并且你的APPID已经设置到相应的文件里,你无需再自行修改(如果出现问题,可参照平台文档内流程设置或重新下载SDK)。本文默认认为你已经了解讯飞开放平台的基本使用方法因此这里就不再过多的提及。
由于文章写的是Windows平台的demo,所以在这里贴一个Windows下的API文档:

MSC for Windows&Linux API

文档里面详尽的提供了API文档应该提供的内容,但是如果之前没有相关经验或者和我一样是那种没有认真写过代码的CS本科生,那么你需要通过一定的实践和认真阅读代码来熟悉和理解。

Visual Studio工程

在这里插入图片描述
如你所见,压缩包里的工程已经整理好你所选中的所有功能,你可以每一个都把玩一下,看看他们运行起来的样子。这有助于理解API函数运行的逻辑,并给你提供一个设计应用的思路。
如你所见,官方提供的Windows\Linux平台API全部都是C语言编写,如果你要根据具体项目开发使用其他编程语言(或许可以使用WebAPI)。
同时,例程项目都是单独生成的,因此每一个功能的例程都是单独运行的。

离线语音识别

我实现的demo是通过本地离线命令词识别来进行语音识别,讯飞开放平台对这个原理的介绍如下:

语法(命令词)识别,是基于语法规则,将与语法一致的自然语言音频转换为文本输出的技术。语法识别的结果值域只在语法文件所列出的规则里,故有很好的匹配率,另外,语法识别结果携带了结果的置信度,应用可以根据置信分数,决定这个结果是否有效。语法识别多用于要更准确结果且有限说法的语音控制,如空调的语音控制等。在使用语法识别时,应用需要先编写一个语法文件,然后通过调用QISRBuildGrammar接口编译本地语法文件,以及获得语法ID,并在会话时,传入语法ID,以使用该语法。

后面我会在讲语法开发怎么做,首先要把拼凑出来的代码跑通。

主函数

int main(int argc, char* argv[])
{
	const char *login_config    = "appid = 123456789"; //登录参数,这里写你的APPID
	UserData asr_data; 
	int ret                    = 0 ;

	ret = MSPLogin(NULL, NULL, login_config); //第一个参数为用户名,第二个参数为密码,传NULL即可,第三个参数是登录参数
	if (MSP_SUCCESS != ret) {
		printf("登录失败:%d\n", ret);
		goto exit;
	}

	memset(&asr_data, 0, sizeof(UserData));
	printf("构建离线识别语法网络...\n");
	ret = build_grammar(&asr_data);  //第一次使用某语法进行识别,需要先构建语法网络,获取语法ID,之后使用此语法进行识别,无需再次构建
	if (MSP_SUCCESS != ret) {
		printf("构建语法调用失败!\n");
		goto exit;
	}
	while (1 != asr_data.build_fini)
		_sleep(300);
	if (MSP_SUCCESS != asr_data.errcode)
		goto exit;
	printf("离线识别语法网络构建完成,开始识别...\n");	
	ret = run_asr(&asr_data);		//执行封装好的语音识别函数
	if (MSP_SUCCESS != ret) {
		printf("离线语法识别出错: %d \n", ret);
		goto exit;
	}

	printf("请按任意键继续\n");
	_getch();
	printf("更新离线语法词典...\n");
	ret = update_lexicon(&asr_data);  //当语法词典槽中的词条需要更新时,调用QISRUpdateLexicon接口完成更新
	if (MSP_SUCCESS != ret) {
		printf("更新词典调用失败!\n");
		goto exit;
	}
	while (1 != asr_data.update_fini)
		_sleep(300);
	if (MSP_SUCCESS != asr_data.errcode)
		goto exit;
	printf("更新离线语法词典完成,开始识别...\n");
	ret = run_asr(&asr_data);
	if (MSP_SUCCESS != ret) {
		printf("离线语法识别出错: %d \n", ret);
		goto exit;
	}

exit:
	MSPLogout();
	printf("请按任意键退出...\n");
	_getch();
	return 0;
}

API提供的函数,几乎所有的函数返回值都是通过宏定义的错误码,而这个错误码可以在官方的查询链接里查询:
错误码查询–讯飞开放平台
对于错误码的及时和解决方法都说的比较笼统,如果你跟我一样缺乏相关经验,估计要花时间来猜测分析错误的原因。

run_asr运行整套流程:

int run_asr(UserData *udata)
{
	char asr_params[MAX_PARAMS_LEN]    = {NULL};
	//离线唤醒的参数设置
	const char *ssb_param = "ivw_threshold=0:1450,sst=wakeup,ivw_res_path =fo|res/ivw/wakeupresource.jet";
	const char *rec_rslt               = NULL;
	const char *session_id             = NULL;
	const char *asr_audiof             = NULL;
	FILE *f_pcm                        = NULL;
	char *pcm_data                     = NULL;
	long pcm_count                     = 0;
	long pcm_size                      = 0;
	int last_audio                     = 0;
	int aud_stat                       = MSP_AUDIO_SAMPLE_CONTINUE;
	int ep_status                      = MSP_EP_LOOKING_FOR_SPEECH;
	int rec_status                     = MSP_REC_STATUS_INCOMPLETE;
	int rss_status                     = MSP_REC_STATUS_INCOMPLETE;
	int errcode                        = -1;
	int aud_src                        = 0;
	const char res[] = "id=\"001\"";
	//离线语法识别参数设置
	_snprintf(asr_params, MAX_PARAMS_LEN - 1, 
		"engine_type = local, \
		asr_res_path = %s, sample_rate = %d, \
		grm_build_path = %s, local_grammar = %s, \
		result_type = xml, result_encoding = GB2312,vad_eos=1000 ",
		ASR_RES_PATH,
		SAMPLE_RATE_16K,
		GRM_BUILD_PATH,
		udata->grammar_id
		);
	//printf("音频数据在哪? \n0: 从文件读入\n1:从MIC说话\n");
	//scanf("%d", &aud_src);
	
	//Getid(res);
	if(1) {
		while (1) //保持运行
		{
			printf("等待唤醒:\n");
			run_ivw(NULL, ssb_param);	//运行唤醒函数
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12);
			printf("你好!小恩正在听……\n");	
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
			run_asr_mic(asr_params);	//运行麦克风语音识别
		}
	} else {
		asr_audiof = get_audio_file();	//获取本地录音文件
		demo_file(asr_audiof, asr_params); 	//运行本地录音识别
	}
	return 0;
}

在原版的例程中是有一个函数是用本地录音进行语音识别,你也可以去掉或者保留用作调试。

唤醒功能的参数设置:

const char *ssb_param = "ivw_threshold=0:1450,\
sst=wakeup,\
ivw_res_path =fo|res/ivw/wakeupresource.jet";

识别功能的参数设置:

_snprintf(asr_params, MAX_PARAMS_LEN - 1, 
		"engine_type = local, \
		asr_res_path = %s, sample_rate = %d, \
		grm_build_path = %s, local_grammar = %s, \
		result_type = xml, result_encoding = GB2312,vad_eos=1000 ",
		ASR_RES_PATH,
		SAMPLE_RATE_16K,
		GRM_BUILD_PATH,
		udata->grammar_id
		);

我在这里将engine_type 参数设置为 local,表示我使用的是本地离线识别。
结果类型为XML类型,result_type = xml,结果编码为result_encoding = GB2312。你也可以设置为json或plain,但要注意更改encoding的类型
这里我增加了允许尾部静音的最长时间这个参数,vad_eos=1000,主要是根据我的需要,默认值为2000。(单位毫秒)

run_ivw运行唤醒:

//======================================================唤醒部分=====================================================
int awkeFlag = 0;	//唤醒状态flag,默认0未唤醒,1已换醒	
struct recorder *recorder;	//初始化录音对象
int record_state = MSP_AUDIO_SAMPLE_FIRST;	//初始化录音状态
int ISR_STATUS = 0;//oneshot专用,用来标识命令词识别结果是否已返回。

//唤醒状态消息提示,喂给回调函数QIVWRegisterNotify
int cb_ivw_msg_proc(const char *sessionID, int msg, int param1, int param2, const void *info, void *userData)
{
	if (MSP_IVW_MSG_ERROR == msg) //唤醒出错消息
	{
		//printf("\n\nMSP_IVW_MSG_ERROR errCode = %d\n\n", param1);
		printf("唤醒失败!");
		awkeFlag = 0;
	}
	else if (MSP_IVW_MSG_WAKEUP == msg) //唤醒成功消息
	{
		//printf("\n\nMSP_IVW_MSG_WAKEUP result = %s\n\n", info);
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 14);
		printf("唤醒成功!");
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
		awkeFlag = 1;		
	}
	
	return 0;
}

//读取录音内容的函数,用于喂给创建录音的函数create_recorder
static void iat_cb(char *data, unsigned long len, void *user_para)
{
	int errcode;
	int ret = 0;
	const char *session_id = (const char *)user_para;//初始化本次识别的句柄。
	//printf("进入录音读取");
	if (len == 0 || data == NULL)
		return;
	
	errcode = QIVWAudioWrite(session_id, (const void *)data, len, record_state);
	
	if (MSP_SUCCESS != errcode)
	{
		printf("QIVWAudioWrite failed! error code:%d\n", errcode);
		ret = stop_record(recorder);
		if (ret != 0) {
			printf("Stop failed! \n");
			//return -E_SR_RECORDFAIL;
		}
		wait_for_rec_stop(recorder, (unsigned int)-1);
		QIVWAudioWrite(session_id, NULL, 0, MSP_AUDIO_SAMPLE_LAST);
		record_state = MSP_AUDIO_SAMPLE_LAST;
		//g_is_awaken_succeed = FALSE;
	}
	if (record_state == MSP_AUDIO_SAMPLE_FIRST) {
		record_state = MSP_AUDIO_SAMPLE_CONTINUE;
	}
}

//运行唤醒的本体
void run_ivw(const char *grammar_list, const char* session_begin_params)//运行唤醒步骤
{
	const char *session_id = NULL;	
	int err_code = MSP_SUCCESS;
	WAVEFORMATEX wavfmt = DEFAULT_FORMAT;
	char sse_hints[128];	//用于设置结束时显示的信息
	int count = 0;
	
	//开始唤醒session
	session_id = QIVWSessionBegin(grammar_list, session_begin_params, &err_code);
	if (err_code != MSP_SUCCESS)
	{
		printf("QIVWSessionBegin failed! error code:%d\n", err_code);
		goto exit;
	}
	err_code = QIVWRegisterNotify(session_id, cb_ivw_msg_proc, NULL);	//为避免丢失句柄,回掉函数应当在此调用
	if (err_code != MSP_SUCCESS)
	{
		_snprintf(sse_hints, sizeof(sse_hints), "QIVWRegisterNotify errorCode=%d", err_code);
		printf("QIVWRegisterNotify failed! error code:%d\n", err_code);
		goto exit;
	}
	//开始录音
	err_code = create_recorder(&recorder, iat_cb, (void*)session_id);
	err_code = open_recorder(recorder, get_default_input_dev(), &wavfmt);
	err_code = start_record(recorder);
	
	//循环监听,保持录音状态
	while (record_state != MSP_AUDIO_SAMPLE_LAST)
	{
		Sleep(200); //阻塞直到唤醒结果出现
		//printf("正在监听%d\n", record_state);
		if (awkeFlag == 1)
		{
			awkeFlag = 0;	//恢复标志位方便下次唤醒
			break;			//跳出循环
		}
		count++;
		if (count == 20)	//为了防止循环监听时写入到缓存中的数据过大
		{
			//先释放当前录音资源
			stop_record(recorder);
			close_recorder(recorder);
			destroy_recorder(recorder);
			recorder = NULL;
			//printf("防止音频资源过大,重建\n");
			//struct recorder *recorder;
			//重建录音资源
			err_code = create_recorder(&recorder, iat_cb, (void*)session_id);
			err_code = open_recorder(recorder, get_default_input_dev(), &wavfmt);
			err_code = start_record(recorder);
			count = 0;
		}
	}

exit:
	if (recorder) {
		if (!is_record_stopped(recorder))
			stop_record(recorder);
		close_recorder(recorder);
		destroy_recorder(recorder);
		recorder = NULL;
	}
	if (NULL != session_id)
	{
		QIVWSessionEnd(session_id, sse_hints); //结束一次唤醒会话
	}
}

QIVWAudioWrite()其实在流程中基本都是在循环调用的:

写入本次唤醒的音频,本接口需要反复调用直到音频写完为止。调用本接口时,推荐用户在写入音频时采取"边录边写"的方式,即每隔一小段时间将采集到的音频通过本接口写入MSC。

得到唤醒结果后,会通过回调注册的函数QIVWRegisterNotify()这样一个异步的机制给你返回结果。
所以QIVWRegisterNotify()函数应当在QIVWSessionBegin()函数执行过后就立即执行。否则会出现丢失句柄的状况。
建议在每执行一个接口后就进行error_code的判断和返回。由于函数的数据传递过程都封装好了,这样可以方便进行调试。
QIVWSessionEnd()主要用于释放这个会话的资源,同时可以给你展示一个你自己定义的结束信息,意味着它正常结束。
当你流程的接口调用方法和顺序不当时,多半会返回这个错误码:
在这里插入图片描述

run_asr_mic麦克风语音识别:

static void run_asr_mic(const char* session_begin_params)
{
	int errcode;
	int i = 0;
	HANDLE helper_thread = NULL;

	struct speech_rec asr;
	DWORD waitres;
	char isquit = 0;
	struct speech_rec_notifier recnotifier = {
		on_result,
		on_speech_begin,
		on_speech_end
	};
	errcode = sr_init(&asr, session_begin_params, SR_MIC, DEFAULT_INPUT_DEVID, &recnotifier);
	if (errcode = sr_start_listening(&asr)) {
		printf("start listen failed %d\n", errcode);
		isquit = 1;
	}
	//Sleep(3000);

	if (errcode = sr_stop_listening(&asr)) {
		printf("stop listening failed %d\n", errcode);
		isquit = 1;
	}
	sr_stop_listening(&asr);
	sr_uninit(&asr);
}

你可以通过单独建立一个Sleep()延时来设置一个你规定的录音时间,
也可以完全依赖API的VAD机制。
官方例程采用的方式是通过按键开始,按键结束这样一个方法来限定录音的时间。
为了有更好的体验,我在sr_stop_listening()函数中,是用了VAD:

int sr_stop_listening(struct speech_rec *sr)
{
	int ret = 0;
	const char * rslt = NULL;
	char rslt_str[2048] = { '\0' };
	int count = 0;
	//如果未开始录音就错误调用了本函数那么返回报错
	if (sr->state < SR_STATE_STARTED) {
		sr_dbg("Not started or already stopped.\n");
		return 0;
	}

	while (1)			//进程阻塞
	{
		if (sr->ep_stat == MSP_EP_AFTER_SPEECH)		//VAD检测为音频末尾
		{
			break;
		}
		
	}
	//采用录音参数为NULL,0,MSP_AUDIO_SAMPLE_LAST
	ret = QISRAudioWrite(sr->session_id, NULL, 0, MSP_AUDIO_SAMPLE_LAST, &sr->ep_stat, &sr->rec_stat);
	if (ret != 0) {
		sr_dbg("write LAST_SAMPLE failed: %d\n", ret);
		QISRSessionEnd(sr->session_id, "write err");
		return ret;
	}

	//反复调用结果函数,直至获取结果
	while (sr->rec_stat != MSP_REC_STATUS_COMPLETE) {
		rslt = QISRGetResult(sr->session_id, &sr->rec_stat, 0, &ret);
		if (MSP_SUCCESS != ret)	{
			sr_dbg("\nQISRGetResult failed! error code: %d\n", ret);
			end_sr_on_error(sr, ret);
			return ret;
		}
		if (NULL != rslt && sr->notif.on_result)
			sr->notif.on_result(rslt, sr->rec_stat == MSP_REC_STATUS_COMPLETE ? 1 : 0);
		Sleep(100);
	}
	strcat(rslt_str, rslt);	//存储结果内容
	printf(rslt_str);	//展示结果
	Getid(rslt_str);	//解析出ID
	GetRawText(rslt_str);	//解析出原文
	//结束本次录音,释放资源
	if (sr->aud_src == SR_MIC) {
		ret = stop_record(sr->recorder);
#ifdef __FILE_SAVE_VERIFY__
		safe_close_file();
#endif
		if (ret != 0) {
			sr_dbg("Stop failed! \n");
			return -E_SR_RECORDFAIL;
		}
		wait_for_rec_stop(sr->recorder, (unsigned int)-1);
	}
	sr->state = SR_STATE_INIT;
	QISRSessionEnd(sr->session_id, "normal");
	sr->session_id = NULL;
	return 0;
}

语法规则:

本文使用的是离线命令词识别,官方使用的语法规则是巴克斯范式BNF。
可以在论坛下载pdf文件去系统学习如何定义规则:
语法开发指南
当你是用本地语法规则是,应当将你的BNF文件编辑好,并在代码中指定文件路径:
在这里插入图片描述
在这里插入图片描述
例程中附带BNF可以给你一个很好范本,作为你“照葫芦画瓢”的对象。

运行效果:

在这里插入图片描述
实际上API只会给你返回一个XML的字符串,如果你要解析你需要的信息,可以尝试用一些库去尝试。其中需要注意的是,如果你的部分语法中的词汇没有指定id,那么在xml中会返回一个默认的最大值65535。所以在编制id的时候应当避免编制到65535这个最大的数值,而且尽量在解析的时候滤除65535的关键词。

2016-12-27 11:04:56 weixin_36429334 阅读数 6382
  • 微信h5支付开发-php开发微信h5支付demo

    会员免费看,http://edu.csdn.net/lecturer/842右侧可办理会员卡。微信h5支付开发是子恒老师《子恒说微信开发》视频教程的第17部。详细讲解了微信H5支付开发,内容包含开通H5支付,实现微信h5支付,订单查询,关闭订单等等。欢迎反馈,微信号:QQ68183131

    8517 人正在学习 去看看 秦子恒

1,首先打开百度语音识别官网,注册一个账户成为开发者,接着创建一个应用,下载百度提供源代码 。

下载地址: http://yuyin.baidu.com/sdk/
官方文档地址:http://yuyin.baidu.com/docs/asr/54

sdk下载

下载demo

2,打开源代码,进行配置参数或修改要识别的语言文件

demo1

<?php 
define('AUDIO_FILE', "./text2audio_1.wav"); //语音文件地址,值支持本地

$url = "http://vop.baidu.com/server_api";

//put your params here
$cuid = "";
$apiKey = "";
$secretKey = "";

$auth_url = "https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id=".$apiKey."&client_secret=".$secretKey;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $auth_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
$response = curl_exec($ch);
if(curl_errno($ch))
{
    print curl_error($ch);
}
curl_close($ch);
$response = json_decode($response, true);
$token = $response['access_token'];

$audio = file_get_contents(AUDIO_FILE);
$base_data = base64_encode($audio);
$array = array(
        "format" => "wav",
        "rate" => 8000,
        "channel" => 1,
//        "lan" => "zh",
        "token" => $token,
        "cuid"=> $cuid,
        //"url" => "http://www.xxx.com/sample.pcm",
        //"callback" => "http://www.xxx.com/audio/callback",
        "len" => filesize(AUDIO_FILE),
        "speech" => $base_data,
        );
$json_array = json_encode($array);
$content_len = "Content-Length: ".strlen($json_array);
$header = array ($content_len, 'Content-Type: application/json; charset=utf-8');

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json_array);
$response = curl_exec($ch);
if(curl_errno($ch))
{
    print curl_error($ch);
}
curl_close($ch);
echo $response;
$response = json_decode($response, true);
var_dump($response);

demo2


define('AUDIO_FILE', "./text.wav");

//put your params here
$cuid = "";
$apiKey = "";
$secretKey = "";

$auth_url = "https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id=".$apiKey."&client_secret=".$secretKey;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $auth_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
$response = curl_exec($ch);
if(curl_errno($ch))
{
    print curl_error($ch);
}
curl_close($ch);
$response = json_decode($response, true);
$token = $response['access_token'];

$url = "http://vop.baidu.com/server_api?cuid=".$cuid."&token=".$token;
$url = $url."&lan=zh";
$audio = file_get_contents(AUDIO_FILE);
$content_len = "Content-Length: ".strlen($audio);
$header = array ($content_len,'Content-Type: audio/pcm; rate=8000',);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_POSTFIELDS, $audio);
$response = curl_exec($ch);
if(curl_errno($ch))
{
    print curl_error($ch);
}
curl_close($ch);
echo $response;
$response = json_decode($response, true);
echo '<pre>';
var_dump($response);

3、运行文件识别,运行后发现调取接口成功,但是识别出来的正确率百分之一都不到,于是查看原因发现,百度语音识别只支持 8k/16k 采样率 16bit 位深的单声道语音,进行音频格式转换后正确率可达成80% 。

注意事项:
语音识别接口支持 POST 方式
目前 API 仅支持整段语音识别的模式,即需要上传整段语音进行识别
语音数据上传方式有两种:隐示发送和显示发送
原始语音的录音格式目前只支持评测 8k/16k 采样率 16bit 位深的单声道语音
压缩格式支持:pcm(不压缩)、wav、opus、speex、amr、x-flac
系统支持语言种类:中文(zh)、粤语(ct)、英文(en)

4、因为是调用接口测试所以在转换音频格式使用的是格式工厂,如果项目需要可使用代码自动转换(自行百度)

这里写图片描述

这里写图片描述

这里写图片描述

然后进行确认转换得出来的格式再进行测试即可,谢谢~

2018-10-10 19:01:28 m0_37605956 阅读数 491
  • 微信h5支付开发-php开发微信h5支付demo

    会员免费看,http://edu.csdn.net/lecturer/842右侧可办理会员卡。微信h5支付开发是子恒老师《子恒说微信开发》视频教程的第17部。详细讲解了微信H5支付开发,内容包含开通H5支付,实现微信h5支付,订单查询,关闭订单等等。欢迎反馈,微信号:QQ68183131

    8517 人正在学习 去看看 秦子恒

摘要: 百度语音识别demo接入至vr设备:
项目所需,要测试百度语音识别对某些特定指令语言在vr设备上的识别正确率,需要首先研究百度语音识别的demo使用,特将整个学习过程记录:

一:百度语音android sdk下载地址
http://ai.baidu.com/sdk#asr
我下载了“离在线融合SDK”的android版本
上述链接的页面点击"使用说明"链接,进入SDK说明页面:
http://ai.baidu.com/docs#/ASR-Android-SDK/top

SDK下载后,参考了两个重要的文档,
第一个是目录下的readme_README_IMPORTANT
第二个是doc_integration_DOCUMENT目录下的"ASR-INTEGRATION-helloworld-V2.0",

二:根据上述文档集成百度asr至helloworld工程
由于下载下来的sdk直接导入到android studio中没有编译通过,所以直接新建项目集成语音识别功能,依据ASR-INTEGRATION-helloworld-V2.0文档,

首先新建一个android helloworld工程:
为了节约时间,没有在官网中注册应用。使用百度demo的各个参数。在工程新建过程中,完全按文档中的进行,包括company domain, appId,appkey,secretkey以及applicationId。在选择activity模板时候,选择了"Empty activity",android的版本号选择了默认的15

其次:工程建好编译通过后,按文档导入原demo的core模块并设置app依赖core,编译时候出现以下错误:
Android dependency ‘com.android.support:appcompat-v7’ has different version for the compile (26.1.0) and runtime (27.1.1) classpath. You should manually set the same version via DependencyResolution

网上搜索原因发现:
是由于app和core两个模块使用的依赖库(appcompat-v7)的版本号不同导致,
app的gradle:
dependencies {
implementation fileTree(include: [’
.jar’], dir: ‘libs’)
implementation ‘com.android.support:appcompat-v7:26.1.0’
implementation ‘com.android.support.constraint:constraint-layout:1.1.3’
testImplementation ‘junit:junit:4.12’
androidTestImplementation ‘com.android.support.test?1.0.2’
androidTestImplementation ‘com.android.support.test.espresso:espresso-core:3.0.2’
implementation project(’:core’)
}*
core的gradle:
dependencies {
api fileTree(include: [’
.jar’], dir: ‘libs’)
implementation ‘com.android.support:appcompat-v7:27.1.1’
}*

于是修改了app模块的库版本至:27.1.1,与core保持一致。
同时修改app模块build.gradle里的compileSdkVersion 27,targetSdkVersion 27,之后编译通过。

之后修改mainactivity如下:
public class MainActivity extends ActivityMiniRecog {

}

编译后安装到android手机可以进行语音识别

三: 将该demo移植至vr设备:
需要修改manifest,在MainActivity的intent-filter下增加:
category android:name=“com.***.intent.category.VRAPP”
这样安装后可以看到该AP

四: vr设备如何测试:
由于不能直接点击,所以在使用controller打开AP后,需要一个辅助软件vysor进行投屏,然后在电脑上面进行点击测试操作。

2018-12-04 10:07:38 b260681014 阅读数 1425
  • 微信h5支付开发-php开发微信h5支付demo

    会员免费看,http://edu.csdn.net/lecturer/842右侧可办理会员卡。微信h5支付开发是子恒老师《子恒说微信开发》视频教程的第17部。详细讲解了微信H5支付开发,内容包含开通H5支付,实现微信h5支付,订单查询,关闭订单等等。欢迎反馈,微信号:QQ68183131

    8517 人正在学习 去看看 秦子恒

科大讯飞语音识别Demo

准备工作

测试Demo

		<dependency>
			<groupId>org.apache.directory.studio</groupId>
			<artifactId>org.apache.commons.codec</artifactId>
			<version>1.8</version>
		</dependency>
import org.apache.commons.codec.digest.DigestUtils;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: jethro
 * @CreateTime: 2018-11-23
 * @Description: 科大讯飞测试类
 */
public class KDXFTest {
    /**
     *科大讯飞语音参数开始
     */
    private static final String URL = "http://openapi.xfyun.cn/v2/aiui";
    private static final String APPID = "";
    private static final String API_KEY = "";
    private static final String DATA_TYPE = "audio";
    private static final String SCENE = "main";
    private static final String SAMPLE_RATE = "16000"; //采样率!!
    private static final String AUTH_ID = "2ff181c8bc23f373ca155d332ece22e9";
    private static final String AUE = "raw";
    private static String FILE_PATH = "C:/a/22.wav";
    // 个性化参数,需转义
    private static final String PERS_PARAM = "{\\\"auth_id\\\":\\\"2894c985bf8b1111c6728db79d3479ae\\\"}";
    /**
     *科大讯飞语音参数结束
     */

    public static void main(String[] args) throws IOException, ParseException {
        Map<String, String> header = buildHeader();
        byte[] dataByteArray = readFile(FILE_PATH );
        String result = httpPost(URL, header, dataByteArray);
         System.out.println(result);

    }
    
    /**
     * 科大讯飞方法开始
     */
    private static Map<String, String> buildHeader() throws UnsupportedEncodingException, ParseException {
        String curTime = System.currentTimeMillis() / 1000L + "";
        String param = "{\"aue\":\""+AUE+"\",\"sample_rate\":\""+SAMPLE_RATE+"\",\"auth_id\":\""+AUTH_ID+"\",\"data_type\":\""+DATA_TYPE+"\",\"scene\":\""+SCENE+"\"}";
        //使用个性化参数时参数格式如下:
        //String param = "{\"aue\":\""+AUE+"\",\"sample_rate\":\""+SAMPLE_RATE+"\",\"auth_id\":\""+AUTH_ID+"\",\"data_type\":\""+DATA_TYPE+"\",\"scene\":\""+SCENE+"\",\"pers_param\":\""+PERS_PARAM+"\"}";
        String paramBase64 = new String(org.apache.commons.codec.binary.Base64.encodeBase64(param.getBytes("UTF-8")));
        String checkSum = DigestUtils.md5Hex(API_KEY + curTime + paramBase64);

        Map<String, String> header = new HashMap<String, String>();
        header.put("X-Param", paramBase64);
        header.put("X-CurTime", curTime);
        header.put("X-CheckSum", checkSum);
        header.put("X-Appid", APPID);
        return header;
    }

    private static byte[] readFile(String filePath) throws IOException {
        InputStream in = new FileInputStream(filePath);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024 * 4];
        int n = 0;
        while ((n = in.read(buffer)) != -1) {
            out.write(buffer, 0, n);
        }
        byte[] data = out.toByteArray();
        in.close();
        return data;
    }

    private static String httpPost(String url, Map<String, String> header, byte[] body) {
        String result = "";
        BufferedReader in = null;
        OutputStream out = null;
        try {

            java.net.URL realUrl = new URL(url);
            HttpURLConnection connection = (HttpURLConnection)realUrl.openConnection();
            for (String key : header.keySet()) {
                connection.setRequestProperty(key, header.get(key));
            }
            connection.setDoOutput(true);
            connection.setDoInput(true);

            //connection.setConnectTimeout(20000);
            //connection.setReadTimeout(20000);
            try {
                out = connection.getOutputStream();
                out.write(body);
                out.flush();
            } catch (Exception e) {
                e.printStackTrace();
            }

            try {
                in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String line;
                while ((line = in.readLine()) != null) {
                    result += line;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 科大讯飞方法结束
     */

}

注意事项

  1. 音频的采样率仅支持8000和16000
  2. 音频格式仅支持pcm/wav/speex/spx文件,且不超过2M
2016-11-24 16:25:52 KwunYamShan 阅读数 6169
  • 微信h5支付开发-php开发微信h5支付demo

    会员免费看,http://edu.csdn.net/lecturer/842右侧可办理会员卡。微信h5支付开发是子恒老师《子恒说微信开发》视频教程的第17部。详细讲解了微信H5支付开发,内容包含开通H5支付,实现微信h5支付,订单查询,关闭订单等等。欢迎反馈,微信号:QQ68183131

    8517 人正在学习 去看看 秦子恒

#科大讯飞-语音识别开发

##在线语音识别
将连续语音快速识别为文字

语音识别在模拟器上是无法测试的,虚拟机mac接收不到声音或者语音识别是访问云端数据,所以如果手机的网络没有开启,就无法实现识别声音的!一定要开启手机的网络,如果手机不存在语音识别功能的话,也是无法启用识别!

##效果图
这里写图片描述

##源码

新下载地址(Android Studio工程):https://download.csdn.net/download/kwunyamshan/11259989
由于旧下载地址下载次数过多分数已经超高所以新建了一个内容一样,放心下载
注意:源码中是我的sdk,只有三个装机量35天试用期限,你们试用需要替换掉SpeechApp中配置的Appid以及so库!

旧下载地址(Android Studio工程):http://download.csdn.net/detail/kwunyamshan/9692791

##集成步骤

开通服务,下载SDK
之前介绍过,地址:http://blog.csdn.net/kwunyamshan/article/details/53320164

Step 1. 导入so库
 
	 eclipse将so库导入到libs目录下
	 AS用户将so导入到jniLibs目录下
	 下载的官方SDK中有七个so库目前已经支持市面上98%的手机
	 armeabi目录下libmsc.so只支持市面上百分之八十的手机,如果不需要做适配的话导入这一个so库也是极好的

这里写图片描述

Step 2. 拷贝资产文件
		将 SDK 资源包assets 路径下的资源文件拷贝至 Android 工程 asstes 目录下

这里写图片描述

Step 3.  初始化
		这是很重要并且是必须的一步操作,实际上初始化的操作是异步进行的,如果初始化还没有完成你就开始调用了语音识别,是会出现很多问题的,建议在你程序刚刚启动的时候调用
public class SpeechApp extends Application {

    @Override
    public void onCreate() {
        // 应用程序入口处调用,避免手机内存过小,杀死后台进程后通过历史intent进入Activity造成SpeechUtility对象为null
        // 如在Application中调用初始化,需要在Mainifest中注册该Applicaiton
        // 注意:此接口在非主进程调用会返回null对象,如需在非主进程使用语音功能,请增加参数:SpeechConstant.FORCE_LOGIN+"=true"
        // 参数间使用半角“,”分隔。
        // 设置你申请的应用appid,请勿在'='与appid之间添加空格及空转义符

        // 注意: appid 必须和下载的SDK保持一致,否则会出现10407错误

        SpeechUtility.createUtility(SpeechApp.this, "appid=" + getString(R.string.app_id));

        // 以下语句用于设置日志开关(默认开启),设置成false时关闭语音云SDK日志打印
        // Setting.setShowLog(false);
        super.onCreate();
    }

}
Step 4.  添加用户权限,官方给的API中不规范有几条权限中间有空格导致编译不通过 ,注意一下
<!--连接网络权限,用于执行云端语音能力 -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <!--获取手机录音机使用权限,听写、识别、语义理解需要用到此权限 -->
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <!--读取网络信息状态 -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <!--获取当前wifi状态 -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <!--允许程序改变网络连接状态 -->
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
    <!--读取手机信息权限 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <!--读取联系人权限,上传联系人需要用到此权限 -->
    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    <!--外存储写权限, 构建语法需要用到此权限 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <!--外存储读权限,构建语法需要用到此权限 -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <!--配置权限,用来记录应用配置信息 -->
    <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
    <!--手机定位信息,用来为语义等功能提供定位, 提供更精准的服务-->
    <!--定位信息是敏感信息, 可通过Setting.setLocationEnable(false)关闭定位请求 -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <!--如需使用人脸识别,还要添加:摄相头权限, 拍照需要用到-->
    <uses-permission android:name="android.permission.CAMERA" />
Step 5. 代码
public class MainActivity extends Activity {


    private StringBuffer mBuffer;
    private TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.tv_translate_text);
    }

    public void startVoice(View view) {
        //1.创建RecognizerDialog对象
        RecognizerDialog mDialog = new RecognizerDialog(this, null);
        //2.设置accent、 language等参数
        mDialog.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
        mDialog.setParameter(SpeechConstant.ACCENT, "mandarin");
        //若要将UI控件用于语义理解,必须添加以下参数设置,设置之后onResult回调返回将是语义理解结果
        // mDialog.setParameter("asr_sch", "1");
        // mDialog.setParameter("nlp_version", "2.0");

        mBuffer = new StringBuffer();
        //3.设置回调接口
        mDialog.setListener(mRecognizerDialogListener);
        //4.显示dialog,接收语音输入
        mDialog.show();
    }

    RecognizerDialogListener mRecognizerDialogListener = new RecognizerDialogListener() {
        //听写结果回调接口(返回Json格式结果,用户可参见附录13.1);
        //一般情况下会通过onResults接口多次返回结果,完整的识别内容是多次结果的累加;
        //关于解析Json的代码可参见Demo中JsonParser类;
        //isLast等于true时会话结束。
        @Override
        public void onResult(RecognizerResult results, boolean isLast) {
            String result = results.getResultString();//语音听写的结果

            String resultString = processData(result);

            mBuffer.append(resultString);

            if (isLast) {
                //话已经说完了
                String finalResult = mBuffer.toString();
                System.out.println("解析结果:" + finalResult);
                tv.setText(finalResult);

            }

        }

        @Override
        public void onError(SpeechError error) {

        }
    };

    //解析json
    protected String processData(String result) {
        Gson gson = new Gson();
        VoiceBean voiceBean = gson.fromJson(result, VoiceBean.class);

        StringBuffer sb = new StringBuffer();

        ArrayList<VoiceBean.WsBean> ws = voiceBean.ws;
        for (VoiceBean.WsBean wsBean : ws) {
            String word = wsBean.cw.get(0).w;
            sb.append(word);
        }

        return sb.toString();
    }


}

layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"

    >
<TextView
    android:padding="5dip"
    android:layout_width="match_parent"
    android:layout_height="230dip"
    android:id="@+id/tv_translate_text"
    android:background="#fff"
    android:textSize="22sp"
    android:textColor="#000"
    android:hint="请点击按钮"
    />
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:background="#F1AF5A"
    android:gravity="center"
    >
    <ImageButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/button"
        android:onClick="startVoice"
        />
</LinearLayout>

</LinearLayout>
Step 6. 目录结构

这里写图片描述

遇到问题可以留言探讨会尽快回复,也可以访问官方地址
网址:http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=13040&fromuid=86908

html5语音识别的demo

阅读数 8950

没有更多推荐了,返回首页