Skip to content

Instantly share code, notes, and snippets.

@xmjw
Last active December 20, 2015 01:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xmjw/6053357 to your computer and use it in GitHub Desktop.
Save xmjw/6053357 to your computer and use it in GitHub Desktop.
Sample code for Twilio IVR Blog. Demonstrates how to create a run a simple IVR System.
get '/build' do
Step.create_tree
"DONE"
end
# We can use this to setup the database,
configure do
#Finalize and store our models.
DataMapper.finalize.auto_upgrade!
#Create some steps...
if Step.all.count == 0
Step.create_tree
end
end
DataMapper.setup(:default, ENV['DATABASE_URL'])
post '/fin' do
Metric.create(cid: params[:CallSid], state: params[:CallStatus])
end
get '/metric' do
@metrics = Metric.all
#erb :metric, :layout => :main_layout
end
require 'sinatra'
require 'data_mapper'
require 'twilio-ruby'
require './step'
require './metric'
#Simple Page to show all the steps.
get '/' do
@steps = Step.all
erb :index, :layout => :main_layout
end
post '/step' do
step = Step.first(:root => true)
Metric.create(cid: params[:CallSid], state: params[:CallStatus], step: step)
step.to_twiml
end
#Get and render a step...
post '/step/:id' do
step = Step.get(params[:id])
#If we are responding to a DTMF sequence, we can simply swap out the current step, and proceed as before.
if params[:Digits] != nil
#We swap the step if the user has entered a keypress.
step = step.children.find {|option| option[:gather] == params[:Digits] }.action
end
Metric.create(cid: params[:CallSid], state: params[:CallStatus], step: step)
content_type 'text/xml'
step.to_twiml
end
#Deletes everything to give a nice clean database...
get '/tank' do
Step.all.each{|step| step.destroy}
Metric.all.each{|metric| metric.destroy}
"DONE"
end
require './call_handler'
run Sinatra::Application
source 'http://rubygems.org'
ruby '1.9.3'
gem 'sinatra'
gem 'thin'
gem 'twilio-ruby'
gem 'pg'
gem 'data_mapper'
gem 'dm-postgres-adapter'
gem 'dm-timestamps'
<table>
<tr>
<th>ID</th>
<th>Say</th>
<th>Parent</th>
<th>Sequence</th>
<th>Gather</th>
<th>Action</th>
</tr>
<% @steps.each do |step| %>
<tr>
<td><%= step.id %></td>
<td><%= step.say %></td>
<td><%= step.parent.say if step.parent != nil %></td>
<td><%= step.sequence %></td>
<td><%= step.gather %></td>
<td><%= step.action.say if step.action != nil%></td>
<tr>
<% end %>
</table>
<!doctype html>
<html>
<head>
<title>Twilio Demo App</title>
</head>
<body>
<%= yield %>
</body>
</html>
<p>Total Calls: <%= @metrics.uniq{|metric| metric.cid}.count %></p>
<p>Total Completed Calls: <%= @metrics.select{|metric| metric.step != nil && metric.step.goal}.uniq{|metric| metric.cid}.count %></p>
#Just in case we reuse this elsewhere.
require 'data_mapper'
require './step'
#A model to hold the call tree.
class Metric
include DataMapper::Resource
property :id, Serial
property :cid, String
property :state, String
belongs_to :step, :required => false
end
#Just in case we reuse this elsewhere.
require 'data_mapper'
require 'twilio-ruby'
class Step
include DataMapper::Resource
property :id, Serial
property :say, String
property :sequence, Integer
property :gather, String
property :root, Boolean, :default => false
property :goal, Boolean, :default => true
belongs_to :parent, :model => Step, :required => false
has n, :children, :model => Step, :child_key => [ :parent_id ]
belongs_to :action, :model => Step, :required => false
end
def self.create_tree
# Create the first varaint of steps...
topStep = Step.create(say: "Thank you for calling Twil'lio Owl Sanctuary.", sequence: 0, gather: nil, root: true)
owl_count = Step.create(say: "Thank you. We have 3 Owls. Three.", sequence: 0, gather: nil, goal: true)
operator = Step.create(say: "This is a demo, we don't really have an operator.", sequence: 0, gather: nil, goal: true)
Step.create(say: "To hear how many Owls we have, press 1.", parent: topStep, sequence: 0, gather: "1", action: owl_count)
Step.create(say: "To speak to an operator, press 2.", parent: topStep, sequence: 1, gather: "2", action: operator,)
end
def to_twiml
#If an error occurs here, the exception will cause Twilio to read out the 'An Application Error has Occured' message.
twiml = Twilio::TwiML::Response.new do |r|
r.Say say, :language => "en-gb", :voice => "alice"
if children.count > 0
r.Gather action: "/step/#{id}" do |gather|
children.each do |options|
gather.Say options.say, :language => "en-gb", :voice => "alice"
end
end
else
r.Say "Goodbye.", :language => "en-gb", :voice => "alice"
r.Hangup
end
end
twiml.text
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment