kun432's blog

Alexaなどスマートスピーカーの話題中心に、Voiceflowの日本語情報を発信してます。たまにAWSやkubernetesなど。

〜スマートスピーカーやVoiceflowの記事は右メニューのカテゴリからどうぞ。〜

Alexaの発話がより感情豊か・自然になるSSMLタグ「amazon:domain」「amazon:emotional」が日本語に対応

f:id:kun432:20201125233345p:plain

久々にAlexa公式ブログに更新があったので早速やってみました。

これまで一部のロケールでしか使えなかったSSMLタグ「amazon:domain」「amazon:emotional」が日本語でも対応したようです。これにより、アレクサをより感情的に発話させたり、より自然に発話させることが可能になります。それぞれ実際にやってみましょう。

公式の日本語ドキュメントはまだ更新されていません。英語ドキュメントの方は更新されていますので、詳しくはそちらをご覧ください。

Speech Synthesis Markup Language (SSML) Reference | Alexa Skills Kit

amazon:domain

公式の日本語ドキュメントから説明だけ抜粋します。

amazon:domain

音声に異なるスタイルを適用します。スタイルでは、読み上げ音声でイントネーション、抑揚、一時停止などのさまざまなバリエーションを使用して、音声をコンテンツの種類に合わせます。例えば、newsスタイルでは、Alexaの音声がテレビやラジオのニュースのような話し方になり、主にニュース記事やその他のニュースベースのコンテンツを聞くユーザー向けに提供されています。

音声合成マークアップ言語(SSML)のリファレンス | Alexa Skills Kit

<amazon:domain name="スタイル">こんにちは。</amazon:domain>

という感じで使います。name=で以下の4種類のスタイルから選択します。ただし、現時点で日本語で対応しているのは現時点で"conversational"のみです。

  • conversational 日本語対応!
    • 友人や家族に話すような、よりカジュアルな会話的に発話します。
  • news ※日本語非対応
    • テレビやラジオのニュースキャスターのようなスタイルで発話します。
  • music ※日本語非対応
    • 音楽ラジオのDJようなスタイルで発話します。
  • long-form ※日本語非対応
    • ポッドキャストや本のような、長いコンテンツの読み上げに適したスタイルで発話します。

では違いを見てみましょう。Alexa開発者コンソールでテストシミュレータを開き、「音声と語調」をクリックします。

f:id:kun432:20201125235528p:plain

下の入力欄に以下に用意したテキストをコピペして全部上書きします。

f:id:kun432:20201126000946p:plain

<speak>
  最初は普通に話します。<break time="2s" />
  こんにちは、私の名前はアレクサです。今日はいい天気ですね。たくさん話しかけてくださいね。<break time="2s" />  
  次はカジュアルに話します。  <break time="2s" />  
  <amazon:domain name="conversational">
    こんにちは、私の名前はアレクサです。今日はいい天気ですね。たくさん話しかけてくださいね。
  </amazon:domain>
  <break time="2s" />
  違いがわかりましたか?  
</speak>

テキストをコピペしたら、言語を「日本語(日本)」にして、「再生」をクリックします。

f:id:kun432:20201126000624p:plain

実際の発話はこんな感じになります。

2回めのほうがとても自然な感じでいいですね!

amazon:emotional

公式の日本語ドキュメントから説明だけ抜粋します。

amazon:emotion

amazon:emotionタグは、Alexaが話すときに感情を表します。これは、ストーリー、ゲーム、ニュース、その他の物語体のコンテンツに役立ちます。たとえば、ゲームでは、正解時に「興奮」の感情を使用し、誤答時には「失望」の感情を使用できます。

音声合成マークアップ言語(SSML)のリファレンス | Alexa Skills Kit

<amazon:emotion name="感情" intensity="感情の強さ">こんにちは。</amazon:emotion>

name=で感情を指定し、intensity=でその強さを表します。nameで指定できるのは以下の2つで、こちらは両方とも日本語対応しています!

  • excited
    • 興奮している感じで話します。
  • disappointed
    • 失望している感じで話します。

intensityは"high"/"medium"/"low"で指定し、"high"のほうがより強く表現されます。

では、以下のサンプルで試してみてください。より違いがわかりやすいようにintensityは"high"にしています。

<speak>
  最初は普通に話します。<break time="2s" />
  本日、福岡ペイペイドームで行われた、プロ野球、日本シリーズ第四戦は、4対1で福岡ソフトバンクホークスが東京読売ジャイアンツに勝利し、4年連続11度目の日本シリーズ制覇となりました。
  <break time="2s" />
  次はかなり興奮して話します。<break time="2s" />
  <amazon:emotion name="excited" intensity="high">
    本日、福岡ペイペイドームで行われた、プロ野球、日本シリーズ第四戦は、4対1で福岡ソフトバンクホークスが東京読売ジャイアンツに勝利し、4年連続11度目の日本シリーズ制覇となりました。
  </amazon:emotion>
  <break time="2s" />
  最後はかなりがっかりして話します。<break time="2s" />
  <amazon:emotion name="disappointed" intensity="high">
    本日、福岡ペイペイドームで行われた、プロ野球、日本シリーズ第四戦は、4対1で福岡ソフトバンクホークスが東京読売ジャイアンツに勝利し、4年連続11度目の日本シリーズ制覇となりました。
  </amazon:emotion>
</speak>

※サンプルに他意はないですのであしからず。我がカープなんてもう・・・

実際の発話はこんな感じです。

かなり変わりますね!ちょっと違いすぎて別人の声ぐらいに聞こえるぐらいなので、intensityはうまく調整したほうがいいかもしれませんね。

公式ブログの方にもサンプルがあるのでそちらも聞いてみてください。

まとめ

いかがでしょうか?SSMLだけで非常にかんたんに自然かつ感情豊かな表現ができるのでとても便利ですね!amazon:domainはコンテンツ全体の内容に合わせて、amazon:emotionalはコンテンツの結果(例えばクイズの場合の正解と不正解)に応じて、というような使い分けができるのではないかと思います。

もちろんVoiceflowでも使えますよ。VoiceflowのSSMLエディタでは対応していないので、Speak Block内に直接入力すればOKです!

f:id:kun432:20201126212141p:plain

ぜひぜひご活用ください!

2020年10月振り返り

f:id:kun432:20201108232540j:plain

10月の振り返りです。バタバタ続きに体調不良も重なってかなりダウンしてます・・・

資格を取る

進捗なし

毎月スキルを作る

ここも進捗なし・・・いかん・・・

公開済15個
申請中0個
開発中7個

アウトプット

勉強会は以下に参加させてもらいました。ありがとうございました。

今月はほぼ音声関連だけ

  • Voice Summitは楽しかったけど、ちょっと時間帯が・・・ということで後半は果ました
  • Alexa Tech Talkは新しいEcho Show10のモーションセンサーの話。ちょっと短かかったので雰囲気だけ。実際に動かしてみないとわからないかなぁ。
  • JAWS KOBE&OSAKAは、Alexa AudioPlayerの話とCloudformationの話だけ。AudioPlayerは楽しいですよ。
  • GDGは音声関連だけ。Googleちょっとやっていかないとなー、ということで。Actions Builder、まだちょっと理解できてないです。
  • VoiceLunchはあとで。

ブログは6本、少なっ!

今月はちょっと音声周りも含めてネタ切れな感じ。途中で止まっている「Voiceflowにおける会話のコンテキストを考える」シリーズもちょっとまとまってなくて書けてないないけど、そろそろ続きを書きたい。あとインフラネタがこれからは増えると思います。

コミュニティ

今月のVoiceLunchJP #3はVFJUGがホストということで、VoiceflowでAudioPlayerスキルを作るハンズオンをやってきました。

1時間ぐらいで終わるもの、ということで、AudioPlayerスキルにしたんだけど、実質30分かからずに終わってしまい、ちょっと失敗。資料もzenn.devで用意してたんだけど、あれなら応用編も1つぐらいは行けたかも。応用編は自学用ということであまり手を動かす感じにはなってないので、少し見直したいと思います。あとは公開申請もどこかでまとめたい。

今回資料はzenn.dev使ったのですがやっぱりいいですね。とても見やすくてハンズオン資料作るのにぴったりです。ただ、GitHub連携してなかったのがやや後悔。VFJUGのアカウント作ってそっちに移転してきっちりGitHubで管理するようにしようかなとか思ったり。

ちなみに資料はこちらです。


あと2ヶ月。11月はほどほどにがんばりたいけど、そうは行かない感じ・・・

GitLabでLet's Encryptを使う

f:id:kun432:20201108151742p:plain

GitLabでLet's Encryptを使ってSSLを設定しょうとしたら盛大にハマったのでメモ。

目次

環境

  • OS: Amazon Linux 2
  • gitLab-ee: 13.5.3

一般的にはgitlab-ceを使うほうが多いんでしょうが、GitLabの公式の以下の説明より、gitlab-eeを使っても問題ないと判断しました。

GitLab EEの有料の機能を使用可能にするためには、ライセンスを購入する必要があります。 もしもライセンスが未登録のGitLab EEを使用している場合は、MITライセンスの無料の機能だけを使用していることになります。

つまり、GitLab EEをインストールしてライセンスを未登録のまま使用することと、GitLab CEをインストールして使用することに表面的な違いはありません。

www.gitlab.jp

ハマったところ

流れだけ。

  • そもそもHTTPでいいのではないか?というところなのだけど、container registryをHTTPで使う場合、docker側でinsecure_registryとして設定する必要があってめんどくさい。まあ時代はHTTPSということで。
  • GitLab自体がLet's Encrypt対応しているので設定変えるだけでいけるはず・・・が、なぜかうまく行かない。

ということで、手動でLet's Encryptの設定を行います。

GitLabにLet's Encryptを導入する記事を見ていると、だいたいnginxに以下のようなcustom設定を追加するものが多い。

nginx['custom_gitlab_server_config'] = "location ^~ /.well-known { root /var/letsencrypt; }"

もしくは、カスタムなnginxの設定ファイルをincludeする。

nginx['custom_nginx_config']         = "include /etc/gitlab/custom_nginx_config.conf;"

includeする設定はこういうの。

server {
    listen 80;
    server_name _;
    access_log  /var/log/gitlab/nginx/access.log;
    error_log   /var/log/gitlab/nginx/error.log;
    location / {
        return 404;
    }
    location /.well-known {
        alias /var/letsencrypt/.well-known;
    }
}

やり方は違うけど、/var/letsencryptをHTTPで公開して、certbotのHTTPアクセスチェックを回避するっていうやり方ですね。

設定を追加してgitlab-ctl reconfigureして、certbotで証明書を取得します。(ドメインはサンプル)

# certbot certonly --webroot --webroot-path=/var/letsencrypt -d gitlab.example.com

で失敗する。

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for gitlab.example.com
Using the webroot path /var/letsencrypt for all unmatched domains.
Waiting for verification...
Challenge failed for domain gitlab.example.com
http-01 challenge for gitlab.example.com
Cleaning up challenges
Some challenges have failed.

IMPORTANT NOTES:
 - The following errors were reported by the server:

   Domain: gitlab.example.com
   Type:   unauthorized
   Detail: Invalid response from
   http://gitlab.example.com/.well-known/acme-challenge/XXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   [XXX.XXX.XXX.XXX]: "<html>\r\n<head><title>404 Not
   Found</title></head>\r\n<body>\r\n<center><h1>404 Not
   Found</h1></center>\r\n<hr><center>nginx</center>\r\n"

   To fix these errors, please make sure that your domain name was
   entered correctly and the DNS A/AAAA record(s) for that domain
   contain(s) the right IP address.

どうもHTTPチェック用のパスにアクセスができてないみたいです。

gitlab-nginxのエラーログを見てみます。

2020/11/08 05:42:02 [error] 9467#0: *24 open() "/var/opt/gitlab/nginx/www/.well-known/acme-challenge/...." failed (2: No such file or directory), ...

どうも違うパスを見ているみたいです。

gitlabが生成するnginxの設定ファイルを見てみましょう。まず、custom_gitlab_server_configを追加した場合は、/var/opt/gitlab/nginx/conf/gitlab-http.confに追加されます。

server {
  listen *:443 ssl http2;

(snip)
  location ^~ /.well-known { root /var/letsencrypt; }
}

む、HTTPSの設定に追加されていますね・・・・そして上にあるHTTPの設定を見ると別のLet's Encrypt用の設定が見えます。(ちなみにこれ以外のhttpアクセスはhttpsにリダイレクトされてます)

server {
  listen *:80;
(snip)
  location /.well-known {
    root /var/opt/gitlab/nginx/www/;
(snip)

ここ違うパスを見ていますね。この設定、GitLabのLet's encrypt対応による設定じゃないかな。おそらく、external_urlにhttpsを指定するとこの設定が自動的に入るのだと思います。external_urlの設定はインストール時に行っていました。

sudo EXTERNAL_URL="${GITLAB_URL}" yum install -y gitlab-e

ということで、結論から言うと、certbotの証明書取得はこうすればOKです。

# certbot certonly --webroot --webroot-path= /var/opt/gitlab/nginx/www -d gitlab.example.com

うまくいきました。これで証明書が/etc/letsencrypt以下に置かれます。

aving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None
Obtaining a new certificate
Performing the following challenges:
http-01 challenge forgitlab.example.com
Using the webroot path /var/opt/gitlab/nginx/www for all unmatched domains.
Waiting for verification...
Cleaning up challenges
Subscribe to the EFF mailing list (email: xxxxxx@example.com).

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/gitlab.example.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/gitlab.example.com/privkey.pem
   Your cert will expire on 2021-02-06. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

ちなみに、custom_nginx_configの方はというと、/var/opt/gitlab/nginx/conf/nginx.confに追加されます。

http {
(snip)
  include /var/opt/gitlab/nginx/conf/gitlab-http.conf;

  include /var/opt/gitlab/nginx/conf/gitlab-registry.conf;

  include /var/opt/gitlab/nginx/conf/nginx-status.conf;

  include /etc/gitlab/custom_nginx_config.conf;
}

さきほどのgitlab-http.confもincludeされているのがわかりますね。つまり、Let's Encrypt用のパス公開設定が2重になってしまうということですね。nginxあまり触ってないのでわからないですが、同じserver設定がある場合は、前勝ちになる、ということなのでしょうか。

うまく行ったのでregistry用にも証明書を発行して、

certbot certonly --webroot --webroot-path=/var/opt/gitlab/nginx/www -d registry.example.com

/etc/gitlab/gitlab.rbにregistry_external_urlを有効化。このときにGitLabのLet's Encrypt integrationを無効化(reconfigureで有効になってしまい再度証明書取得プロセスが走ってしまう)、各証明書はcertbotで生成したものを指すようにします。

letsencrypt['enable'] = false
nginx['ssl_certificate']              = "/etc/letsencrypt/live/gitlab.example.com/fullchain.pem"
nginx['ssl_certificate_key']          = "/etc/letsencrypt/live/egistry.example.com/privkey.pem"
registry_external_url "https://regstry.example.com"
registry_nginx['ssl_certificate']     = "/etc/letsencrypt/live/gitlab.example.com/fullchain.pem"
registry_nginx['ssl_certificate_key'] = "/etc/letsencrypt/live/registry.example.com/privkey.pem"
$ gitlab-ctl reconfigure

これでOKです。

まとめ

これ以外にもPackerで作ったGitLabのAMIである程度gitlabの設定も入れていたのでAMI作り直したり、失敗しすぎてLet's Encryptのレート制限に引っかかったりもしてたので、ハマりにハマりました・・・

GitLabのnginx設定ファイルの構成とかもちょっとわかったので良かったですが、GitLab側のLet's Encrypt Integration、やっぱりよくわかりません。certbotで一度生成成功すると、reconfigureでエラーも出なくなるので、卵・鶏の話のような気もします。更新時のこととかを考えるとちょっと怖くて使えないですね。まあそういうケースでは有償の証明書を使うべきだと思いますが。