エンジニア

2016.12.07

眠すぎる朝のPolly

眠すぎる朝のPolly

テバサキワ
ハンズラボ 吉田です。
乗り継ぎ3時間待ちが非常に辛いです。。。
ここで寝たら日本に帰れないので書いています
img_1926
割とどうでも良いのですが、自分、ベガスでこの高さからダイブしました。
すっげーーー気持ちいい。次はスカイダイビングしてみたいです。
本題に移ります

この記事の内容

AWS-CLIを用いてPollyをいじっていきます。
APIの基本はCLI!!

pollyとは

  • ざっくり言うと音声読み上げのサービスです
  • 入力として渡したテキストに従って音声ファイルを出力します
  • テキストは通常テキストとSSMLを指定できます
  • 出力はMP3/ogg_vorbis/pcmから選択できます

SSMLとは

XMLみたいなもの。ポリーさんにこの文章こう話せと指定するテキストです。同様のことをレキシコンを使っても指定できます
SSL公式サンプル

<?xml version="1.0"?>
<speak version="1.1"
       xmlns="http://www.w3.org/2001/10/synthesis"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.w3.org/2001/10/synthesis http://www.w3.org/TR/speech-synthesis11/synthesis.xsd"
       xml:lang="en-US">Hello World</speak>

詳細はドキュメントに任せるとして、息継ぎのタイミングや発音とかもいじれるので職人芸に期待できます

CLIサブコマンド一覧

  • list-lexicons
  • get-lexicon
  • put-lexicon
  • delete-lexicon
  • describe-voices
  • synthesize-speech

そんなに数は無いです。レキシコンに関するコマンド(取得・追加・削除)とボイスの情報取得、音声ファイルの生成が提供されています

前提条件

Pollyに対してAPIを発行するIAM権限を有していること

  • 当記事の内容を検証するにあたって、その他の部分でハマることを避けるためフル権限を有していることを推奨します

AWSCLIのバージョン

  • 1.11.24にて実施しています
$ aws --version
aws-cli/1.11.24 Python/2.7.10 Darwin/15.6.0 botocore/1.4.81

バージョンによってはpollyコマンドが入っていないのでバージョンが足りない人はバージョンを上げましょう。

注意

  • CLIコマンドで使用するプロファイルが想定どおりになっているか確認してからCLIコマンドを発行してください
  • 現在Pollyは下記リージョンで使用できます(2016/12/06現在)
    • バージニア北部
    • オハイオ
    • オレゴン
    • アイルランド

今回はオレゴン(us-west-2)を使用します
指定リージョンを環境変数へセット

export AWS_DEFAULT_REGION='us-west-2'

日本語のボイス情報を取得します

日本語のボイス情報を取得します

aws polly describe-voices --language-code 'ja-JP'

結果

{
    "Voices": [
        {
            "Gender": "Female",
            "Name": "Mizuki",
            "LanguageName": "Japanese",
            "Id": "Mizuki",
            "LanguageCode": "ja-JP"
        }
    ]
}

日本語ボイスのidミズキ(Mizuki)に関しての情報が取得できました。
リファレンスから確認できるlanguage-codeの値は下記になります
language-code一覧

cy-GB
da-DK
de-DE
en-AU
en-GB
en-GB-WLS
en-IN
en-US
es-ES
es-US
fr-CA
fr-FR
is-IS
it-IT
ja-JP
nb-NO
nl-NL
pl-PL
pt-BR
pt-PT
ro-RO
ru-RU
sv-SE
tr-TR

参考

英語ボイスの一覧を見てみると・・・
es-US

{
    "Voices": [
        {
            "Gender": "Female",
            "Name": "Joanna",
            "LanguageName": "US English",
            "Id": "Joanna",
            "LanguageCode": "en-US"
        },
        {
            "Gender": "Female",
            "Name": "Salli",
            "LanguageName": "US English",
            "Id": "Salli",
            "LanguageCode": "en-US"
        },
        {
            "Gender": "Female",
            "Name": "Kimberly",
            "LanguageName": "US English",
            "Id": "Kimberly",
            "LanguageCode": "en-US"
        },
        {
            "Gender": "Female",
            "Name": "Kendra",
            "LanguageName": "US English",
            "Id": "Kendra",
            "LanguageCode": "en-US"
        },
        {
            "Gender": "Male",
            "Name": "Justin",
            "LanguageName": "US English",
            "Id": "Justin",
            "LanguageCode": "en-US"
        },
        {
            "Gender": "Male",
            "Name": "Joey",
            "LanguageName": "US English",
            "Id": "Joey",
            "LanguageCode": "en-US"
        },
        {
            "Gender": "Female",
            "Name": "Ivy",
            "LanguageName": "US English",
            "Id": "Ivy",
            "LanguageCode": "en-US"
        }
    ]
}

やはり日本語に比べて遥かに多いです。
日本語もそのうちいい感じに増えるのでしょうか?

テキストの音声化

pollyに話してもらいましょう
変数

OUT_PUT_FORMAT='mp3'
INPUT_TEXT='ハンズラボの手羽の会'
INPUT_TEXT_TYPE='text'
VOICE_ID=`aws polly describe-voices --language-code 'ja-JP' | jq -r '.Voices[].Id'`
OUT_PUT_FILE_NAME='TEBA'

コマンド

aws polly synthesize-speech \
    --output-format ${OUT_PUT_FORMAT} \
    --text ${INPUT_TEXT} \
    --text-type ${INPUT_TEXT_TYPE} \
    --voice-id ${VOICE_ID} \
    ${OUT_PUT_FILE_NAME}.mp3

結果

{
    "ContentType": "audio/mpeg",
    "RequestCharacters": "10"
}

確認

ls | grep 'TEBA'
TEBA.mp3

ローカルに保存されています

こんな形で音を聞くことが出来ます

lexicons(レキシコン)について

一般的な単語は、「g3t sm4rt」 (get smart) のように文字を数字に置き換えたスタイルで書かれる場合があります。人間はこれらの単語を正しく読むことができます。ただし、テキスト読み上げ機能 (TTS) エンジンでは文字をそのまま読み上げ、名前をスペルどおりに発音します。このような場合、Amazon Polly でレキシコンを活用し、合成された音声をカスタマイズできます。この例では、レキシコンで「g3t sm4rt」という単語に「get smart」というエイリアスを指定できます。

参考:http://docs.aws.amazon.com/ja_jp/polly/latest/dg/managing-lexicons.html
まあ、要するにthx!って打ったらあんがとーって言わせたい時に使えばいいっぽいです。

デフォルトの状態のレキシコンの取得

コマンド

aws polly list-lexicons

結果

{
    "Lexicons": []
}

何もしていないのでまだ何も登録されていません

レキシコンファイルの準備

レキシコンサンプル

<?xml version="1.0" encoding="UTF-8"?>
<lexicon version="1.0"
      xmlns="http://www.w3.org/2005/01/pronunciation-lexicon"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.w3.org/2005/01/pronunciation-lexicon
        http://www.w3.org/TR/2007/CR-pronunciation-lexicon-20071212/pls.xsd"
      alphabet="ipa"
      xml:lang="ja-Ja">
  <lexeme>
    <grapheme>押すなよ</grapheme>
    <alias>早く押せ</alias>
  </lexeme>
</lexicon>

上記サンプルを登録します。
変数

LEXICON_FILE_NAME='LEXICON_INPUT.pls'

コマンド

cat << EOF > ${LEXICON_FILE_NAME}
<?xml version="1.0" encoding="UTF-8"?>
<lexicon version="1.0"
      xmlns="http://www.w3.org/2005/01/pronunciation-lexicon"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.w3.org/2005/01/pronunciation-lexicon
        http://www.w3.org/TR/2007/CR-pronunciation-lexicon-20071212/pls.xsd"
      alphabet="ipa"
      xml:lang="ja-Ja">
  <lexeme>
    <grapheme>押すなよ</grapheme>
    <alias>早く押せ</alias>
  </lexeme>
</lexicon>
EOF

確認

cat ${LEXICON_FILE_NAME}

ちゃんと表示されるか確認します

レキシコンの登録

変数

LEXICON_NAME='OstrichClub'

コマンド

aws polly put-lexicon \
    --name ${LEXICON_NAME} \
    --content file://${LEXICON_FILE_NAME}

結果

An error occurred (UnsupportedPlsLanguageException) when calling the PutLexicon operation: Unsupported PLS language

あれま・・・日本語ダメみたいですねー。。。

英語で試します

使わないので先程のファイルを削除します
コマンド

rm ${LEXICON_FILE_NAME}

コマンド

cat << EOF > ${LEXICON_FILE_NAME}
<?xml version="1.0" encoding="UTF-8"?>
<lexicon version="1.0"
      xmlns="http://www.w3.org/2005/01/pronunciation-lexicon"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.w3.org/2005/01/pronunciation-lexicon
        http://www.w3.org/TR/2007/CR-pronunciation-lexicon-20071212/pls.xsd"
      alphabet="ipa"
      xml:lang="en-US">
  <lexeme>
    <grapheme>thx</grapheme>
    <alias>Thank you</alias>
  </lexeme>
</lexicon>
EOF

確認

cat ${LEXICON_FILE_NAME}

ちゃんと表示されるか確認します
変数

LEXICON_NAME='THANKYOU'

コマンド

aws polly put-lexicon \
    --name ${LEXICON_NAME} \
    --content file://${LEXICON_FILE_NAME}

確認

レキシコンファイルが登録されたか確認します
コマンド

aws polly list-lexicons

結果

{
    "Lexicons": [
        {
            "Attributes": {
                "LanguageCode": "en-US",
                "LastModified": 1480957317.243,
                "Alphabet": "ipa",
                "LexemesCount": 1,
                "LexiconArn": "arn:aws:polly:us-west-2:XXXXXXXXXXXX:lexicon/THANKYOU",
                "Size": 476
            },
            "Name": "THANKYOU"
        }
    ]
}

登録されました。
レキシコンの言語について

xml:lang 属性はレキシコンが適用される言語コード、en-US を指定します。SynthesizeSpeech 呼び出しで指定する音声が同じ言語コード (en-US) である場合、Amazon Polly はこの例のレキシコンを使用できます。

と公式ドキュメントに書いてある通り、このレキシコンはミズキちゃんには適応出来ません。。。

レキシコンを試す

  • まずはレキシコンを指定しないで作成します

変数

OUT_PUT_FORMAT='mp3'
INPUT_TEXT='thx'
INPUT_TEXT_TYPE='text'
VOICE_ID=`aws polly describe-voices --language-code 'en-US' | jq -r '.Voices[0].Id'`
OUT_PUT_FILE_NAME='thx'

コマンド

aws polly synthesize-speech \
    --output-format ${OUT_PUT_FORMAT} \
    --text ${INPUT_TEXT} \
    --text-type ${INPUT_TEXT_TYPE} \
    --voice-id ${VOICE_ID} \
    ${OUT_PUT_FILE_NAME}.mp3

結果

{
    "ContentType": "audio/mpeg",
    "RequestCharacters": "3"
}

確認

確認

ls | grep 'thx'
thx.mp3

ローカルに保存されたmp3はティー・エイチ・エックスと発音します

  • レキシコンを指定します

変数

OUT_PUT_FORMAT='mp3'
INPUT_TEXT='thx'
INPUT_TEXT_TYPE='text'
VOICE_ID=`aws polly describe-voices --language-code 'en-US' | jq -r '.Voices[0].Id'`
OUT_PUT_FILE_NAME='LEXICON_THX'

コマンド

aws polly synthesize-speech \
    --lexicon-names ${LEXICON_NAME} \
    --output-format ${OUT_PUT_FORMAT} \
    --text ${INPUT_TEXT} \
    --text-type ${INPUT_TEXT_TYPE} \
    --voice-id ${VOICE_ID} \
    ${OUT_PUT_FILE_NAME}.mp3

結果

{
    "ContentType": "audio/mpeg",
    "RequestCharacters": "3"
}

確認

確認

ls | grep 'LEXICON_THX'
LEXICON_THX.mp3

今度は出力されたファイルは Thank you と発音します。

登録したレキシコンの削除

  • レキシコンの削除してみます

レキシコンの確認

コマンド

aws polly get-lexicon \
    --name ${LEXICON_NAME}

結果

{
    "Lexicon": {
        "Content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<lexicon version=\"1.0\" \n      xmlns=\"http://www.w3.org/2005/01/pronunciation-lexicon\"\n      xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n      xsi:schemaLocation=\"http://www.w3.org/2005/01/pronunciation-lexicon \n        http://www.w3.org/TR/2007/CR-pronunciation-lexicon-20071212/pls.xsd\"\n      alphabet=\"ipa\" \n      xml:lang=\"en-US\">\n  <lexeme>\n    <grapheme>thx</grapheme>\n    <alias>Thank you</alias>\n  </lexeme>\n</lexicon>\n",
        "Name": "THANKYOU"
    },
    "LexiconAttributes": {
        "LanguageCode": "en-US",
        "LastModified": 1480957317.243,
        "Alphabet": "ipa",
        "LexemesCount": 1,
        "LexiconArn": "arn:aws:polly:us-west-2:XXXXXXXXXXXXX:lexicon/THANKYOU",
        "Size": 476
    }
}

削除

コマンド

aws polly delete-lexicon \
    --name ${LEXICON_NAME}

返り値はありません

削除できたか確認

コマンド

aws polly get-lexicon \
    --name ${LEXICON_NAME}

結果

An error occurred (LexiconNotFoundException) when calling the GetLexicon operation: Lexicon not found

無事に削除されました。

まとめ

Pollyの雰囲気がつかめたのではないでしょうか。
入力したテキストを音声ファイルで返してくれるサービスなので使い所は多そうです
ああ。。。眠すぎる。
誤字チェックとか再検証日本でやろう。。。後は頼んだ。日本の俺。。。

おこたに入りながらやったよ!ロサンゼルスの僕!

おまけ

おこたで頑張ったで!
nodejsでいじってみましょうか

describeVoices

'use strict';
const aws = require('aws-sdk');
aws.config.loadFromPath('<クレデンシャルへのパス>');
let polly = new aws.Polly({apiVersion: '2016-06-10',region:'us-west-2'});
// describeVoices
let descParams = {
    LanguageCode: 'ja-JP'
};
polly.describeVoices(descParams, (err, data)=>{
   if(err){
       console.log(err);
   } else {
       console.log(JSON.stringify(data))
   }
});
{"Voices":[{"Gender":"Female","Id":"Mizuki","LanguageCode":"ja-JP","LanguageName":"Japanese","Name":"Mizuki"}],"NextToken":null}

synthesizeSpeechをつかってmp3ファイルを取得

'use strict';
const aws = require('aws-sdk');
const fs = require('fs');
aws.config.loadFromPath('<クレデンシャルへのパス>');
let polly = new aws.Polly({apiVersion: '2016-06-10',region:'us-west-2'});
let msg = 'せっしゃおやかたともうすは、おたちあいのうちに、ごぞんじのおかたもござりましょうが、おえどをたってにじゅうりかみがた、そうしゅうおだわらいっしきまちをおすぎなされて、あおものちょうをのぼりへおいでなさるれば、らんかんばしとらやとうえもん、ただいまはていはついたして、えんさいとなのりまする。';
// describeVoices
let descParams = {
    LanguageCode: 'ja-JP'
};
polly.describeVoices(descParams, (err, data)=> {
    if (err) {
        console.log(err);
    } else {
        //console.log(JSON.stringify(data));
        let voiceId = data.Voices[0].Id;
        // synthesizeSpeech
        let textMsg = msg;
        let speechParams = {
            OutputFormat: 'mp3',
            VoiceId: voiceId,
            Text: textMsg,
            SampleRate: '22050',
            TextType: 'text'
        };
        polly.synthesizeSpeech(speechParams, (err, data) => {
            if (err) {
                console.log(err);
            } else {
                console.log(data);
                fs.writeFile('polly.mp3', data.AudioStream, (err) => {
                    if (err) {
                        console.log(err);
                    } else {
                        console.log('Success');
                    }
                });
            }
        });
    }
});

噛まずに言える。そう、pollyならね

一覧に戻る