text -> Polly -> mp3 -> DynamoDB -> api response -> blob -> html5 audio
をやっていきたいと思います。
リアルタイムのAPIに音声合成を組み込む場合の実装例になります。
環境
- AWS Lambda + Boto3
- Vue.js
前提
S3にファイルを保存するのではなく、バイナリとしてDynamoDBに格納します。
合成音声が短い文章である場合、この方法は十分に有効です。
Pollyで音声を合成
lambdaからboto3で使っていきます。
リアルタイム変換を行いますが、200文字でもAPIに組み込めるレベルの応答時間(1,000ms程度)です。
ポイントはresponse['AudioStream']
がStreamingBodyクラスになります。
https://botocore.amazonaws.com/v1/documentation/api/latest/reference/response.html
def text_to_speach(text):
polly = boto3.client("polly")
response = polly.synthesize_speech(
Text=text,
OutputFormat="mp3",
VoiceId="Mizuki")
return response["AudioStream"].read()
DynamoDBへの格納
Pollyで変換したmp3のバイナリデータをDynamoDBに格納すると、バイナリ型として格納されます。
これはBase64でエンコードされたバイナリデータになります。
BlobURLの作成
DynamoDBに格納されたデータを何らかのAPIを通じてクライアントで取得します。
この際まだ音声データはBase64でエンコードされたバイナリデータです。
これをBlob形式に変換するには、以下のようにします。
ポイントは
- base64をデコードしてUnit8Arrayを作る
- Unit8Arrayから
audio/mpeg
を指定してBlobを作る - BlobからBlobURLを作る
となります。
private base64ToBlob(base64Data) {
const byteCharacters = atob(base64Data)
const byteNumbers = new Array(byteCharacters.length)
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i)
}
const byteArray = new Uint8Array(byteNumbers)
const blobUrl = URL.createObjectURL(
new Blob([byteArray], {
type: 'audio/mpeg',
})
)
return blobUrl
}
再生
あとはこのBlobURLをaudioコンポーネントのsrcに指定してください。(以下はVueの場合)
<audio v-bind:src="srcBlobUrl" autoplay />
まとめ
- Pollyのリアルタイム音声合成はAPIに組み込めるくらい速い
- DynamoDBにバイナリをBase64エンコードで格納することができる
- Base64をオンメモリでBlobに変換してaudioコンポーネントに利用できる