emora-chat / emora_stdm

State Transition Dialogue Manager
24 stars 9 forks source link

#SET and #IF assume variables are Strings #18

Open talynfan opened 1 year ago

talynfan commented 1 year ago

SET sets variables to a String type. #IF compares against a String, too. This issue is illustrated in the attached interactive script.

https://github.com/emora-chat/emory-virtual-assistant/blob/188ae6a3e85fb0d815ecdf69baeb028b862c6297/personal_workspaces/talyn/tutorials/all_vars_are_strings_example.py

#!natex
# Talyn Fan
# Created 2/8/2023
# Here we are illustrating the limitations of emora-stdm #SET and #IF macros.
# Basically, variables get set (and then tested) as Strings within the DialogueFlow syntax.

from emora_stdm import DialogueFlow, Macro

class Set_Bool_True(Macro):
    # args: the name of a variable you want to set True
    # Dollar sign is optional.
    def run(self, ngrams, vars, args):
        variable = args[0]
        if variable[0] == '$':
            variable = variable[1:]
        vars[variable] = True  # This is a Boolean True!

        return True  # just go back

class Set_Bool_False(Macro):
    # args: the name of a variable you want to set False
    # Dollar sign is optional.
    def run(self, ngrams, vars, args):
        variable = args[0]
        if variable[0] == '$':
            variable = variable[1:]
        vars[variable] = False  # This is a Boolean False!

        return True  # just go back

class Set_None(Macro):
    # args: the name of a variable you want to set None
    # Dollar sign is optional.
    def run(self, ngrams, vars, args):
        variable = args[0]
        if variable[0] == '$':
            variable = variable[1:]
        vars[variable] = None  # This is the real None.

        return True  # just go back

df = DialogueFlow(
    'start', end_state='end',
    transitions= {
        'state': 'start',
        "`Give me an option 0 through 6 and see what happens.`": {
            '{0}': {
                "`Using the #SET macro, the variable foo is set to a String 'hello'.` #SET($foo=hello)": {
                    'error': {
                        "`So right now, foo is` $foo `.`" : {
                            'error': {
                                "#IF($foo=hello) `foo passed the #IF check. 'hello' == 'hello'`": 'start',  # loop back
                                "`foo did not pass the #IF check. BUT I SHOULD NEVER SAY THIS!`": {
                                    'score': 0,
                                    'state': 'start'
                                }
                            }
                        }
                    }
                }
            },
            '{1}': {
                "`Using the #SET macro, the variable foo is set to a String 'True'.` #SET($foo=True)": {
                    'error': {
                        "`So right now, foo is` $foo `.`": {
                            'error': {
                                "#IF($foo=True) `foo passed the #IF check. 'True' == 'True'`": 'start',  # loop back
                                "`foo did not pass the #IF check. BUT I SHOULD NEVER SAY THIS!`": {
                                    'score': 0,
                                    'state': 'start'
                                }
                            }
                        }
                    }
                }
            },
            '{2}': {
                "`Using the #SET macro, the variable foo is set to a String 'False'.` #SET($foo=False)": {
                    'error': {
                        "`So right now, foo is` $foo `.`": {
                            'error': {
                                "#IF($foo=False) `foo passed the #IF check. 'False' == 'False'`": 'start',  # loop back
                                "`foo did not pass the #IF check. BUT I SHOULD NEVER SAY THIS!`": {
                                    'score': 0,
                                    'state': 'start'
                                }
                            }
                        }
                    }
                }
            },
            '{3}': {
                "`Using the #SET macro, the variable foo is set to a String 'None'.` #SET($foo=None)": {
                    'error': {
                        "`So right now, foo is` $foo `. BUT I SHOULD NEVER SAY THIS!`": 'start',
                        "`foo is 'None', which gets interpreted as actually None. So you can't reference it to say what it is, because it doesn't exist.`": {
                            'score': 0,
                            'error': {
                                "#IF($foo=None) `foo passed the #IF check. 'None' == 'None'`": 'start',  # loop back
                                "`foo did not pass the #IF check. BUT I SHOULD NEVER SAY THIS!`": {
                                    'score': 0,
                                    'state': 'start'
                                }
                            }
                        }
                    }
                }
            },
            '{4}': {
                "`Using the #SETBOOLTRUE macro, the variable foo is set to a Boolean True.` #SETBOOLTRUE($foo)": {
                    'error': {
                        "`So right now, foo is` $foo `. The boolean True gets stripped out and the transition is evaluated as True.`": {
                            'error': {
                                "#IF($foo=True) `foo passed the #IF check. BUT I SHOULD NEVER SAY THIS!`": 'start',
                                "`foo did not pass the #IF check. True != 'True'`": {
                                    'score': 0,
                                    'state': 'start'  # loop back
                                }
                            }
                        }
                    }
                }
            },
            '{5}': {
                "`Using the #SETBOOLFALSE macro, the variable foo is set to a Boolean False.` #SETBOOLFALSE($foo)": {
                    'error': {
                        "`So right now, foo is` $foo `. BUT I SHOULD NEVER SAY THIS!`": 'start',
                        "`foo is False, so you can't reference it to say what it is, because then the whole transition is False.`": {
                            'score': 0,
                            'error': {
                                "#IF($foo=False) `foo passed the #IF check. BUT I SHOULD NEVER SAY THIS!`": 'start',
                                "`foo did not pass the #IF check. False != 'False'`": {
                                    'score': 0,
                                    'state': 'start'  # loop back
                                }
                            }
                        }
                    }
                }
            },
            '{6}': {
                "`Using the #SETNONE macro, the variable foo is set to None, meaning it doesn't exist anymore.` #SETNONE($foo)": {
                    'error': {
                        "`So right now, foo is` $foo `. Weirdly enough, this transition works?`": {
                            'error': {
                                "#IF($foo=None) `foo passed the #IF check. BUT I SHOULD NEVER SAY THIS!`": 'start',
                                "`foo did not pass the #IF check. None != 'None'`": {
                                    'score': 0,
                                    'state': 'start'  # loop back
                                }
                            }
                        }
                    }
                }
            },
            'error': {
                "`You are not doing a good job of following instructions.`": 'start' # loop back
            }
        }
    },
    macros={
        'SETBOOLTRUE': Set_Bool_True(),
        'SETBOOLFALSE': Set_Bool_False(),
        'SETNONE': Set_None()
        # I can't have underscores, because the stdm doesn't support underscores in string literals
        # (thus I can't talk about the macros in the dialogue output...)
    }
)

if __name__ == '__main__':
    # Turn debugging=True to really see what's happening.
    df.run(debugging=False)