電話で自動応答するプログラムを書く
こんにちは。KDDI ウェブコミュニケーションズ(KWC)の小原です。
IVR とは
IVR(Interactive Voice Response)とは、電話で入力された数字や音声を認識し、自動で応答するサービスです。
たとえば次のようなものです。
- 電話で『7 を押すか「おみくじ」といってください』と案内し、数字か音声の入力を待つ
- 「7」もしくは「おみくじ」を受け取ったら、「大吉」などをランダムに返す。「7」や「おみくじ」以外なら 1. に戻す
この IVR であれば、Vonage(ボネージ)を利用することで JSON と簡単なプログラムで実現できます。
Vonage とは
Vonage はエリクソン傘下の CPaaS で、電話、SMS、ビデオなどを REST API や JSON で利用できるサービスを提供しています。弊社(KWC)は再販と日本語サポートを提供しています。
この記事では Vonage を利用して「おみくじ IVR」を作ります。Vonage アカウントと電話番号の取得がまだの場合は下記手順が必要です。
※050/0120/0800 の取得には本人確認(KYC)が必要です。そのため取得に時間がかかります。アメリカの電話番号であれば KYC が不要なため、すぐに IVR を利用可能です。ただし通話料金が国際料金になるためご注意ください。
IVR の流れ
ユーザが Vonage で取得した 050 に電話をかけると、Vonage は案内と入力待ちをします。ユーザが入力したらおみくじの結果を返します。
そのためには電話番号とプログラムの紐づけが必要になります。
NCCO はテキストの読み上げや、数字・音声を取得する Vonage 特有の JSON です。NCCO はのちほど紹介します。
サーバの用意
プログラムの保存
おみくじ IVR の全ソースコードは下記です。app.rb
として保存してください。
# frozen_string_literal: true
require 'sinatra'
IVR_URL = 'https://your-sub-domain.ngrok-free.app/ivr'
# 1.電話を着信
get '/answer' do
content_type :json
[
# 案内
{
action: 'talk',
text: '7 を押すか「おみくじ」といってください',
language: 'ja-JP',
style: rand(6),
bargeIn: true
},
# 数字(dtmf)もしくは音声(speech)を入力待ちし、入力値を eventUrl に渡す
{
action: 'input',
type: %w[dtmf speech],
eventUrl: [IVR_URL],
dtmf: {
maxDigits: 1
},
speech: {
language: 'ja-JP',
context: %w[おみくじ くじ くじびき]
}
}
].to_json
end
# 2. 電話に入力された値を Vonage から受け取る
post '/ivr' do
params = JSON.parse(request.body.read)
# 7 か「くじ」なら、おみくじを返す
if params['dtmf']['digits'] == '7' ||
params['speech']['results']&.any? { |result| result['text'].include?('くじ') }
content_type :json
[
{
action: 'talk',
text: %w[大吉 吉 中吉 小吉 末吉 凶 大凶].sample,
language: 'ja-JP',
style: rand(6)
}
].to_json
# それ以外なら 1. に戻す
else
redirect '/answer'
end
end
# 電話の着信時や終了時に呼ばれる
post '/event' do
''
end
今回は Ruby の Sinatra を使用しますが、Vonage は NCCO (JSON) のやり取りができれば問題ないため、ほかの言語でも実装可能です(Vonage 公式の各種言語のサンプルはこちらです)。
Ruby のインストールはバージョン管理のできる mise がおすすめです。
ライブラリのインストール
必要なライブラリをインストールします。
bundle init
bundle add sinatra
bundle add rackup
bundle add rerun
サーバの起動
app.rb
を起動します。
$ bundle exec rerun ruby app.rb
[2024-08-26 18:31:50] INFO WEBrick 1.8.1
[2024-08-26 18:31:50] INFO ruby 3.3.4 (2024-07-09) [x86_64-linux]
== Sinatra (v4.0.0) has taken the stage on 4567 for development with backup from WEBrick
サーバは Vonage からアクセスできれば AWS や Cloudflare など、どこでも構いません。今回はお手軽な ngrok を利用します。
$ ngrok http 4567
Account kwcplus (Plan: Free)
Version 3.14.1
Region Japan (jp)
Latency 4ms
Web Interface http://127.0.0.1:4040
Forwarding https://your-sub-domain.ngrok-free.app -> http://localhost:4567
ngrok の出力にある Forwarding の https://your-sub-domain.ngrok-free.app
はのちほど Vonage のダッシュボードにも設定するためメモしておいてください。
まずは app.rb
の 5 行目にある IVR_URL を Forwarding の URL に変更します。rerun
を利用しているため、ファイルが更新されると自動でサーバが再起動します。
IVR_URL = 'https://your-sub-domain.ngrok-free.app/ivr'
プログラムや JSON はのちほど説明します。
アプリケーションの作成
プログラムと Vonage を紐づけるために、Vonage のダッシュボードにログインし、アプリケーションを作成します。
- 画面左のメニューから「アプリケーション」を選択
- 「新しいアプリケーションを作成する」ボタンを押す
アプリケーションとプログラムの紐づけ
「機能」にある「音声」のチェックボックスを ON にします。
名前と回答 URL、イベント URL を設定し、最後に「新しいアプリケーションの生成」を押します。
項目 | 設定 |
---|---|
名前 | おみくじ IVR(任意) |
回答 URL |
HTTP GET にして https://your-sub-domain.ngrok-free.app/answer
|
イベント URL |
HTTP POST にして https://your-sub-domain.ngrok-free.app/event
|
「回答 URL」は電話を着信すると呼び出される Webhook です。
「イベント URL」は今回利用しませんが、必須項目になります。イベント URL には電話の着信時や終了時のイベントが届きます。のちほど電話をした際に ngrok の Web Interface で確認してみてください。
アプリケーションと電話番号の紐づけ
取得した電話番号の「リンク」ボタンを押します。アプリケーションに紐づくと「リンク解除」に変わります。
これにより、電話を着信すると、アプリケーションに設定された回答 URL が呼ばれます。
これで IVR の完成です。取得した番号に電話してみてください。
「7」を押すか、「おみくじ」と言うことで、おみくじの結果が返ってきましたか?
参考資料:Getting Started with Voice API | Vonage API Documentation
NCCO
テキストの読み上げや、IVR の入力に JSON を書きました。この JSON を Vonage は NCCO (Nexcmo Call Control Object) と呼びます。
NCCO は着信した電話の振る舞いを定義します。
talk
talk は text の内容を読み上げます。
{
"action": "talk",
"text": "7 を押すか「おみくじ」といってください",
"language": "ja-JP",
"style": 0,
"bargeIn": true
}
オプション | 概要 |
---|---|
text | テキスト読み上げ内容を指定。SSML も無料で利用可能 |
bargeIn |
true だとテキスト読み上げ中も IVR を受付可能 |
language | 言語の種類。日本語であれば ja-JP
|
premium |
true を指定すると読み上げが流暢になります。デフォルト false 。false は無料ですが、true の場合は 100 文字あたり 0.4 円 |
style | 声色や性別。日本語であれば 0 ~ 5 を指定可能。language や premium 対応有無、音声サンプルはこちら
|
input
input は IVR の入力待ちをし、入力されたら eventUrl に入力された値を送ります。
{
"action": "input",
"eventUrl": [
"https://you-sub-domain.ngrok-free.app/ivr"
],
"type": [
"dtmf",
"speech"
],
"dtmf": {
"maxDigits": 1
},
"speech": {
"language": "ja-JP",
"context": [
"おみくじ",
"くじ",
"くじびき"
]
}
}
オプション | 概要 |
---|---|
type | 数字だけ(["dtmf"] )、音声だけ(["speech"] )、両方(["dtmf", "speech"] )を指定可能 |
eventUrl | 入力された内容を送る URL |
dtmf オプション
電話で数字入力する方式を DTMF といいます。DTMF 専用のオプション。
オプション | 概要 |
---|---|
timeOut | 入力を待つ秒数。デフォルト 3 。最大 10
|
maxDigits | 入力文字数。指定した文字数を入力すると eventUrl を呼ぶ。デフォルト 4 。最大 20
|
submitOnHash |
true を指定すると # を押すと eventUrl を呼ぶ。デフォルトは false
|
speech オプション
音声認識専用のオプション。
オプション | 概要 |
---|---|
endOnSilence | 話をしたあとに、指定した秒数の無音で eventUrl を呼ぶ。デフォルト 2.0 。0.4 ~ 10.0 を指定可能 |
language | 認識する言語。日本語であれば ja-JP
|
context | 配列で音声認識の精度を上げるヒントを指定 |
startTime | ユーザが話し始めるまで待つ秒数。デフォルト 10 。1 ~ 60 を指定可能 |
maxDuration | 音声認識する秒数。デフォルトは 60 。1 ~60 を指定可能。15 秒あたり 2.5 円 |
saveAudio |
true を指定すると録音。録音データのある URL は eventUrl に recording_url として送信。無料ですが 30 日後に自動削除。デフォルトは false
|
eventUrl に送信されるサンプル
eventUrl には、Vonage から JSON で送られます。
発信元(from)が渡されるため、CRM と連携をすれば、誰が電話をしたか判別可能です。
dtmf サンプル
入力された数字は文字列として渡されます。
{
"speech": {
"results": []
},
"dtmf": {
"digits": "7",
"timed_out": false
},
"from": "8180xxxxyyyy",
"to": "8150xxxxyyyy",
"uuid": "xxxx6ed87e66bd731aba84cca626xxxx",
"conversation_uuid": "CON-a6077a9f-xxxx-xxxx-xxxx-02f43861d28f",
"timestamp": "2024-08-22T14:51:38.554Z"
}
speech サンプル
音声認識結果は複数渡されます。このサンプルでは 2 件ですが、8 件くらい渡される場合もあります。
confidence の値が大きいほど確度が高いとされます。
{
"speech": {
"timeout_reason": "end_on_silence_timeout",
"results": [
{
"confidence": "0.9158283",
"text": "くじ"
},
{
"confidence": "0.9121674",
"text": "おみくじ"
}
]
},
"dtmf": {
"digits": null,
"timed_out": false
},
"from": "8180xxxxyyyy",
"to": "8150xxxxyyyy",
"uuid": "xxxx4246e5dd8199616dc8e136a5xxxx",
"conversation_uuid": "CON-d46c6c3c-xxxx-xxxx-xxxx-d49dbd1fa4bf",
"timestamp": "2024-08-22T14:53:59.677Z"
}
項目 | 概要 |
---|---|
timeout_reason |
end_on_silence_timeout 、max_duration 、start_timeout
|
error | エラーがあった場合はエラーメッセージが入ります |
参考資料:Speech Recognition Results
未入力サンプル
何も入力せず、発声もしない場合は、speech は []
、dtmf は ""
が渡されます。
{
"speech": {
"timeout_reason": "start_timeout",
"results": []
},
"dtmf": {
"digits": "",
"timed_out": true
},
"from": "8180xxxxyyyy",
"to": "8150xxxxyyyy",
"uuid": "xxxx4246e5dd8199616dc8e136a5xxxx",
"conversation_uuid": "CON-d46c6c3c-xxxx-xxxx-xxxx-d49dbd1fa4bf",
"timestamp": "2024-08-22T14:53:55.288Z"
}
まとめ
- Vonage は、電話や SMS といったコミュニケーションをプログラムできる CPaaS です
- NCCO と呼ばれる JSON で、電話がかかってきたときの処理を設定できます。たとえば、「7 を押してください」と案内したり、入力された言葉を認識したりと、さまざまな挙動を制御できます
- Web サーバーには、ユーザーが入力した数字や言葉が送られ、それに応じた結果(おみくじの結果など)を返すことで IVR を実現します
Discussion