Node.jsからのhttp2リクエストでAmazon Transcribeストリーミングサービスを使用しようとしています。これは、私がフォローしているドキュメントリンクです ストリーミングリクエストの形式 。このドキュメントによると、エンドポイントは https:// transcribe-streaming 。<'region'> .amazonaws.comですが、このURLにリクエストを送信すると、URLが見つからないというエラーが発生します。しかし Javaの例 でエンドポイントが https:// transcribestreaming 。 ''バック。私たちはus-east-1リージョンから試みています。
これが私が使っているコードです。
const http2 = require('http2');
var aws4 = require('aws4');
var opts = {
service: 'transcribe',
region: 'us-east-1',
path: '/stream-transcription',
headers:{
'content-type': 'application/json',
'x-amz-target': 'com.amazonaws.transcribe.Transcribe.StartStreamTranscription'
}
}
var urlObj = aws4.sign(opts, {accessKeyId: '<access key>', secretAccessKey: '<aws secret>'});
const client = http2.connect('https://transcribestreaming.<region>.amazonaws.com');
client.on('error', function(err){
console.error("error in request ",err);
});
const req = client.request({
':method': 'POST',
':path': '/stream-transcription',
'authorization': urlObj.headers.Authorization,
'content-type': 'application/json',
'x-amz-content-sha256': 'STREAMING-AWS4-HMAC-SHA256-EVENTS',
'x-amz-target': 'com.amazonaws.transcribe.Transcribe.StartStreamTranscription',
'x-amz-date': urlObj['headers']['X-Amz-Date'],
'x-amz-transcribe-language-code': 'en-US',
'x-amz-transcribe-media-encoding': 'pcm',
'x-amz-transcribe-sample-rate': 44100
});
req.on('response', (headers, flags) => {
for (const name in headers) {
console.log(`${name}: ${headers[name]}`);
}
});
let data = '';
req.on('data', (chunk) => { data += chunk; });
req.on('end', () => {
console.log(`\n${data}`);
client.close();
});
req.end();
私がここで欠けているものを誰かが指摘できますか? HTTP/2でこれを実装する例も見つかりませんでした。
更新:Content-typeをapplication/jsonに変更すると、応答ステータス200が返されますが、次の例外があります。
`{"Output":{"__type":"com.Amazon.coral.service#SerializationException"},"Version":"1.0"}`
アップデート(2019年4月22日):
req.setEncoding('utf8');
req.write(audioBlob);
var audioBlob = new Buffer(JSON.stringify({
"AudioStream": {
"AudioEvent": {
"AudioChunk": audioBufferData
}
}
リクエストを終了する前に、シリアライズによってペイロードとして「audioblod」を追加しています。私の「audioBufferData」は、ブラウザからの生のPCMオーディオ形式です。私は documentation からペイロードを "Event Stream Encoding"にエンコードする必要があることを確認しましたが、それを実装する方法を理解できませんでした。
したがって、現在このイベントストリームエンコーディングを使用しないと、200の応答ステータスで次の例外が発生します。
{"Output":{"__type":"com.Amazon.coral.service#UnknownOperationException"},"Version":"1.0"}
これは直接質問に答えることはできませんが、コメントではなく回答として投稿するのに十分便利だと思います。
AWS 発表済み Amazon TranscribeのWebSocketサポート。 ドキュメントはこちら 、そして クライアント側のサンプルアプリ はこちらです。最大の違い、そして私がWebSocketとの統合をより簡単にするのは、http/2のように各オーディオチャンクに署名する必要がないことです。
署名済みURLを使用して接続を承認および開始するための関連コードは lib/aws-signature-v4.js
exports.createPresignedURL = function(method, Host, path, service, payload, options) {
options = options || {};
options.key = options.key || process.env.AWS_ACCESS_KEY_ID;
options.secret = options.secret || process.env.AWS_SECRET_ACCESS_KEY;
options.protocol = options.protocol || 'https';
options.headers = options.headers || {};
options.timestamp = options.timestamp || Date.now();
options.region = options.region || process.env.AWS_REGION || 'us-east-1';
options.expires = options.expires || 86400; // 24 hours
options.headers = options.headers || {};
// Host is required
options.headers.Host = Host;
var query = options.query ? querystring.parse(options.query) : {};
query['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256';
query['X-Amz-Credential'] = options.key + '/' + exports.createCredentialScope(options.timestamp, options.region, service);
query['X-Amz-Date'] = toTime(options.timestamp);
query['X-Amz-Expires'] = options.expires;
query['X-Amz-SignedHeaders'] = exports.createSignedHeaders(options.headers);
var canonicalRequest = exports.createCanonicalRequest(method, path, query, options.headers, payload);
var stringToSign = exports.createStringToSign(options.timestamp, options.region, service, canonicalRequest);
var signature = exports.createSignature(options.secret, options.timestamp, options.region, service, stringToSign);
query['X-Amz-Signature'] = signature;
return options.protocol + '://' + Host + path + '?' + querystring.stringify(query);
};
そして、それを lib/main.js
:
function createPresignedUrl() {
let endpoint = "transcribestreaming." + region + ".amazonaws.com:8443";
// get a preauthenticated URL that we can use to establish our WebSocket
return v4.createPresignedURL(
'GET',
endpoint,
'/stream-transcription-websocket',
'transcribe',
crypto.createHash('sha256').update('', 'utf8').digest('hex'), {
'key': $('#access_id').val(),
'secret': $('#secret_key').val(),
'protocol': 'wss',
'expires': 15,
'region': region,
'query': "language-code=" + languageCode + "&media-encoding=pcm&sample-rate=" + sampleRate
}
);
}
必要なものをイベントストリームメッセージ形式でパッケージ化するには、 PCMエンコードされたオーディオをJSONエンベロープにラップしてバイナリに変換します
function convertAudioToBinaryMessage(audioChunk) {
let raw = mic.toRaw(audioChunk);
if (raw == null)
return;
// downsample and convert the raw audio bytes to PCM
let downsampledBuffer = audioUtils.downsampleBuffer(raw, sampleRate);
let pcmEncodedBuffer = audioUtils.pcmEncode(downsampledBuffer);
// add the right JSON headers and structure to the message
let audioEventMessage = getAudioEventMessage(Buffer.from(pcmEncodedBuffer));
//convert the JSON object + headers into a binary event stream message
let binary = eventStreamMarshaller.marshall(audioEventMessage);
return binary;
}
function getAudioEventMessage(buffer) {
// wrap the audio data in a JSON envelope
return {
headers: {
':message-type': {
type: 'string',
value: 'event'
},
':event-type': {
type: 'string',
value: 'AudioEvent'
}
},
body: buffer
};
}
ノードjsでWebSocket APIを使用してAWS transcribeサービスを使用するための同様の要件がありました。公式パッケージではこれに対するサポートがまだないため、私は先に進んで、この実装に続くパッケージを作成しました githubで 。これはAWS-transcribeと呼ばれ、 here にあります。お役に立てば幸いです。
これは、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)