最近要跟着导师做一个语音识别的工程项目,由于在前期只需要快速的建立软件架构,所以选择使用科大讯飞提供的云接口进行快速开发,但科大讯飞在Linux的sdk中只提供了c++的实现,为了今后的开发方便,我将其进行了Python封装,也把源码分享在这里,为大家提供方便。

一、概述

      虽然在我的github源码中已经写了README,不过为了广大程序员朋友考虑,我还是写这样一个博客为好,既是为了方便大家使用,也是为自己以后提供便利。全文就是大致介绍一个实现思路和使用方法,视自己情况而定,如果不需要的话,可直接调到最后去star。
      对于本项目来说实现起来并不复杂(虽然过程中我也是去参考了一些人的代码),主要的思路就是把科大讯飞提供的sdk加载进来,然后由于里面是c的实现,所以这里需要使用python自带的ctypes库,将数据类型进行一下转换,这里相信对于尝试过python和c混合编程的人来说应该不是什么困难的事情。为了大家的编程方便,这里提供几个科大讯飞的Linux SDK文档资料。

二、 语音识别类ISR

      对于语音识别的实现,我主要封装了一个ISR的类用于实现,具体可参见我的github源码,大体思路是针对每一个在语音识别中用到的科大讯飞API函数,都在其上面封装一层功能相同的python函数,这样实现python编程时的灵活调用,这样说可能确实很抽象,下面我举几个具体的实现例子给大家看。

MSPLogin()

@classmethod
    def MSPLogin(cls):
        """
        /**
         * @fn		MSPLogin
         * @brief	user login interface
         *
         *  User login.
         *
         * @return	int MSPAPI			- Return 0 in success, otherwise return error code.
         * @param	const char* usr		- [in] user name.
         * @param	const char* pwd		- [in] password.
         * @param	const char* params	- [in] parameters when user login.
         * @see
         */
        int MSPAPI MSPLogin(const char* usr, const char* pwd, const char* params);
        """

        assert cls.dll is not None, 'Please load libmsc.dll, Before load this function'

        _MSPLogin = cls.dll.MSPLogin
        _MSPLogin.argtypes = (ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p)
        _MSPLogin.restype = (ctypes.c_int)

        c_usr = get_c_char_p(cls.login['usr'])
        c_pwd = get_c_char_p(cls.login['pwd'])
        c_params = get_c_char_p(cls.login['params'])
        ret = _MSPLogin(c_usr, c_pwd, c_params)

        if ret != MSP_SUCCESS:
            raise ISRException('MSPLogin failed, error code: %d.' % (ret))

        if ret == MSP_SUCCESS:
            cls.ret = ret
            cls.login['logined'] = True

        return ret

      比如这个函数,可以看到我其实并没有做什么特别的工作,只是定义了一个_MSPLogin函数和它的参数类型、返回值类型,然后就把参数传入进去,获得返回值,完成的就只是原来接口实现的功能而已,只不过给它套了一个python的壳子。

QISRGetResult()

    def QISRGetResult(self):
        """
        /**
         * @fn		QISRGetResult
         * @brief	Get the text of the audio data
         *
         *  Get the text of the audio data from website
         *
         * @return	const char* - Return the recognition result
         * @param   const char*                 - [in]  sessionID which used to keep alive
         * @param   int*                        - [out] the status of result
                                                    0: recognize successfully
                                                    1: no match
                                                    2: recognizing
                                                    5: finished
         * @param   int                         - [in]  no use, make it 0
         * @param	int* errorCode				- [out] error code if failed, 0 to success.
         * @see
         */
         const char* MSPAPI QISRGetResult(const char *sessionID, int *rsltStatus, int waitTime, int *errorCode)
        """
        # 检查sessionID状态
        assert self.sessionID is not None, 'seesionId is None,Please call QISRSessionBegin defore QTTSSessionEnd called'

        _QISRGetResult = self.dll.QISRGetResult
        _QISRGetResult.argtypes = (ctypes.c_char_p, ctypes.POINTER(ctypes.c_int), ctypes.c_int, ctypes.POINTER(ctypes.c_int))
        _QISRGetResult.restype = ctypes.c_char_p

        c_sessionID = get_c_char_p(self.sessionID)
        c_rsltStatus = ctypes.c_int()
        c_waitTime = ctypes.c_int(0)
        c_errorCode = ctypes.c_int()

        bstr = _QISRGetResult(c_sessionID, c_rsltStatus, c_waitTime, c_errorCode)
        if bstr is not None:
            string = str(bstr, encoding='utf8')
        else:
            string = ''

        ret = c_errorCode.value
        self.ret = ret
        if ret != MSP_SUCCESS:
            self.MSPLogout()
            raise ISRException('QISRGetResult failed, error code: %d' % (ret))

        return string, ret, c_rsltStatus.value

      再比如这个函数,同样的开始先定义一个_QISRGetResult函数,以及它的参数类型、返回值类型,然后再传入函数的参数,获取返回值等等,这里有一点不同的是返回了多个不同的值。这是因为在科大讯飞中由于调用的是c++函数,只能有一个返回值,但在某些情况下,要监视不同的变量,那要怎么办呢,常用的方法就是用指针或者引用参数,通过参数把要返回的状态参数带回去。科大讯飞的很多函数都是采用这种方法,但如果用python的话,就大可不必那么麻烦了,直接返回就好,所以这里其实多返回的就是那些引用参数而已。
      大家可能会觉得我以上举的两个例子只是比较简单的个例,其实并不是,要在c++的基础上进行python封装其实就是这么简单!so easy!

三、语音合成类TTS

      语音合成其实是和语音识别是一样的,也同样是定义了一个TTS类用于控制与科大讯飞语音合成进行交互的一系列动作,当然会有一些操作上的不同,但也不会有太大差异,基本的思想都是一样的,这里我就不赘述了,如果有不明白的,非常欢迎在下方留言,我会及时回复的!

四、其他的一些必要的类或参数

      以上是提到了两个最主要的实现类,除此之外当然还有一些比如ISRException异常类、ISRSessionParam会话参数类等等,但这些其实就是为了更好的实现ISR和TTS所定义的一些结构,对整个实现的思路没有什么影响,无非是把代码写的好看一些,我就只做一个大体的陈述吧!

  • ISRSessionParam类,这个类定义了用于与科大讯飞相应服务建立会话的一些参数,下面针对类里面的几个函数做简要介绍(因为调接口的时候也并不会用到),需要提一下的是这个参数在ISR类中被作为成员变量使用,其中QISRSessionBegin()函数可以对Param进行设置,如果不进行设置,则使用默认参数。
    • 构造函数,用于初始化默认的参数,如无特殊需求,则无需对会话参数进行设置。
    • param()函数,用于将字典类型的参数传入转化为合法的字符串类型
    • setter,用于设置param参数,可传入合法字符串或字典
  • ISRException类,这个类还没有进行什么特殊的实现,目前仅仅继承了Exception类,用于捕获异常
  • utils.py,这个py文件中定义了一些功能函数,比如get_c_char_p()用来将一个python字符串类型值转化为c的char*类型
  • define.py,这个py文件中定义了一些常量,方便使用和修改

      这里就仅以语音识别为例进行举例,语音合成的结构和类框架也是类似的

五、API的使用

语音识别

      语音识别API存放在ISR_API.py文件中,这里的speech_to_text函数实现语音到文本的转化,它主要需要三个参数,isr、fp、piceLen,下面分别对这三个参数进行说明。

  • isr:是一个ISR类的对象,isr = ISR(),直接用初始化的ISR()就可以使用,如需特殊设置可自行解决
  • fp:是语音文件句柄,fp = open(‘文件路径’, ‘rb’)
  • piceLen:步长,就是一次传输的字节数,可自行定义

语音合成

      语音合成API存放在TTS_API.py文件中,这里的text_to_speech函数实现文本到语音的转化,它主要需要三个参数,tts、fp、src_text,下面分别对这三个参数进行说明。

  • tts:是一个TTS类对象,tts = TTS(),直接用初始化的TTS()就可以使用,如需特殊设置可自行解决
  • fp:是输出文件句柄,这里需要提醒的是,输出文件需要是用wave.open打开,即fp = wave.open(‘文件路径’, ‘wb’)
  • src_text:待转化的字符串,可含标点符号

以上是对Python API接口的大致说明,如果还是不理解的话,可下载我的github代码,其中有我实现的简单demo

六、关于APPID

      大家如果嫌麻烦的话,可以先使用我的APPID,但最好自己申一个,也都是免费的,这里我附上我另一篇关于申请APPID的博文,也算是进行科大讯飞接口使用的前期工作吧。
      【语音识别学习】科大讯飞APPID的申请以及SDK下载
      如果要修改APPID的话,在代码中的define.py中修改即可

七、总结

      之前,我是给大家提供源码链接的,但由于这是给公司做的项目,在产品没出来前公开源码不太好,所以我就暂时把链接关闭了,但如果有做类似项目(语音识别、语音合成、情感识别、声纹识别)遇到问题的,非常欢迎与我讨论!

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐