※ twilio APIは2021年くらい?から個人開発者を対象にした日本向け新規電話番号の発行ができなくなっているようです(新規取得はビジネス利用に限定され、法人番号の登録・承認が必須になったそうです)。電話をプログラミングで操作できるおもしろAPIだったのに残念。
はじめに
新郎新婦には内緒で「ご結婚おめでとう」の「声」を友人から集めてプレゼントするという、「祝電2.0」的なアプリを作成しました。元ネタは2013年のコチラの素敵なブログ
読まれたことが無い方は是非一読して頂きたいです。「プログラマーってほんとにかっこいいな」と思えます。このブログに痛く感動したので、こちらの内容を完コピして作成しました。
ブログ内容を簡単に要約すると、
- Twilioという音声APIを使って自動応答メッセージの電話アプリを作成
- 新郎新婦友人に指定の電話番号に電話してもらい、「結婚おめでとう」のメッセージを録音してもらう
- iPodなどにお祝いのメッセージを入れてプレゼント
ブログの内容と今回の差分は、
- 元ネタ: Rubyで実装 → 今回: Python(Flask)で実装
- 元ネタ: twilioAPIで取得したデータをハンドリングするためにいい感じにGUIページを作成 → 今回: GUIは作成せず、twilioAPIの管理画面ページでデータ管理(手抜きした)
上記のブログや企画メンバーのエンジニアの方のブログには処理フローに関する言及はされているものの、動く形の完全なコードは公開されていなかったので、ブログ内容を参考にしながら同じ動作をするものをPythonで実装したという感じです。断片的なスクリプトはエンジニアメンバーの方がブログで公開されていました。
自分は普段はPythonを使ってデータ分析する仕事をしているので、Flaskのようなウェブフレームワークを使ってアプリっぽいものを作ったことも、Herokuのようなホスティングサービスを使ったこともありませんでした。
そんなわけで、webアプリ(?)素人がいろいろコケた点や、TwilioAPI公式ドキュメントでは詳しく解説されていない点についてメモとして残します。
TwilioAPIへの登録
Twilioの登録・課金方法・電話番号の購入・静的サンプルファイルのS3への設置と挙動確認などは以下のブログが参考になりました。今回は静的ファイルを扱わないのでスルーしてもok。ひとまずAPIへの登録が完了すれば大丈夫です。
Twilioは有料のAPIサービス(無料枠は無し)で、まず2000円をミニマム金額として課金し、以後1000円単位で追加課金する仕組み。1通話が0.1~2円程度なので、簡単なアプリ開発などなら最初の2000円で十分量だと思います。
ちなみに、「S3って何?」って場合はこちらページが参考になります。
S3は、Amazonが運営するクラウドのファイルサーバーです。最初のクレジットカード登録などは面倒ですが、非常にお安く簡単に利用できるので使いましょう。(S3には自動電話案内のための音声データ置き場になります)
ローカル環境の作成
上記のページに従ってローカルの開発環境を整えます。主にやることは、以下のインストールです。
- pythonのインストール
- vertualenvのインストール
- Flaskのインストール
- Twilio Python SDKのインストール
- ngrokのインストール(後述)
vertualenvは仮想環境の構築を行うものです。webアプリのスクリプト一式をHerokuサーバーにホスティングするときに、不必要なモジュールなどが紛れ込まないようにvertualenvで今回のアプリ用に環境を切り離しておきます。後で面倒なことにならないようにインストールしておきましょう(anacondaのパッケージで仮想環境を作りたい場合は後述を参照)
ngrokについては詳細を後述しています。
TwilioAPIの理解
開発環境の設定が終わったら上記のクイックスタートの内容を眺めてみて、TwilioAPIで実際にどういうタスクがどんな感じで書けるのか確認します。(自分は実際に動かしてみてどんな感じで挙動するか逐一確かめないと理解できないタイプなので...)
Twilioは電話がかかってくると指定したURLにTwiML(XML的なもの)を見に来てくれて、そこで定義されているフォーマットの処理を随時実行していってくれます。
上記のチュートリアルをみてみると、TwiMLの書き方や動的な生成の仕方がわかりますが、一部古い記述(最新のAPI仕様に合っていない記述)があったり、肝心のwebサーバーにFlaskスクリプトをホストする方法が不親切だったりするのでいろいろコケます。。。
このチュートリアルでは「TwilioAPIの書き方ってだいたいこういう雰囲気なのね」ということを確認する程度でも良いと思います。
今回作成するアプリでは、TwilioAPIの機能のうち、主に着信通話のハンドリングに当たる「電話を受け付ける」「録音済みの音声ファイルを流す」「ユーザからのメッセージを録音する」「番号の入力を受け付ける」などを利用しています。
実際のアプリのシーケンスは以下のような流れです(hmskさんのブログから引用)
- (1) 電話を受け付けてウェルカムなメッセージを流す
- (2) メッセージ入力方法の説明を流す(終わったら#押してねみたいな)
- (3) 発信音を鳴らして録音を実施する(#で終了する)
- (4) 録音したメッセージを流すよと宣言して流す
- (5) このメッセージで良かったら"1"を押せ、もう一度録るなら"3"を押せと促しつつ入力を待つ
- (6) 入力された数字が、"1"なら(7)へ、"3"なら(2)へ、それ以外なら(5)へリダイレクト
- (7) お礼を流して電話を切る
以下が各機能のチュートリアルとなりますが、上で書いた通り、チュートリアル通りに書いても動かない箇所があるので注意してください。
上記のシーケンスと、チュートリアル、最新APIの使い方を参考にしながら書いた完成版のFlaskスクリプトを以下に置いておきます
(スクリプト中で呼び出しているmp3ファイルは、S3に設置した自動応答用の音声データです。)
ローカル環境での実行(ngrokの使い方)
次に、作成したwebアプリ(Flaskスクリプト)が正しく動くかローカルでテストをします。
面倒なのでデプロイ(サーバにアップ)することなく挙動をテストしたいですが、そんなときはngrok
が便利です。無料なので是非使いましょう。
OSに合ったngrokを公式ページからDLします。Macならbrew install ngrok
でok
DLしたファイルを解凍します
$ unzip /path/to/ngrok.zip
その後、./negrok help
などで表示が確認されればok
ngrok
を実際に使うためには、ngrok公式ページからsign upでユーザー登録する必要があります(無料)
ユーザ登録してログインした後、Get Startedの画面で表示されている./ngrok authtoken (文字列が続く)
をターミナルで実行しておきます
(もしかしたら、このユーザ登録とauthtokenの登録は必須ではないかも)
ngrokの操作が一通り完了したら、動かしたいFlaskスクリプトの.pyを実行します
(実行すると localhost:5000 に表示できる状態になる)
Flaskが動いている状態で、別ウィンドウで./ngrok http 5000
を実行します。
すると、新しく立ち上がる画面に
Forwarding http://乱数.ngrok.io -> localhost:5000
Forwarding https://乱数.ngrok.io -> localhost:5000
みたいなものが書かれているので、(httpでもhttpsの方でもいいが)表示されたURLをtwilioAPIの管理画面の「Webhook」のところに登録して保存します。
これで、ローカルで実行した内容がウェブサーバーで実行されているかのように処理されるようになります。
その後、当該の電話番号に電話するとFlaskで書かれた処理が実行されるはず。
ちなみに、ngrokは起動する度にランダムなurlを返します。もしこれを固定にしたい場合はこのページの「ランダム文字列が面倒くさい」の項目を参照してください。
(※しかし、2017年4月段階では固定URLを取得するためには有料会員にならないといけなくなっているかも?)
webサーバーへのホスト(Herokuの使い方)
静的な挙動(例えば、電話がかかってきたら指定のmp3を自動再生するだけ)をするためのTwiMLを作成するpythonスクリプトであれば、それをS3に置いて、スクリプトのURLをTwilioAPIの管理ページに登録すれば実行できます。
しかし、ユーザが入力する番号によって処理を変えたいなどの(今回のような)複雑な処理を行いたい場合は、外部のサーバーにpythonスクリプトを設置し、ユーザの入力内容に応じて動的にTwiMLが生成されるようにしなければいけません。
スクリプトを設置する外部サーバの選択肢として、Amazon Web Service (AWS)のEC2やGoogle Cloud Platform (GCP)のGoogle App Engine (GAE)などが低料金で使用可能ですが、今回は目的とする処理が単純ということもあり、設置も簡単で、かつ無料で利用できる Herokuを利用することにしました。
Herokuは、gitで管理されたwebスクリプト一式を指定のHerokuサーバにpushするだけで、アプリを動かすことができるありがたいサービスです。
Pythonで書かれたwebアプリケーション(DjangoやFlask)をHeroku上で実行するための手順は以下の公式チュートリアルを参考にしました。
- Getting Started on Heroku with Python
- (上記の内容の日本語版的なものがQiitaにもあった)
チュートリアルで行われている大まかな流れは、
- Herokuアカウントの作成
- Heroku Command Line Interface (CLI)のDL
- CLIを使ってherokuへのログイン
-
heroku create
でHeroku上にアプリ用のリポジトリを作成 - 作成したレポジトリに
git push heroku master
でスクリプトをpush -
heroku open
でアプリの起動
という感じです。お手軽。
ちなみに、今回作成するアプリではDB系の操作を行わないので、SQLAlchemyやpsycopg2などのインストール処理などは全てぶっ飛ばしています。
アプリを動かすためにHerokuにpushしなければならない最低限のファイルは以下の3つです。
- main.py ・・・ Flaskのスクリプトが書かれた本体ファイル(ここでは仮にmain.pyというファイル名にしているだけ)
- Procfile ・・・ main.pyを実行するためのコマンドが書かれたファイル(詳細は後述)
- requirements.txt ・・・ main.pyでimportされるモジュールのリストファイル
(注意)以下の処理はvertualenvやanacondaでアプリ用に切り分けた仮想環境に入ってから操作します。
Herokuアカウントを登録します http://www.heroku.com/
ここからOSに合ったHerokuのCLIツールをインストールします。
ユーザ登録とCLIインストール後、ターミナルでheroku login
します
% heroku login
#-> herokuのIDパスワードを入力
Herokuサーバーにデプロイしたいpythonスクリプト(Flaskのスクリプト)が格納されたディレクトリをgitの管理下に置きます
$ cd /path/to/dir
$ git init
同じディレクトリ下で、先にrequirements.txtとProcfileを作っておきます
$ pip freeze > requirements.txt
(もしも gunicornをインストールしていなければ pip install gunicorn
する)
("main"の部分はFlaskのファイル名に合わせる)
$ touch Procfile
$ echo web: gunicorn main:app --log-file - >> Procfile
git init
した(同じ)ディレクトリでheroku create
します
$ heroku create <任意のアプリ名> --buildpack heroku/python
heroku create
するとHerokuのURLが発行されます
このURLをtwilioAPIコンソールのwebookのところに登録します(忘れやすいので注意)
スクリプトをherokuへpush
します
$ git add -A
$ git commit -m “hogehoge”
$ git push heroku master
ざらざらと文字が流れます
masterに無事pushされ、エラーが出なければok
$ heroku open
すると、pushした内容が正しければ、ブラウザーでアプリが表示されるはず。
ローカルで正しく動作していたのに動かない場合は、
- requirements.txt に書き足していないモジュールは無いか
- Procfileの書き方は正しいか
を確認してみます(たいていProcfileの方に何かしら問題がある)
上記の一連の内容はこちらのQiita記事にすっきりまとまっていて参考になりました
Procfileについて
Herokuにpushしたアプリケーションの実行コマンドはProcfileなるものに書いておかなければならないようです(Procfileについての詳細はこちらに書かれていますが、よくわからなくてもとりあえず以下のように書けば動きます)。
gunicornなるものを使ってProcfileを書く場合、こちらのブログを真似して書いてみました。
例えば main.py という名前のFlaskのスクリプトをHeroku上で実行したい時、Procfileには
web: gunicorn main:app --log-file -
という一行だけを書いて保存しておけば良いらしいです。( python main.py
ではない。)
(gunicorn
はいろんな記事でこれを使うことが推奨されているっぽいので、実はよくわかっていないですがとりあえず使ってます。もしもgunicorn
を使わない場合は、port 5000でFlaskやdjangoが立ち上がるときに問題がでるらしいです)
Herokuにpushしたアプリを確認する
現在Herokuにpushされているアプリを確認します(無料枠では最大5つまで)
$ heroku apps
不要なアプリの削除
$ heroku destroy --app <アプリ名>
#-> 再度確認のためアプリ名をタイプする
現在 herokuのサーバーで動いているスクリプトを確認します(無料枠で起動できる残り時間なども表示される)
$ heroku ps
logの確認
$ heroku logs # —tailオプションでlogのtailが見れる
その他のHeroku CLIについてはこちらを参照
その他
海外からの電話には応答できない?
Twilioで購入した電話番号は海外からは応答できないことが途中でわかり、海外に住んでいる友人からは結局ボイスレコーダーアプリで録ってもらった音源を送ってもらうことになりました。電話アプリにした意味。。。
もしかすると、購入した電話番号が日本国内限定のものだったかも?(詳しくは調べていません)
mp3ファイルのトリミング
APIによって録音されたユーザのメッセージデータはhttps://jp.twilio.com/login/kddi-webからログインした先にあるコンソールからDLなどができます。(どれくらいのメッセージ数が保存できるかきちんと調べていませんが、自分の場合は60件は保存されているのを確認しました)
データの保存形式はmp3やWAVなどが選べたと思います。自分の場合はmp3で音声データをDLしていました。
音声データの先頭部分やお尻の部分を切り取って簡単に編集したい場合はこちらが無料で使え、かつ便利でした。ブラウザ上で簡単に音声トリミングができます(特に上限ファイル数なども無し)。
Play動詞とm4aファイル問題
iPhoneのボイスレコーダーアプリが標準で出力するm4aファイルは twilioAPIのplay動詞で再生出来ないので注意!(mp3が無難)
anacondaで仮想環境を作る
vertualenvではなくanacondaで環境を切りたい人用(通常はvertualenvを使えば良いと思う)
anacondaでenvを創ってそこに出入りする方法は以下
仮想環境の構築
$ conda create -n <環境名> python=<バージョン> <インストールしたいライブラリをスペース区切りで書く>
例: conda create -n py_ver2 python=2.7 numpy scipy pandas jupyter
anaconda環境をまとめて、新たな環境として作ることも可能(anacondaでanacondaの仮想環境を作るということ)
$ conda create -n anaconda2 python=2.7 anaconda
現在存在する condaで作った仮想環境一覧を表示
$ conda env list
仮想環境に入る
$ source activate <環境名>
仮想環境から抜ける
$ source deactivate
参考
上記のリンク以外で参考にしたページ
余談
このアプリを作った背景的なものを個人ブログに書きました。ご興味あれば。