arrow-left

All pages
gitbookPowered by GitBook
1 of 7

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

4.1. State Referencing

hashtag
Start State

Let us create transitions for a virtual agent that handles time, weather, and playing music:

  • #5: shows the current time (although it is correct only twice a day at the moment).

  • #8: informs the current weather in Sunnyville.

  • #11: plays the song "".

  • #14: print the error message and references to the start state.

Notice that when the user input does not match any of the conditions, it prints the error message and loops back to the start state.

hashtag
Custom States

It is possible to name any transition you create as a state:

  • #6: names the state as time.

  • #9: names the state as weather.

hashtag
Exit State

State referencing can be abused to create transitions that never end (infinite loop). It is important to design an exit state so you can terminate the conversation without throwing errors:

  • #6,10,14,17: loops back to the start state.

  • #19-21: creates an exit state to terminate the dialogue.

What is the main difference between an error transition and an exit state?

An error transition defines a default action for uninterpretable user input, whereas an exit state terminates the current session of the dialogue.

transitions = {
    'state': 'start',
    '`What can I do for you?`': {
        '[{time, clock}]': {
            '`It\'s 3PM.`': 'end'
        },
        '[{weather, forecast}]': {
            '`It\'s sunny outside`': 'end'
        },
        '[play, raining tacos]': {
            '`It\'s raining tacos. From out of the sky ...`': 'end'
        },
        'error': {
            '`Sorry, I didn\'t understand you.`': 'start'
        }
    }
}
#13: names the state as play_raining_tacos.
  • #17: references to the play_raining_tacos state.

  • Raining Tacosarrow-up-right
    S: What can I do for you?
    U: What time is it now?
    S: It's 3PM.
    S: What can I do for you?
    U: What's the weather like?
    S: It's sunny outside
    S: What can I do for you?
    U: Play rainy taco
    S: Sorry, I didn't understand you. What can I do for you?
    U: Play raining tacos
    S: It's raining tacos. From out of the sky ...
    transitions = {
        'state': 'start',
        '`What can I do for you?`': {
            '[{time, clock}]': {
                'state': 'time',
                '`It\'s 3PM.`': 'end'
            },
            '[{weather, forecast}]': {
                'state': 'weather',
                '`It\'s sunny outside`': 'end'
            },
            '[play, raining tacos]': {
                'state': 'play_raining_tacos',
                '`It\'s raining tacos. From out of the sky ...`': 'end'
            },
            'error': {
                '`Sorry, I didn\'t understand you.`': 'play_raining_tacos'
            }
        }
    }
    S: What can I do for you?
    U: Play rainy taco
    S: Sorry, I didn't understand you. It's raining tacos. From out of the sky ...
    transitions = {
        'state': 'start',
        '`What can I do for you?`': {
            '[{time, clock}]': {
                'state': 'time',
                '`It\'s 3PM.`': 'start'
            },
            '[{weather, forecast}]': {
                'state': 'weather',
                '`It\'s sunny outside`': 'start'
            },
            '[play, raining tacos]': {
                'state': 'play_raining_tacos',
                '`It\'s raining tacos. From out of the sky ...`': 'start'
            },
            'error': {
                '`Sorry, I didn\'t understand you.`': 'start'
            },
            '[exit]': {
                'state': 'exit',
                '`Goodbye!`': 'end'
            }
        }
    }
    S: What can I do for you?
    U: time
    S: It's 3PM. What can I do for you?
    U: weather
    S: It's sunny outside What can I do for you?
    U: play raining tacos
    S: It's raining tacos. From out of the sky ... What can I do for you?
    U: exit
    S: Goodbye!

    4.2. Advanced Interaction

    hashtag
    Built-in Macros

    Besides #ONT for checking an ontology, STDM provides several macros useful for dialogue design.

    hashtag
    #LEM

    The following example shows a use case of the macro #LEM that uses the to match lemmas of "raining tacos":

    • #5: maches the input with the lemma of "rain" or "rainy", then the lemma of "taco".

    hashtag
    #UNX

    The #UNX macro can be used as an alternative to the 'error' transition, which prepends a short acknowledgment phrase (e.g., "yeah", "sure") to the error statement:

    • #8: prepends an acknowledgment phrase to the error statement, "Thanks for sharing" in #8.

    • #3,5: add acknowledgment phrases given the user inputs.

    • #7: does not add an acknowledgment phrase when the user input is short.

    When the user input contains fewer than three tokens, #UNK does not add any acknowledgment.

    triangle-exclamation

    Seldomly, #UNKgets selected even when conditions in other transitions match the input (due to an STDM bug). If you notice this during testing, assign a very slow to the #UNK state to ensure it gets the lowest priority among other branches.

    hashtag
    #SET & #IF

    Let us update the above transitions so that it sometimes refuses to sing the same song:

    • #6: can be picked if the variable $RAINING_TACOS equals to the string 'True'.

    • #7: sets $RAINING_TACOS to 'True' after prompting the system output.

    circle-info

    Once $RAINING_TACOS is set to 'True', STDM randomly picks a statement in #6 or #7 as the system output.

    Notice that the #SET macro only assigns a string value to the variable. It is possible to write a macro to set any variable to an actual boolean value (e.g., True, False):

    • #3-4: checks if there are two arguments.

    • #6-8: retrieves the variable name.

    • #10-12

    Given MacroSetBool, the above transitions can be updated as follow:

    • #6: is selected if $RAINING_TACOS is True.

    • #0: sets the variable $RAINING_TACOS to the boolean value True.

    Currently, STDM randomly chooses the statements in #6 and #7 once $RAINING_TACOS becomes True. We can write another macro that prompts #7 only for the first time:

    • #3: the method in returns the value corresponding to the key, RAINING_TACOS if exists; otherwise, False.

    Given MacroPlayRainingTacos, the transitions can be updated as follow:

    • #7: is selected if the macro #PLAY_RAINING_TACOS returns True.

    • #17: adds #PLAY_RAINING_TACOS to the macro dictionary.

    hashtag
    Music

    It is possible to make our system actually sings instead of prompting the lyric. Let us first install the package:

    Then, import the package and update the MacroPlayRainingTacos macro to play the MP3 file, :

    • #1: imports the VLC package.

    • #6: creates a VLC media player and plays the specified MP3 file.

    When you run the above dialogue flow, it now plays the MP3 file and prompts the lyric.

    hashtag
    Time

    The transitions in prompt the same time (3PM) upon every request. Let us create a new macro that checks the current (system) time:

    • #1: imports the package.

    • #5: retrieves the current time in the specified format using the method.

    • #6

    The macro MacroTime can be called to generate the system output:

    • #11: calls the TIME macro to generate the system output displaying the current time.

    • #22: adds #TIME to the macro dictionary.

    hashtag
    Weather

    The transitions in prompt the same weather (sunny) upon every request. Let us retrieve the latitude and the longitude of the system using :

    Then, use a web API provided by the to retrieve the grid correlates to the coordinate:

    • Look for the forecast field under properties:

    Write a macro that retrieves the current weather for the grid using another web API:

    • #1: imports the package.

    • #2: imports the package.

    • #6

    Finally, update the transitions with the weather macro:

    • #15: calls the WEATHER macro to generate the system output displaying today's weather.

    • #22: adds #WEATHER to the macro dictionary.

    circle-info

    The time and the weather retrieved by the above macros are oriented to the system, not the user. It is possible to anticipate the users' location if one's IP address is provided; however, this is not possible unless the user uses a specific device (e.g., Amazon Echo, smartphone) and agrees to send one's private information to our system.

    : checks if the argument is a proper boolean value.
  • #14: stores the boolean value to the variable.

  • : returns the current time using the
    method.
    : specifies the forecast URL.
  • #7: retrieves the content from the URL in JSON.

  • #8: saves the JSON content to a dictionary.

  • #9: retrieves forecasts for all supported periods.

  • #10: retrieves the forecast for today.

  • #11: returns today's forecast.

  • S: What can I do for you?
    U: Play raining tacos
    S: It's raining tacos. From out of the sky ... What can I do for you?
    U: Play raining taco
    S: It's raining tacos. From out of the sky ... What can I do for you?
    U: Play rain taco
    S: It's raining tacos. From out of the sky ... What can I do for you?
    U: Play rainy taco
    S: It's raining tacos. From out of the sky ... What can I do for you?
    U: Bye
    S: Sorry, I didn't understand you.
    NLTK Lemmatizerarrow-up-right
    score
    get()arrow-up-right
    dictarrow-up-right
    VLCarrow-up-right
    resources/raining_tacos.mp3arrow-up-right
    Section 4.1
    timearrow-up-right
    strftimearrow-up-right
    Section 4.1
    Google Mapsarrow-up-right
    National Weather Servicearrow-up-right
    https://api.weather.gov/points/33.7904,-84.3266arrow-up-right
    https://api.weather.gov/gridpoints/FFC/52,88/forecastarrow-up-right
    jsonarrow-up-right
    requestsarrow-up-right
    Mathematics and Science Center at Emory University (400 Dowman Dr, Atlanta, GA, 30322)
    str.formatarrow-up-right
    transitions = {
        'state': 'start',
        '`What can I do for you?`': {
            '[play, [!{#LEM(rain), rainy}, #LEM(taco)]]': {
                'state': 'play_raining_tacos',
                '`It\'s raining tacos. From out of the sky ...`': 'start'
            },
            'error': {
                '`Sorry, I didn\'t understand you.`': 'end'
            },
        }
    }
    transitions = {
        'state': 'start',
        '`What can I do for you?`': {
            '[play, [!{#LEM(rain), rainy}, #LEM(taco)]]': {
                'state': 'play_raining_tacos',
                '`It\'s raining tacos. From out of the sky ...`': 'start'
            },
            '#UNX': {
                '`Thanks for sharing.`': 'end'
            },
        }
    }
    S: What can I do for you?
    U: My name is Jinho
    S: Right. Thanks for sharing. What can I do for you?
    U: I am a professor
    S: Yeah. Thanks for sharing. What can I do for you?
    U: Hello world
    S:  Thanks for sharing. What can I do for you?
    U: Play raining tacos
    S: It's raining tacos. From out of the sky ...
    transitions = {
        'state': 'start',
        '`What can I do for you?`': {
            '[play, [!{#LEM(rain), rainy}, #LEM(taco)]]': {
                'state': 'play_raining_tacos',
                '#IF($RAINING_TACOS=True) `Don\'t make me sing this again!`': 'start',
                '`It\'s raining tacos. From out of the sky ...` #SET($RAINING_TACOS=True)': 'start',
            },
            '#UNX': {
                '`Thanks for sharing.`': 'start'
            },
        }
    }
    S: What can I do for you?
    U: Play raining tacos
    S: It's raining tacos. From out of the sky ...   What can I do for you?
    U: Play raining tacos
    S:  Don't make me sing this again! What can I do for you?
    ...
    class MacroSetBool(Macro):
        def run(self, ngrams: Ngrams, vars: Dict[str, Any], args: List[str]):
            if len(args) != 2:
                return False
    
            variable = args[0]
            if variable[0] == '$':
                variable = variable[1:]
    
            boolean = args[1].lower()
            if boolean not in {'true', 'false'}:
                return False
    
            vars[variable] = bool(boolean)
            return True
    transitions = {
        'state': 'start',
        '`What can I do for you?`': {
            '[play, [!{#LEM(rain), rainy}, #LEM(taco)]]': {
                'state': 'play_raining_tacos',
                '#IF($RAINING_TACOS) `Don\'t make me sing this again!`': 'start',
                '`It\'s raining tacos. From out of the sky ...` #SETBOOL(RAINING_TACOS, True)': 'start',
            },
            '#UNX': {
                '`Thanks for sharing.`': 'start'
            },
        }
    }
    
    macros = {
        'SETBOOL': MacroSetBool()
    }
    class MacroPlayRainingTacos(Macro):
        def run(self, ngrams: Ngrams, vars: Dict[str, Any], args: List[str]):
            return not vars.get('RAINING_TACOS', False)
    transitions = {
        'state': 'start',
        '`What can I do for you?`': {
            '[play, [!{#LEM(rain), rainy}, #LEM(taco)]]': {
                'state': 'play_raining_tacos',
                '#IF($RAINING_TACOS) `Don\'t make me sing this again!`': 'start',
                '#IF(#PLAY_RAINING_TACOS) `It\'s raining tacos. From out of the sky ...` #SETBOOL(RAINING_TACOS, True)': 'start',
            },
            '#UNX': {
                '`Thanks for sharing.`': 'start'
            },
        }
    }
    
    macros = {
        'SETBOOL': MacroSetBool(),
        'PLAY_RAINING_TACOS': MacroPlayRainingTacos()
    }
    
    df = DialogueFlow('start', end_state='end')
    df.load_transitions(transitions)
    df.add_macros(macros)
    df.run()
    S: What can I do for you?
    U: Play raining tacos
    S:  It's raining tacos. From out of the sky ...    What can I do for you?
    U: Play raining tacos
    S:  Don't make me sing this again! What can I do for you?
    U: Play raining tacos
    S:  Don't make me sing this again! What can I do for you?
    ...
    pip install python-vlc
    import vlc
    
    class MacroPlayRainingTacos(Macro):
        def run(self, ngrams: Ngrams, vars: Dict[str, Any], args: List[str]):
            if not vars.get('RAINING_TACOS', False):
                vlc.MediaPlayer("resources/raining_tacos.mp3").play()
                return True
            return False
    import time
    
    class MacroTime(Macro):
        def run(self, ngrams: Ngrams, vars: Dict[str, Any], args: List[str]):
            current_time = time.strftime("%H:%M")
            return "It's currently {}.".format(current_time)
    transitions = {
        'state': 'start',
        '`What can I do for you?`': {
            '[play, [!{#LEM(rain), rainy}, #LEM(taco)]]': {
                'state': 'play_raining_tacos',
                '#IF($RAINING_TACOS) `Don\'t make me sing this again!`': 'start',
                '#IF(#PLAY_RAINING_TACOS) `It\'s raining tacos. From out of the sky ...` #SETBOOL(RAINING_TACOS, True)': 'start',
            },
            '[{time, clock}]': {
                'state': 'time',
                '#TIME': 'end'
            },
            '#UNX': {
                '`Thanks for sharing.`': 'start'
            },
        }
    }
    
    macros = {
        'SETBOOL': MacroSetBool(),
        'PLAY_RAINING_TACOS': MacroPlayRainingTacos(),
        'TIME': MacroTime()
    }
    S: What can I do for you?
    U: What time is it now?
    S: It's currently 05:27.
    {
        ...,
        "properties": {
            "@id": "https://api.weather.gov/points/33.7904,-84.3266",
            ...,
            "forecast": "https://api.weather.gov/gridpoints/FFC/52,88/forecast",
            ...
        }
    }
    import json
    import requests
    
    class MacroWeather(Macro):
        def run(self, ngrams: Ngrams, vars: Dict[str, Any], args: List[Any]):
            url = 'https://api.weather.gov/gridpoints/FFC/52,88/forecast'
            r = requests.get(url)
            d = json.loads(r.text)
            periods = d['properties']['periods']
            today = periods[0]
            return today['detailedForecast']
    transitions = {
        'state': 'start',
        '`What can I do for you?`': {
            '[play, [!{#LEM(rain), rainy}, #LEM(taco)]]': {
                'state': 'play_raining_tacos',
                '#IF($RAINING_TACOS) `Don\'t make me sing this again!`': 'start',
                '#IF(#PLAY_RAINING_TACOS) `It\'s raining tacos. From out of the sky ...` #SETBOOL(RAINING_TACOS, True)': 'start',
            },
            '[{time, clock}]': {
                'state': 'time',
                '#TIME': 'end'
            },
            '[{weather, forecast}]': {
                'state': 'weather',
                '#WEATHER': 'end'
            },
            '#UNX': {
                '`Thanks for sharing.`': 'start'
            },
        }
    }
    
    macros = {
        'SETBOOL': MacroSetBool(),
        'PLAY_RAINING_TACOS': MacroPlayRainingTacos(),
        'TIME': MacroTime(),
        'WEATHER': MacroWeather()
    }
    S: What can I do for you?
    U: How is the weather today?
    S: A chance of rain showers. Cloudy, with a high near 68. South wind 0 to 5 mph. Chance of precipitation is 30%.

    4.6. Quiz

    hashtag
    Overview

    You aim to create a chatbot that makes a movie or a song recommendation. Your system should conduct dialogue including the following aspects:

    1. Greet with respect to the current time and/or weather.

    2. Ask about the user's name (with a different way of asking each time the user logins).

    3. If it is the first time the system sees the name, then prompt the first-time greeting. Otherwise, greet by asking about its previous recommendation.

    4. Recommend a movie or a song, depending on the user's request. Do not make the same recommendation more than once for each genre.

    5. If the user requests a different recommendation, make another suggestion.

    6. Provide more information about the recommendation upon request.

    Here is an example dialogue for a user talking to this chatbot for the first time:

    Here is an example dialogue for a user coming back for the second time:

    Your chatbot should give an appropriate response to every user response.

    hashtag
    Task 1

    1. Create a Python file under the package.

    2. Update it to design a dialogue flow for the chatbot.

    hashtag
    Task 2

    Create a PDF file quiz4.pdf that describes the following:

    • Sample dialogues that your chatbot can conduct.

    • Explanations of your approach.

    hashtag
    Submission

    1. Commit and push quiz4.py to your GitHub repository.

    2. Submit quiz4.pdf to Canvas.

    4. Interaction Design

    hashtag
    Content

    1. State Referencing

    hashtag
    Resource

    • Source code:

    4.3. Compound States

    hashtag
    Multiple Topics

    A dialogue flow can be complex when you start adding multiple topics. In this case, you can create a separate transition dictionary for each topic.

    Let us create transitions talking about music and movies:

    Advanced Interaction
    Compound States
    Global Transition
    Saving and Loading
    Quiz
    interaction_design.pyarrow-up-right
    quiz4.pyarrow-up-right
    quizarrow-up-right
    S: Good afternoon; it's sunny today. What should I call you?
    U: Call me Jinho.
    S: Hi, Jinho. Nice to meet you. What do you want me to recommend?
    U: A movie, please.
    S: How about "Spider-Man: Homecoming"? It's my personal favorite.
    U: I've already seen that.
    S: Got ya. How about "The Sound of Music"? It's classic.
    U: Sure, I'll watch that one. Thanks.
    S: Don't mention. 
    S: Good morning; it's cloudy today. What's your name?
    U: I'm Jinho.
    S: Welcome back, Jinho. Did you get to watch "The Sound of Music"?
    U: Yes, I did. I loved it.
    S: Wonderful. What else do you want me to recommend?
    U: Maybe, a song?
    S: How about "Raining Tacos"?
    U: What is it about?
    S: It's a fun children's song by Parry Gripp.
    U: Sure, I'll listen to that.
    S: Enjoy!
    #3: directs to the music state.
  • #4: directs to the movie state.

  • The music and movie states can be defined in separate transition dictionaries:

    • #5: directs to the start state.

    • #8: directs to the movie state.

    • #5: directs to the start state.

    • #8: directs to the music state.

    Finally, all three transition dictionaries can be loaded to the same dialogue flow:

    Overview of the above transitions combining three transition dictionaries.

    When the dialogue flow runs, it randomly selects one of the 3 states, music, movie, and end:

    • #1: randomly selects the music state.

    • #3: switches to the movie state when it does not understand the user input.

    • #5: switches to the music state when it does not understand the user input.

    • #7: goes back to the start state when it understands the user input, and randomly selects the movie state.

    • #9: goes back to the start state when it understands the user input, and randomly selects the music state.

    • #11: goes back to the start state when it understands the user input, and randomly selects the end state.

    • #1: randomly selects the end state and terminates the dialogue.

    hashtag
    Gating

    The randomness in the above transitions can be quite annoying because it may end the dialogue immediately after it runs or repeats the same topic over and over. This can be alleviated by using the #GATE built-in macro:

    • #3: puts the music topic to an open gate.

    • #4: puts the movie topic to an open gate.

    • #4: has no gate to open (so it can be selected at any time).

    Once an output is selected, #GATE closes the door for that output such that it will never be selected again.

    circle-info

    It is important to have at least one output with no gate; otherwise, the system will crash unless one of the outputs leads to the end state.

    hashtag
    Scoring

    The gating prevents the system from repeating the same topic, but the end state can still be selected at any time without consuming all the other topics. To ensure that the end state gets selected last, we use scoring:

    • #6: indicates that this is the end state.

    • #7: assigns the score of this state to 0.1.

    By default, all states receive a score of 1; thus, assigning a score below 1 would make that state not selected at all unless there are dynamic scoring changes through macros such as #GATE.

    4.5. Saving and Loading

    hashtag
    Saving

    Let us create a simple transition that counts how many times the user visits:

    • #4: calls the macro #VISITS defined in #7.

    MacroVisits can be defined as follow:

    • #10-13: uses the statements to return the appropriate literal.

    The challenge is that we must save the number of visits to make this macro effective (and correct). This can be achieved by saving the variable dictionary into a binary file using the built-in Python object serialization called :

    • #1: takes a dialogue flow df and a file path varfile for saving the variable dictionary to.

    • #3: creates a dictionary by copying only user-generated variables.

    After running this code, you will see the visits.pkl file saved under the resources directory.

    hashtag
    Loading

    The following code shows how to load the saved dictionary to a new dialogue flow:

    • #1: takes a dialogue flow df and a file path varfile for loading the variable dictionary from.

    • #2: opens a readable (r) and binary (b) file and loads the object as a dictionary.

    4.4. Global Transition

    hashtag
    Exercise

    1. Draw a diagram describing the following dialogue flow.

    2. What is the role of MacroWhatElse?

    hashtag
    Global Transitions

    It is often the case that the user says something out of the topic that the system expects. One way of handling such occasions is by using global transitions that anticipate common cases:

    • #1-8: creates global transitions.

    • #10: adds the global transitions to the dialogue flow.

    circle-info

    Notice that after prompting an output in the global transitions, it will direct to the good state defined in the regular transitions.

    The global transitions are fired whenever the user content matches their conditions, which can cause multiple matching conditions as follow:

    • #5: matches the condition in the movie state.

    • #5: matches the condition in the global transition.

    Thus, it is recommended to put lower scores on the conditions in global transitions such that local transitions are prioritized over them:

    transitions_music = {
        'state': 'music',
        '`What is your favorite song?`': {
            '[[!{#LEM(rain), rainy}, #LEM(taco)]]': {
                '`I love children\'s songs by Parry Gripp.`': 'start',
            },
            'error': {
                '`Sorry, I don\'t know that song.`': 'movie'
            }
        }
    }
    transitions_movie = {
        'state': 'movie',
        '`What is your favorite movie?`': {
            '[{#LEM(avenger), iron man, hulk}]': {
                '`I love the Marvel Cinematic Universe.`': 'start',
            },
            'error': {
                '`Sorry, I don\'t know that movie.`': 'music'
            }
        }
    }
    S: Let's talk about music. What is your favorite song?
    U: Doremi Song
    S: Sorry, I don't know that song. What is your favorite movie?
    U: Superman
    S: Sorry, I don't know that movie. What is your favorite song?
    U: Raining Tacos
    S: I love children's songs by Parry Gripp. Let's talk about movies. What is your favorite movie?
    U: Iron man
    S: I love the Marvel Cinematic Universe. Let's talk about music. What is your favorite song?
    U: It's raining tacos
    S: I love children's songs by Parry Gripp. That\'s all I can talk about.
    S:  Let's talk about music. What is your favorite song?
    U: Raining Tacos
    S: I love children's songs by Parry Gripp.  Let's talk about movies. What is your favorite movie?
    U: Iron Man
    S: I love the Marvel Cinematic Universe. That's all I can talk about.
    transitions = {
        'state': 'start',
        '#GATE `Let\'s talk about music.`': 'music',
        '#GATE `Let\'s talk about movies.`': 'movie',
        '`That\'s all I can talk about.`': 'end',
    }
    transitions = {
        'state': 'start',
        '`Let\'s talk about music.`': 'music',
        '`Let\'s talk about movies.`': 'movie',
        '`That\'s all I can talk about.`': 'end'
    }
    df = DialogueFlow('start', end_state='end')
    df.load_transitions(transitions)
    df.load_transitions(transitions_music)
    df.load_transitions(transitions_movie)
    df.run()
    transitions = {
        'state': 'start',
        '#GATE `Let\'s talk about music.`': 'music',
        '#GATE `Let\'s talk about movies.`': 'movie',
        '`That\'s all I can talk about.`': 'end',
    }
    transitions = {
        'state': 'start',
        '#GATE `Let\'s talk about music.`': 'music',
        '#GATE `Let\'s talk about movies.`': 'movie',
        '`That\'s all I can talk about.`': {
            'state': 'end',
            'score': 0.1
        }
    }
    def visits() -> DialogueFlow:
        transitions = {
            'state': 'start',
            '`It\'s your` #VISITS `visit!`': 'end'
        }
    
        macros = {
            'VISITS': MacroVisits()
        }
    
        df = DialogueFlow('start', end_state='end')
        df.load_transitions(transitions)
        df.add_macros(macros)
        return df
    S: That\'s all I can talk about.
    transitions = {
        'state': 'start',
        '`Hi there, how are you doing today?`': {
            '[{good, fantastic}]': {
                'state': 'good',
                '`Glad to hear that.` #WHAT_ELSE': {
                    '[#LEM(movie)]': 'movie',
                    '[music]': 'music',
                    'error': {
                        'state': 'goodbye',
                        '`Goodbye!`': 'end'
                    }
                }
            },
            'error': 'goodbye'
        }
    }
    
    music_transitions = {
        'state': 'music',
        '`My favorite song is "Raining Tacos"! What\'s yours?`': {
            'error': 'good'
        }
    }
    
    movie_transitions = {
        'state': 'movie',
        '`My favorite movie is "Spider-Man: Homecoming"! What\'s yours?`': {
            'error': 'good'
        }
    }
    
    macros = {
        'WHAT_ELSE': MacroWhatElse()
    }
    
    class MacroWhatElse(Macro):
        def run(self, ngrams: Ngrams, vars: Dict[str, Any], args: List[Any]):
            vn = 'HAVE_TALK'
            if vn in vars and vars[vn]:
                return 'What else do you want to talk about?'
            else:
                vars[vn] = True
                return 'What do you want to talk about?'
    
    df = DialogueFlow('start', end_state='end')
    df.load_transitions(transitions)
    df.load_transitions(music_transitions)
    df.load_transitions(movie_transitions)
    df.add_macros(macros)
    S: Hi there, how are you doing today?
    U: Fantastic!
    S: Glad to hear that. What do you want to talk about?
    U: Let's talk about movies
    S: My favorite movie is "Spider-Man: Homecoming"! What's yours?
    U: The Sound of Music
    S: Glad to hear that. What else do you want to talk about?
    U: How about music?
    S: My favorite song is "Raining Tacos"! What's yours?
    U: Amazing Grace
    S: Glad to hear that. What else do you want to talk about?
    U: That's it..
    S: Goodbye!
    gloabl_transitions = {
        '[{covid, corona, virus}]': {
            '`I hope you are OK.`': 'good'
        },
        '[{birthday}]': {
            '`Happy birthday to you!`': 'good'
        }
    }
    
    df.load_global_nlu(gloabl_transitions)
    S: Hi there, how are you doing today?
    U: Good
    S: Glad to hear that. What do you want to talk about?
    U: Music
    S: My favorite song is "Raining Tacos"! What's yours?
    U: I got vaccinated for COVID
    S: I hope you are OK. Glad to hear that. What else do you want to talk about?
    U: It's my birthday
    S: Happy birthday to you! Glad to hear that. What else do you want to talk about?
    U: I'm done
    S: Goodbye!
    S: Hi there, how are you doing today?
    U: Good
    S: Glad to hear that. What do you want to talk about?
    U: Let's talk about virus movies
    S: My favorite movie is "Spider-Man: Homecoming"! What's yours?
    S: Hi there, how are you doing today?
    U: Good!
    S: Glad to hear that. What do you want to talk about?
    U: Let's talk about virus movies
    S: I hope you are OK. Glad to hear that. What else do you want to talk about?
    gloabl_transitions = {
        '[{covid, corona, virus}]': {
            'score': 0.5,
            '`I hope you are OK.`': 'good'
        },
        '[{birthday}]': {
            'score': 0.5,
            '`Happy birthday to you!`': 'good'
        }
    }
    #4: a writable (w) and binary (b) file and dumps the dictionry object into the file.

    #3: adds all variables in the loaded dictioinary to the variable dictionary of df.

  • #5: saves the new variable dictionary to the same file.

  • matcharrow-up-right
    picklearrow-up-right
    class MacroVisits(Macro):
        def run(self, ngrams: Ngrams, vars: Dict[str, Any], args: List[Any]):
            vn = 'VISITS'
            if vn not in vars:
                vars[vn] = 1
                return 'first'
            else:
                count = vars[vn] + 1
                vars[vn] = count
                match count:
                    case 2: return 'second'
                    case 3: return 'third'
                    case default: return '{}th'.format(count)
    S: It's your first visit!
    def save(df: DialogueFlow, varfile: str):
        df.run()
        d = {k: v for k, v in df.vars().items() if not k.startswith('_')}
        pickle.dump(d, open(varfile, 'wb'))
    
    save(visits(), 'resources/visits.pkl')
    def load(df: DialogueFlow, varfile: str):
        d = pickle.load(open(varfile, 'rb'))
        df.vars().update(d)
        df.run()
        save(df, varfile)
    S: It's your second visit!
    S: It's your third visit!
    S: It's your 4th visit!
    opensarrow-up-right