カテゴリー別アーカイブ: Twilio

Twilioで受けた電話の着信履歴を、APIGatewayだけでkintoneに保存

ふと思った

 

Twilio使って、電話申し込みを受け付ける場合で「電話番号だけ取得すればいい」というケースってありますよね?
でまぁ、Twilioからサーバー経由でkintoneに着信情報を保存とかで出来るわけです。t2k_01

 

最近だと、サーバーレスアーキテクチャという事で、
t2k_02

こんな構成がよくありますよね。

でも、この前、こんなサイトを見つけまして。。。
Kintone_REST_APIを呼ぶAmazon_APIGatewayをCloudFormationで作る_-_Qiitahttp://qiita.com/monamu/items/5fb59ac0d747b8db09c4

いやまぁ、「ズンドコキヨシ」のリンクを追っかけてて気づいたんですけどね(汗

あ、Kが大文字・・・

kintoneへAPIGatewayから直接POST出来るなら、Twilioからも出来るよね!

t2k_03

という事で試してみました。

 

実際にやってみよう

 

Integration Requestでは、こんな変換が必要t2k_04

あと、受け取ったのを再マッピングで、こんな感じ名称未設定

これを、こんな風にマッピング。
API_Gateway

ここまでで、kintoneへ通話履歴を追加する事ができます。・・・たぶん、出来るはずです。。。

 

まだ足りない

 

このままだと、Twilio側はTwiMLが返ってこないので、いきなり回線が切れたり、アプリケーションエラーとか言われたりなど、使う上ではちょっと問題があります。

なので、TwiMLを返せるようにもう少し修正します。

kintoneにレコード追加した場合のレスポンスは、

{"id":"21","revision":"1"}

という感じなので、TwiMLには使えそうにありません。しかもjsonで返ってくるので、application/xmlに変換する必要もあります。
なので、こんな感じで、Integration Responseに追加します。API_Gateway

あと、Response Modelにもapplication/xmlを設定しておく必要があります。多分。API_Gateway

というか、この辺は理解が浅いので、間違ってるかもです。ちゃんとしたのがあれば教えてくだされー

でまぁ、ここまで出来れば、
・電話を受け付けて発信元番号を記録
ってのが、超サーバーレスで実現します。

こうして作ったアプリに、プロ生Twilioデモ_-_レコードの一覧
みたいな、一括発信ボタンを配置すれば、無敵ですね!

このボタンの詳細は、プロ生を見た人だけが知っていたり。
http://pronama.azurewebsites.net/2016/05/28/pronama-41-at-matsuyama/

 

ちなみに、APIGatewayをもう1つ作れば、プッシュでアンケートも出来ますね。更には、kintoneからGETして喋らせるのも出来るはず。多分。
それを、Cloudformationで一括作成できるので、構築が楽で良い事づくめ!

Lambdaを使った構成で、これと同じなのを作ってはいるのですが、やはりやってみたくて手を出してしましました(^^;;
Lambdaで作ったほうが100倍速いとかいうツッコミは聞こえません(ぉ

Twilio x AWS x kintone の組み合わせは可能性無限大で楽しいですね。おすすめ。

kintone スモールオフィスシリーズ「現場指示勤怠管理 テルメール」

ご挨拶

外回りの営業担当者や作業現場に少人数でいくチームなど、組織内での人の動きが分散して把握しづらくなっています。

そこで、メールと電話とkintoneを使って、作業指示や連絡などが手軽に出来るような仕組みをご提案します。

 

概要

作業指示はメールの文章でおこない、作業開始や連絡は電話でおこないます。
これにより、再確認が必要な情報と、リアルタイムな反応が必要な情報を最適な連絡手段でおこなうことができます。

 

業務指示

通常のメールでおこないます。いつもお使いいただいているメールソフトをご使用いただけます。また、送信したメールは、各担当者ごとに送信履歴が表示されます。

テルメール_詳細

作業開始と終了

作業開始報告用電話番号に電話していただくことで時間が記録されます。開始時と終了時の番号を分けることで、ボタン操作なしで記録が可能です。

テルメール_一覧

専用の番号を用意するため、終了時間が固まった時に管理者に負担が発生しません。また、終了時に報告がある場合は、電話した時にメッセージを記録していただければ、kintoneで確認可能です。

 

よくあるケース

予定通りの時間に現場に着いているかを管理するのが大変

各担当者が作業開始時に、作業開始報告用電話番号に連絡してもらうことで、各担当者のステータスが作業開始に変更になります。

作業開始報告用電話番号は同時に複数からかかってきても話し中にはなりません。同じ時間帯に作業が開始する場合でも問題なくお使いいただけます。

 

10人くらいが別々に動いていて管理者は1人。連絡しようにも管理者に電話が繋がらない

管理者へ連絡しようにも、他の人と話し中の場合は連絡がつかない事があります。

管理者を呼び出しても繋がらない場合、自動的に留守番電話になりメッセージを残す事ができます。
管理者はkintoneの画面で録音履歴を確認する事ができます。

 

料金

現在、ベータ版ですので料金についてはお問い合わせください。

また、転送にかかる通話料金は、お客様負担となります。

免責

kintone及びTwilioを利用しているため、それぞれのメンテナンス期間は機能が使用できません。

kintone及びTwilioのバージョンアップなどに伴い改修の必要が発生した場合は、影響範囲の調査などを行い対応いたします。調査の結果、対応を見送ることもあります。

 

kintone スモールオフィスシリーズ 「kintone 050オフィス」

ご挨拶

kintoneをお使いの全国数千万のユーザーの皆様、こんにちは。
今回は、kintoneの利活用として、外出先の携帯からでも事務所にいるように電話が出来る「kintone 050オフィス」をご提案いたします。

概要

050から始まる番号を事務所の電話番号として用意します。その番号に着信があった場合は、登録されている携帯電話番号へ転送致します。

また、登録されている携帯電話番号から050の番号へ発信すると、電話転送モードになります。メッセージにしたがい相手の電話番号を入力すると、050から発信した通話として機能します。

機能

  • 電話転送機能

通話録音設定

050に着信があった場合、呼び出し電話番号へ転送します。

 

  • 営業時間外留守番機能

営業時間指定

「受付開始時間」から「受付終了時間」以外に着信があった場合、「時間外メッセージ」を再生しメッセージ録音になります。

 

  • 050発信機能

登録されている「呼び出し電話番号」から、番号通知で「受信電話番号」へかけた場合のみ、050発信機能が作動します。
メッセージに従い相手の電話番号を入力して#を押すと、相手側には「受信電話番号」から電話がかかってきたように表示されます。

「呼び出し電話番号」は通知されませんので、事務所からかけたような運用が可能です。

 

  • 通話履歴機能

通話履歴_一覧

通話履歴は自動的に保存されます。
月別通話件数などのグラフや営業時間内外の対比など、通話履歴を様々な用途で分析可能です。

  • 通話録音機能

録音履歴

通話履歴にも録音データへのリンクが設定されていますが、録音履歴だけでも別途アプリをご用意しています。CallStatusなど通話の状況をご確認されたい場合は、こちらをご利用ください。

料金

現在、ベータ版ですので料金についてはお問い合わせください。

また、転送にかかる通話料金は、お客様負担となります。

 

免責

kintone及びTwilioを利用しているため、それぞれのメンテナンス期間は機能が使用できません。

kintone及びTwilioのバージョンアップなどに伴い改修の必要が発生した場合は、影響範囲の調査などを行い対応いたします。調査の結果、対応を見送ることもあります。

 

kintoneでTwilioを使う時のjsカスタマイズをまとめました

これは、kintone Advent Calendar 2015の記事ではありません(ぉぃ

以前、kintoneのTwilioプラグインを作成しまして、それについてはここで紹介しております。
これで簡単にTwilio使うのも良いんですが、せっかくなら一斉発信とか出来る方が面白いですよね。

という事で、Twilioで通話とSMSの両方を使えるようにするjsカスタマイズを紹介します。これを元に、全レコード一斉発信とかテーブルからの一斉発信とか、色々と改造してお楽しみください。

Twilioアカウント取得

Twilioアカウントの取得方法はこちらから。(岩崎さん、またお借りしますー(^^;)

カスタマイズビューからレコード登録

カスタマイズビューを用意

twilio-kintone-customizeview.txt

<style type="text/css">
td{font-size: 40px; border: 0px; padding:10px;}
input{font-size: 40px;}
.header{font-size: 40px; font-weight:bold;}

.css_btn_class {
    font-size: 1.4em;
    font-weight: bold;
    padding: 10px 30px;
    background-color: #248;
    color: #fff;
    border-style: none;
    border-radius: 10px;
    -webkit-border-radius: 10px;    /* Safari,Google Chrome用 */
    -moz-border-radius: 10px;   /* Firefox用 */
}

.css_btn_class:hover {
    background-color: #24d;
    color: #fff;
}
</style>

<table>
  <tr>
    <td colspan="2" style="text-align:center; font-size: 35px">受付システム</td>
  </tr>
  <tr>
    <td class="header">名前</td>
    <td><input type="text" id="visitor_name" style="width:450px; ime-mode: active;" placeholder="ぼうず たろう"></td>
  </tr>
  <tr>
    <td class="header">電話</td>
    <td><input type="text" id="visitor_tel" style="width:450px; ime-mode: disabled;" placeholder="09099999999"></td>
  </tr>
  <tr>
    <td class="header">人数</td>
    <td><input type="text" id="visitor_number" style="width:100px; ime-mode: disabled;" placeholder="3"></td>
  </tr>
  <tr>
    <td class="header">座席</td>
    <td style="font-size: 40px;"><input type="radio" name="visitor_seat" value="テーブル" checked>テーブル <input type="radio" name="visitor_seat" value="カウンター">カウンター</td>
  </tr>
  <tr>
    <td colspan="2" style="text-align:center;"><a href="#" class="css_btn_class" id="btn_reserve">受け付け</a></td>
  </tr>
</table>

カスタマイズビューのJavaScript

function () {

    "use strict";

    function loadJS(src) {
        document.write('<script type="text/javascript" src="' + src + '"></script>');
    }
    loadJS('https://cdn.jsdelivr.net/foundation/5.2.2/js/vendor/jquery.js');

    //レコード一覧表示イベント
    kintone.events.on('app.record.index.show', function(event) {

        //カスタマイズビュー以外の場合は終了。
                //ここの値は自身のカスタマイズビューIDと入れ替える。
        if (event.viewId != 5119208) return;

        //==================================================
        //カスタマイズビューの登録ボタンクリック時の処理
        //==================================================
        $('#btn_reserve').click(function() {

            //入力データの取得
            var name = $("#visitor_name").val();
            var tel = $("#visitor_tel").val();
            var number = $("#visitor_number").val();
            var seat = $("input[name='visitor_seat']:checked").val();

            //kintone登録用のJSONデータ作成
            var kintoneData = {};
            kintoneData.app = kintone.app.getId();
            var record = {};
            record.name = {value: name};
            record.tel = {value: tel};
            record.number = {value: number};
            record.seat = {value: seat};
            kintoneData.record = record;

            //kintoneへデータを登録
            kintone.api('/k/v1/record', 'POST', kintoneData, function(resp) {
                alert("受け付けが完了しました。n呼び出しまでお待ち下さい。");
                location.reload();
            },function(resp) {
                alert("登録に失敗しました。n" + resp.message);
            });

        });

    });

})();

発信処理を作成

ここからは、Twilioでの発信処理を作成していきます。

初期設定でTwilioの設定を入力

    // Twilio認証パラメーター(Twilioダッシュボードで確認可能)
    var ACCOUNT_SID = '{account_sid}';
    var AUTH_TOKEN  = '{auth_token}';
    // 呼び出し用の発信元番号。050が使用可能
    var FROM_DIAL = '{from_dial}';
    // SMS送信用の発信元番号。050が使えないので、USの番号を使用する事
    var FROM_SMS    = '{from_sms}';

ボタンの作成

        // 呼び出しボタンを表示
        var DialButton = document.createElement('button');
            DialButton.id = 'dial_button';
            DialButton.innerHTML = '呼び出し';
        DialButton.onclick = function () {
            dial(event);
            }
        kintone.app.record.getHeaderMenuSpaceElement().appendChild(DialButton);
        // 呼び出しボタンを表示
        var SendSMSButton = document.createElement('button');
            SendSMSButton.id = 'send_sms_button';
            SendSMSButton.innerHTML = 'SMS送信';
        SendSMSButton.onclick = function () {
            sendSMS(event);
            }
        kintone.app.record.getHeaderMenuSpaceElement().appendChild(SendSMSButton);

SMS送信処理

この処理では、特に変わったことはなく、普通にメッセージなどを作成してPOSTします。

        // SMS送信処理
        function sendSMS(event) {
            // レコードから名前と電話番号を取得
            var rec = kintone.app.record.get();
            var name = rec.record.name.value;
            var to = rec.record.tel.value;

            // Twilio APIのURL
            var url = "https://" + ACCOUNT_SID + ":" + AUTH_TOKEN +
                    "@api.twilio.com/2010-04-01/Accounts/" + ACCOUNT_SID + "/Messages";

            // HTTPヘッダー
            var headers = {'Content-Type': 'application/x-www-form-urlencoded'};

            // SMS送信先の電話番号。入力されたパターンに応じてプレフィックスをつける。
            if ((" " + to).indexOf(" 0") !== -1) {
                to = (" " + to).replace(/ 0/g, "+81");
            } else if ((" " + to).indexOf(" +") === -1){
                to = "+" + to;
            }

            // 送信データ
            var data = 'From=' + encodeURIComponent(FROM_SMS) +
                        '&To=' + encodeURIComponent(to) +
                        '&Body=' + name + "様n間もなく順番です。";

            kintone.proxy(url, 'POST', headers, data, function (body, status, headers) {
                if (status === 201) {
                    alert(name + '様へのSMSの送信が完了しました。');
                } else {
                    alert(name + '様へのSMSの送信に失敗しました。¥n' + status + '¥n' + body);
                }
            });
        }

呼び出し処理

呼び出し処理では TwiMLのURLを指定する必要があるので、SMSのように文章を自由に変えるのが面倒です。そこで、Twimletsを使用してTwiMLのURLを作成します。

        // 呼び出し処理
        function dial(event) {

            // レコードから名前と電話番号を取得
            var rec = kintone.app.record.get();
            var name = rec.record.name.value;
            var tel_to = rec.record.tel.value;

            // Twilio APIのURL
            var url = "https://" + ACCOUNT_SID + ":" + AUTH_TOKEN +
                    "@api.twilio.com/2010-04-01/Accounts/" + ACCOUNT_SID + "/Calls.json";
            // HTTPヘッダー
            var headers = {'Content-Type': 'application/x-www-form-urlencoded'};

            // 発信先の電話番号。入力されたパターンに応じてプレフィックスをつける。
            if ((" " + tel_to).indexOf(" 0") !== -1) {
                tel_to = (" " + tel_to).replace(/ 0/g, "+81");
            } else if ((" " + tel_to).indexOf(" +") === -1){
                tel_to = "+" + tel_to;
            }

            // TwiMLを生成
            var twiMl = '<Response><Say voice="woman" language="ja-jp">' +
                    name + '様。予約の順番が来ました。カウンターまでお越しください。</Say></Response>';
            // Twimletsを利用して、TwiMLのURLを生成
            var twiMlUrl = 'http://twimlets.com/echo?Twiml='+encodeURIComponent(twiMl);

            // 送信データ
            var data = 'From='+encodeURIComponent(FROM_DIAL) +
                        '&To='+encodeURIComponent(tel_to) +
                        '&Url='+encodeURIComponent(twiMlUrl);

            kintone.proxy(url, 'POST', headers, data, function (body, status, headers) {
                if (status === 201) {
                    alert(name + '様への呼び出しが完了しました。');
                } else {
                    alert(name + '様への呼び出しが失敗しました。¥n' + status + '¥n' + body);
                }
            });
        }

いま、ソースを見てたら、E.164処理(頭に+81を付ける処理)がダブってますね。しかも、元のコピーライト残ってるしw
まぁ、いいか。

という事で、これらのソースをまとめたものはこちらで公開しております。
改造するさいのデバッグで電話をかけまくるとお金がかかるので、Twilioに慣れる前はトライアルアカウントのままにしておくのをお勧めします。実際に運用するさいはアップグレードが必要ですが、開発用にはトライアルアカウントを使うようにしましょう。

参考サイト

kintoneマッシュアップのための豆知識(curlコマンドとkintone.proxy()の対応)
Twilio × kintone ハンズオン用サンプルプログラム

kintoneで胴元になろう

これは、kintone Advent Calendar 2015の19日目です。怒られたら差し替えます。(差し替え予定の真面目なのはこっち

年末ジャンボは買いましたか? 当選したら人生変わりそうですよね。
まぁ、当選しても大体失敗する方に転がる可能性が高いとか言われているので、私は買ってません。いえ、決して、お金がないから負け惜しみ言ってるわけじゃないですよ。ええ(涙
まぁ、お金がないのは間違いないんですが、昔、無駄に買って懲りた事あるのでー。

でも、買う方がダメでも、もしかしたら胴元になればいけるかも? でも、胴元になるパターンってどんなのがあるんだろう。よし、考えてみよう!

ノミ屋?

公営競技のアレを元に、独自にあれこれしてってパターンなので、こうかな?
ノミ屋_-_1_-_レコードの詳細

これなら、当選パターンに合わせての配当金試算も出来て、倍率が高いパターンへの警告も可能かな。しかも、確定後は当選者に通知もボタンひとつで出来るってのも可能かなぁ。
でも、倍率の管理とかもあるだろうし、項目足りないかも。

ちなみに、Twilioプラグインは複数番号とかテーブルには対応していないので、そのままでは使えません。kintone Café大阪のLTでデモをした自作の抽選アプリでは一斉発信に対応してるので、何かの機会があればー。

富くじ?

発行枚数があって、実際の販売数がある、と。んでもって当選番号があるくらいかな。
富くじ_旧

いやまてよ、普通は1等から3等とか分かれてるからこうかな?
富くじ_-_1_-_レコードの詳細

当選番号は手動で決めても問題なさそうなので、番号を決める管理者と当選者を確認する担当者でフィールドのアクセス権限を設定すればいけそうかな。
当選者の顔写真とかを添付して確認とかでもいいかな?

 

とまぁ考えても、当然ですが法的な問題で胴元にはなれませんよねー。

・・・現金じゃなきゃ良いのか?

ロンダリー

ギフト券のコードで申し込みして、当選もギフト券コードで返却。
amazon_-_1_-_レコードの詳細

ちなみに、ギフト券でギフト券は買えないので、その辺の変換作業は地味に必要です。

なお、この場合に必要な関連技術で、ギフト券コードをアカウントに自動で登録するだとか、任意の額のギフト券コードを取得するとかが必要ですね。
そういえば、さくらのサーバーにこんなPHPのソースがw 何年前だこれ(爆 謎の基礎研究を結構やってたからなー(遠い目

automail_php_-__Users_okiyasu256_Dropbox_php_sorce_usdvd_amaauto

 

という風にkintoneを使うと、考えた形そのままでアプリが作れて実際に動作可能という、夢のような環境を手にすることができます。
しかも、各種サービスと連携させると自動化などもサクサク構築可能なので、プロトタイプのデモがあっという間に量産できますね!

 

そういえば、特定商品を検索するツール作って、ギフト券で商品を買いまくれば現金化の自動化が簡・・。

・・・おや誰か来たようだ。続きはまた今度。

Twilio – API Gateway – Lambda – kintone と繋いで、応答メッセージを楽に変えてみよう

これは、Twilio Advent Calendar 2015の12月17日の記事です。

さいしょに

この記事は、

kintone Advent Calendar 2015の2日目の、
kintone APIを使ってスペースを有効活用する(サーバーレスで)

と、

Twilio Advent Calendar 2015の9日目の、
Twilioサーバーレス化作業記録 – RequestURLもサーバーレス化

に刺激されて作りました。ソースとかはコピペ満載なので、ふいんき(何故か変換できない)をお楽しみ下さい。

リカちゃん電話運用サービスを作る

基本的な流れ。

1 決まった番号に電話する
2 応答メッセージが流れる

  • メッセージは管理画面から差し替え
  • MP3と合成音声のどちらでも可
  • 特別な場合に備えて、生TwiMLも可にした

kintone側の準備

1 アプリの作成フォーム

受付番号には、Twilioの番号を入力します。これで識別するので+付きの番号になります。理論上は何番号でも運用可能!

応答パターンを切り替えることで、何で返すかを選ぶことができます。その他はテキストでオッケー。MP3の場所もURLをテキスト入力です。MP3の置き場として今回はS3を用意しましたが、転送費用とかが気になる場合は別サーバーをお勧めします。

API Gateway & Lambdaの準備

Twilioサーバーレス化作業記録 – RequestURLもサーバーレス化 で紹介されている方法でお願いします。まずはLambdaのサンプルメッセージが返ってくるのを試してください。

Lambdaで、ソース修正

kintone APIを使ってスペースを有効活用する(サーバーレスで) で紹介されているソースを参考に、アプリIDやドメインを自分の環境の数値にしてください。Twilio-telservice_-_NetBeans_IDE_8_0_2

次に、アプリ内のフィールド情報を指定していきます。Twilio-telservice_-_NetBeans_IDE_8_0_2 2
body_getsalesamountの方だけ修正してください。ポイントは、Twilioの番号で検索する事と、必要なフィールドの指定を間違えない事です。

kintone側に番号が登録されてない場合の別メッセージを変更できるように、ダミーで111という番号を使うようになっています。この辺は、申し込みサイトへの誘導とか色々とできそうですね。

最後にレコードの内容からTwiMLを作成します。Twilio-telservice_-_NetBeans_IDE_8_0_2 3

以上で、作業は終わりです。

 

kintone側にこんな感じで入力しておくと、対応したメッセージを返します。通常は音声案内で、時間限定イベントで秘密のメッセージ流してとかができますね。テレフォンサービス_-_レコードの一覧

 

という感じですが、他に色々と繋ぐと楽しめそうなので、次はAmazonギフト券と繋いでみます(ぉ

Twilioアカウント取得時のハマりパターン

これは、Twilio Advent Calendar 2015の12月15日の記事です。

【12月14日】Twilioで日毎に作業者から確認連絡をしてもらうのを自動化する
【12月16日】Twilioサーバーレス化作業記録 – Token生成サーバーレス化

 

なんか、投稿枠が空いていたのと、ちょろっとしたデモが早めに出来て時間が空いたのとで、チャンスとばかりに書いてみました。
技術話は出てきません。Twilioアカウントを取得時に落とし穴に勝手に落ちた話です。

Twilioアカウントには2種類あるのはご存知?

まぁ、ここを見てるような方なら、アメリカと日本との2つのアカウントがあって、ログインIDなども別というのは知ってますよね。
で、ハンズオンとかでもアカウント取得の時には、
「www.twilio.com じゃなくて、jp.twilio.comなので注意」
という話だと思い込んでたんですが、

jp.twilio.com じゃなかった

という話です。

お前は何を言ってるんだ?

とりあえず、下の2つのキャプチャを見ていただくと、URLとか画面構成とかほぼ一緒で、どちらもjp.twilio.comで始まっているというのはわかると思います。でも、上がアメリカで下が日本なんです。
違いは、KDDIのロゴがあるかどうか。

jp-com jp-jp

どうしてこうなった?

www.twilio.comから何も考えずに、手打ちでURL変更してjp.twilio.comに行くとこんな感じ。

com

jp

あー、画面変わったから日本になったんだろうなーとか思ったら大間違い。

本当の日本のサインアップ画面は、これ。
http://twilio.kddi-web.com/
jp-home

なんだよー、http://twilio.kddi-web.com/ じゃないか、何を間違ってたんだ俺!

とサインアップを押すと、この画面。
https://jp.twilio.com/try-twilio/kddi-webjp-signup

https://jp.twilio.com/ だ! でも後ろに、/try-twilio/kddi-web が付いてる!!

ここでうっかり、https://jp.twilio.com/try-twilio にしちゃうとアメリカアカウントになります(たしか)。

ということで、サインアップのURLがわからなくなったら、googleで聞くのが一番でした。
とまぁ、私は不具合を引き寄せる才能に溢れているので(涙)、こういう何でもないところで引っかかるんですわー。という共有話でした。

 

ちょっと時間は稼いだ、残りの空き枠を頼むー。バタリ。