基于 python 的语音识别 API 调用

腾讯 AI 开放平台 开放了语音、图像等多种 AI 功能接口。本文尝试基于 python 完成对语音识别接口的本地调用。

1. 准备工作

API 调用需要身份认证。我们首先需要注册并获得 AppID 和 AppKey。

官网注册后,进入控制台,创建一个新应用,并在接口选择栏,为应用勾选“语音识别”。应用创建成功后,记下 AppID 和 AppKey。

2. 接口鉴权

接口鉴权的要求见官方说明。为完成鉴权,我们需要定义一些辅助函数,代码见这里

2.1 哈希

认证需要用到 MD5 哈希算法,这里我们调用 hashlib 库的实现。

import hashlib

def md5(string):
    md = hashlib.md5()
    md.update(string)
    md5 = md.hexdigest().upper()
    return md5

2.2 签名

认证要求使用包括 AppKey 在内的参数拼接字符串的 MD5 值做为签名,其中 AppKey 要位于字条串最后:

def signify(args, app_key):
    query_str = urlencode(args)
    query_str = query_str + '&app_key=' + app_key
    signiture = md5(query_str)
    return signiture

参数需要按键值排序,实现如下:

import urllib

def urlencode(args):
    tuples = [(k, args[k]) for k in sorted(args.keys()) if args[k]]
    query_str = urllib.urlencode(tuples)
    return query_str

3. 语音识别

语音识别接口的具体调用信息见官网说明,提供了整段语音和流式两种调用方式。这里我们识别整段语音识别及 AI Lab 流式语音识别两个接口的调用。完成代码见这里

调用使用的是 post 方式,简单封装如下:

import requests
def http_post(api_url, args):
    resp = requests.post(url=api_url, data=args)
    resp = json.loads(resp.text)
    return resp

3.1 echo 版

echo 版对整段音频进行语音识别,并返回语音的文字内容。

class BaseASR(object):
    ext2idx = {'pcm': '1', 'wav': '2', 'amr': '3', 'slk': '4'}

    def __init__(self, api_url, app_id, app_key):
        self.api_url = api_url
        self.app_id = app_id
        self.app_key = app_key

    def stt(self, audio_file, ext, rate):
        raise Exceptin("Unimplemented!")

class BasicASR(BaseASR):
    """ Online ASR from Tencent
    https://ai.qq.com/doc/aaiasr.shtml
    """
    def __init__(self, api_url='https://api.ai.qq.com/fcgi-bin/aai/aai_asr',
                 app_id='???', app_key='???'):
        super(BasicASR, self).__init__(api_url, app_id, app_key)

    def stt(self, audio_file, ext='wav', rate=16000):
        if ext == 'wav':
            wf = wave.open(audio_file)
            nf = wf.getnframes()
            audio_data = wf.readframes(nf)
            wf.close()
        else:
            raise Exception("Unsupport audio file format!")

        args = {
            'app_id': self.app_id,
            'time_stamp': str(int(time.time())),
            'nonce_str': '%.x' % random.randint(1048576, 104857600),
            'format': self.ext2idx[ext],
            'rate': str(rate),
            'speech': base64.b64encode(audio_data),
        }

        signiture = signify(args, self.app_key)
        args['sign'] = signiture
        resp = http_post(self.api_url, args)
        text = resp['data']['text'].encode('utf-8')

        if DEBUG:
            print('msg: %s, ret: %s, format: %s' %
                  (resp['msg'], resp['ret'], resp['data']['format']))

        return text

3.2 流式版(AI Lab)

class BasicStreamASR(BaseASR):
    """ Online ASR from Tencent AI Lab
    https://ai.qq.com/doc/aaiasr.shtml
    """

    def __init__(self, api_url='https://api.ai.qq.com/fcgi-bin/aai/aai_asrs',
                 app_id='???', app_key='???'):
        super(BasicStreamASR, self).__init__(api_url, app_id, app_key)

    def stt(self, audio_file, ext='wav', rate=16000, chunk=4800):
        if ext == 'wav':
            wf = wave.open(audio_file)
        else:
            raise Exception("Unsupport audio file format!")

        total_len = wf.getnframes() * wf.getsampwidth()
        seq, end = 0, '0'
        while end != '1':
            data = wf.readframes(chunk)
            length = len(data)
            end = '0' if length + seq < total_len else '1'

            args = {
                'app_id': self.app_id,
                'time_stamp': str(int(time.time())),
                'nonce_str': '%.x' % random.randint(1048576, 104857600),
                'format': self.ext2idx[ext],
                'rate': str(rate),
                'seq': str(seq),
                'len': str(length),
                'end': end,
                'speech_id': '0',
                'speech_chunk': base64.b64encode(data),
            }

            signiture = signify(args, self.app_key)
            args['sign'] = signiture
            resp = http_post(self.api_url, args)

            seq += length

            if DEBUG:
                print('seq: ', seq)
                print(resp['data']['speech_text'])

        return resp['data']['speech_text'].encode('utf-8')

4. 测试

语音必须符合 16k 或 8K 采样率、16bit 采样位数、单声道。支持 PCM、WAV、AMR、SILK 四种编码格式。这里我们只示例了无压缩的 WAV 格式。流式识别对于 AMR、SILK 的分片方式有其他要求,具体可以参见接口说明。

def test_basic_asr():
    audio_files = ['0.wav', '1.wav', '2.wav']
    asr_engine = BasicASR()
    for audio_file in audio_files:
        text = asr_engine.stt(audio_file)
        print(text)

def test_stream_asr():
    audio_files = ['0.wav', '1.wav', '2.wav']
    asr_engine = BasicStreamASR()
    for audio_file in audio_files:
        text = asr_engine.stt(audio_file)
        print(text)

小结

本文基于本地音频文件,识别了基于 python 的语音识别接口调用。基于流式掊,接合 ALSA 、PortAudio 等系统录音工具,我们实现实时的语音采样和识别。

语音识别接合语音唤醒(e.g snowboy)、静音检测(e.g. werbrtc VAD)等技术,可以实现一个简单但完整的语音交互前端(一个简单的 demo 见这里)。

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页