我想在 PowerPoint VBA 项目中使用 Amazon Polly 将笔记转换为 mp3。我认为没有SDK,但是可以通过API签名吗?
问问题
582 次
1 回答
0
请参阅下面我最近构建的VBA 模块和VBA 类,允许从 MS Office 中直接调用 Amazon Web 服务 Polly,将生成的 MP3 保存到文件中。几点注意事项:
- 我只确认在 Windows 10 上使用 Office 365 版本的 MS Word 和 MS Excel 成功调用了 Amazon Polly,但鉴于我过去的 VBA 经验,没有任何理由相信该代码不适用于其他变体。
- 入口点是callAwsPolly。
- 您将需要相应地调整 AWS 参数(即aws.host、aws.region、aws.service和aws.uri)。
- 凭证(aws.accessKey和aws.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 回答