Templates

Essa seção apresenta as informações básicas de como utilizar templates com o Texto Fala em uma aplicação. Detalhes sobre as classes da API pública em C/C++ podem ser consultados acessando a seção Interface de Programação e a em Java na seção Interface de Programação.

O que é um template

No nosso contexto, consideramos um template um padrão de texto, utilizado por aplicações, nas quais há pequenas variações em alguns trechos, como nomes, endereços, por exemplo.

Para que a aplicação não precise sempre enviar esse mesmo padrão, com pequenas variações, foi criado um mecanismo de template estendendo o SSML. Essa extensão consiste em adicionar tags especiais no SSML, cujo conteúdo são instruções em linguagem de programação. Através dessa tag especial é possível introduzir lógica de programação que afeta a saída SSML gerada, bem como introduzir o uso de variáveis.

O preenchimento do template requer um conjunto de dados de entrada, que serão fornecidos através de mensagens. Uma mensagem é um documento em JSON contendo conjuntos de pares chave-valor. Uma única mensagem pode fazer uso de vários templates.

As mensagens contém apenas os dados a serem utilizados no template. Definições sobre como as informações devem ser verbalizadas estão contidas no template (e.g. através da tag say-as).

Com o template preenchido e as variáveis definidas, o API pública do Texto Fala irá processar essas informações e gerar um SSML que deverá ser utilizado na síntese.

Linguagem do template

A linguagem que descreve os templates é uma extensão do SSML. Nessa extensão é introduzida uma tag especial, delimitada por <% e %>, na qual é possível implementar lógica através de uma linguagem de programação simples. Todo conteúdo que esteja fora dessas tags será considerado como conteúdo SSML e será emitido sem qualquer alteração.

O template inicia na abertura da tag speak e é finalizado no fechamento desta tag. Se houver mais de uma tag speak definida, um erro será retornado.

Exemplo

<speak>
  <% if (name not empty) then %>
      Olá <%= Name %>
  <% else %>
      Olá cliente <% emptyName = true %>
  <% end %>
</speak>

O nome do template pode ser indicado de duas formas:

  • Parâmetro específico na API do TTS ou

  • Nome do arquivo em disco.

Mais detalhes podem ser consultados na seção API do Texto Fala.

Variáveis

O script do template utiliza tipagem forte (cada variável tem um tipo definido) e dinâmica (os tipos são definidos durante a execução). As variáveis são declaradas implicitamente na primeira atribuição, o que também define seu tipo. A partir do momento, em que uma variável foi declarada, seu tipo não pode ser alterado.

Variáveis possuem o escopo global, seu nome é sensível à caixa e deve ser composto por uma letra seguida de letras, números ou sublinhas.

Os tipos válidos são:

  • Lógico (booleano): true ou false;

  • Numérico: qualquer valor numérico decimal, inteiro ou ponto-flutuante;

  • Textual: sequência de caracteres entre aspas duplas.

Exemplo

<%
        // cria a variável do tipo booleana
        skipOrderInfo = true
        // cria uma string
        name = "Sebastiano"
        // variáveis não podem mudar de tipo
        name = 56.33   // ERRO!
        print(name)
%>

Campos

Os campos tem um funcionamento similar ao das variáveis, porém seus valores não podem ser alterados.

Exemplo

Supondo a mensagem:

[
        {
           "template": "modelo1",
           "fields": [
              {"id": "Nome", "value": "Sebastiano"}
           ]
        }
]

Um template poderia conter:

<%
        print(Nome)  // imprime 'Sebastiano'
        value = Nome // cria variável com o conteúdo de Nome
        print(value) // imprime 'Sebastiano'
%>

Operadores

Os operadores têm um funcionamento similar aos operadores de linguagens de programação. E foram limitados conforme abaixo.

Operadores condicionais:

  • not: operador de negação que deve ser utilizado entre parênteses

  • !=

  • ==

  • >=

  • <=

  • >

  • <

  • empty: operador utilizado em conjunto com o operador not. Exemplo: not empty

  • exist: operador que verifica se um campo existe. Ele deve ser utilizado entre parênteses

  • and

  • or

Operadores aritméticos:

  • +

  • -

  • *

  • /

Operadores de atribuição:

  • =

  • +=

Exemplo

Supondo a mensagem:

[
{
   "template": "modelo1",
   "fields": [
      {"id": "Nome", "value": "Sebastiano"}
   ]
}
]

Um template poderia conter:

<%
        print(Nome)  // imprime 'Sebastiano'
        value = Nome + "Silva" // variável = Sebastiano Silvia
        print(value) // imprime 'Sebastiano Silvia'
%>

Função print

Existe apenas a função print no template que insere na saída exatamente o texto definido. O parâmetro da função aceita qualquer tipo: string, numérico, booleano, variáveis e campos.

Exemplo

// insere o texto “Número bê á: <say-as interpret-as='spell'>” na saida
print("Número bê á: <say-as interpret-as='spell'>")

Callback

Em determinados momentos, o usuário pode invocar uma função interna da sua aplicação que retorna uma string tratada de uma maneira diferente. Essa chamada pode ser feita via callback definida da seguinte maneira:

<say-as interpret-as = "none" callback="<nome da função>"> texto </say-as>

Exemplo

<say-as interpret-as = "none" callback="trataTelefone"> 1937055828 </say-as>

A chamada da função trataTelefone, irá tratar o texto 1937055828 e irá retornar um texto alterado de acordo com a função da aplicação.

Spell

Para utilizar a normalização do spell juntamente com uma callback, o usuário pode utilizar o atributo spell na tag say-as em conjunto com o atributo callback.

Ao utilizar em conjunto, primeiramente o processamento da callback é realizado e no texto retornado será aplicado o spell, de acordo com a opção escolhida(soletrar tudo, somente números ou somente as letras).

Exemplo

<say-as interpret-as="spell" format="number" callback="TrataBA">
        <%= NumeroBA %>
</say-as>

Soletra os números após a formatação do campo NumeroBA chamado na callback TrataBA.

Construção condicional

Permite executar uma ou mais construções mediante uma condição. Deve possuir uma cláusula if e opcionalmente as cláusulas elseif e else.

<% if ( <expressão> ) then %>
   ...
<% elseif ( <expressão> ) then %>
  ...
<% else %>
   ...
<% end %>

Exemplo

<% // verifica se a variável "NumeroBA" não é vazia
   if (NumeroBA not empty) then %>
        Número bê á: <say-as interpret-as="spell"> <%= NumeroBA %>
        </say-as> <break time="1000ms"/>
<% else %>
      Número bê á não fornecido <% skipOrderInfo = true %>
<% end %>

Comentário

Comentários são permitidos no template, através do marcador <!--    > ou dentro do código com o marcador //. Não será permitido comentário dentro do marcador <%=.

Exemplo

<!-- análise do count  -->
<% //condicional que verifica se o contador não é vazio
if (count != 0) then %>
...

Exemplo de template

<speak>
        O cliente possui <%= NUMERO_PROJETOS %> ativos. Com as seguintes descrições:
        <% if (ID_PROJETO != "") then %>
                Número do projeto: <say-as interpret-as="none" callback="TrataProjeto"> <%= ID_PROJETO_CRE %> </say-as>. <break time="1000ms"/>
        <% end %>
        <% if (NUMERO_TELEFONE != "") then %>
                Número do telefone: <say-as interpret-as="spell"> <%= NUMERO_TELEFONE %> </say-as>. <break time="1000ms"/>
        <% end %>
        <% if (exist(TIPO_LOGRAD) and (TIPO_LOGRAD == "AV")) then %>
                Endereço: Avenida <break time="500ms"/>
        <% elseif (exist(TIPO_LOGRAD) and (TIPO_LOGRAD == "R")) then %>
                Endereço: Rua <break time="500ms"/>
        <% elseif (((exist(TIPO_LOGRAD) and (TIPO_LOGRAD != "AV")) and (exist(TIPO_LOGRAD) and (TIPO_LOGRAD != "R"))) and (exist(TIPO_LOGRAD) and (TIPO_LOGRAD != ""))) then %>
                Endereço:  <%= TIPO_LOGRAD_ATENDIMENTO %>  <break time="500ms"/>
        <% end %>
        ...
</speak>

Mensagem

O preenchimento do template requer um conjunto de dados de entrada, que serão fornecidos através de mensagens. Uma mensagem é um documento JSON contendo conjuntos de pares chave-valor. Uma única mensagem pode fazer uso de vários templates.

As mensagens contém apenas os dados a serem utilizados no template. Definições sobre como as informações devem ser verbalizadas estão contidas no template (e.g. através da tag say-as).

Definindo uma mensagem

A mensagem é composta pelo nome do template e por campos.

Uma única mensagem pode fazer uso de vários templates criando diferentes grupos.

O nome do template é o identificador do template carregado na biblioteca Texto Fala.

Os campos são definidos com elementos fields. Obrigatoriamente, é preciso informar os atributos id e value, que indicam o nome e o valor do campo, respectivamente. Existe ainda o atributo opcional type que permite definir o tipo de dado utilizado como valor: number, string ou boolean. Por padrão todos os valores são considerados como sendo do tipo string. Definir o tipo de dado do valor possibilita fazer comparações utilizando o tipo adequado (e.g. informar que o campo é numérico para poder utilizar os operadores < e > em comparações).

Os nomes dos campos e templates seguem as mesmas regras definidas para nomes de variáveis.

A saída SSML gerada para uma mensagem consiste no processamento dos grupos, na ordem em que aparecem. Para cada grupo na mensagem, o mecanismo irá processar o template especificado com os campos definidos no grupo. O SSML resultante é a concatenação dos resultados parciais para cada grupo. É importante destacar que a ordem dos campos dentro de um grupo é irrelevante para o processamento de um template (a ordem segue o preenchimento do template), porém a ordem dos grupos vai determinar a ordem na qual os templates serão processados para gerar a saída.

Exemplo

[
{
   "template": "Template1",
   "fields": [
      {"id": "ID_PROJETO", "value": "124310452202068"},
      {"id": "NUMERO_TELEFONE", "value": "36985257", "type": "number"}
   ]
},
{
   "template": "Template2",
   "fields": [
      {"id": "Nome", "value": "Sebastiano"},
      {"id": "Endereco", "value": "R. Alberto Sapo, 99, Campinas"}
   ]
}
]

Exemplo de uso

Após os conceitos apresentados acima, iremos exemplificar passo a passo a utilização do template.

  • Utilizando template sem callback:

    1. Criar um template: Arquivo de teste Template1.txt

      <speak>
              O cliente possui <%= NUMERO_PROJETOS %> ativos. Com as seguintes descrições:
              <% if (ID_PROJETO != "") then %>
                      Número do projeto: <say-as interpret-as="spell" format="number"> <%= ID_PROJETO_CRE %> </say-as>. <break time="1000ms"/>
              <% end %>
              <% if (NUMERO_TELEFONE != "") then %>
                      Número do telefone: <say-as interpret-as="spell"> <%= NUMERO_TELEFONE %> </say-as>. <break time="1000ms"/>
              <% end %>
      </speak>
      
    2. Criar uma mensagem: Arquivo de teste mensagem.txt

      [
      {
         "template": "Template1",
         "fields": [
            {"id": "ID_PROJETO", "value": "124310452202068"},
            {"id": "NUMERO_TELEFONE", "value": "36985257", "type": "number"}
         ]
      }
      
    3. Carregar um template:

      Load em C

      TTS_LoadTemplate("Template1.txt");
      

      Load em Java

      engine.loadTemplate("Template1.txt");
      
    4. Processar uma mensagem:

      ProcessMessage em C

      string message = main_loadInputFile("message.txt");
      TTS_ProcessMessage(message.c_str(), TEMPLATE_MESSAGE_DONT_CHECK, &output);
      

      ProcessMessage em Java

      String message = loadInputFile("message.txt");
      String ssml = engine.processMessage(message, 0);
      
    5. Passo opcional: validar o resultado do processamento da mensagem.

      ValidateSSML em C

      TTS_ValidateSSML(output);
      

      validateSSML em Java

      engine.validateSSML(ssml);
      
    6. Utilizar o texto da mensagem processada:

      TextToSpeech em C

      TTS_TextToSpeech(handle, output);
      

      textToSpeech em Java

      session.textToSpeech(ssml);
      
    7. Descarregar um template:

      UnloadTemplate em C

      TTS_UnloadTemplate("Template1.txt");
      

      unloadTemplate em Java

      engine.unloadTemplate("Template1.txt");
      
  • Utilizando template com callback:

    1. Criar um template com callback: Arquivo de teste Template2.txt

      <speak>
              O cliente possui <%= NUMERO_PROJETOS %> ativos. Com as seguintes descrições:
              <% if (ID_PROJETO != "") then %>
                      Número do projeto: <say-as interpret-as="none" callback="TrataProjeto"> <%= ID_PROJETO_CRE %> </say-as>. <break time="1000ms"/>
              <% end %>
              <% if (NUMERO_TELEFONE != "") then %>
                      Número do telefone: <say-as interpret-as="spell"> <%= NUMERO_TELEFONE %> </say-as>. <break time="1000ms"/>
              <% end %>
      </speak>
      
    2. Criar uma mensagem: Arquivo de teste mensagem.txt

      [
      {
         "template": "Template2",
         "fields": [
            {"id": "ID_PROJETO", "value": "148596"},
            {"id": "NUMERO_TELEFONE", "value": "35896652", "type": "number"}
         ]
      }
      
    3. Criar uma callback:

      RegisterInterpretation em C

      void userCallback( void* context, const char *input, TTS_INTERPRET_OUTPUT_CALLBACK *output, void *data )
      {
              string out = input;
              out += " esse texto";
          output(context, out.c_str());
      }
      

      callback em Java

      public static class MyCallback extends InterpretedListener
      {
              MyCallback(boolean normalize, Object data) {
                      super("TrataProjeto", normalize, data);
              }
      
      
              @Override
              public String callback(String input, Object data) {
                      return input + " meu teste";
              }
      }
      
    4. Registrar uma callback:

      RegisterInterpretation em C

      TTS_RegisterInterpretation("TrataProjeto", userCallback, NULL, true);
      

      registerInterpretation em Java

      MyCallback myCallback = new MyCallback(true, null);
      engine.registerInterpretation( myCallback);
      
    5. Carregar um template:

      LoadTemplate em C

      TTS_LoadTemplate("Template2.txt");
      

      loadTemplate em Java

      engine.loadTemplate("Template2.txt");
      
    6. Processar uma mensagem:

      ProcessMessage em C

      string message = main_loadInputFile("message.txt");
      TTS_ProcessMessage(message.c_str(), TEMPLATE_MESSAGE_DONT_CHECK, &output);
      

      processMessage em Java

      String message = loadInputFile("message.txt");
      String ssml = engine.processMessage(message, 0);
      
    7. Passo opcional: validar o resultado do processamento da mensagem.

      ValidateSSML em C

      TTS_ValidateSSML(output);
      

      validateSSML em Java

      engine.validateSSML(ssml);
      
    8. Utilizar o texto da mensagem processada:

      TextToSpeech em C

      TTS_TextToSpeech(handle, output);
      

      textToSpeech em Java

      session.textToSpeech(ssml);
      
    9. Descarregar um template:

      UnloadTemplate em C

      TTS_UnloadTemplate("Template2.txt");
      

      unloadTemplate em Java

      engine.unloadTemplate("Template2.txt");
      

Nota

Os exemplos completos do uso do template estão disponíveis no GitHub em C (https://github.com/CPqD/tts-examples-c) e Java (https://github.com/CPqD/tts-sdk-java.)