Skip to content

DSUL.ai (v1)

Digital Service Univeral Language.
A language created by Prisme.ai to describe applications.
This language is universal, transparent and intuitive. Prisme.ai has the ambition to make DSUL a new standard of connected Virtual Assistant creation.

Sommaire

  1. Hello World
  2. Section Intents.when
    • match phrases
    • match events
  3. Section Intents.parameters
  4. Section Entities
  5. Sections Intents.outputContexts & Intents.inputContexts
    • User authentication
  6. Section Intents.do
    • Visual responses
    • Event buttons
    • Emit an event without user interaction
    • Channels customization
    • Conditions
  7. Section Resources
    • Searchengine
    • Webhook
    • Dataflow
    • Jobs
  8. Translations

Hello World

Intents:
    HelloWorld:
        when:
            match phrases:
                - Salut
                - bonjour
        do:
            - say text: Bienvenue à toi !

Section Intents.when

It is this section that defines when an intent is triggered. Two mechanisms are available: match phrases et match events.

match phrases

match phrases allows to detect an intent with training sentences:

Intents:
    Welcome Intent:
        when:
            match phrases:
                - Salut
                - bonjour 
Each time a sentence similar to these is sent by the user, the intent associated workflow (Intent.do) will be executed.

match events

Rather than waiting for a user sentence, it is also possible to automatically trigger intents with event buttons :

Intents:
    - name: step.one
        ...
        do:
            - say event:
                text: Accéder à l'étape 2
                value: STEP_2
In order to be triggered as soon as this STEP_2 event is emitted, another intent can declare it in match events :
Intents:
    - name: step.one
        when:
            match phrases:
                - je veux accéder à l'intent secrète !
        do:
            - say text: "Voici ce que je peux te proposer :"
            - say event:
                text: Accéder à l'étape 2
                value: STEP_2

    - name: step.two
        when:
            match events:
                - STEP_2
        do:
            - Text: Bravo !
As explained in section Intents.do, it is also possible to emit events without any user intervention.

Intents.parameters

Within training phrases (when.match phrases section), it is possible to specify parameters that would be extracted from user messages in order to gather complementary details about their request.
Each of these parameters must be described in Intents.*.parameters section:

  • entity : indicates the entity's name, which must be detailed in Entities section if it's a custom entity. Differents builtin entities are automatically provided to extract generic kinds of information (numbers, dates, duration, ... exhaustive list within Entities section)
  • isRequired : configures whether this is a required parameter (false by default)
  • questions : indicates a few alternative questions to ask if the parameter is missing although isRequired is set to true
  • displayEntityValues : when set to true, displays every possible values as clickable buttons
Intents:
    I_LIKE_FRUIT:
        when:
            match phrases:
                - j'aime la [poire](fruit)
                - j'aime bien les [pommes](fruit)
                - j'aime les fruits
        parameters:
            fruit:
                entity: Fruit
                isRequired: true
                questions:
                    - Quel fruit tu aimes ?
        do:
            - say text: je suis vraiment ravi d'apprendre que tu aimes les $fruit !

Each parameter expected by training phrases must be specified as follows :
- Parameters' value must be enclosed in square brackets (poire, pommes) - Parameters' name must be enclosed in parenthesis right next to the closing bracket

In the example above, one training phrase does not contain any parameter : j'aime les fruits
If someone would send this sentence or an equivalent formulation without the expected parameter inside, and since isRequired is true, the application would automatically ask one of the defined questions : Quel fruit tu aimes ?

As the entity name (Fruit) is not prefixed with ggwg/, we know that is a custom entity described in Entities section.

Entities

An entity corresponds to a category of information that might be extracted from user messages, and Prisme.ai provides some builtin entities available to all intentions :
- ggwg/amount-money : Detects amounts of money : "20€", "15€", ...
- ggwg/date-time : Detects date ("Friday, October 23th"), and more informal expressions as well :"Friday", "next week", ...
- ggwg/duration : Detects durations : "1h", "during 20 minuts", "3 months", ...
- ggwg/number : Detects numbers : "1", "525", "18", ...
- ggwg/ordinal : Detects ordinal numbers : "premier", "troisième", "second"
- ggwg/percentage : Detects percentages : "15%", "20 %", ...
- ggwg/temperature : Detects temperatures : "15°C"
- ggwg/any : Detects anything that fits right where the training phrase is expecting the parameter

If one needs an additional entity, it can be specified within Entities :

Entities:
    Fruit:
        automaticallyExtensible: false
        useSynonyms: true    
        values:
            fr:
                - value: poire
                  synonyms:
                    - poires
                - value: banane
                - value: pomme
                  synonyms:
                    - pome

Main options :
* automaticallyExtensible : false by default, this allows any value to be considered as the entity even if it's not part of the configured values
* useSynonyms : true by default, this allows to bind a list of synonyms to a value. Even if the user types one of the synonyms, the intent would always receive the standardized value (values.value)
* values : Only mandatory setting, this is where you will list every possible values, categorized by language

Structure of values :
* First depth level of values indicate needed languages' code (fr, en, ...)
* Each language structure contains a list of value, where each of them have optional synonyms
* Important : synonyms option must be exactly aligned with the beginning of value, otherwise the file could not be parsed

Intents.outputContexts & Intents.inputContexts

Every intent maintains a context where all retrieved parameters are saved. By default, an intent's context expires as soon as we jump to another intent.
However, any intent might expose its context to the following ones for a specified lifetime (as a number of messages):

Intents:
    topup.ask:
        parameters:
            amount:
              entity: ggwg/amount-money    
        outputContexts:
            TopUp: 3
Any intent can now declare TopUp as an input context in order to access amout parameter, as long as they are triggered during the 3 first messages after topup.ask :
Intents:
    topup.confirm:
        inputContexts:
            - TopUp

Moreover, an intent specifying inputContexts cannot be triggered by training phrases if the input contexts have not been emitted.

Intents:
    topup.ask:
        outputContexts:
            TopUp: 3
        when:
            match phrases:
                - recharge mon forfait de [5 €](amount)
                - je veux recharger [10 €](amount) sur mon forfait
        parameters:
            amount:
              entity: ggwg/amount-money
              isRequired: true
              questions:
                  - de combien voulez-vous recharger votre forfait ?                 

        do:
            - say text: Confirmez-vous la demande de rechargement de $amount € sur votre forfait ?
            - say button:
                text: Oui
                value: Je confirme

    topup.confirm:
        inputContexts:
            - TopUp
        when:
            match phrases:
                - Je confirme
        parameters:
            amount:
                entity: ggwg/amount-money
        do:
            - say text: Très bien, $amount € ont bien été rechargés sur votre forfait.
Important : An intent receiving a context must indicate again the parameters name & entity in order to use them.

User authentication

In order to authenticate webchat users, we can pass authenticating data to the webchat injection script's originalRequest parameter.
Any intent can access these data by declaring originalContext in both inputContexts and parameters :

Intents:
    hello:
        inputContexts:
            - originalRequest
        when:
            match phrases:
                - Salut
                - Bonjour
        parameters:
            originalRequest:
                entity: ggwg/any                
        do:
            - say text: Bonjour $originalRequest.firstName !

Section Intents.Do

Visual responses

Every visual responses are prefixed with say :

Intents:
  show_responses:
    ...
    do:
      - say text: Montre moi plus d'actualités
      - say random text:
          - Premiere formulation
          - Deuxieme formulation
      - say richText:
          - |-
            <h3>Texte enrichi</h3>
            <p>Sur plusieurs lignes</p>
      - say random richText:
          - <h3>Premiere possibilité de texte enrichi</h3>
          - <h3>Deuxieme possibilité de texte enrichi</h3>
      - say button:
          text: Plus d'actu
          value: Montre moi plus d'actualités
      - say card:
          title: Titre card
          text: 'Texte en dessous'
          image: https://.../url_image.png
          buttons:
            - say button:
                text: Titre Bouton 1 card
                value: Valeur bouton 1 card
      - say link:
          text: Titre lien
          value: 'https://www.google.com'
These response name are not case-sensitive and whitespaces are not mandatory either.

Event buttons

The first manner to trigger an event is to send an event button to the user with say event :

Intents:
  My_Intent:
    ...
    do:    
      - say event:
          text: Plus d'actu
          value: MORE_NEWS
As soon as the user clicks this button, MORE_NEWS event will be emitted, trigerring any intent that declared MORE_NEWS in when.match events.

Emit an event without user interaction

We can also automatically trigger an event as soon as a given intent is run, without manual intervention from the user :

Intents:
    My_Intent:
        ...
        do:
            - say text: Vous allez être redirigé vers une nouvelle intent !
            - jump: MORE_NEWS

    Intent_2:
        when:
            match events:
                - MORE_NEWS
        ...
As soon as My_Intent required parameters are fulfilled and the workflow executed, the jump would automatically trigger Intent_2 intent.

Channels customization

Intents.do can be adapted for each available channel :

Intents:
    Welcome Intent:
        description: un intent qui dit bonjour
        when:
          match phrases: '${i18n.hello}'
        do:
          - on default:
              - say text: default channel
          - on web:
              - say text: Depuis le web
          - on telephony:
              - say text: depuis un appel
          - on speaker:
              - say text: depuis un speaker (alexa & cie)
          - on messenger:
              - say text: depuis messenger
          - on whatsapp:
              - say text: depuis whatsapp
          - on slack:
              - say text: depuis slack

Actions & Ressources

Ressources are differents entities which can be created and shared between bots, providing several actions dealing with the same type of task.
Each action name is prefixed by a call, and those that do not need any other parameter than the corresponding resource name can be written on a single line :

    ...
    - call myAction: myResourceName
And, in its customizable form :
    ...
    - call myAction:
        resource: myResourceName
        parameter1: value1

For every resource, we can reuse those already existing within the authenticated Prisme.ai user instead of creating them on each DSUL import :

Resources:
    MySearchengine:
        type: searchengine
        external: true

    MyDataflow:
        type: dataflow
        external: true

    ...

If external is not set to true but authenticated user already has a resource with the same type & name, it would not be created again either.

Actions result display & Repeat
Although most actions returning data provide a responses parameter configuring how these data are visually formatted, it is sometimes necessary to separate the action execution time from when its result is displayed.
In this regard, some actions have an output parameter specifying the name of a context variable in which to store their result, so that it can be displayed later on within the workflow.
When this result is a list (as it might be the case for webbook or dataflow actions), we need to loop on each entry of this list using a repeat block :

Intents:
    MyIntent:
        ...
        do:
            - call myAction:
                resource: myResourceName
                output: resultVariable
            - repeat on $resultVariable:
                - say text: $text
For more complex or mulit-step processes, these repeat blocks can themselves nest new actions and repeats.

Searchengine

Resources:
    MySearchengine:
        type: searchengine
        description: ce searchengine permet de rechercher dans https://docs.prisme.ai
        settings:
            websites:
                - https://docs.prisme.ai

The only searchengine action transmits user message to the searchengine and automatically formats matching web pages as cards.

Intents:
    Fallback Intent:
        isFallback: true
        do:
            - call search: MySearchengine

Resources:
    MySearchengine:
        type: searchengine
        external: true

Here, we call search within Fallback Intent workflow so that the searchengine will take over only when the application cannot process the request itself.

Webhook

Resources:
    MyWebhook:
        type: webhook
        description: 'webhook '
        settings:
            url: 'http://localhost:4444'    
            auth:
                username: MyUsername
                password: MyPassword
            headers:
                Content-Type: application/json

Action webhook

The only webhook actions simply calls underlying HTTP route :

Intents:
    Call_Webhook:
        when:
            match phrases:
                - Appelle mon webhook
                - Lance le webhook
        do:
            - call webhook: MyWebhook
Resources:
    MyWebhook:
        type: webhook
        external: true
Visual response depends on the webhook's result itself, which needs to follow Prisme.ai specifications in order to use any of the provided responses (text, card, ...).

However, if webhook's result does not meet Prisme.ai standards, it is also possible to save its result in a context variable and display it later on :

Intents:
    Call_Webhook:
        when:
            match phrases:
                - Appelle mon webhook
                - Lance le webhook
        do:
            - call webhook:
                resource: MyWebhook
                output: names
            - repeat on $names:
              - say card:
                  title: $name
                  text: "$tel"
Resources:
    MyWebhook:
        type: webhook
        external: true

Dataflow

Resources:
    MyRecipes:
        type: dataflow
        description: ce dataflow stocke des recettes

Action read dataflow

Intents:
    recipes.ideas:
        description: ask for some recipes ideas
        when:
            match phrases:
                - Idée d'un plat à cuisiner ? 
                - Que pourrais-je cuisiner ?
                - Je ne sais pas quoi faire pour manger
        parameters:
            ingredient:
                isRequired: true
                entity: Ingredient
                questions:
                    - De quel ingrédient disposes-tu ?
        do:
            - call read dataflow:
                resource: MyIngredientsDataflow
                query: {"ingredient": "$ingredient"}
                responses:
                    - say card:
                        title: $recipe
                        text: Il faut $count $ingredient

Resources:
    MyIngredientsDataflow:
        type: dataflow
        external: true

As for webhook, it is also possible to save its result in a context variable and display it later on :

Intents:
    recipes.ideas:
        description: ask for some recipes ideas
        when:
            match phrases:
                - Idée d'un plat à cuisiner ? 
                - Que pourrais-je cuisiner ?
                - Je ne sais pas quoi faire pour manger
        parameters:
            ingredient:
                isRequired: true
                entity: Ingredient
                questions:
                    - De quel ingrédient disposes-tu ?
        do:
            - call read dataflow:
                resource: MyIngredientsDataflow
                query: {"ingredient": "$ingredient"}
                output: recipes
            - repeat on $recipes:
                - say card:
                    title: $recipe
                    text: Il faut $count $ingredient

Resources:
    MyIngredientsDataflow:
        type: dataflow
        external: true

Action write dataflow

Insert a new dataflow row, containing every declared parameters :

Intents:
    ingredients.new:
        description: Enregistre un nouvel ingrédient
        when:
            match phrases:
                - j'ai acheté un [oeuf](ingredient)
        parameters:
            ingredient:
                entity: Ingredient
            count:
                entity: ggwg/number
                defaultValue: 1
        do:
            - call write dataflow: MyIngredientsDataflow
            - say text: J'ai retenu que tu as maintenant un $ingredient !

Resources:
    MyIngredientsDataflow:
        type: dataflow
        external: true        

Action update dataflow

Updates a row from the dataflow with every declared parameters :

Intents:
    ingredients.delete:
        description: Supprime un ingrédient
        when:
            match phrases:
                - Ma quantité d'[oeuf](ingredient) a changé !
        parameters:
            ingredient:
                entity: Ingredient
            count:
                entity: ggwg/number
                isRequired: true
                questions:
                    - Combien en as-tu ?
        do:
            - call update dataflow:
                resource: MyIngredientsDataflow
                query: {"ingredient": "$ingredient"}
            - say text: J'ai retenu que tu as maintenant $count $ingredient !

Resources:
    MyIngredientsDataflow:
        type: dataflow
        external: true        

Action delete dataflow

Delete a row from the dataflow :

Intents:
    ingredients.delete:
        description: Supprime un ingrédient
        when:
            match phrases:
                - je n'ai plus d'[oeuf](ingredient)
        parameters:
            ingredient:
                entity: Ingredient
        do:
            - call delete dataflow:
                resource: MyIngredientsDataflow
                query: {"ingredient": "$ingredient"}
            - say text: J'ai retenu que tu n'as plus de $ingredient !

Resources:
    MyIngredientsDataflow:
        type: dataflow
        external: true        

Job

Intents:
  Welcome Intents:
    when:
      MatchPhrases:
        - Salut
    do:
      - Text: Veux-tu appeler l'API ? 
      - Event:
          text: Oui
          value: CALL_API

  RunAPI:
    when:
      MatchEvents:
        - CALL_API
    do:
      - Call: MyAPI
      - Text: L'API a bien été appelée !

Resources:
  MyAPI:
    type: webhook
    description: 'L'API visée par la tâche périodique '
    settings:
      url: 'http://localhost:4444'    

  MyJob:
    type: cron
    description: 'cette tâche permet de déclencher périodiquement l'évènement CALL_API'
    settings:
      type: sendEvent
      schedule: 0 */3 * * *
      parameters:
        event: TEST

settings.type specifies the kind of task. Available tasks are : sendEvent
settings.schedule specifies desired periodicity using cron format.

Parameters of each task : * sendEvent
* settings.parameters.event : event name to trigger
* Once the resource is created after the DSUL import, you need to manually bind it to your application created in the meantime.
* Initial scheduling is manual as well

No action is provided by this resource yet.

Conditions

do:
  - if:
      condition: age < 18
      then:
        - say text: Tu es donc mineur !
  - else if:
      condition: age > 50
      then:
        - say text: En voilà un avec de la bouteille !
  - else:
    - say text: Bravo, te voilà majeur !  
  - say text: Ce texte sera affiché quelque soit la condition exécutée. Il doit toujours se situer après les conditions et jamais avant.

Every usual responses and actions might be used within these conditions.
Channels customization can be used within conditions as well, but the inverse is not possible.

Translations

In an application, 4 differents elements might be translated :
1. Training phrases
2. Required parameters' questions
3. Responses
4. Entities

Nested translations

For each of the previously quoted elements, the first translation method consists in duplicating linguistic structures in a substructure for each needed language :

Settings:
    languages:
        - fr
        - en

Intents:
    MyCountry:
        when:
            match phrases:
                fr:
                    - Je viens du [Portugal](country)
                    - Je suis originaire de [France](country)
                    - Mon pays d'origine est le ...
                    - Mon pays d'origine est le [Maroc](country)
                en:
                    - I'm from [Portugal](country)
                    - Hello, I'm coming from [France](country)
                    - Hello, I'm coming from [Morocco](country)
        parameters:
            country:
                entity: Country
                isRequired: true
                displayEntityValues: true
                questions:
                    fr:
                        - D'où viens-tu ?
                        - De quel pays viens-tu ?
                    en:
                        - Where are you from ?
                        - Where do you come from ?
        do:
            fr:
                - say text: Et c'est beau le $country ?
            en:
                - say text: Is $country beautiful to see ?

Entities:
    Country:
        values:
            fr:
                - value: France
                - value: Portugal
                - value: Maroc
            en:
                - value: France
                - value: Portugal
                - value: Morocco

Settings.languages is important, indicating which languages are supported by the application.

Section Translations

A last section allows you to gather together only translations : Translations. For now, only training phrases and required parameters' questions can benefit from this section.
Like with the previous solution, Translations root only contains sub structures of translated languages.
The user is free to organize these substructures as he wish, as long as they are all identically organized.

Thus, we can use i18n variable as a translation path in when.match phrases and parameters.questions attributes :

Settings:
    languages:
        - fr
        - en

Intents:
    MyCountry:
        when:
            match phrases: '${i18n.MyCountry.phrases}'

        parameters:
            country:
                entity: Country
                isRequired: true
                displayEntityValues: true
                questions: '${i18n.MyCountry.countryQuestions}'

        do:
            fr:
                - say text: Et c'est beau le $country ?
            en:
                - say text: Is $country beautiful to see ?

Entities:
...


Translations:
    fr:
        MyCountry:
            phrases:
                - Je viens du [Portugal](country)
                - Je suis originaire de [France](country)
                - Mon pays d'origine est le ...
                - Mon pays d'origine est le [Maroc](country)

            countryQuestions:
                - D'où viens-tu ?
                - De quel pays viens-tu ?
    en:
        MyCountry:
            phrases:
                - I'm from [Portugal](country)
                - Hello, I'm coming from [France](country)
                - Hello, I'm coming from [Morocco](country)

            countryQuestions:
                - Where are you from ?
                - Where do you come from ?