Search code examples
javavoicexmlrivr

How to specify language in addPrompt() in Rivr Java VoiceXML library


My VoiceXML provider, Nexmo, seems not to handle the xml:lang="es-ES" attribute in the root vxml (This is generated by Rivr with a context.setLanguage("es-ES") in my Dialog)

I want Nexmo to use a spanish TTS engine but as I am using Rivr, I can't see where I can specify that I want the "prompt" to include, for example, xml:lang="es-es-female", so it generates VoiceXML:

<prompt xml:lang="es-es-female">
Hola.
</prompt>

interaction().addPrompt() only accepts the SpeechSynthesis object which does not allow (as far as I see) language options.

I've also tried include SSML in the SpeechSynthesis object (using a DocumentFragment as I see in Rivr Javadoc) but that won't work. Probably Nexmo does not support SSML.

Any workarounds? (A part from changing to a better VoiceXML provider) Thanks a lot!!!


Solution

  • If you only want to play a message without getting input from the user, use can use the Message class:

    //Play a synthesis message in another language
    Message message = new Message("synthesis-french-message",
                          new SpeechSynthesis("Ceci est un message."));
    
    message.setLanguage("fr-CA");
    DialogueUtils.doTurn(message, context);
    

    If you need to specify the language for a prompt in an Interaction, this can be done with the InteractionBuilder. The setLanguage() method can be used before the addPrompt() method. Multiple languages can be used within the same interaction:

    Interaction interaction = OutputTurns.interaction("multilingual-interaction")
            .setLanguage("es-ES")
            .addPrompt(new SpeechSynthesis("Holá."))
            .setLanguage("fr-CA")
            .addPrompt(new SpeechSynthesis("Bonjour."))
            .build(new SpeechRecognition(new GrammarReference("grammar.grxml")),
                   Duration.seconds(2));
    
    DialogueUtils.doTurn(interaction, context);
    

    If you don't want to use the builder, you can do it by hand but it's much longer:

    List<Interaction.Prompt> prompts = new ArrayList<Interaction.Prompt>();
    
    Interaction.Prompt spanishPrompt = new Interaction.Prompt(new SpeechSynthesis("Holá."));
    spanishPrompt.setLanguage("es-ES");
    prompts.add(spanishPrompt);
    
    Interaction.Prompt frenchPrompt = new Interaction.Prompt(new SpeechSynthesis("Bonjour."));
    frenchPrompt.setLanguage("fr-CA");
    prompts.add(frenchPrompt);
    
    SpeechRecognition speechRecognition = new SpeechRecognition(new GrammarReference("grammar.grxml"));
    
    FinalRecognitionWindow finalRecognitionWindow = new FinalRecognitionWindow(speechRecognition,
                                                                               Duration.seconds(2));
    Interaction interaction2 = new Interaction("multilingual-interaction2",
                                               prompts,
                                               finalRecognitionWindow);
    
    DialogueUtils.doTurn(interaction2, context);
    

    The output VoiceXML is:

    <?xml version="1.0" encoding="UTF-8"?>
    <vxml application="/rivr-cookbook-message-language/dialogue/root/efe10575-1766-48fb-9e13-572a771bc5f4" version="2.1"
      xmlns="http://www.w3.org/2001/vxml">
      <script>application.rivr.localErrorHandling = false; application.rivr.inputTurn = {};</script>
      <form id="form">
        <block name="prompt0">
          <prompt bargein="false" xml:lang="es-ES">Holá.</prompt>
        </block>
        <block name="prompt1">
          <prompt bargein="false" xml:lang="fr-CA">Bonjour.</prompt>
        </block>
        <field name="recognition">
          <grammar mode="voice" src="grammar.grxml" />
          <property name="timeout" value="2000ms" />
        </field>
        <filled mode="any">
          <script>application.rivr.addRecognitionResult()</script>
          <goto next="#submitForm" />
        </filled>
      </form>
      <catch>
        <if cond="_event.substring(0, 5) == &quot;error&quot;">
          <if cond="application.rivr.localErrorHandling">
            <goto next="#fatalErrorForm" />
            <else />
            <script>application.rivr.localErrorHandling=true</script>
          </if>
        </if>
        <script>application.rivr.addEventResult(_event, _message)</script>
        <goto next="#submitForm" />
      </catch>
      <form id="fatalErrorForm">
        <block>
          <exit />
        </block>
      </form>
      <form id="submitForm">
        <block>
          <var expr="application.rivr.toJson(application.rivr.inputTurn)" name="inputTurn" />
          <if cond="application.rivr.hasRecording(application.rivr.inputTurn)">
            <var expr="application.rivr.inputTurn.recordingMetaData.data" name="recording" />
            <assign expr="undefined" name="application.rivr.inputTurn.recordingMetaData.data" />
            <submit enctype="multipart/form-data" method="post" namelist="inputTurn recording"
              next="/rivr-cookbook-message-language/dialogue/efe10575-1766-48fb-9e13-572a771bc5f4/0/multilingual-interaction2" />
            <else />
            <submit method="post" namelist="inputTurn"
              next="/rivr-cookbook-message-language/dialogue/efe10575-1766-48fb-9e13-572a771bc5f4/0/multilingual-interaction2" />
          </if>
        </block>
      </form>
    </vxml>