Formato de archivo .lg

SE APLICA A: SDK v4

En el archivo .lg se describen las plantillas de generación de lenguajes con referencias de entidad y su composición. En este artículo se tratan los diversos conceptos que se expresan con el formato de archivo .lg.

Caracteres especiales

Comentarios

Use > para crear un comentario. El analizador omitirá todas las líneas que tengan este prefijo.

> This is a comment.

Carácter de escape

Use \ como carácter de escape.

# TemplateName
- You can say cheese and tomato \[toppings are optional\]

Matrices y objetos

Creación de una matriz

Para crear una matriz, usa la sintaxis ${[object1, object2, ...]}. Por ejemplo, la expresión:

${['a', 'b', 'c']}

Devuelve una matriz ['a', 'b', 'c'].

Creación de un objeto 

Para crear un objeto, usa la sintaxis ${{key1:value1, key2:value2, ...}}. Por ejemplo, la expresión:

${{user: {name: "Wilson", age: 27}}}

Devuelve el siguiente objeto JSON:

{
  "user": {
    "name": "Wilson",
    "age": 27
  }
}

Templates (Plantillas [C++])

Las plantillas son el concepto principal del sistema de generación de lenguajes. Cada plantilla tiene un nombre y uno de los elementos siguientes:

  • una lista de valores de texto de variación one-of
  • una definición de contenido estructurada
  • una colección de condiciones, cada una con:

Nombres de plantilla

Los nombres de plantilla distinguen mayúsculas de minúsculas y solo pueden contener letras, caracteres de subrayado y números. A continuación, se muestra un ejemplo de una plantilla llamada TemplateName.

# TemplateName

Las plantillas no pueden empezar con un número y ninguna parte de un nombre de plantilla dividido por . no puede empezar con un número.

Variaciones de respuesta de plantilla

Las variaciones se expresan como una lista de Markdown. Puede colocar el carácter -, ' o + como prefijo de cada variación.

# Template1
- text variation 1
- text variation 2
- one
- two

# Template2
* text variation 1
* text variation 2

# Template3
+ one
+ two

Plantilla de respuesta simple

Una plantilla de respuesta simple incluye una o más variaciones de texto que se usan para la composición y la expansión. La biblioteca LG seleccionará una de las variaciones proporcionadas de forma aleatoria.

A continuación se muestra un ejemplo de una plantilla simple que incluye dos variaciones.

> Greeting template with two variations.
# GreetingPrefix
- Hi
- Hello

Plantilla de respuesta condicional

Las plantillas de respuesta condicional permiten crear contenido seleccionado en función de una condición. Todas las condiciones se expresan mediante expresiones adaptadas.

Importante

Las plantillas condicionales no se pueden anidar en una sola plantilla de respuesta condicional. Use la composición en una plantilla de respuesta estructurada para anidar condicionales.

Plantilla if-else

La plantilla if-else permite crear una plantilla que elija una colección en función de un orden de condiciones en cascada. La evaluación es de arriba abajo y se detiene cuando una condición se evalúa como true o se alcanza el bloque ELSE.

Las expresiones condicionales se incluyen entre llaves ${}. Este es un ejemplo en el que se muestra una definición de plantilla de respuesta condicional IF ELSE simple.

> time of day greeting reply template with conditions.
# timeOfDayGreeting
- IF: ${timeOfDay == 'morning'}
    - good morning
- ELSE:
    - good evening

Este es otro ejemplo en el que se muestra una definición de plantilla de respuesta condicional if-else. Tenga en cuenta que puede incluir referencias a otras plantillas de respuesta simple o condicional en la variación para cualquiera de las condiciones.

# timeOfDayGreeting
- IF: ${timeOfDay == 'morning'}
    - ${morningTemplate()}
- ELSEIF: ${timeOfDay == 'afternoon'}
    - ${afternoonTemplate()}
- ELSE:
    - I love the evenings! Just saying. ${eveningTemplate()}

Plantilla switch

La plantilla switch permite diseñar una plantilla que haga coincidir el valor de una expresión con una cláusula CASE y genera una salida basada en ese caso. Las expresiones de condición se incluyen entre llaves ${}.

A continuación se indica cómo puede especificar un bloque SWITCH CASE DEFAULT en LG.

# TestTemplate
- SWITCH: ${condition}
- CASE: ${case-expression-1}
    - output1
- CASE: ${case-expression-2}
    - output2
- DEFAULT:
   - final output

Este es un ejemplo de SWITCH CASE DEFAULT más complicado:

> Note: Any of the cases can include reference to one or more templates.
# greetInAWeek
- SWITCH: ${dayOfWeek(utcNow())}
- CASE: ${0}
    - Happy Sunday!
-CASE: ${6}
    - Happy Saturday!
-DEFAULT:
    - ${apology-phrase()}, ${defaultResponseTemplate()}

Nota:

Las plantillas switch, al igual que las plantillas condicionales, tampoco se pueden anidar.

Plantilla de respuesta estructurada

Las plantillas de respuesta estructurada permiten definir una estructura compleja que admita la funcionalidad principal de LG, como la creación de plantillas, la composición y la sustitución, a la vez que se deja la interpretación de la respuesta estructurada a criterio del autor de llamada de la biblioteca LG.

En el caso de las aplicaciones de bot, admitimos lo siguiente de forma nativa:

  • definición de la actividad
  • definición de la tarjeta

Lea acerca de las plantillas de respuesta de estructura para obtener más información.

Composición y expansión de plantillas

Referencias a plantillas

El texto de la variación puede incluir referencias a otra plantilla con nombre para ayudar con la composición y resolución de respuestas sofisticadas. Las referencias a otras plantillas con nombre se indican mediante llaves, como ${<TemplateName>()}.

> Example of a template that includes composition reference to another template.
# GreetingReply
- ${GreetingPrefix()}, ${timeOfDayGreeting()}

# GreetingPrefix
- Hi
- Hello

# timeOfDayGreeting
- IF: ${timeOfDay == 'morning'}
    - good morning
- ELSEIF: ${timeOfDay == 'afternoon'}
    - good afternoon
- ELSE:
    - good evening

Llamar a la plantilla GreetingReply puede dar lugar a una de las siguientes resoluciones de expansión:

Hi, good morning
Hi, good afternoon
Hi, good evening
Hello, good morning
Hello, good afternoon
Hello, good evening

Entities

Cuando se usan directamente en un texto de variación one-of, las referencias de entidad se indican incluyéndolas entre llaves, como $ {entityName}, o sin llaves cuando se usan como parámetro.

Las entidades se pueden usar como parámetro:

Usar funciones precompiladas en variaciones

Las funciones precompiladas compatibles con expresiones adaptadas también se pueden usar en línea en un texto de variación one-of para lograr una composición de texto aún más eficaz. Para usar una expresión en línea, basta con incluirla entre llaves.

# RecentTasks
- IF: ${count(recentTasks) == 1}
    - Your most recent task is ${recentTasks[0]}. You can let me know if you want to add or complete a task.
- ELSEIF: ${count(recentTasks) == 2}
    - Your most recent tasks are ${join(recentTasks, ', ', ' and ')}. You can let me know if you want to add or complete a task.
- ELSEIF: ${count(recentTasks) > 2}
    - Your most recent ${count(recentTasks)} tasks are ${join(recentTasks, ', ', ' and ')}. You can let me know if you want to add or complete a task.
- ELSE:
    - You don't have any tasks.

En el ejemplo anterior se usa la función precompilada join para mostrar todos los valores de la colección recentTasks.

Dado que las plantillas y funciones precompiladas comparten la misma firma de invocación, el nombre de una plantilla no puede ser el mismo que el de una función precompilada.

El nombre de una plantilla no debe coincidir con el de una función precompilada. La función precompilada tiene prioridad. Para evitar estos conflictos, puede anteponer lg. al hacer referencia al nombre de la plantilla. Por ejemplo:

> Custom length function with one parameter.
# length(a)
- This is use's customized length function

# myfunc1
> will call prebuilt function length, and return 2
- ${length('hi')}

# mufunc2
> this calls the lg template and output 'This is use's customized length function'
- ${lg.length('hi')}

Texto multilínea en variaciones

Cada variación one-of puede incluir texto multilínea entre comillas triples.

# MultiLineExample
    - ```This is a multiline list
        - one
        - two
        ```
    - ```This is a multiline variation
        - three
        - four
    ```

La variación multilínea puede solicitar la expansión de plantillas y la sustitución de entidades incluyendo la operación solicitada entre llaves, ${}.

# MultiLineExample
    - ```
        Here is what I have for the order
        - Title: ${reservation.title}
        - Location: ${reservation.location}
        - Date/ time: ${reservation.dateTimeReadBack}
    ```

Con la compatibilidad multilínea, puede hacer que el subsistema de generación de lenguajes resuelva por completo un JSON o XML complejo (como el texto ajustado SSML para controlar la respuesta oral del bot).

Parametrización de plantillas

Para ayudar con la reusabilidad contextual, las plantillas se pueden parametrizar. Los distintos autores de llamada a la plantilla pueden pasar valores diferentes para su uso en la resolución de expansión.

# timeOfDayGreetingTemplate (param1)
- IF: ${param1 == 'morning'}
    - good morning
- ELSEIF: ${param1 == 'afternoon'}
    - good afternoon
- ELSE:
    - good evening

# morningGreeting
- ${timeOfDayGreetingTemplate('morning')}

# timeOfDayGreeting
- ${timeOfDayGreetingTemplate(timeOfDay)}

Importar referencias externas

Puede dividir las plantillas de generación de lenguajes en archivos independientes y hacer referencia a una plantilla de un archivo en otro. Puede usar vínculos de estilo Markdown para importar plantillas definidas en otro archivo.

[Link description](filePathOrUri)

Se extraerán todas las plantillas definidas en el archivo de destino. Asegúrese de que los nombres de plantilla son únicos (o se les ha aplicado un espacio de nombres con # \<namespace>.\<templatename>) en los archivos en proceso de extracción.

[Shared](../shared/common.lg)

Funciones insertadas por LG

Las expresiones adaptadas proporcionan la capacidad de insertar un conjunto personalizado de funciones. Lea las funciones insertadas desde la biblioteca LG para obtener más información.

Opciones

Los desarrolladores puede establecer opciones del analizador para personalizar aún más la forma en que se evalúa la entrada. Use la notación > !# para establecer opciones del analizador.

Importante

La última configuración encontrada en el archivo altera cualquier configuración anterior que se encuentre en el mismo documento.

Opción strict

Los desarrolladores que no quieran permitir un resultado NULL para un resultado evaluado NULL pueden implementar la opción strict. Aquí tiene un ejemplo de una opción strict sencilla:

> !# @strict = true
# template
- hi

Si la opción strict está activada, los errores NULL producirán un mensaje descriptivo.

# welcome
- hi ${name}

Si el nombre es NULL, el diagnóstico sería 'name' evaluado como NULL. [welcome] Error al evaluar '- hi ${name}'.. Si strict se establece en false o no está establecido, se proporcionará un resultado compatible. En el ejemplo anterior se produciría hi null.

Opción replaceNull

Los desarrolladores pueden crear delegados para reemplazar valores NULL en expresiones evaluadas mediante la opción replaceNull:

> !# @replaceNull = ${path} is undefined

En el ejemplo anterior, la entrada NULL de la variable path se reemplazaría por ${path} is undefined. La entrada siguiente, donde user.name es NULL:

hi ${user.name}

Daría como resultado hi user.name is undefined.

Opción lineBreakStyle

Los desarrolladores pueden establecer opciones para la forma en que el sistema LG representa saltos de línea mediante la opción lineBreakStyle. Actualmente se admiten dos modos:

  • default: los saltos de línea en texto multilínea crean saltos de línea normales.
  • markdown: los saltos de línea en texto multilínea se convertirán automáticamente en dos líneas para crear una nueva línea.

En el ejemplo siguiente se muestra cómo establecer la opción lineBreakStyle en markdown:

> !# @lineBreakStyle = markdown

Opción de espacio de nombres

Puede registrar un espacio de nombres para las plantillas de LG que quiere exportar. Si no especifica ningún espacio de nombres, el espacio de nombres se establecerá en el nombre de archivo sin extensión.

En el ejemplo siguiente se muestra cómo establecer la opción de espacio de nombres en foo:

> !# @Namespace = foo

Opción Exports

Puede especificar una lista de plantillas de LG para exportar. Se puede llamar a las plantillas exportadas como funciones precompiladas.

En el ejemplo siguiente, se muestra cómo establecer la opción Exports en template1, template2:

> !# @Namespace = foo
> !# @Exports = template1, template2

# template1(a, b)
- ${a + b}

# template2(a, b)
- ${join(a, b)}

Use foo.template1(1,2), foo.template2(['a', 'b', 'c'], ',') para llamar a estas plantillas exportadas.

Ámbito de caché

Las opciones de ámbito de caché permiten controlar cuándo el evaluador lg vuelve a evaluar una expresión que ha visto antes y cuándo almacena y usa un resultado almacenado en caché.

  • La caché global es efectiva en el ciclo de vida de una evaluación. LG almacena en caché todos los resultados de evaluación y, si el nombre y los parámetros de la plantilla son los mismos, devuelve el resultado de la memoria caché.
  • El ámbito de caché local es el valor predeterminado. En la misma capa, si se ha llamado a la plantilla anterior con el mismo nombre de plantilla y los mismos parámetros, el resultado almacenado en caché se devuelve directamente.
  • Ningún ámbito de caché deshabilita todo el ámbito de caché y cada vez devuelve el nuevo resultado.

Para obtener ejemplos, consulta los ejemplos de ámbito de caché global y local.

> !# @cacheScope= global // global cache
> !# @cacheScope= local // local cache
> !# @cacheScope= none // none cache
> !# @cacheScope= xxx // fallback to local cache

Ten en cuenta que la opción de ámbito de caché no distingue mayúsculas de minúsculas.

> !# @cacheScope= global // ok
> !# @CACHESCOPE= global // ok
> !# @cachescope= global // ok

Ten en cuenta que el ámbito de caché sigue el ámbito del archivo .lg de Entrada de Microsoft.

Supongamos que tienes dos archivos: a.lg y b.lg, que se muestran a continuación:

a.lg

> !# @cacheScope= global
 [import](b.lg)

b.lg

> !# @cacheScope= none
# template1
- ${template2()} ${template2()}

# template2
- ${rand(1, 10000000)}

Si ejecutas el código siguiente, observarás que template2 usa el resultado almacenado en caché del primer resultado evaluado debido a la opción global de ámbito de caché en a.lg:

var templates = Templates.ParseFile("a.lg");
var result = templates.Evaluate("template1"); // the second "template2" would use the cache of the first evaluate result

Influencia de la marca de nueva ejecución

Si el nombre de la plantilla termina con "!", la plantilla fuerza la nueva ejecución. Este resultado no se agregará a la memoria caché independientemente del ámbito de la caché.

Supongamos que tienes la plantilla siguiente:

# template2
- ${template1()} ${template1!()} ${template1()}

template1!() se activa y el resultado se agrega a la memoria caché. El segundo template1() sobreescribe accidentalmente el resultado de la primera template1(). La llamada final usa los resultados almacenados en la memoria caché.

Ejemplo de ámbito de caché global

Supongamos que tienes la siguiente plantilla:

# template1
- ${template2()} ${template3()}

# template2
- ${rand(1, 10)}
- abc
- hi

# template3
- ${template2()}

template2 se evaluaría una vez y la segunda ejecución en template3 aplicaría la memoria caché de la primera.

Otro ejemplo es el siguiente fragmento de código:

var templates = Templates.ParseFile("xxx.lg");
var result1 = templates.Evaluate("template", null, new EvaluationOptions { CacheScope = LGCacheScope.Global});

// The second evaluation would drop all the results cached before.
var result2 = templates.Evaluate("template", null, new EvaluationOptions { CacheScope = LGCacheScope.Global});

Una plantilla se analiza mediante la función Templates.ParseFile() y los resultados de evaluación de la plantilla se almacenan en result1. Ten en cuenta que los segundos resultados de evaluación, result2, quitan todos los resultados previamente almacenados en caché.

Ejemplo de ámbito de caché local

Los ejemplos siguientes muestran cuándo funciona el ámbito de caché local y no funciona. Supongamos que t() y subT() son plantillas que toman un parámetro:

>  Cache works, the second template call would re-use the first's result.
# template1
- ${t(param)} ${t(param)}

> Cache doesn't work because param1's value is different with param2's. value)
# template2
- ${t(param1)} ${t(param2)}

> Cache doesn't work because of different layers.
# template3
- ${subT(param1)} ${t(param2)}

# subT(param)
- ${t(param)}

Recursos adicionales