14

我正在尝试使用来自 Go 1.11 的 Amazon 新的流式转录 API。目前亚马逊仅提供 Java SDK,所以我正在尝试低级方式。

唯一相关的文档在这里,但它没有显示端点。我在一个Java 示例中找到了它https://transcribestreaming.<region>.amazonaws.com,我正在尝试爱尔兰地区,即https://transcribestreaming.eu-west-1.amazonaws.com. 这是我打开 HTTP/2 双向流的代码:

import (
    "crypto/tls"
    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/aws/external"
    "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
    "golang.org/x/net/http2"
    "io"
    "io/ioutil"
    "log"
    "net/http"
    "os"
    "time"
)

const (
    HeaderKeyLanguageCode   = "x-amzn-transcribe-language-code"  // en-US
    HeaderKeyMediaEncoding  = "x-amzn-transcribe-media-encoding" // pcm only
    HeaderKeySampleRate     = "x-amzn-transcribe-sample-rate"    // 8000, 16000 ... 48000
    HeaderKeySessionId      = "x-amzn-transcribe-session-id"     // For retrying a session. Pattern: [a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}
    HeaderKeyVocabularyName = "x-amzn-transcribe-vocabulary-name"
    HeaderKeyRequestId = "x-amzn-request-id"
)

...

region := "eu-west-1"

cfg, err := external.LoadDefaultAWSConfig(aws.Config{
    Region: region,
})
if err != nil {
    log.Printf("could not load default AWS config: %v", err)
    return
}

signer := v4.NewSigner(cfg.Credentials)

transport := &http2.Transport{
    TLSClientConfig: &tls.Config{
        // allow insecure just for debugging
        InsecureSkipVerify: true,
    },
}
client := &http.Client{
    Transport: transport,
}

signTime := time.Now()

header := http.Header{}
header.Set(HeaderKeyLanguageCode, "en-US")
header.Set(HeaderKeyMediaEncoding, "pcm")
header.Set(HeaderKeySampleRate, "16000")
header.Set("Content-type", "application/json")

// Bi-directional streaming via a pipe.
pr, pw := io.Pipe()

req, err := http.NewRequest(http.MethodPost, "https://transcribestreaming.eu-west-1.amazonaws.com/stream-transcription", ioutil.NopCloser(pr))
if err != nil {
    log.Printf("err: %+v", err)
    return
}
req.Header = header

_, err = signer.Sign(req, nil, "transcribe", region, signTime)
if err != nil {
    log.Printf("problem signing headers: %+v", err)
    return
}

// This freezes and ends after 5 minutes with "unexpected EOF".
res, err := client.Do(req)
...

问题是执行请求 ( client.Do(req)) 冻结了五分钟,然后以“意外 EOF”错误结束。

任何想法我做错了什么?有人在没有 Java SDK 的情况下成功使用了新的流式转录 API 吗?

编辑(2019 年 3 月 11 日):

我再次对此进行了测试,现在它不会超时,而是立即返回200 OK响应。但是,响应正文中有一个“异常”:{"Output":{"__type":"com.amazon.coral.service#SerializationException"},"Version":"1.0"}

io.Pipe我尝试使用(如上面的代码)以及文档中描述的 JSON 主体打开 HTTP2 流:

{
    "AudioStream": { 
        "AudioEvent": { 
            "AudioChunk": ""
        }
    }
}

结果是一样的。

编辑(2019 年 3 月 13 日):

正如@gpeng 所提到的,content-type从标头中删除将修复SerializationException. 但随后出现 IAM 异常,需要将transcription:StartStreamTranscription权限添加到您的 IAM 用户。这虽然在 AWS IAM 控制台中无处可寻,但必须手动添加为自定义 JSON 权限:/

这里还有一个新的/另一个文档文档显示不正确host和一个新的content-type(不要使用它content-type,请求将返回 404)。

删除content-type并添加新权限后,现在我得到了一个异常{"Message":"A complete signal was sent without the preceding empty frame."}。也永远写入管道块,所以我又被卡住了。新文档中描述的消息与旧文档中的消息不同,现在终于二进制了,但我不明白它们。任何想法如何在 Go 中发送此类 HTTP2 消息?

编辑(2019 年第 15 场比赛):*

如果您收到有关签名不匹配的 HTTP 403 错误,请不要设置transfer-encodingx-amz-content-sha256HTTP 标头。当我设置它们时,使用 AWS SDK 的 V4 签名者对请求进行签名,然后我收到 HTTP 403The request signature we calculated does not match the signature you provided.

4

4 回答 4

4

我联系了 AWS 支持,他们现在建议尽可能使用 websockets 而不是 HTTP/2(此处为博文)

如果这适合您的用例,我强烈建议您查看新的示例存储库:https ://github.com/aws-samples/amazon-transcribe-websocket-static ,它在 JS 中显示了基于浏览器的解决方案。

我还注意到演示的作者在他的个人 Github 上有一个快速示例:https ://github.com/brandonmwest/amazon-transcribe-websocket-express但我尚未确认这是否有效。

感谢这些示例不在 Python 中,但我认为使用 Websocket 客户端而不是 HTTP/2 会更好(说实话,这仍然有点可怕:P)

于 2019-07-01T12:16:49.837 回答
1

尝试不设置内容类型标题,看看你得到什么响应。我正在尝试做同样的事情(但在 Ruby 中)并且“修复”了SerializationException. 仍然无法让它工作,但我现在有一个新错误要考虑:)

更新:我现在已经开始工作了。我的问题是签名。如果同时传递host和标头,则在检查签名时,它们将与服务器端连接并被视为服务器端,因此签名永远不会匹配。在 AWS 方面,这似乎不是正确的行为,但在 Go 中它看起来不会成为您的问题。authority,host

于 2019-03-13T09:42:43.737 回答
0

我还在用 Node.js 来解决这个问题。关于文档尚不清楚的是,在一个地方它说不Content-Type应该是application/json,但在其他地方,它看起来应该将有效负载编码为application/vnd.amazon.eventstream。看起来负载应该仔细格式化为二进制格式而不是 JSON 对象,如下所示:

Amazon Transcribe 使用称为事件流编码的格式进行流式转录。这种格式编码的二进制数据带有描述每个事件内容的标题信息。您可以将此信息用于调用 Amazon Transcribe 终端节点的应用程序,而无需使用 Amazon Transcribe 开发工具包。Amazon Transcribe 使用 HTTP/2 协议进行流式转录。流式传输请求的关键组件是:

  • 一个标题帧。这包含请求的 HTTP 标头,以及授权标头中的签名,Amazon Transcribe 将其用作种子签名以对以下数据帧进行签名。

  • 事件流编码中的一个或消息帧。该帧包含元数据和原始音频字节。

  • 一个结束帧。这是事件流编码中的签名消息,正文为空。

有一个示例函数展示了如何使用 Java 实现所有这些,这可能会为如何完成这种编码提供一些启示。

于 2019-04-09T08:11:18.497 回答
0

我对在节点 js 中使用 AWS 转录服务和他们的 WebSocket API 有类似的要求。由于官方包中还没有对此的支持,所以我继续编写了一个名为 AWS-transcribe 的包,可以在此处找到。我希望这会有所帮助。

它提供了一个围绕 WebSocket 的流接口,可以像下面的例子一样使用

import { AwsTranscribe, StreamingClient } from "aws-transcribe"

const client = new AwsTranscribe({
    // if these aren't provided, they will be taken from the environment
    accessKeyId: "ACCESS KEY HERE",
    secretAccessKey: "SECRET KEY HERE",
})

const transcribeStream = client
    .createStreamingClient({
        region: "eu-west-1",
        sampleRate,
        languageCode: "en-US",
    })
    // enums for returning the event names which the stream will emit
    .on(StreamingClient.EVENTS.OPEN, () => console.log(`transcribe connection opened`))
    .on(StreamingClient.EVENTS.ERROR, console.error)
    .on(StreamingClient.EVENTS.CLOSE, () => console.log(`transcribe connection closed`))
    .on(StreamingClient.EVENTS.DATA, (data) => {
        const results = data.Transcript.Results

        if (!results || results.length === 0) {
            return
        }

        const result = results[0]
        const final = !result.IsPartial
        const prefix = final ? "recognized" : "recognizing"
        const text = result.Alternatives[0].Transcript
        console.log(`${prefix} text: ${text}`)
    })

someStream.pipe(transcribeStream)
于 2020-03-29T00:29:13.513 回答