恋するプログラムをSinatraでWebアプリにするPart.3[CHAPTER4 あこがれのGUI]②
記事の概要
『恋するプログラム』の[CHAPTER4 あこがれのGUI]で作成するGUI版チャットボットプログラムを参考に、Webアプリ版チャットボットのインターフェースを作成し、ブラウザに表示します。
目次
開発環境
- OSX 10.11.2 El Capitan
- テキストエディタ: MacVim
- ターミナルエミュレータ: Macターミナル
- シェル: zsh
- パッケージマネージャ: Homebrew
- ブラウザ: Firefox - Ruby 2.0.0p645
- バージョンマネージャ: rbenv
- Webフレームワーク: Sinatra
参考記事
Rubyの開発環境構築は、こちらの記事を参考にさせていただきました。
ノビィに話しかける
テキストチャットとキャラクターのアニメーションをブラウザに表示し、ビデオチャットのようなインターフェースを作成します。
アプリケーションディレクトリの構成
~/programinlove
|- proto.rb // CUIチャットボットのメインファイル
|- unmo.rb // チャットボットオブジェクトのモデル
|- responder.rb // 応答オブジェクトのモデル
|- app.rb // Webアプリのメインファイル
|- /views // ビューのテンプレートを配置するディレクトリ
| |- index.erb // チャットのインターフェースを表示するビュー
|- /public // 静的ファイルを配置するディレクトリ
|- styles.css // チャットのインターフェースをレイアウトするcss
|- /img // 画像ファイルを格納するディレクトリ
|- /normal // 平常時の画像を格納するディレクトリ
| |-0000.png
|- /blink // 瞬きの画像を格納するディレクトリ
|-0000.png
|-0001.png
ソースコード
app.rb
は、ほぼルーティングメソッドのみとなり、ユーザからのアクセスに応じてビューを表示した後は、入力された文字列を受け取った順番に配列に格納し、インスタンス変数@talk_log
を生成してビューに表示します。
index.erb
にはチャットのインターフェースの要素を設置し、styles.css
でレイアウトを整え、サンプルプログラムに似せた配置にしています。
<body>
要素の最後の方に記述しているJavascriptでは、配列に格納された画像を順番に表示し、キャラクターが瞬きをするアニメーションを作成しています。
ただ、アニメーションを作成している
flipAnime
関数はバグっていて((clearTimeoutがclerTimeoutになっている))、
エラーによって無理矢理ループが止まっている状態です。
記事を書いている最中に気付き、修正を試みましたが、誤字を修正するとループが止まらなくなったので、諦めてそのまま放置((直し方がわかったら直したいと思います))しています。
timeoutId = setTimeout(flipAnime, 100);
を、clearTimeout(timeoutId);
の前に記述したら直りました。
app.rb
require 'sinatra' require 'sinatra/reloader' # 会話ログを格納する配列 talk = [] # URL'/'にアクセス get '/' do # nobyfomを表示 erb :index end # URL'/'にPOSTメソッドでアクセス post '/' do # ユーザの入力を会話ログに表示 talk << "#{params['inputarea']}<br>" @talk_log = talk.join erb :index end
views/index.erb
<html> <!-- publicフォルダのcssファイルを読み込む --> <link href="styles.css" rel="stylesheet"> <body> <!-- チャットのインターフェースを囲う枠 --> <div id="nobyform"> <!-- キャラクターの画像を表示 --> <div id="nobycanvas"> <img src="img/normal/0000.png"> </div> <!-- キャラクターからの応答メッセージを表示 --> <div id="responsearea"> <p></p> </div> <!-- 会話やオプションの状態をPOSTするフォーム --> <div> <form action="/" method="post"> <!-- ボタンを押すと会話を'/'にPOSTする --> <div> <input type="text" name="inputarea" placeholder="会話を入力"> <button type="submit">話す</button> </div> <!-- ログにResponderを表示するオプション --> <div> <label><input type="checkbox" name="respoption" value="show">Responderを表示</label> </div> </form> </div> </div> <!-- 会話のログを表示 --> <div id="logarea"> <%= @talk_log %> </div> <!-- キャラクターの画像をアニメーションさせるJavaScript --> <script> document.addEventListener('DOMContentLoaded', function(){ var index = 0; /* 配列の要素番号 */ var cnt = 0; /* 瞬きの回数 */ /* 瞬きのアニメーション用の画像 */ var blinkImg = ["img/normal/0000.png", "img/blink/0000.png", "img/blink/0001.png", "img/normal/0000.png" ]; /* 瞬きのアニメーションを作成 */ /* 2回の瞬きでアニメーション終了 */ function flipAnime(){ timeoutId = setTimeout(flipAnime, 100); document.getElementById("nobycanvas").getElementsByTagName("img")[0].src = blinkImg[index]; index++; if (index >= blinkImg.length){ index = 0; cnt++; } if (cnt > 1){ cnt = 0; clearTimeout(timeoutId); } }; /* 瞬きのアニメーションを表示する */ setInterval(flipAnime, 3000); }); </script> </body> </html>
public/styles.css
/*---------------------------- * 全要素に対して直感的な * サイズ指定を可能にする ----------------------------*/ * { box-sizing: border-box; } /*---------------------------- * チャット用の要素を配置する * インターフェースの外枠 ----------------------------*/ #nobyform { display: table-cell; vertical-align: middle; } /*---------------------------- * 応答メッセージを表示する * 角丸の吹き出し ----------------------------*/ #responsearea { width: 290px; margin-top: 30px; margin-bottom: 30px; border: 1px solid #333; border-radius: 10px; background: #333; } /* 吹き出しの三角部分 */ #responsearea:before { content: ''; position: relative; top: -40px; left: 30%; border-top: 20px solid transparent; border-right: 20px solid transparent; border-left: 20px solid transparent; border-bottom: 25px solid #333; } /* 吹き出しの中の文字 */ #responsearea p{ height: 40px; margin-top: 5px; margin-bottom: 10px; color: #fff; text-align: center; font-size: 100%; } /*---------------------------- * 会話のログを表示する ----------------------------*/ #logarea { width: 300px; height: 380px; display: table-cell; background-color: #f9f9f9; overflow: scroll; }
実行結果
ターミナルでapp.rb
を動かし、ブラウザにhttp://localhost:4567
を入力します。
~/programinlove $ruby app.rb [2016-01-10 12:35:45] INFO WEBrick 1.3.1 [2016-01-10 12:35:45] INFO ruby 2.0.0 (2015-04-13) [x86_64-darwin12.6.0] == Sinatra (v1.4.6) has taken the stage on 4567 for development with backup from WEBrick [2016-01-10 12:35:45] INFO WEBrick::HTTPServer#start: pid=8299 port=4567
WebサーバのWEBrickが起動し、ターミナルにGETでアクセスしたログが表示されます。
CSSファイルや画像にもアクセスしているため、ログが多くなります。
::1 - - [10/Jan/2016:12:36:50 +0900] "GET / HTTP/1.1" 200 2329 0.0316 localhost - - [10/Jan/2016:12:36:50 JST] "GET / HTTP/1.1" 200 2329 - -> / ::1 - - [10/Jan/2016:12:36:50 +0900] "GET /styles.css HTTP/1.1" 304 - 0.0007 localhost - - [10/Jan/2016:12:36:50 JST] "GET /styles.css HTTP/1.1" 304 0 http://localhost:4567/ -> /styles.css ::1 - - [10/Jan/2016:12:36:50 +0900] "GET /img/normal/0000.png HTTP/1.1" 304 - 0.0007 localhost - - [10/Jan/2016:12:36:50 JST] "GET /img/normal/0000.png HTTP/1.1" 304 0 http://localhost:4567/ -> /img/normal/0000.png ::1 - - [10/Jan/2016:12:36:53 +0900] "GET /img/blink/0000.png HTTP/1.1" 304 - 0.0004 localhost - - [10/Jan/2016:12:36:53 JST] "GET /img/blink/0000.png HTTP/1.1" 304 0 http://localhost:4567/ -> /img/blink/0000.png ::1 - - [10/Jan/2016:12:36:53 +0900] "GET /img/blink/0001.png HTTP/1.1" 304 - 0.0004 localhost - - [10/Jan/2016:12:36:53 JST] "GET /img/blink/0001.png HTTP/1.1" 304 0 http://localhost:4567/ -> /img/blink/0001.png
レイアウトを整えたインターフェースを表示しているだけなので、瞬きをしているキャラクターに話しかけることは出来ますが応答はありません。
参考書籍
参考記事
Sinatraについては、こちらの記事を参考にさせていただきました。
- Rubyの入門や書き捨てアプリを作る場合は sinatraがオススメ! - むかぁ~ どっと こむ
- SinatraとjQueryでおよそ100行で作るAjax掲示板アプリケーション - gaaamiiのブログ
- Sinatra: README (Japanese)
CSSのレイアウトについては、こちらの記事を参考にさせていただきました。
関連記事
- 恋するプログラムをSinatraでWebアプリにするPart.0[はじめに]
- 恋するプログラムをSinatraでWebアプリにするPart.1[CHAPTER3 ほんとに無能]
- 恋するプログラムをSinatraでWebアプリにするPart.2[CHAPTER4 あこがれのGUI]①
- 恋するプログラムをSinatraでWebアプリにするPart.4[CHAPTER4 あこがれのGUI]③
- 恋するプログラムをSinatraでWebアプリにするPart.5[CHAPTER5 辞書を片手に]
- 恋するプログラムをSinatraでWebアプリにするPart.6[CHAPTER6 感情コントロールの魔術師]①
- 恋するプログラムをSinatraでWebアプリにするPart.7[CHAPTER6 感情コントロールの魔術師]②
- 恋するプログラムをSinatraでWebアプリにするPart.8[CHAPTER7 学習のススメ]①
- 恋するプログラムをSinatraでWebアプリにするPart.9[CHAPTER7 学習のススメ]②
- 恋するプログラムをSinatraでWebアプリにするPart.10[CHAPTER7 学習のススメ]③
- 恋するプログラムをSinatraでWebアプリにするPart.11[CHAPTER8 文章を作り出す]
- 恋するプログラムをSinatraでWebアプリにするPart.12[CHAPTER9 ノビィ、ネットワークにつながる]
- 恋するプログラムをSinatraでWebアプリにするPart.13[おわりに]