Edited at

3だけアホになるスマートスピーカー計算機。

「クソアプリ Advent Calendar 2018」18日目の担当、covayashi (@0rga)です。

VUI、皆さんやってますか?最近キテますねー!

というわけで僕もVUIでクソアプリ作りたいと思ったので、Google Assitant のアクションでクソアプリ作りました!


作ったもの

「123123123123 × 33は?」





※ 音がでますのでご注意下さい(でもVUIですので音しかありません)


技術解説

肝となる部分の解説のみにします。

Googleアシスタントのアクションの作り方は調べればたくさんありますので。


とりあえずGoogleアシスタントに喋ってもらう

上記のtwitterに挙げた例ですと「123123123123 × 33は?」の答えは

4063063063059

になります。

これをそのままGoogleアシスタントに読み上げてもらうと、

4063063063059

 ↓
よんちょう ろっぴゃくさんじゅうおく ろくせんさんびゃくろくまん さんぜんごじゅうきゅう

になります。

ですが、3だけおかしく言わせるために

4063063063059

 ↓
406さああぁあん06さああぁあん06さああぁあん059

とした場合、Googleアシスタントは

406さああぁあん06さああぁあん06さああぁあん059

 ↓
よんひゃくろく さああぁあん ぜろろく さああぁあん ぜろろく さああぁあん ぜろごーきゅう

と読み上げます。

これじゃまったく理解できません。


SSMLで頑張って喋らせる

なのでSSMLを使って人間が理解できるように喋ってもらいましょう。

SSMLとは音声合成マークアップ言語の事で、人間が聞きやすいような音声を作り上げる事ができるものです。

4063063063059という文字列をforEachと正規表現を駆使して、

4063063063059

 ↓
<speak>
答えは、4兆<break time='9ms'/>
<say-as interpret-as='cardinal'>600</say-as>
さああぁあんじゅう億<break time='9ms'/>
<say-as interpret-as='cardinal'>6000</say-as>
さああぁあんびゃく6万<break time='9ms'/>
さああぁあんぜん
<say-as interpret-as='cardinal'>59</say-as><break time='9ms'/>
です。
</speak>

という感じにしてあげます。


タグの簡単な解説


speak

<speak> はhtmlでいう <html> タグのようなものです。ここからここまでSSMLだよと指定してあげます。


break time

<break time='xxx'/> は息継ぎのようなもので、次の文字を読み上げるまで指定の秒数待機させれます。


say-as

<say-as interpret-as='cardinal'>600</say-as> こちらは文字列の形の指定といいますか、600 は基数ですよと指定してあげれます。

そうなると 600ろくぜろぜろ ではなく ろっぴゃく と発音してくれるようになります。

型の指定は他にもたくさんあります。

これを喋ってもらうと、

4063063063059

 ↓
<speak>
答えは、4兆<break time='9ms'/>
<say-as interpret-as='cardinal'>600</say-as>
さああぁあんじゅう億<break time='9ms'/>
<say-as interpret-as='cardinal'>6000</say-as>
さああぁあんびゃく6万<break time='9ms'/>
さああぁあんぜん
<say-as interpret-as='cardinal'>59</say-as><break time='9ms'/>
です。
</speak>
 ↓
よんちょう ろっぴゃく さああぁあんじゅうおく ろくせん さああぁあんびゃくろくまん さああぁあんぜん ごじゅうきゅう 

と人間が桁数を理解できるようになりました。


コード(一部)

肝の部分のコードも晒しておきますので、正規表現マスターとSSMLマスターが見ておられましたらレビューおなしゃすしゃす m(_ _)m

const num = String(4063063063059).replace(/(\d)(?=(\d{4})+(?!\d))/g, '$1,')

const numArry = num.split(',')
const digit1 = ['', '', '', '']
const digit2 = ['ぜん', 'びゃく', 'じゅう', '']
const digit3 = ['000', '00', '0', '']
let text = '答えは、'
const d1 = digit1.slice(-numArry.length)
if(numArry.length < 5){
numArry.forEach((v, i) => {
v = v.replace(/^[0]{1,}/g, '')
const d2 = digit2.slice(-v.length)
const d3 = digit3.slice(-v.length)
let flg = false
let _text = ''
v.split('').forEach((_v, _i) => {
if(_v == '3'){
if(_i != '0' && !flg){
_text = `${_text}` + `${d3[_i-1]}`
}
_text = `${_text}` + `さああぁあん` + `${d2[_i]}`
flg = true
}else {
_text = `${_text}` + `${_v}`
flg = false
}
if(d2[_i] == ''){
_text = `${_text}` + `${d1[i]}` + `<break time='9ms'/>`
}
})
_text = _text.replace(/([あ-ん])([0]{1,})/g, '$1')
text = text + _text
})
text = text.replace(/([0]{1,})([1-9])/g, '$2')
text = text.replace(/[0-9]{2,}/g, `<say-as interpret-as='cardinal'>$&</say-as>`)
console.log(text)
}else {
console.log(`すみません、ちょっと計算結果の桁数が多すぎます。9999兆以下でお願いします。`)
}


おわりに

3だけおかしな計算機 は実際に遊べますので、よかったら遊んでみてください。

「OK Goole 3だけおかしな計算機」

で遊べます!