This tutorial will show how to make a text-to-speech voice application using Hanami, the Vonage Ruby SDK, and the Voice API. This tutorial will require creating a Vonage application with voice capabilities.
You can also find the code and the fully working app shown in this tutorial on GitHub.
- Vonage Voice application
- Vonage provisioned phone number
- Ruby and Hanami installed on your machine
Hanami is a fully-featured Ruby web framework. It offers an alternative to Ruby on Rails that is more lightweight and consumes less memory. It is based on the same MVC (models, views, and controllers) methodology as Rails. One of its key design differences is that it breaks functionality down to its smallest possible part. As a result, a Hanami web app might have more files to accomplish the same thing a Rails web app does, but each file is responsible for as little as possible. This makes bug tracking, feature adding, and refactoring more streamlined.
It is not uncommon to find extensive models and controllers in a Ruby on Rails application. Often, a lot of that code is rearchitected to a services area or helper classes. However, in a Hanami application, because of its overall design, it is quite hard to end up filling a single model or a single controller with so much code that it becomes unwieldy.
This tutorial requires a Vonage API account. If you do not have one already, you can sign up and start building with free credit today. After creating an account, you will find your API key and secret at the top of the Vonage Dashboard.
We will need a Vonage virtual provisioned phone number for this tutorial as well. To acquire one, go to Numbers > Buy Numbers and search for a phone number capable of voice calls in the country code that is suitable for you.
To create a web application that utilizes the Vonage Voice API, we will need to create a Vonage Voice Application in the Dashboard. Navigate to Your Applications from the menu in the side nav. Generate a new application with any name you choose and then select "Generate public and private key". This will download the
private.key file to your computer. Once we begin creating our Hanami application, we will move that file to its root folder.
Make sure to turn on the "Voice" capability under Capabilities when creating the application. Once you are done, click Save. If you forget to click Save, then the public and private key information will not persist in the Vonage application, and you will need to generate a new public and private key pair all over again.
Voice applications in Vonage require externally accessible webhook addresses to be provided for data from the Vonage Voice API. In this tutorial, we are not going to do anything with this data. Still, it is good practice in production environments when working with webhooks to, at the very least, acknowledge the information being sent from the API. You can use ngrok to make your local development environment externally accessible when creating or working on an application. If you have never used ngrok before, you can follow this tutorial for instructions on how to set it up and use it in your Vonage application.
After you finish creating the Voice application in the Dashboard, you will have an application ID. This will be important in our app, so make a note of it.
Now that we have a Vonage Voice application and a Vonage virtual number, we are ready to build our app!
The first step in our new application is to initialize it. From the command line run:
$ hanami new voice_app --database=postgres
This will create a new directory called
voice_app from where we executed this command with the scaffolding of a web app using PostgreSQL for the database. Go ahead and change into that directory and open it up with your preferred code editor.
We can now start writing the code for our text-to-speech application.
The first task we want to do is to add the Vonage Ruby SDK as a gem dependency to the
Open up the
Gemfile from the root folder and add
gem 'vonage' to it. Once you have done so, you can run
bundle install from the command line.
To instantiate an authenticated Vonage SDK client capable of making voice calls, we need to provide some Vonage API credentials. The
private.key file you downloaded from the Vonage Dashboard can now be moved to the root folder of your Hanami app. We also need to provide our Vonage application ID, and we will also use this moment to add our Vonage phone number. If one does not yet exist, create a
.env file in the root folder, or open up the current one, and add the following:
VONAGE_APPLICATION_ID=Your Vonage Application ID Goes Here
VONAGE_NUMBER=Your Vonage Number Goes Here
You need to replace the text after each equal sign with the required value. You can keep the value for the
VONAGE_PRIVATE_KEY as that is accurately pointing to your private key file.
At this point, we are going to ready our database for the application. We will use the database to persist a list of language options for our text-to-speech application. Users will be able to pick any one of the available languages in the database to create a message to send via a phone call.
We will generate a new model that will hold the information for our languages. Within Hanami, the logic for a database model is stored in an
entity, and the data is stored in a
entity is decoupled from the database, whereas the
repository is the data level itself.
To generate our language model, we can use the Hanami generator again by running
bundle exec hanami generate model language.
This will create a new entity in
language.rb, a new repository in
language_repository.rb and a new database migration in
db/migrations. The migration file will start with a timestamp and end with
create_languages.rb. The generator builds a few spec files for us, too.
We need to open up the migration file and edit it to include columns for the language name and the language IETF BCP-47 code designation.
The migration file will look like this when you open it up initially:
create_table :languages do
column :created_at, DateTime, null: false
column :updated_at, DateTime, null: false
primary_key :id line, add the code to create two new columns of data:
column :name, String, null: false
column :code, String, null: false
You can save the file and then run the following command to create our database with the languages table and its columns we added:
$ bundle exec hanami db prepare
Lastly, let's add some languages to our database. The fastest way for us to do this now is to drop into the Hanami console from the terminal and add a few. You can choose from the list of available languages on the Vonage API Developer Portal or use the ones in the sample code below. First, to enter the console, run
bundle exec hanami console from the command line. Then, to create the data, run the following code, either using the sample languages in the code snippet below or changing them from the ones you chose:
>> repository = LanguageRepository.new
>> repository.create(language: 'English', code: 'en-US')
>> repository.create(language: 'Danish', code: 'da-DK')
>> repository.create(language: 'Tamil', code: 'ta-IN')
We now have a database of languages created in our new application and are ready to proceed to the next step, generating the views.
For this tutorial, we will build actions structured on the
home folder that Hanami ships with to keep our code uncomplicated. As such, for our first action, which corresponds to our root
/ path, we will use the Hanami generator from the command line to create an
index action. This will create a controller for the
index view and the HTML template for it inside
Additionally, this generator will also automatically add a route for us inside
get '/', to: 'home#index'.
We run the following to create the above:
bundle exec hanami generate action web home#index.
We're going to use this moment to generate the other actions we need for our application. In short, we require the following:
POSTaction for the form users will submit with their phone call information
create: The action to create a new text-to-speech call with the form data
success: The action that'll display the view after initializing the call
To create these, go ahead and run the following. Each one is split into a separate line for clarity sake:
$ bundle exec hanami generate action web home#new
$ bundle exec hanami generate action web home#create
$ bundle exec hanami generate action web home#success
Each of the above generator actions created its controller and template folder structure, just like the first
We will add HTML for two views for our application. The first view will be the root
index view, and the second will be the
success view after the form submission.
Open up the
/apps/web/templates/home/index.html.erb file and add the following:
<h1>Text-to-Speech Calls on Hanami</h1>
<p>Let's make a phone call!</p>
<form action="/create" method="post">
<label for="number">Enter a recipient number:</label>
<input type="text" id="number" name="number">
<label for="language">Choose a language:</label>
<select id="language" name="language">
<% languages.each do |voice| %>
<option value=<%= language.code %>><%= language.name %></option>
<% end %>
<label for="message">Enter a message:</label>
<textarea id="message" name="message" col="10">
<input type="submit" value="Submit">
index view contains a small HTML form that holds three inputs and a submit button. The first input is the number the user wants to dial. The second input is the language selection. Lastly, the third input is the message to be delivered in the call.
The language dropdown selection in the second input is generated from the languages in our language repository. However, you will notice that they are accessed via a local variable
voices in the view. Where did that variable come from? We'll make that variable accessible in our next step of this tutorial.
Now, let's add the
success view. Open up
/apps/web/templates/home/success.html.erb and add the following:
<p>Congrats, you sent your message!</p>
<p>Care to <a href="/">try again?</a>
This view contains a congratulations message on completing the call and an invitation to try again.
Let's add the logic to our controllers to make the
voices local variable work in the view and perform the phone call.
As we mentioned in the step before this one, we need to provide the variable's context in the
index view. Otherwise, our application will see it as undefined. We do that by defining an instance variable definition in the
index controller inside
apps/web/controllers/home/index.rb. Two steps are required. First, we need to expose the data to the controller. Hanami does not assume every controller needs access to every data store, so it requires you to be intentional about what data a controller can access. Second, we need to instantiate a variable in the
#call method with the data.
This is what the
index controller looks like:
include Web::Action line, add another line with
expose :languages. This will make the languages database table available to our controller. Then, inside the
#call action, add the following:
@languages = LanguageRepository.new.all to pass all the languages inside the repository to the
Now, let's go ahead and incorporate the Vonage Ruby SDK into the
create controller. We will instantiate a credentialed instance of the SDK and use it to generate the phone call with the user's text sent in the call via text-to-speech. You can add the following to your
client = Vonage::Client.new(
response = client.voice.create(
On the first line in the code snippet, we
require the Vonage Ruby SDK. Then, inside the
#call method, we create our client and then use the SDK's
voice#create instance method to send the call. The
voice#create method follows the API specification for the Voice API in the required and optional parameters that it accepts. At a minimum, the method requires:
toparameter: An array holding a hash with
fromparameter: A hash with two keys of
nccoparameter: An array with a hash that contains the instructions sent to the Voice API.
You are now ready to run your application! To start your Hanami web app, run the following command from your terminal:
$ bundle exec hanami server
The above command will start a web server on port 2300. You can now use your web browser to navigate to
http://localhost:2300. You will see the form you created to send text-to-speech over a phone call. Go ahead and fill it out, perhaps using your phone number as the recipient number. Once you press "Submit," you should receive the call with your message, and your browser should be redirected to the
Congrats! You built a fully functioning voice application using the text-to-speech feature of the Vonage Voice API with Hanami.
Now that you have begun to experiment with the possibilities of what you can do with the Vonage Voice API, there is so much more to discover. The following resources can be a good place to continue your journey: