Alexaで自然な発話を目指そう!音声合成マークアップ言語「SSML」を使う方法
こんにちは、エンジニア兼ライターのちゃんとくです。
Alexaスキルの開発では、基本的にテキストを渡すとそのまま読み上げてくれ、句読点を入れると休止に置き換えてくれたり疑問符を入れると語尾をあげたりと、ある程度は自然に調整してくれます。
でも、「なんだか読み上げが不自然……」「もっと細かく調整したい……」ということがありますよね。
そんな時は、Alexa Skills Kitで用意されている音声合成マークアップ言語「SSML」を使ってみましょう!SSMLを利用すると簡単に効果音・音源を差し込んだり、イントネーションやブレスを細かく整えたりすることができます。
※SSML…Speech Synthesis Markup Language
はじめてAlexaスキル開発するよ!という方はこちらから。
SSMLとは
「SSML」はAlexa Skills Kitで用意されている音声合成マークアップ言語です。
聞きなれないかもしれませんが、HTMLのタグのように簡単な記述でプログラムに埋め込むことができます。
例えば下記のようにテキストを渡すプログラムの場合、
'LaunchRequest': function () {
const speechOutput = 'こんにちは。ちゃんとくのスキルです。'
const reprompt = 'ちゃんとくスキルです。'
this.emit(':ask', speechOutput, reprompt);
},
SSMLを組み込むと下記のような記述になります。
'LaunchRequest': function () {
const speechOutput = '<say-as interpret-as="interjection">こんにちは。</say-as><break time="0.5s"/>ちゃんとくのスキルです。'
const reprompt = 'ちゃんとくスキルです。'
this.emit(':ask', speechOutput, reprompt);
},
基本的には①ドキュメントからコピーして、②埋め込むだけ、です。簡単そうですよね?
ここからは大まかにカテゴリ分けしてSSMLタグを紹介していきます!
「サッとどんな感じか知りたいんじゃ!」という方は、SSML全部乗せを試してみるのデモ動画をご覧ください。
特殊な読ませ方をさせるタグ
amazon:effect / エフェクト(ささやき声)
Amazonで提供されている固有のエフェクトが適用されます。今のところ用意されているのは「whispered
」というささやき声のエフェクトだけみたいです。
let speechOut = 'ささやき声にしたい部分をタグで囲います。';
speechOut += '<amazon:effect name="whispered">この部分をささやきます。</amazon:effect>';
this.emit(':tell', speechOut);
怒鳴り声とか、悲しい声とか、今後いろいろと実装されたら面白そうですね!
say-as / 特殊な文章を解釈
読んで字のごとく、「〜として読ませる」タグで、テキストの形をAlexaに解釈させることができます。例えば「電話番号として読ませる」「一文字ずつとして読ませる」などの機能があります。
let speechOut = '例えば93を一文字ずつ読むと<break time="1s"/>';
speechOut += '<say-as interpret-as="digits">93</say-as><break time="1s"/>'; // きゅー、さん
speechOut += '日付として読むと<break time="1s"/>';
speechOut += '<say-as interpret-as="date" format="m">9</say-as><say-as interpret-as="date" format="d">3</say-as><break time="1s"/>'; // くがつ、みっか
this.emit(':tell', speechOut);
ちなみに、英字はローマ字読みされるので例えば「IoT」は「いおっと」となってしまいます。
「アイオーティ」と読ませたい場合は<say-as interpret-as="characters">IoT</say-as>
と一文字ずつ読ませるか、テキストで「アイオーティ」と渡してあげましょう。
また解釈の一つとして、「Speechcon」という感嘆詞の読み上げが用意されています。「こんにちは」「まあ」「あら」など、日常的な発話が自然に組み込めるオススメの機能 です!
こちらは別記事にまとめました。
sub / 置き換え
テキストに対して指定の読み方をさせることができます。「宇宙」と書いて「コスモ」と読むような、ルビ的なあれですね……!
基本的にスキルの利用シーンはVUIのみですが、プログラムの可読性を高めるのに使われるのかなあと思っています。
let speechOut = '好きなアニメは';
speechOut += 'とある科学の<sub alias="レールガン">超電磁砲</sub>です。';
this.emit(':tell', speechOut);
音源を挿入するタグ
audio / MP3の挿入
スキル内にMP3音源を埋め込んで再生することができます。
MP3音源は用意されているライブラリの他に自身が用意したものも利用できますが、長さやフォーマットが細かく指定 されています。
使い方の詳細は下記記事にまとめました。
ブレス、区切りを挿入するタグ
break / 休止の挿入
休止時間を秒(s)またはミリ秒(ms)で指定します。または、
let speechOut = '3秒間待ってやる。<break time="3s"></break>';
speechOut += '用意はいいな?';
this.emit(':tell', speechOut);
※最大10秒なので、残念ながら3分待つことはできません。
p / 段落の挿入
囲った部分を段落として解釈させます。「。」よりも長めの休止が入ります。これは<break strength="x-strong" />
を入れるのと同様の結果になります。
let speechOut = '<p>こんにちは。ちゃんとくです。今から大事な話をします。</p>';
speechOut += '<p>実は、すごく焼肉が好きなんですよ。</p>';
this.emit(':tell', speechOut);
S / 文章区切りの挿入
囲った部分を一文として解釈させます。これは末尾に「。」を入れたり、<break strength="strong" />
を入れたりするのと同様の結果になります。
let speechOut = '<s>こんにちは</s>';
speechOut += '今日はすごく暑いですね<break strength="strong" />';
speechOut += 'こんな日はビールが飲みたい!';
this.emit(':tell', speechOut);
速さ、高さ、音量、発音を詳細に設定するタグ
emphasis / 速さと音量で強調
level
という属性で、音量、速度などを調整して強調させることができます。
const speechOut = '今日は<emphasis level="strong">すごく</emphasis>暑いですね。';
this.emit(':tell', speechOut);
prosody / 音量、高さ、速さ
速さ、高さ、音量をそれぞれ指定して調整することができます。
let speechOut = '今日は<prosody pitch="x-low">すごく</prosody>暑いですね。';
speechOut += 'こんな日はビールが<prosody volume="loud" pitch="high">飲みたい!</prosody>';
this.emit(':tell', speechOut);
SSML全部乗せを試してみる
読ませてみなきゃわからない、ってことで、SSMLをもりもり使ったサンプルを用意してみました。百聞は一聴にしかず!
プログラムは下記(とりあえず動く程度でちょっと雑です)。
'use strict';
const Alexa = require('alexa-sdk');
const handlers = {
'LaunchRequest': function () {
const speechOutput = 'こんにちは。音を流してと言ってみてください。'
const reprompt = '音を流します。'
this.emit(':ask', speechOutput, reprompt);
},
'WhisperIntent': function () {
let speechOut = 'こんな風に囁きます。';
speechOut += '<amazon:effect name="whispered">秘密ですよ?</amazon:effect>';
this.emit(':ask', speechOut);
},
'SayAsIntent': function () {
let speechOut = '例えば93を一文字ずつ読むと<break time="1s"/>';
speechOut += '<say-as interpret-as="digits">93</say-as><break time="1s"/>';
speechOut += '日付として読むと<break time="1s"/>';
speechOut += '<say-as interpret-as="date" format="m">9</say-as><say-as interpret-as="date" format="d">3</say-as><break time="1s"/>';
speechOut += 'ちなみにちゃんとくさんの誕生日みたいですよ。<say-as interpret-as="interjection">きゃ〜</say-as>';
this.emit(':ask', speechOut);
},
'SubIntent': function () {
let speechOut = '例えば炭素を表すCと書いて、';
speechOut += '<sub alias="カーボン">C</sub>と読ませることができます。';
this.emit(':ask', speechOut);
},
'SoundIntent': function () {
let speechOut = '音も簡単に流せますよ。';
speechOut += '<audio src="https://s3.amazonaws.com/ask-soundlibrary/animals/amzn_sfx_dog_med_bark_2x_02.mp3"/>';
this.emit(':ask', speechOut);
},
'EmphasisIntent': function () {
let speechOut = '私本当に、';
speechOut += '<emphasis level="strong">本当に</emphasis>';
speechOut += '焼肉が好きなんです。';
this.emit(':ask', speechOut);
},
'ProsodyIntent': function () {
let speechOut = '大事なことは<prosody rate="x-slow">ゆっくり</prosody>、';
speechOut += '嬉しいことは<prosody pitch="x-high">高い声で</prosody>';
speechOut += 'しゃべっちゃいます。';
this.emit(':ask', speechOut);
},
'AMAZON.HelpIntent': function () {
this.emit(':tell', this.t(''));
},
'AMAZON.CancelIntent': function () {
this.emit(':tell', this.t(''));
},
'AMAZON.StopIntent': function () {
this.emit(':tell', this.t(''));
},
};
exports.handler = function(event, context, callback) {
const alexa = Alexa.handler(event, context, callback);
alexa.registerHandlers(handlers);
alexa.execute();
}
まとめ
ドキュメントを見て試してみたところ、発音や品詞の解釈など一部日本語スキルには対応していないものもあるようです。
また一部重複する機能もあるので、可読性や統一性を考えながら実装していくのがよさそうです。
使いどころを抑えて、Alexaの自然な発話を目指していきましょう!