Attached scripts
Attached scripts are Groovy scripts that are attached to a syntax condition or a part of a syntax condition. There are two types of attached scripts in Teneo: Propagation scripts and Predicate scripts. The former may be used to access and extract information from the user input, while the latter are used to impose further restrictions on the matching.
Propagation scripts
With an attached script, you can determine exactly what information should be extracted. For example, you can access the 'used words' of a matching condition part or entity variables from matched entities. Moreover, attached scripts allow you to reliably recognize multiple entities of the same type within the same input. This makes your syntax condition very flexible.
Attachment
Attached scripts contain snippets of Groovy code. They have to be put into curly brackets and their content has to conform with Groovy syntax. Below, we show how to attach the propagation script {orderedCoffeeType = lob.coffeeType} using the operator '^' to the entity COFFEES_SERVED.ENTITY. This makes it so that the flow variable orderedCoffeeType is assigned the value of the entity variable coffeeType, which has been defined in the entity COFFEES_SERVED.ENTITY. This value is propagated to the flow variable, hence the name 'propagation script'.
Propagation scripts can also be attached directly to any part of a syntax condition. It must not always be attached to an entity or language condition. However, you need to bracket the part of the condition to which the script is attached, as shown below. Note that, in this case, the flow variable orderedCoffeeSize is directly assigned the value 'small'.
Optionality
Sometimes the user utterance may contain useful information that is not mandatory but still good for your bot to catch. One way to catch such information is by using the optionality operator (:O) together with an attached script.
In the example below, ( with >> milk ) and %DECAFF.ADJ.LEX are optional. If the user says with milk, the variable orderedMilk is set to 'yes', and if the user says 'lactose free', the variable milkWithLactose is set to 'no'. Otherwise, the variables are simply not changed.
tlml
1%COFFEE.NN.LEX &^ ((with >> milk)^{orderedMilk = 'yes'}):o &^ (%LACTOSE_FREE.ADJ.MUL^{milkwithLactose= 'no'}):O
2
Optionality can also be used to capture multiple occurrences of the same type in an input. The example below matches user inputs containing the phrase 'I_WANT.PHR' and up to three coffee types and their sizes. The optionality operator (:O) indicates that the 2nd and 3rd bracketed expressions are optional and can thus remain unmatched. However, if they are matched, the placing of the propagation scripts ensures that each size is stored together with the respective coffee type that the user ordered.
tlml
1%I_WANT.PHR &^
2(%SIZES.ENTITY^{orderedCoffeeSize1 = lob.size} >> %COFFEES_SERVED.ENTITY^{orderedCoffeeType1 = lob.coffeeType}) &^
3(%SIZES.ENTITY^{orderedCoffeeSize2 = lob.size} >> %COFFEES_SERVED.ENTITY^{orderedCoffeeType2 = lob.coffeeType}):O &^
4(%SIZES.ENTITY^{orderedCoffeeSize3 = lob.size} >> %COFFEES_SERVED.ENTITY^{orderedCoffeeType3 = lob.coffeeType}):O
5
Predicate Scripts
With predicate scripts you can add additional constraints to the evaluation of a language object, input annotation, entity, or bracketed syntax condition. These value-dependent constraints are based on information available during the matching process as follows:
- NLU variables: any variables set by the language object or entity
- Input annotation variables: any annotation information set by the object
- Used words: of the language object, entity, or bracketed condition
Predicate scripts are attached to condition objects in a similar way as propagation scripts. If the predicate script is evaluated as false, the match is disregarded. In a sense predicate scripts allow you to "re-engineer" a language object to only react to a sub-category of its content. This allows you to quickly make the most of existing language resources, without having to create specialized versions of the objects. In the example below we use the language object containing a list of all countries and make it applicable for European countries only:
It is also possible to combine predicate scripts with propagation scripts. In this case the predicate script should be attached first, followed by the propagation script. The example below shows how we can use the number annotation to find a value under 1000, then save the found value using an attached propagation script.
The table below shows additional ways that you can use predicate scripts along with an explanation of when each case might be useful.
TLML Syntax | Description |
---|---|
%$BOOK_FLIGHT.TOP_INTENT:{lob.confidence > 0.75} | This example shows how to apply a customized confidence threshold. E.g. if the solution's confidence threshold is set to .45 for all class triggers, but that is sometimes too low for a specific intent |
%$BOOK_FLIGHT.INTENT:{lob.confidence > 0.3} | In this example, if we have detected a book flight input with 30% confidence or better, we decide to prefer this intent, even if a different top intent was selected. |
%AIRPORT.LIST:{AirportHelpers.IsKnownDestination( lob.airportCode )}^{ destinations << lob.airportCode } | This example shows calling a service to see if a detected airport is one of the destinations covered by the travel system. If the predicate script is true, the propagation script will additionally append the airport code to a list of destinations. |
%$NUMBER:{(lob.numericValue.remainder( java.math.BigDecimal.ONE )) == 0} | Use the number annotation to match to whole numbers only. |
(%$PERSON.NER/%NAMES.LIST):{!(_USED_WORDS.toLowerCase() in ["frank" , "frankie", "franklin"])} | Match to all names except variations of "Frank", e.g. in case Frank is the bot's name. Note: this condition could also be rewritten as ((%$PERSON.NER/%NAMES.LIST)!&=(frank/frankie/franklin)) |
%CONTACT_REQUEST.PHR:{ lob.chatAvailable == "true" } | The language object for contact requests could call a service to check if a live agent is available, and if so, signal it via an NLU variable. The flow using this trigger condition would start the live chat immediately. |
%CONTACT.NNVB.SYN + %COMPANY_CITIES.ENTITY:{ lob.telephone != ""}^{ telephone = lob.telephone } | Here we have an entity COMPANY_CITIES.ENTITY that recognizes all company locations, but only some of them have a contact number. If a location does not have a number, the NLU variable would be blank. The predicate script prevents our contact flow from triggering for cities that cannot yet be contacted. |
%COUNTRIES_EUROPE_EU.LIST:{ lob.TLR_sCountryCode != "SE" } | All countries in the European Union, excluding Sweden. |