AWS Step Functionsを利用し、S3バケット内の音声ファイルをAmazon Transcribeで文字起こししてみた
はじめに
AWS Step Functions ステートマシンを使用して、S3バケット内の音声ファイルをAmazon Transcribeで文字起こししてみました
システム構成は以下の通りです。
Step Functions ステートマシンを起点として、S3バケット内の音声ファイルをTranscribeで文字起こしし、生成されたテキストファイルを別のS3バケットに保存します。
S3バケット作成
以下のS3バケットを2つ作成します。
- 音声ファイル保存用(cm-hirai-audio-for-transcription)
- 文字起こししたテキストファイルを保存用(cm-hirai-transcription-output)
バケット名以外の設定はすべてデフォルトのままとしています。
IAMポリシー作成
ステートマシン用のIAMポリシーを作成します。
cm-hirai-transcribejob-policyという名前で以下の権限で作成します。アカウントIDは各自で値を変えてください。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::cm-hirai-transcription-output/*"
},
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::cm-hirai-audio-for-transcription/*"
},
{
"Effect": "Allow",
"Action": "transcribe:GetTranscriptionJob",
"Resource": "arn:aws:transcribe:ap-northeast-1:123456789012:transcription-job/*"
},
{
"Effect": "Allow",
"Action": "transcribe:StartTranscriptionJob",
"Resource": "*"
}
]
}
ステートマシン作成
次に、Step Functions のステートマシンを作成します。
まず、ステートマシンの定義画面からコードタブに移動し、以下のJSONコードをペーストします。
{
"Comment": "Transcription job using Amazon Transcribe",
"StartAt": "StartTranscriptionJob",
"States": {
"StartTranscriptionJob": {
"Type": "Task",
"Resource": "arn:aws:states:::aws-sdk:transcribe:startTranscriptionJob",
"Parameters": {
"TranscriptionJobName.$": "$$.Execution.Name",
"LanguageCode": "ja-JP",
"Media": {
"MediaFileUri.$": "$.inputFile"
},
"OutputBucketName": "cm-hirai-transcription-output",
"OutputKey.$": "States.Format('{}.json', $$.Execution.Name)",
"Settings": {
"ShowSpeakerLabels": true,
"MaxSpeakerLabels": 2
}
},
"Next": "Wait",
"Catch": [
{
"ErrorEquals": [
"BadRequestException",
"ConflictException",
"InternalFailureException",
"LimitExceededException"
],
"Next": "TranscriptionJobFailed"
}
]
},
"Wait": {
"Type": "Wait",
"Seconds": 1,
"Next": "GetTranscriptionJob"
},
"GetTranscriptionJob": {
"Type": "Task",
"Resource": "arn:aws:states:::aws-sdk:transcribe:getTranscriptionJob",
"Parameters": {
"TranscriptionJobName.$": "$.TranscriptionJob.TranscriptionJobName"
},
"Next": "CheckStatus",
"Catch": [
{
"ErrorEquals": [
"BadRequestException",
"InternalFailureException",
"LimitExceededException",
"NotFoundException"
],
"Next": "TranscriptionJobFailed"
}
]
},
"CheckStatus": {
"Type": "Choice",
"Choices": [
{
"Variable": "$.TranscriptionJob.TranscriptionJobStatus",
"StringEquals": "COMPLETED",
"Next": "TranscriptionJobSucceeded"
},
{
"Variable": "$.TranscriptionJob.TranscriptionJobStatus",
"StringEquals": "FAILED",
"Next": "TranscriptionJobFailed"
}
],
"Default": "Wait"
},
"TranscriptionJobSucceeded": {
"Type": "Succeed"
},
"TranscriptionJobFailed": {
"Type": "Fail",
"Cause": "Transcription job failed",
"Error": "TranscriptionJobFailedException"
}
}
}
OutputBucketName
は、文字起こししたテキストファイルを保存するS3バケット名です。各自の環境に合わせて変更してください。- Transcribeジョブ名と文字起こししたテキストファイル名は、ステートマシン実行名と同一にしています。
- ステートマシン実行名は、ステートマシンやその実行に関する情報を含むコンテキストオブジェクトから取得しています。
ワークフローは以下の通りです。
設定タブに移動し、ステートマシン名を入力します。
画面右上の「作成」ボタンをクリックします。
IAMロールは自動的に作成されますが、TranscribeやS3へのアクセス権限は手動で追加する必要があります。
ステートマシンの作成後、自動生成されたIAMロールに、先ほど作成したステートマシン用のIAMポリシーを適用します。
テスト
音声ファイル保存用のS3バケット(cm-hirai-audio-for-transcription)にtest1.wav
とtest1.json
を保存します。
ステートマシンの入力として以下のJSONを設定し、実行します。
{
"inputFile": "s3://cm-hirai-audio-for-transcription/test1.wav"
}
ステートマシンが正常に実行完了しました。
文字起こししたテキストファイルを保存するS3バケット(cm-hirai-transcription-output)には、ステートマシン実行名やTranscribeジョブ名と同じファイル名e3ac9297-120e-4bc7-8104-b12873717550.json
で、以下の内容が保存されていました。
{
"jobName": "",
"accountId": "xxxxxxxxxxxx",
"status": "COMPLETED",
"results": {
"transcripts": [
{ "transcript": "あこんにちは。もしもし?クラスメソッドテテストです" }
],
"speaker_labels": {
"segments": [
{
"start_time": "6.719",
"end_time": "7.949",
"speaker_label": "spk_0",
"items": [
{
"speaker_label": "spk_0",
"start_time": "6.829",
"end_time": "7.079"
},
{
"speaker_label": "spk_0",
"start_time": "7.09",
"end_time": "7.82"
}
]
},
{
"start_time": "8.479",
"end_time": "10.479",
"speaker_label": "spk_0",
"items": [
{
"speaker_label": "spk_0",
"start_time": "8.59",
"end_time": "9.199"
},
{
"speaker_label": "spk_0",
"start_time": "9.5",
"end_time": "9.869"
},
{
"speaker_label": "spk_0",
"start_time": "9.88",
"end_time": "10.39"
}
]
},
{
"start_time": "11.649",
"end_time": "13.93",
"speaker_label": "spk_1",
"items": [
{
"speaker_label": "spk_1",
"start_time": "11.789",
"end_time": "11.899"
},
{
"speaker_label": "spk_1",
"start_time": "12.92",
"end_time": "13.35"
},
{
"speaker_label": "spk_1",
"start_time": "13.359",
"end_time": "13.659"
}
]
}
],
"channel_label": "ch_0",
"speakers": 2
},
"items": [
{
"type": "pronunciation",
"alternatives": [{ "confidence": "0.897", "content": "あ" }],
"start_time": "6.829",
"end_time": "7.079",
"speaker_label": "spk_0"
},
{
"type": "pronunciation",
"alternatives": [{ "confidence": "0.996", "content": "こんにちは" }],
"start_time": "7.09",
"end_time": "7.82",
"speaker_label": "spk_0"
},
{
"type": "punctuation",
"alternatives": [{ "confidence": "0.0", "content": "。" }],
"speaker_label": "spk_0"
},
{
"type": "pronunciation",
"alternatives": [{ "confidence": "0.998", "content": "もしもし" }],
"start_time": "8.59",
"end_time": "9.199",
"speaker_label": "spk_0"
},
{
"type": "punctuation",
"alternatives": [{ "confidence": "0.0", "content": "?" }],
"speaker_label": "spk_0"
},
{
"type": "pronunciation",
"alternatives": [{ "confidence": "0.998", "content": "クラス" }],
"start_time": "9.5",
"end_time": "9.869",
"speaker_label": "spk_0"
},
{
"type": "pronunciation",
"alternatives": [{ "confidence": "0.997", "content": "メソッド" }],
"start_time": "9.88",
"end_time": "10.39",
"speaker_label": "spk_0"
},
{
"type": "pronunciation",
"alternatives": [{ "confidence": "0.459", "content": "テ" }],
"start_time": "11.789",
"end_time": "11.899",
"speaker_label": "spk_1"
},
{
"type": "pronunciation",
"alternatives": [{ "confidence": "0.996", "content": "テスト" }],
"start_time": "12.92",
"end_time": "13.35",
"speaker_label": "spk_1"
},
{
"type": "pronunciation",
"alternatives": [{ "confidence": "0.999", "content": "です" }],
"start_time": "13.359",
"end_time": "13.659",
"speaker_label": "spk_1"
}
]
}
}
別のケースとして、音声ファイルではない以下のJSONを入力して実行すると、エラーが発生します。
{
"inputFile": "s3://cm-hirai-audio-for-transcription/test1.json"
}
最後に
本記事では、AWS Step Functions ステートマシンを使用して、S3バケット内の音声ファイルをAmazon Transcribeで文字起こしする方法を紹介しました。
Step Functionsを利用することで、ローコードで実装やエラーハンドリングが可能となり、効率的なワークフロー構築が実現できます。
参照