はじめに
RubyとS3とLambdaとTranscribeを使ってS3にアップロードされた動画を自動的に文字起こしするフローを作ってみました。 この記事はその時の手順などをまとめたものになります。
何故やったかというと、妻が「中国語の動画の字幕が欲しい」と言っていたのがきっかけ。 良い感じに動画の文字起こしができるものがないかと探してたところ、S3とLambdaとTranscribeで行けそうな感じだったのでやってみた感じです
やったこと
S3にアップロードされた動画をLambdaで受け取る
まずはS3にアップロードされた動画をLambdaで受け取ることができるようにします。
AWS Lambdaで以下のように関数を作成します。
作成する関数名はs3-upload-hook
とします。
また「ランタイム」はRuby 2.7
、「デフォルトの実行ロールの変更」は「基本的な Lambda アクセス権限で新しいロールを作成」を選択します。
最後に「関数の作成」をクリックしてLambdaの関数を作成します。
関数の作成後、使用するコードを以下のように変更します。
require 'json' require 'logger' def lambda_handler(event:, context:) logger = Logger.new($stdout) logger.info("Hook Event") logger.info(event) record = event["Records"][0] s3 = record["s3"] region = record["awsRegion"] bucket = s3["bucket"]["name"] object_key = s3["object"]["key"] path = "https://#{bucket}.s3-#{region}.amazonaws.com/#{object_key}" job_name = "TranscriptionJobName_#{object_key.sub(/movie\//, "")}" output_key = object_key.sub(/movie/, "text").sub(/\.mp4/, "") logger.info("S3 info") logger.info(bucket) logger.info(object_key) logger.info(path) end
コードの内容としては、S3から受け取ったバケットなどの情報を最終的に出力しています。
次に、S3でファイルがアップロードされたイベントをフックできるようにします。
「バケット」には動画がアップロードされるバケットを指定します。特定のディレクトリを指定したい場合はプレフィックスにmovie/
のようにディレクトリ名を指定します
最後に「追加」をクリックしてトリガーを追加します。
ここまでの段階で、S3にアップロードされた動画ファイルをLambdaで受け取ることができるようになります。
Transcribeで文字起こしをするジョブを作成
次に、LambdaからTranscribeへと文字起こしをするジョブの処理を追加します。
Lambdaのコードに以下の部分を追加します。
require 'json' + require 'aws-sdk-transcribeservice' require 'logger' def lambda_handler(event:, context:) logger = Logger.new($stdout) logger.info("Hook Event") logger.info(event) record = event["Records"][0] s3 = record["s3"] region = record["awsRegion"] bucket = s3["bucket"]["name"] object_key = s3["object"]["key"] path = "https://#{bucket}.s3-#{region}.amazonaws.com/#{object_key}" job_name = "TranscriptionJobName_#{object_key.sub(/movie\//, "")}" output_key = object_key.sub(/movie/, "text").sub(/\.mp4/, "") logger.info("S3 info") logger.info(bucket) logger.info(object_key) logger.info(path) + client = Aws::TranscribeService::Client.new(region: region) + response = client.start_transcription_job({ + transcription_job_name: job_name, + language_code: "ja-JP", + media_format: "mp4", + media: { + media_file_uri: path + }, + output_bucket_name: bucket, + output_key: "#{output_key}.txt" + }) + + logger.info("TranscriptionJob start #{response.transcription_job.transcription_job_name}") end
client = Aws::TranscribeService::Client.new(region: region)
でTranscribeへ投げるジョブを作成するためのクライアントを生成します。
次に、以下の部分でTranscribeへ投げるジョブを生成しています。
response = client.start_transcription_job({ transcription_job_name: job_name, language_code: "ja-JP", media_format: "mp4", media: { media_file_uri: path }, output_bucket_name: bucket, output_key: "#{output_key}.txt" })
transcription_job_name
は実行するジョブの名前を指定しています。ジョブの名前は一意でないといけないため、同じ名前のジョブがあるとエラーになるので注意が必要です。
language_code
では文字起こしする動画ファイルの言語を指定し、media_format
では変換元のファイルの種類を指定します。
media_file_uri
には変換元の動画ファイルのパスを渡しています。また、output_bucket_name
やoutput_key
で文字起こししたテキストをS3のどこに保存するかを指定しています。
ここまでの段階で、動画をS3にアップロードすると自動的に文字起こしされたファイルがS3に作成されるようになります。
おわりに
意外と簡単に実装できたので、このフローをベースに海外の動画の文字起こしサービスとか作っても面白そうかなと思いました。