続・Google TTSを利用してAsteriskのIVRで日本語読み上げ

phone 2
© Bart Anestin.

前の記事は、「IVRで日本語読み上げ」というタイトルにも関わらず応答しか書かなかったので今度こそIVR。(さわりだけ)

/usr/local/etc/asterisk/extensions.conf (このPathはFreeBSDの場合)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
[globals]
SPEAKINGCLOCK=117
MORNINGCALL=840
MYNUMBER=031234xxxx

[default]
;時刻読み上げAGI (内線117)
exten => ${SPEAKINGCLOCK},1,Answer()
exten => ${SPEAKINGCLOCK},n,Wait(1)
exten => ${SPEAKINGCLOCK},n,AGI(speaktime.agi)
exten => ${SPEAKINGCLOCK},n,Hangup()

;モーニングコールAGI (内線840)
exten => ${MORNINGCALL},1,Answer()
exten => ${MORNINGCALL},n,Wait(1)
exten => ${MORNINGCALL},n,AGI(wakeup.agi)
exten => ${MORNINGCALL},n,Hangup()

;IVR試験用 (内線999)
exten => 999,1,Goto(ivr-menu,s,1)

; 外線発信 内線5000~6000に0から始まる番号を許可 それ以外はbang
exten => _0.,1,GotoIf($[ ${CALLERID(number)} < 5000 ]?bang)
exten => _0.,n,GotoIf($[ ${CALLERID(number)} > 6000 ]?bang)
exten => _0.,n,Dial(SIP/${EXTEN}@sip-trunk,120,T)
exten => _0.,n,Hangup()
exten => _0.,n(bang),Answer()
exten => _0.,n,Wait(1)
exten => _0.,n,agi(googletts.agi,"この内線番号からは外線発信できません。",ja)
exten => _0.,n,Hangup()

;内線5100 -> SIP電話機ID:5100を呼び出し -> 後処理
exten => 5100,1,Dial(SIP/5100,60)
exten => 5100,n,NoOp( Dial Status: ${DIALSTATUS})
exten => 5100,n,Goto(DO-${DIALSTATUS},1)

;内線5200 -> SIP電話機ID:5200を呼び出し -> 後処理
exten => 5200,1,Dial(SIP/5200,60)
exten => 5200,n,NoOp( Dial Status: ${DIALSTATUS})
exten => 5300,n,Goto(DO-${DIALSTATUS},1)

;内線5300 -> SIP電話機ID:5300を呼び出し -> 後処理
exten => 5300,1,Dial(SIP/5300,60)
exten => 5300,n,NoOp( Dial Status: ${DIALSTATUS})
exten => 5300,n,Goto(DO-${DIALSTATUS},1)

;後処理
exten => DO-NOANSWER,1,Hangup()
exten => DO-CONGESTION,1,Congestion(10)
exten => DO-CONGESTION,2,Hangup()
exten => DO-CANCEL,1,Congestion(10)
exten => DO-CANCEL,2,Hangup()
exten => DO-BUSY,1,Busy(10)
exten => DO-BUSY,2,Hangup()
exten => DO-CHANUNAVAIL,1,agi(googletts.agi,"おかけになった電話は電源が入っていないか、電波が届かない場所にあるため呼び出すことができません。",ja)
exten => DO-CHANUNAVAIL,2,Congestion(10)
exten => DO-CHANUNAVAIL,3,Hangup()
exten => DO-,1,Congestion

; 未使用1桁入力と内線該当無し
exten => _X,1,Answer()
exten => _X,n,Wait(2)
exten => _X,n,agi(googletts.agi,"無効な番号です。番号をお確かめの上もう一度入力して下さい。",ja)
exten => _X,n,Congestion(10)
exten => _X,n,Hangup()
exten => _X.,1,Answer()
exten => _X.,n,Wait(2)
exten => _X.,n,agi(googletts.agi,"無効な内線番号です。かけさきの内線番号をお確かめの上もう一度入力して下さい。",ja)
exten => _X.,n,Congestion(10)
exten => _X.,n,Hangup()

[inbound]
;外線着信(03-1234-xxxx) -> IVR 非通知はanonymousに飛ばす
exten => ${MYNUMBER},1,GotoIf($["${CALLERID(name)}"="unknown"]?anonymous,s,1)
exten => ${MYNUMBER},n,GotoIf($["${CALLERID(name)}"="Unknown"]?anonymous,s,1)
exten => ${MYNUMBER},n,GotoIf($["${CALLERID(name)}"="UNKNOWN"]?anonymous,s,1)
exten => ${MYNUMBER},n,Goto(ivr-menu,s,1)

;外線着信(06-1111-yyyy) -> 内線5100に渡す 非通知はanonymousに飛ばす
exten => 061111yyyy,1,GotoIf($["${CALLERID(name)}"="unknown"]?anonymous,s,1)
exten => 061111yyyy,n,GotoIf($["${CALLERID(name)}"="Unknown"]?anonymous,s,1)
exten => 061111yyyy,n,GotoIf($["${CALLERID(name)}"="UNKNOWN"]?anonymous,s,1)
exten => 061111yyyy,n,Goto(default,5100,1) ; [Default]にある内線5100に移る
exten => 061111yyyy,n,Hangup()

[anonymous]
;番号非通知で着信した場合は応答 -> メッセージ -> 切断
exten => s,1,Answer()
exten => s,n,Wait(1)
exten => s,n,agi(googletts.agi,"発信者番号が非通知のため、この電話をお繋ぎすることができません。発信者番号通知の設定を変更するか、電話番号の前に、イチ、ハチ、ロク、をつけておかけ直し下さい。",ja)
exten => s,n,Wait(1)
exten => s,n,Congestion(10)
exten => s,n,Hangup()

[ivr-menu]
exten => s,1,Answer()
exten => s,n,Wait(1)
exten => s,n,agi(googletts.agi,"お電話ありがとうございます",ja)
exten => s,n(try-again),Wait(1)
;exten => s,n,agi(googletts.agi,"仕事関係の連絡は1を、サンプル音声の読み上げは2を、あなたの電話番号を確認するには3を、用事がなければ電話をお切り下さい。",ja)
exten => s,n,Background(ivrmenu-msg) ;上の音声をファイルにしたもの
exten => s,n,WaitExten(10)      ;選択待ち
exten => s,n,Goto(s,try-again)  ;最初に戻る
exten => 1,1,Playback(digits/1) ;押した番号「1」を言う(音声ファイル)
exten => 1,n,Goto(menu-1,s,1)   ;menu-1へ
exten => 2,1,Playback(digits/2) ;押した番号「2」を言う(音声ファイル)
exten => 2,n,Goto(menu-2,s,1)   ;menu-2へ
exten => 3,1,agi(googletts.agi,"あなたの電話番号わ",ja)
exten => 3,n,Wait(1)
exten => 3,n,SayDigits(${CALLERID(number)})
exten => 3,n,Wait(1)
exten => 3,n,agi(googletts.agi,"あなたのコールめいわ",ja)
exten => 3,n,Wait(1)
exten => 3,n,SayAlpha(${CALLERID(name)})
exten => 3,n,Wait(1)
exten => 3,n,Goto(s,try-again)
exten => i,1,agi(googletts.agi,"無効な番号です。番号をお確かめの上もう一度入力して下さい。",ja)
exten => i,n,Goto(s,try-again)  ;挨拶の後に戻る

[menu-1]
exten => s,1,agi(googletts.agi,"呼び出します",ja)
;exten => s,n,Set(FROMNUM=${CALLERID(number)})
;exten => s,n,Set(CALLERID(name)=${FROMNUM})
;exten => s,n,Set(CALLERID(number)=${FROMNUM})
exten => s,n,Dial(SIP/5100&SIP/5200&SIP/5300,60,m)
exten => s,n,GotoIf($["${DIALSTATUS}"="BUSY"]?busy)
exten => s,n,GotoIf($["${DIALSTATUS}"="CONGESTION"]?busy) ;後処理 通話中へ
exten => s,n,agi(googletts.agi,"只今電話の側にいないか電話に出られない状態です。のちほどお掛け直し下さい",ja)
exten => s,n,Congestion(10)  ;プープープー音
exten => s,n,Hangup()
exten => s,n(busy),agi(googletts.agi,"只今電話中のためお繋ぎできません。のちほどお掛け直し下さい",ja)   ;後処理 通話中
exten => s,n,Congestion(10)
exten => s,n,Hangup()

[menu-2]
exten => s,1,Wait(2)
exten => s,n,agi(googletts.agi,"吉野家ってのはな、もっと殺伐としてるべきなんだよ。",ja)
exten => s,n,agi(googletts.agi,"Uの字テーブルの向かいに座った奴といつ喧嘩が始まってもおかしくない、刺すか刺されるか、そんな雰囲気がいいんじゃねーか。女子供は、すっこんでろ。",ja)
exten => s,n,agi(googletts.agi,"で、やっと座れたかと思ったら、隣の奴が、大盛つゆだくで、とか言ってるんです。 そこでまたぶち切れですよ。",ja)
exten => s,n,agi(googletts.agi,"あのな、つゆだくなんてきょうび流行んねーんだよ。ボケが。得意げな顔して何が、つゆだくで、だ。",ja)
exten => s,n,agi(googletts.agi,"お前は本当につゆだくを食いたいのかと問いたい。問い詰めたい。小1時間問い詰めたい。",ja)
exten => s,n,agi(googletts.agi,"お前、つゆだくって言いたいだけちゃうんかと。 吉野家通の俺から言わせてもらえば今、吉野家通の間での最新流行はやっぱり、ねぎだく、これだね。大盛りねぎだくギョク。これが通の頼み方。",ja)
exten => s,n,agi(googletts.agi,"ねぎだくってのはねぎが多めに入ってる。そん代わり肉が少なめ。これ。で、それに大盛りギョク。これ最強。",ja)
exten => s,n,agi(googletts.agi,"しかしこれを頼むと次から店員にマークされるという危険も伴う、諸刃の剣。 素人にはお薦め出来ない。",ja)
exten => s,n,agi(googletts.agi,"まあお前らド素人は、牛鮭定食でも食ってなさいってこった。",ja)
exten => s,n,Wait(2)
exten => s,n,agi(googletts.agi,"呼び出します",ja)
exten => s,n,Congestion(10)
exten => s,n,Hangup()

sip.confの契約している外線用のSIPトランクのコンテクストはinboundとする。

context=inbound

あくまでもサンプルのextension.confなので細かいところは抜かしている。でも、内線含め発着信も以前の記事の設定のように一通り入っている。上の方のspeaktime.agiやwakeup.agiは省略。スクリプトでいろいろやりたければAGIのお世話になるという例のつもり。

番号非通知の着信はCALLERID(name)が「Unknown」になっていることが多いのかな?「がとらぼ」の中の人の使ってる幾つかのIP電話では全てそうなのでCALLERID(name)で非通知を検知している。

IVRの[3](電話番号読み上げ)は僅か数行の処理なので分けないでメニュー内で済ませている。

なお、IVRでボタン入力を促すメッセージについてはメッセージを喋っている途中でも入力を許可する方が電話をかけている人にとって使い勝手が良いので、入力催促のメッセージだけは音声ファイルにした上で、Background(message-file)で喋らせる方が良い。TTSに喋らせたりPlayback(message-file)を使うと喋っている間は電話のボタンを押しても無視されるので誠に都合が悪い。

つまり、agi(googletts.agi,"メッセージ",lang)はPlayback(message-file)の代替としてはとても優秀だが、Background(message-file)の代替にはするべきではない。

そこで、上の例の100行目の行頭のコメント ; を外し、101行目の行頭に ; を付けてコメントにする。asteriskを再起動するかダイヤルプランを再読込する。IVRに喋らせると/tmpに******.slnが作成されるのでivrmenu-msg.slnというファイル名に変更する。それを/usr/local/share/asterisk/sounds/ja/に置く。
再度extensions.confをエディタで開き、100行目をコメント行にして101行目を有効行にする。
再度Asteriskを再起動するかダイヤルプランを再読込する。

上の例みたいに定形メッセージだけの読み上げにGoogle TTSを使うのはあまり意味がないが、動的にメッセージを生成して喋らせると面白いと思う。

関連記事: