Odelia>Technologiesbeta

La voix de Grails : créer une application VoiceXML avec Grails

| | | |

Saviez-vous que vous pouvez mettre vos connaissances en matière de développement web en pratique dans l'écriture d'une application vocale ?
Dans cet article, nous exploitons la puissance du framework Grails pour créer une application web capable de délivrer des documents VoiceXML de manière dynamique.
Inspiré de l'article XQuery and VoiceXML, notre application Grails a pour but de lire, par synthèse vocale, les premiers billets de l'agrégateur de contenu GroovyBlogs.org.

L'accès à l'application se faisant au travers d'un serveur vocal, celui-ci invoque à son tour le contenu dynamique de notre application au moyen d'une URL paramétrée, puis interprète le document VoiceXML ainsi reçu.

Hébergée chez Voxeo, notre application web de démonstration est en ligne sur GrailsBox, et gratuitement accessible par Skype à ce numéro : +99000936 9996076439.

Vous trouverez dans l'article Create VoiceXML pages within a Java Web developer framework la marche à suivre pour mettre en oeuvre une application vocale VoiceXML chez l'hébergeur Voxeo.

Dans le cadre du développement de votre propre application, vous pouvez dans un premier temps réaliser des tests sur des documents statiques VXML déployés sur votre compte Voxeo, pour en vérifier le bon fonctionnement, puis ensuite vous atteler à l'aspect génération dynamique dans votre application web.

Prompt avec un contrôleur et une vue Grails

Une des possibilités de génération d'un document VXML avec Grails est l'utilisation d'une vue .gsp ; dans l'exemple ci-dessous, nous générons un document qui permettra au serveur vocal de réaliser la synthèse vocale du texte transmis dans le paramètre prompt au travers de l'URL <url_base>/<controleur>/prompt?prompt=Hello world!

Nous avons donc une classe contrôleur possédant l'action prompt, dont le code est reproduit ci-dessous :

def prompt = {         
  if (!params.prompt) params.prompt = 'Hello world!'           
       
  render(view: 'prompt', contentType: 'text/xml', encoding: 'UTF-8')
}

La vue prompt.gsp utilisée ici par le framework permet de générer en sortie le document VXML :

<vxml version="2.1">
  <form>               
    <block>
      <prompt>${params.prompt}</prompt>
    </block>                   
  </form>
</vxml>

Le service de lecture de fils d'actualité

Revenons maintenant au sujet de notre application de démonstration, qui consiste à concevoir un service de lecture de fils d'actualité, ou flux RSS. Bien que proposant le choix entre deux fils d'actualité au travers d'un menu, le service que nous avons mis en ligne ne donnera lecture que des derniers billets du site web GroovyBlogs.org, par simplification.
Voyons comment le menu VoiceXML est mis en œuvre dans une vue Grails, ici listeflux.gsp :

<vxml version="2.1">
  <form id="fils">                 
    <field name="fil">
      <prompt>Welcome to the Feed Reader service.<break/></prompt>
      <prompt>Please, choose a topic. </prompt>   
      <prompt>For GroovyBlogs, press 1.</prompt>
      <prompt>For Java.net Articles, press 2.</prompt>
      <option dtmf="1">GroovyBlogs</option>
      <option dtmf="2">Java.net</option>
    </field>
    <filled>
      <prompt>Thank you - listing feeds in the <value expr="fil"/> topic.</prompt>
      <submit next="${createLink(action: 'lecture')}" namelist="fil"/>
    </filled>
  </form>
</vxml>

Le document VXML qui résultera de la génération de cette vue Grails, inclura un formulaire contenant un champ unique de nom fil. Lors de son interprétation, et à la lecture du texte compris dans les éléments prompt, l’utilisateur devra sélectionner le fil d’actualité de son choix, en appuyant sur la touche 1 ou la touche 2 de son téléphone.
Une fois le choix pris en compte par le serveur vocal, l'exécution se poursuivra dans l'élément filled, dans lequel le serveur rappellera le choix de l'utilisateur, puis soumettra ce choix à notre application web au travers d'une commande http ; tout comme une soumission de formulaire web classique, et en passant le paramètre fil avec sa valeur.

Remarquez que nous avons recours à createLink pour générer une URL correspondant à une action précise. Si l'utilisateur choisit par exemple l'option 1, la donnée du formulaire sera transmise via l'URL :

<url_base>/<controleur>/lecture?fil=GroovyBlogs

Ainsi, l'action lecture de notre contrôleur pourra générer le document VXML contenant les textes des derniers billets de GroovyBlogs.org.

Construction du modèle de données

La tâche principale de l'action lecture est de lire le flux RSS de GroovyBlogs.org, afin de constituer un modèle qui sera transmis à la vue lecture.gsp.
C'est là que la classe Groovy XmlSlurper nous est d'un grand secours ; le flux RSS est ici récupéré en une seule instruction :

def rss = new XmlSlurper().parse('http://feeds.feedburner.com/groovyblogs')

Vient ensuite l'appel à la méthode render qui termine l'implémentation de l'action lecture :

render(view: 'lecture', contentType: 'text/xml', encoding: 'UTF-8',
                        model : [items: rss.channel.item[0..4].collect {
                                [title: validerTexte(it.title.toString()),
                                 description: validerTexte(it.description.toString())] }])
 

Rien de bien complexe dans ce code, mais voici quelques explications : le modèle est une map Groovy contenant la clé items. Cette dernière a comme valeur une liste de maps dont chacun des éléments est une map contenant les clés title et description correspondant respectivement au titre et à la description d'une actualité donnée.
Le code Groovy rss.channel.item[0..4] permet de sélectionner les 5 actualités les plus récentes sous la forme d'une liste, tandis que la méthode collect, appliquée à celle-ci, permet de constituer la liste de maps discutée plus haut.

La méthode de contrôleur validerTexte dont nous n'avons pas encore parlé, permet de filtrer le texte qui sera repris dans la vue ; il faut en effet s'assurer que ce texte soit lisible par le navigateur vocal : notamment, le fil d'actualité GroovyBlogs.org utilise parfois des références d'entité XML tel que &amp;, le & commercial, ou encore &#nnnn; pour encoder un caractère unicode.
La méthode validerTexte renvoie donc un texte débarrassé de ces références d'entités en faisant usage des expressions régulières pour les retrouver et les remplacer par les caractères correspondants.

La vue lecture.gsp

Le code de la vue lecture.gsp est celui-ci, dans lequel nous réutilisons l'élément items du modèle qui est une collection reprenant les informations dont nous avons besoin :

<vxml version="2.1">
  <form id="billets">
    <g:each in="${items}" var="item">   
      <block>
        <prompt>${item.title}<break size="small"/>
          ${item.description}
          <break size="medium"/>
        </prompt>
      </block>     
    </g:each>
    <block>
      <goto next="${createLink(action: 'listeflux')}"/>
    </block>
  </form>
</vxml>
 

Après avoir lu les dernières actualités, le navigateur revient au menu de départ, conformément à la présence de l'élément goto apparaissant dans la vue lecture.gsp.

Synthèse et reconnaissance vocale multilingue

Dans un document VXML, il est possible d'indiquer la langue dans laquelle le serveur vocal doit interpréter le document, au travers de l'utilisation de l'attribut xml:lang soit dans l'élément vxml ou bien dans l'élément prompt. Par exemple :

<vxml version="2.1" xml:lang="fr-FR">

Le compte Voxeo de développeur utilisé avec notre application Grails de démonstration en ligne permet normalement une prise en charge de la langue française ; toutefois nous n'avons pas encore ajouté un fil d'actualité qui serait lu en français par synthèse vocale, du fait d'un problème technique sur la plateforme de l'hébergeur, en relation avec Skype, à l'heure où nous écrivons ces lignes.

Nous espérons bientôt pouvoir le démontrer !

balises dans Langages et systèmes

AJAX cajo Camel DSL Grails Groovy Java JBI prefuse RSS ServiceMix SOA