0
0

More than 3 years have passed since last update.

Amazon TranscribeでKeyError: 'TranscriptFileUri'となったときの対処方法について

Posted at

はじめに

最近AWSでつくるAIプログラミング入門という本をやっています。
この本が書かれたのは、2019年末で当初は英語でしか動かなかったシステムも今では日本語で動くようになっているものがいくつかあります。
その中にAmazon Transcribeがあり、日本語で本書のコードの一部を変更して対応させていましたが、エラーに遭遇したので今回はまとめたいと思います。

問題

以下のコードを実行したところエラーになりました。
このコードは本書のコードを一部変更したものになります。

import boto3
import json
import pprint
import time
import uuid
import urllib

bucket = str(uuid.uuid1())
print('bucket:', bucket)
region = 'ap-northeast-1'
s3 = boto3.client('s3', region)
result = s3.create_bucket(
    Bucket=bucket,
    CreateBucketConfiguration={'LocationConstraint': region})

file = 'scribe_file_in.mp3'
key = 'input'
s3.upload_file(file, bucket, key)

transcribe = boto3.client('transcribe', region)
job = str(uuid.uuid1())
uri = 'https://s3-'+region+'.amazonaws.com/'+bucket+'/'+key
result = transcribe.start_transcription_job(
    TranscriptionJobName=job, Media={'MediaFileUri': uri},
    MediaFormat='mp3', LanguageCode='ja-JP')
print('start_transcription_job:')
pprint.pprint(result)

start = time.time()
while True:
    result = transcribe.get_transcription_job(TranscriptionJobName=job)
    status = result['TranscriptionJob']['TranscriptionJobStatus']
    if status != 'IN_PROGRESS':
        break
    time.sleep(10)
    print('time:', time.time()-start)
print('get_transcription_job:')
pprint.pprint(result)

uri = result['TranscriptionJob']['Transcript']['TranscriptFileUri']
print('uri:', uri)
with urllib.request.urlopen(uri) as file_in:
    transcripts = json.load(file_in)
with open('scribe_file_out.json', 'w', encoding='utf-8') as file_out:
    json.dump(transcripts, file_out, indent=4)

print('transcript:')
for transcript in transcripts['results']['transcripts']:
    print(transcript['transcript'])

transcribe.delete_transcription_job(TranscriptionJobName=job)
s3.delete_object(Bucket=bucket, Key=key)
s3.delete_bucket(Bucket=bucket)

変更点は以下の2点です。
1. regionがus-east-2からap-northeast-1に変更
2. transcribe.start_transcription_jobのLanguageCodeがen-USからja-JPに変更

同じディレクトリには、ボイスレコーダーで自分の声を録音したscribe_file_in.m4ascribe_file_in.mp3にJupyterNotebook上で名前を変更しました。

すると、以下のエラーが出ます。

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-19-68aeffcf87d9> in <module>
     38 pprint.pprint(result)
     39 
---> 40 uri = result['TranscriptionJob']['Transcript']['TranscriptFileUri']
     41 print('uri:', uri)
     42 with urllib.request.urlopen(uri) as file_in:

KeyError: 'TranscriptFileUri'

解決方法

resultをみたところ、以下のようになっていました。

{'ResponseMetadata': {'HTTPHeaders': {'connection': 'keep-alive',
                                      'content-length': '562',
                                      'content-type': 'application/x-amz-json-1.1',
                                      'date': 'Mon, 31 May 2021 13:48:28 GMT',
                                      'x-amzn-requestid': 'fd6eb86c-4668-4f0d-8af6-6847b09f9c40'},
                      'HTTPStatusCode': 200,
                      'RequestId': 'fd6eb86c-4668-4f0d-8af6-6847b09f9c40',
                      'RetryAttempts': 0},
 'TranscriptionJob': {'CreationTime': datetime.datetime(2021, 5, 31, 13, 48, 19, 219000, tzinfo=tzlocal()),
                      'FailureReason': 'The media format that you specified '
                                       "doesn't match the detected media "
                                       'format. Check the media format and try '
                                       'your request again.',
                      'LanguageCode': 'ja-JP',
                      'Media': {'MediaFileUri': 'https://s3-ap-northeast-1.amazonaws.com/da8910de-c216-11eb-8f7b-0242ac190002/input'},
                      'MediaFormat': 'mp3',
                      'Settings': {'ChannelIdentification': False},
                      'Transcript': {},
                      'TranscriptionJobName': 'db3498b4-c216-11eb-8f7b-0242ac190002',
                      'TranscriptionJobStatus': 'FAILED'}}

この中の以下の箇所をみると、Transcriptが空({})となっていました。

                      'MediaFormat': 'mp3',
                      'Settings': {'ChannelIdentification': False},
                      'Transcript': {},

空になっているので、そもそも文字おこし自体が失敗しています。
これが、`KeyError: 'TranscriptFileUri'の原因でした。

ちなみに以下の箇所がFAILEDになっているので失敗していることがわかります。

                      'TranscriptionJobStatus': 'FAILED'}}

この処理は、非同期で行われます。このコードではCOMPLETEDになるまで繰り返し表示がありますが、そのようなコードにしていない場合は、何度か実行してCOMPLETEDになるまで待つ必要があります。

では、なぜFAILEDになっているのでしょうか。

それは、.m4a.mp3に変えたことでした。
.m4aをアップロードしてFormatをmp4にしても動きます。

以下のコードで解決しました。

import boto3
import json
import pprint
import time
import uuid
import urllib

bucket = str(uuid.uuid1())
print('bucket:', bucket)
region = 'ap-northeast-1'
s3 = boto3.client('s3', region)
result = s3.create_bucket(
    Bucket=bucket,
    CreateBucketConfiguration={'LocationConstraint': region})

file = 'scribe_file_in.m4a'
key = 'input'
s3.upload_file(file, bucket, key)

transcribe = boto3.client('transcribe', region)
job = str(uuid.uuid1())
uri = 'https://s3-'+region+'.amazonaws.com/'+bucket+'/'+key
result = transcribe.start_transcription_job(
    TranscriptionJobName=job, Media={'MediaFileUri': uri},
    MediaFormat='mp4', LanguageCode='ja-JP')
print('start_transcription_job:')
pprint.pprint(result)

start = time.time()
while True:
    result = transcribe.get_transcription_job(TranscriptionJobName=job)
    status = result['TranscriptionJob']['TranscriptionJobStatus']
    if status != 'IN_PROGRESS':
        break
    time.sleep(10)
    print('time:', time.time()-start)
print('get_transcription_job:')
pprint.pprint(result)

uri = result['TranscriptionJob']['Transcript']['TranscriptFileUri']
print('uri:', uri)
with urllib.request.urlopen(uri) as file_in:
    transcripts = json.load(file_in)
with open('scribe_file_out.json', 'w', encoding='utf-8') as file_out:
    json.dump(transcripts, file_out, indent=4)

print('transcript:')
for transcript in transcripts['results']['transcripts']:
    print(transcript['transcript'])

transcribe.delete_transcription_job(TranscriptionJobName=job)
s3.delete_object(Bucket=bucket, Key=key)
s3.delete_bucket(Bucket=bucket)

データはボイスレコーダーでつくられたファイル形式そのままです。
これで動きました。

さいごに

AWSのエラーは割と起きると解決までたどり着くのが難しい気がしています。
あまり、解決のための記事というのが日本語ではすくなく、全体としても少ないです。
直接問い合わせるのがよさそうですね。

参考記事

AWSでつくるAIプログラミング入門

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0