Tropo is part of CiscoLearn More

Creating an internationalized Restaurants Finder application in minutes with Grails and Tropo

Posted on September 21, 2011 by mpermar

Grails Logo In a previous blog post I already showed how we could pretty quickly create applications in Grails with the Tropo Grails Plugin and host them in Cloud Foundry with almost no effort. In this blog post I’m going to show a more ellaborated example. But, hey! In Tropo and Grails ellaborated examples don’t take more than 100 lines of code 🙂

One of the advantages of Tropo against its competitors is speech recognition and several internationalization features. Tropo understands 24 languages, so I thought that it would be pretty cool to create an application to find restaurants in a non-English speaking country as most of our blog posts are commonly focused on English. To implement my restaurants finder application I used the 11870 API service which is a Spanish web service that gives you the names, phone numbers and reviews of many services across any city in Spain (pretty cool).

So whats the idea around this restaurant finder? Basically imagine that you are on holidays with your wife in a city that you don’t know. And back in the hotel you made a reservation to a nice restaurant. Then you go through the day to visit the city and when it is time to go to the restaurant you realize that you don’t know where it is. Damn, you forgot the map! You don’t have any tourist service nearby, locals don’t know the restaurant location and you don’t have internet connection or an smartphone at hand. And of course your wife is starving! What do you do? Your marriage and peaceful holidays are at risk! Hopefully my restaurants finder could help you here 🙂 Basically you dial a phone number, say the name of the city you are in, say the name of the restaurant and the application will tell you the phone number of the restaurant (it would be a one-liner change in the application to actually transfer your call to the restaurant’s phone).

But let’s look to some of the code. A first Grails action loads the name of all the cities with population bigger than 10.000. I’ve got a list from the Internet and just built a comma-separated list of cities. I use that list to create my choices statement that instructs Tropo to only accept one of those cities:


def index = {

    def citiesFile = applicationContext.getResource(
                            'classpath:cities.txt').file
    def citiesString = new String(IOUtils.toByteArray(
                            new FileInputStream(citiesFile)))
    def cities = citiesString.tokenize(',')

    def tropo = new TropoBuilder()
        tropo.tropo {
            say(value:"Bienvenido al servicio de información...", 
                  voice:"carmen")
            ask(name:'city',mode:"speech",
                         recognizer:"es-es", voice:"carmen") {
                say(value:"Diga el nombre de una ciudad")
                choices(value:citiesString)
            }
            on(event:'continue',next:'/tropo/restaurant')
        }
        tropo.render(response)	
}

That will prompt the user for the name of the city. Once the user says the name of a city a second Grails action will be triggered. In that action we call the 11870 API to fetch the list of available restaurants in that city. With that list I create another choices attribute that will instruct Tropo to only accept restaurants with a name in that list.

def restaurant = {

    def tropoRequest = request.JSON
    def place = tropoRequest.result.actions.value

    def map = restaurantMap(place)
    session["restaurants"] = map
    def restaurants = restaurantList(map)

    def tropo = new TropoBuilder()
    tropo.tropo {
        ask(name:'restaurante', mode:'speech', 
                      recognizer:'es-es', voice:'carmen') {
	    say(value:"Diganos el nombre de un restaurante en ${place}")
	    choices(value:restaurants)
	}
	on(event:'continue',next:'/tropo/info')
    }
    tropo.render(response)
}

In the code above, the method restaurantMap takes the name of the place and returns a map with all the restaurants in that place and their phone numbers. That map is stored in the HTTP session so later can be used to retrieve the phone number for the restaurant that the user has told. This is the actual code that invokes 11870 API and builds the map:

def restaurantMap(def place) {

    def query = "http://api.11870.com/api/v2/search?appToken=..."

    def feed = new XmlParser().parse(query)

    def restaurants = []
    def map=[:]
    feed.entry.each {
        restaurants << it.title.text()
        map.put(it.title.text(),it.'oos:telephone'.text())
    }
    map
}

Finally, once the user says the name of a restaurant, one last action will take the input and will use it to find the phone number of the restaurant:

def info = {

    def tropoRequest = request.JSON
    def restaurant = tropoRequest.result.actions.value

    def map = session["restaurants"]
    def phone = map.get(restaurant)

    def tropo = new TropoBuilder()
    tropo.tropo {
        say(value:"El teléfono de ${restaurant} es ${phone}...", 
              voice:"carmen")
        hangup()
    }
    tropo.render(response)		
}

That was pretty easy, wasn’t it? In very few lines of code we get a quite useful application. Provided you have an API to fetch restaurants from and a list of cities of a country then it would be fairly simple to add support for extra countries to this little example. There is many other things that could be done like handling nomatches and timeouts to make the application more reliable and user friendly, or dial the phone number of the restaurant and transfer the call. I hope you don’t mind if I leave these as exercises to the reader.

But wait, do you want to see the app in action? I’ve recorded a short video that goes through the source code and also shows the application working.

And that is it. I hope you liked it!

2 Responses

  1. […] Creating an internationalized Restaurants Finder application in minutes with Grails and Tropo […]

  2. […] Creating an internationalized Restaurants Finder application in minutes with Grails and Tropo […]

Leave a Reply