使用函数计算方式的录音文件识别

本文为您介绍如何使用函数计算方式进行录音文件识别。

概述

对于将音频文件存储在阿里云OSS上的用户,除使用SDK集成录音文件识别的开发方式外,还可以通过函数计算的方式,录音文件识别通过触发器函数自动执行,将识别结果保存回OSS或者其他存储器上,您只需关注最终的识别结果,减少SDK集成开发工作量。对于非开发人员,可以通过该方式快速获取识别结果进行分析。函数计算的详细介绍,请参见什么是函数计算

前提条件

已开通如下服务,且需要给开通函数计算服务的账号授权OSS服务的读写权限:

  • 已开通OSS服务,有对应的AccessKey ID、AccessKey Secret、OSS EndPoint,详情参见对象存储

  • 已开通函数计算服务,详情参见函数计算

  • 已开通智能语音交互服务,有对应的AccessKey ID、AccessKey Secret、Appkey,详情参见智能语音交互

效果

说明

本文使用的OSS Bucket为nls-file-trans,音频文件存放路径为filetrans/raw,识别结果存放路径为filetrans/result。识别结果保存在JSON文件中,以文件名_taskId.json表示识别成功的结果,文件名_taskId_failed.json表示识别失败的结果。使用中,请根据实际情况,修改为自己的Bucket和文件存放路径。

  • 通过OSS控制台上传音频文件

    单击上传文件,上传音频文件到指定的Bucket路径filetrans/raw

    上传文件

    对应函数计算的触发器:

    函数计算触发器

    识别结果存放路径filetrans/result

    存储路径

    上传的nls-sample-16k.wav音频文件识别结果:

    {
        "Result": {
            "Sentences": [{
                "EndTime": 2365,
                "SilenceDuration": 0,
                "BeginTime": 340,
                "Text": "北京的天气。",
                "ChannelId": 0,
                "SpeechRate": 177,
                "EmotionValue": 5.0
            }]
        },
        "TaskId": "fb0474184c6d11e9a213e11db149****",
        "StatusCode": 21050000,
        "StatusText": "SUCCESS",
        "RequestTime": 1553237085804,
        "SolveTime": 1553237086146,
        "BizDuration": 2956
    }

  • 通过OSS常用工具上传音频文件

    以ossutil为例,与控制台上传音频文件的识别流程相同。

    ossutil cp nls-sample-16k.wav https://gw.alipayobjects.com/os/bmw-prod/0574ee2e-f494-45a5-820f-63aee583045a.wav

实现方式

需要在函数计算上实现的内容如下:

  1. 创建函数计算的服务。

  2. 创建生成任务的函数,使用OSS触发器,设置第3步的回调URL,生成录音文件识别任务。

  3. 创建接收回调的函数,使用HTTP触发器,生成回调URL,用于将录音文件识别结果写回OSS。

步骤一:创建服务

  1. 在函数计算的控制台创建一个服务。

    可以在创建时进行高级配置,也可以创建后再进行设置。

    创建服务

  2. 创建服务角色。

    高级配置 > 权限配置中,如果没有已有角色,需要创建一个新角色,系统模板授权选择AliyunOSSFullAccess,单击点击授权

    权限配置
  3. 添加权限。

    登录RAM访问控制,在左侧导航栏选择RAM角色管理,添加AliyunOSSFullAccessAliyunSTSAssumeRoleAccessAliyunNLSFullAccess权限(如果已经授权,则不需要添加)。

    添加权限

步骤二:生成任务

生成任务用于提交录音文件识别请求,OSS上传音频文件时将触发OSS触发器,调用函数,提交录音文件识别请求。

  1. 编写函数。

    在创建的服务下,创建一个函数,用于生成任务:

    • 函数名称:call_filetrans

    • 函数入口:call_filetrans.handler

    • 运行环境:Python 3

    • 函数执行内存:128 MB(选择最小值128 MB即可,该值与函数计算的计费相关)

    • 超时时间:600s

    函数内容如下,需要您替换如下参数:

    • OSS账号相关的AccessKey ID、AccessKey Secret、OSS EndPoint(选择外网访问)

    • 录音文件识别账号相关的AccessKey ID、AccessKey Secret、Appkey、回调URL(创建HTTP触发器时获取)

    # -*- coding: utf-8 -*-
    import json
    import time
    from aliyunsdkcore.acs_exception.exceptions import ClientException
    from aliyunsdkcore.acs_exception.exceptions import ServerException
    from aliyunsdkcore.client import AcsClient
    from aliyunsdkcore.auth.credentials import StsTokenCredential
    from aliyunsdkcore.request import CommonRequest
    import oss2
    import logging
    ossEndPoint = "your OSS EndPoint"            # oss账号EndPoint,请选择外网访问。
    fileTransAppkey = "your appkey"   # 录音文件识别账号Appkey,获取Appkey请前往控制台:https://nls-portal.console.aliyun.com/applist
    fileTransCallbackUrl = "您的回调URL" # 在创建HTTP触发器时获取。
    def handler(event, context):
        logger = logging.getLogger()
        logger.info(event)
        eventObj = json.loads(event)["events"]
        eventName=eventObj[0]["eventName"]
        bucketName=eventObj[0]["oss"]["bucket"]["name"]
        ossFileName=eventObj[0]["oss"]["object"]["key"]
        logger.info("eventName: %s" % eventName)
        logger.info("bucketName: %s" % bucketName)
        logger.info("ossFileName: %s" % ossFileName)
        appKey = fileTransAppkey
        # 如下取值固定。
        REGION_ID = "cn-shanghai"
        PRODUCT = "nls-filetrans"
        DOMAIN = "filetrans.cn-shanghai.aliyuncs.com"
        API_VERSION = "2018-08-17"
        POST_REQUEST_ACTION = "SubmitTask"
        GET_REQUEST_ACTION = "GetTaskResult"
        KEY_APP_KEY = "appkey"
        KEY_FILE_LINK = "file_link"
        KEY_VERSION = "version"
        KEY_TASK = "Task"
        KEY_TASK_ID = "TaskId"
        KEY_STATUS_TEXT = "StatusText"
        creds = context.credentials
        # 创建AcsClient实例
        sts_token_credential = StsTokenCredential(creds.accessKeyId, creds.accessKeySecret, creds.securityToken)
        client = AcsClient(region_id=REGION_ID, credential=sts_token_credential)
        # 创建提交录音文件识别请求,并设置请求参数。
        postRequest = CommonRequest()
        postRequest.set_domain(DOMAIN)
        postRequest.set_version(API_VERSION)
        postRequest.set_product(PRODUCT)
        postRequest.set_action_name(POST_REQUEST_ACTION)
        postRequest.set_method('POST')
        filename = ossFileName.split('/')[-1]
        # create file url
        auth = oss2.StsAuth(creds.accessKeyId, creds.accessKeySecret, creds.securityToken)
        bucket = oss2.Bucket(auth, ossEndPoint, bucketName)
        fileLink = bucket.sign_url('GET', ossFileName, 3600)
        logger.info("file link = " + fileLink)
        # 如下回调地址,在第二步中生成。
        callback_url = fileTransCallbackUrl + "/" + filename
        logger.info("callback url = " + callback_url)
        task = {"SecurityToken": creds.securityToken, KEY_APP_KEY : appKey, KEY_FILE_LINK : fileLink, KEY_VERSION : "4.0", "enable_words" : False, "enable_callback" : True, "callback_url" : callback_url}
        task = json.dumps(task)
        #logger.info (task)
        postRequest.add_body_params(KEY_TASK, task)
        taskId = ""
        try :
            # 提交录音文件识别请求,处理服务端返回的响应。
            postResponse = client.do_action_with_exception(postRequest)
            postResponse = json.loads(postResponse)
            logger.info(postResponse)
            # 获取录音文件识别请求任务的ID,以供识别结果查询使用。
            statusText = postResponse[KEY_STATUS_TEXT]
            if statusText == "SUCCESS" :
                logger.info("录音文件识别请求成功响应!")
                taskId = postResponse[KEY_TASK_ID]
                logger.info("taskId = " + taskId)
            else :
                logger.info ("录音文件识别请求失败!")
        except ServerException as e:
            logger.error(e)
        except ClientException as e:
            logger.error(e)
        logger.info('hello world')
        logger.info(taskId)
        return taskId

  2. 创建并配置OSS触发器。

    重要

    由于上传音频文件到OSS的Bucket中,有两种方式:Put和Post。所以为了触发所有的上传事件,需要创建两个OSS触发器。

    参数

    说明

    触发器类型

    对象存储触发器。

    触发器名称

    自定义名称。

    触发事件

    分别选择oss:ObjectCreated:PutObjectoss:ObjectCreated:PostObject创建两个触发器。

    触发规则:前缀

    filetrans/raw/

    触发规则:后缀

    .wav

    角色

    如果已有合适角色,可直接选择;如果没有角色,则选择新建角色。

    创建成功后,可以在OSS控制台对应Bucket的函数计算中找到这两个触发器。

    • oss:ObjectCreated:PutObject事件:

      创建结果1
    • oss:ObjectCreated:PostObject事件:

      创建结果2

步骤三:接收回调

录音文件识别服务识别完成后,将识别结果通过HTTP触发器,写回OSS的Bucket中。在创建HTTP触发器的时候可以获得回调URL,请设置到生成任务函数的回调URL中。

  1. 编写函数。

    在创建的服务下,创建一个函数,用于将识别结果写回OSS:

    • 函数名称:put_http_post_to_oss

    • 函数入口:index.handler

    • 运行环境:Python 3

    • 函数执行内存:128 MB(选择最小值128 MB,该值与函数计算的计费相关)

    • 超时时间:600s

    函数内容如下,需要您替换如下参数:

    • OSS的EndPoint(外网访问)

    • OSS Bucket名称

    • OSS Bucket中的目录,用于存放识别结果文件。

    # -*- coding: utf-8 -*-
    import logging
    import oss2
    import json
    endpoint = "您的OSS EndPoint" # oss配置
    bucketName = "您的OSS Bucket名称" # oss配置
    resultOssPath = "您的录音文件识别结果存放目录" # oss路径,用于存储识别结果文件。
    B_OK = b"ok"
    def handler(environ, start_response):
        logger = logging.getLogger()
        context = environ['fc.context']
        request_uri = environ['fc.request_uri']
        for k, v in environ.items():
          if k.startswith("HTTP_"):
            # process custom request headers
            pass
        logger.info("request_uri = " + request_uri)
        filename = request_uri.split('/')[-1]
        logger.info('filename = ' + filename)
        # get request_body
        try:
            request_body_size = int(environ.get('CONTENT_LENGTH', 0))
        except (ValueError):
            request_body_size = 0
        request_body = environ['wsgi.input'].read(request_body_size)
        # parse result
        postResponse = json.loads(request_body)
        taskId = postResponse['TaskId']
        statusText = postResponse['StatusText']
        # put to oss
        creds = context.credentials
        auth = oss2.StsAuth(creds.accessKeyId, creds.accessKeySecret, creds.securityToken)
        logger.info("creds.accessKeyId = " + creds.accessKeyId)
        logger.info("creds.accessKeySecret = " + creds.accessKeySecret)
        logger.info("creds.securityToken = " + creds.securityToken)
        bucket = oss2.Bucket(auth, endpoint, bucketName)
        if statusText == "SUCCESS" :
          filename = resultOssPath + "/" + filename + "_" + taskId + '.json'
        else :
          filename = resultOssPath + "/" + filename + "_" + taskId + '_failed.json'
        logger.info('filename = ' + filename)
        bucket.put_object(filename, request_body)
        # do something here
        status = '200 OK'
        response_headers = [('Content-type', 'text/plain')]
        start_response(status, response_headers)
        return [B_OK]

  2. 创建并配置HTTP触发器。

    根据下表说明创建成功后,会自动生成路径作为回调URL。请将其设置到生成任务函数的回调URL中。

    参数

    说明

    服务类型

    HTTP触发器

    触发器名称

    http_post_caller

    认证方式

    anonymous

    请求方式

    POST

    路径信息