0

我想在 PowerPoint VBA 项目中使用 Amazon Polly 将笔记转换为 mp3。我认为没有SDK,但是可以通过API签名吗?

4

1 回答 1

0

请参阅下面我最近构建的VBA 模块VBA 类,允许从 MS Office 中直接调用 Amazon Web 服务 Polly,将生成的 MP3 保存到文件中。几点注意事项:

  • 我只确认在 Windows 10 上使用 Office 365 版本的 MS Word 和 MS Excel 成功调用了 Amazon Polly,但鉴于我过去的 VBA 经验,没有任何理由相信该代码不适用于其他变体。
  • 入口点是callAwsPolly
  • 您将需要相应地调整 AWS 参数(即aws.hostaws.regionaws.serviceaws.uri)。
  • 凭证(aws.accessKeyaws.secretKey)是标准的 AWS 示例凭证,显然需要用您自己的 AWS 凭证替换。
  • 请注意,在代码中嵌入凭据是非常糟糕的做法。我不确定您的具体应用程序,但在我的情况下,我创建了自己的密钥库,可选择使用密码或 MAC 地址作为密钥库的解密密钥。凭证管理的概念是另一个主题,我不在这里讨论...

要将功能合并到 MS Office 产品中,请将以下内容添加为 VBA 模块...



Option Explicit

Sub callAwsPolly()

    Dim aws As amazonWebService
    Set aws = New amazonWebService

    aws.host = "polly.us-east-2.amazonaws.com"
    aws.region = Split(aws.host, ".")(1)
    aws.service = "polly"
    aws.uri = "/v1/speech"

    ' !!! NOTE:  The following is very bad practice to embed credentials in code!!!

    aws.accessKey = "AKIAIOSFODNN7EXAMPLE"
    aws.secretKey = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"

    Dim requestParameters As String
    requestParameters = "{#OutputFormat#: #mp3#, #Text#: #Polly want a cracker?#, #TextType#: #ssml#, #VoiceId#: #Emma#}"
    requestParameters = Replace(requestParameters, "#", """")

    Dim httpResponse As Object
    Set httpResponse = aws.callWebService("application/json", requestParameters)

    If httpResponse Is Nothing Then
        MsgBox "Call to AWS Polly failed."
    ElseIf httpResponse.Status = 200 Then
        MsgBox "Call to AWS Polly succeeded!  MP3 file being saved."

        Dim iFile As Long:  iFile = FreeFile
        Open ActiveWorkbook.FullName & ".mp3" For Binary Access Write As #iFile
        Put iFile, , httpResponse.Responsebody
        Close #iFile
    Else
        MsgBox "Call to AWS Polly failed:" + CStr(httpResponse.Status) + " " + httpResponse.StatusText + " " + httpResponse.ResponseText
    End If

End Sub


' Adapted from https://stackoverflow.com/questions/36384741/cant-use-getbytes-and-computehash-methods-on-vba

Public Function hmacSha256(key As Variant, stringToHash As Variant) As Byte()

    Dim ssc As Object
    Set ssc = CreateObject("System.Security.Cryptography.HMACSHA256")

    ssc.key = str2byte(key)
    hmacSha256 = ssc.ComputeHash_2(str2byte(stringToHash))

    Set ssc = Nothing

End Function

Public Function sha256(stringToHash As Variant) As Byte()

    Dim ssc As Object
    Set ssc = CreateObject("System.Security.Cryptography.SHA256Managed")

    sha256 = ssc.ComputeHash_2(str2byte(stringToHash))

    Set ssc = Nothing

End Function

Public Function str2byte(s As Variant) As Byte()

    If VarType(s) = vbArray + vbByte Then
        str2byte = s
    ElseIf VarType(s) = vbString Then
        str2byte = StrConv(s, vbFromUnicode)
    Else
        Exit Function
    End If

End Function

Public Function byte2hex(byteArray() As Byte) As String

    Dim i As Long
    For i = 0 To UBound(byteArray)
        byte2hex = byte2hex & Right(Hex(256 Or byteArray(i)), 2)
    Next
    byte2hex = LCase(byte2hex)

End Function


...并将以下代码添加为 VBA 类模块,将其命名为“ amazonWebService ”...



'
' Class Module:  amazonWebService
'
Private className As String

Public host As String
Public region As String
Public service As String
Public uri As String

Public accessKey As String
Public secretKey As String

Private Sub Class_Initialize()

    className = "amazonWebService"

    host = ""
    region = ""
    uri = ""
    service = ""

    accessKey = ""
    secretKey = ""

End Sub

Public Function callWebService(contentType As String, requestParameters As String) As Object

    If host = "" Or region = "" Or uri = "" Or service = "" Or accessKey = "" Or secretKey = "" Then
        Err.Raise _
            1000, _
            className, _
            className + ": Please set properties before calling the amazon web service:  host, region, uri, service, accessKey, and secretKey."
        callWebService = Null
        Exit Function
    End If

    Dim amzDate As String, dateStamp As String
    amzDate = date2iso8601(GMT())
    dateStamp = Left(amzDate, 8)

    ' ************* TASK 1: CREATE A CANONICAL REQUEST *************
    ' http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html

    'Step 1 is to define the verb (GET, POST, etc.)
    Dim method As String
    method = "POST"

    ' Step 2: Create canonical URI (set by the calling program)
    Dim canonicalUri As String
    canonicalUri = uri

    ' Step 3: Create the canonical query string. In this example (POST), request
    ' parameters are passed in the body of the request and the query string
    ' is blank.
    Dim canonicalQueryString As String
    canonicalQueryString = ""

    ' Step 4: Create the canonical headers. Header names must be trimmed
    ' and lowercase, and sorted in code point order from low to high.
    ' Note that there is a trailing \n.
    Dim canonicalHeaders As String
    canonicalHeaders = _
        "host:" + host + vbLf + _
        "x-amz-date:" + amzDate + vbLf

    ' Step 5: Create the list of signed headers. This lists the headers
    ' in the canonical_headers list, delimited with ";" and in alpha order.
    ' Note: The request can include any headers; canonical_headers and
    ' signed_headers include those that you want to be included in the
    ' hash of the request. "Host" and "x-amz-date" are always required.
    Dim signedHeaders As String
    signedHeaders = "host;x-amz-date"

    ' Step 6: Create payload hash. In this example, the payload (body of
    ' the request) contains the request parameters.
    Dim payloadHash As String
    payloadHash = byte2hex(sha256(requestParameters))

    ' Step 7: Combine elements to create canonical request
    Dim canonicalRequest As String
    canonicalRequest = method + vbLf + _
        canonicalUri + vbLf + _
        canonicalQueryString + vbLf + _
        canonicalHeaders + vbLf + _
        signedHeaders + vbLf + _
        payloadHash

    ' ************* TASK 2: CREATE THE STRING TO SIGN*************
    ' Match the algorithm to the hashing algorithm you use, either SHA-1 or
    ' SHA-256 (recommended)
    Dim algorithm As String, credentialScope As String, stringToSign As String
    algorithm = "AWS4-HMAC-SHA256"
    credentialScope = dateStamp + "/" + region + "/" + service + "/aws4_request"
    stringToSign = _
        algorithm + vbLf + _
        amzDate + vbLf + _
        credentialScope + vbLf + _
        byte2hex(sha256(canonicalRequest))

    ' ************* TASK 3: CALCULATE THE SIGNATURE *************
    ' Create the signing key using the function defined above.
    Dim signingKey() As Byte, signature As String
    signingKey = getSignatureKey(secretKey, dateStamp, region, service)

    ' Sign the string_to_sign using the signing_key
    signature = byte2hex(hmacSha256(signingKey, stringToSign))

    ' ************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************
    ' Put the signature information in a header named Authorization.
    Dim authorizationHeader As String
    authorizationHeader = _
        algorithm + " " + _
        "Credential=" + accessKey + "/" + credentialScope + ", " + _
        "SignedHeaders=" + signedHeaders + ", " + _
        "Signature=" + signature

    ' ************* SEND THE REQUEST TO AWS! *************

    Dim http As Object
    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")

    http.Open "POST", "https://" + host + uri, False
    http.setrequestheader "content-type", contentType
    http.setrequestheader "host", host
    http.setrequestheader "x-amz-date", amzDate
    http.setrequestheader "authorization", authorizationHeader

    http.Send requestParameters

    ' If the result is 403 Forbidden, then clear the current selected credentials.

    If http.Status = 403 Then
        accessKey = ""
        secretKey = ""
    End If

    ' Return the HTTP response back to the calling program.

    Set callWebService = http

End Function

Private Function GMT() As Date

    Dim dt As Object
    Set dt = CreateObject("WbemScripting.SWbemDateTime")

    dt.SetVarDate Now
    GMT = dt.GetVarDate(False)

    Set dt = Nothing

End Function

Private Function date2iso8601(dateTime As Date) As String

    date2iso8601 = Format(dateTime, "yyyymmdd\Thhnnss\Z")

End Function

Private Function getSignatureKey(key As String, dateStamp As String, regionName As String, serviceName As String) As Byte()
    Dim kDate() As Byte, kRegion() As Byte, kService() As Byte, kSigning() As Byte

    kDate = hmacSha256("AWS4" + key, dateStamp)
    kRegion = hmacSha256(kDate, regionName)
    kService = hmacSha256(kRegion, serviceName)
    kSigning = hmacSha256(kService, "aws4_request")

    getSignatureKey = kSigning

End Function

于 2018-09-16T16:57:41.010 回答