How can I randomly fill slots with actions?

You can see my actions page in the image. I want to assign the data in the if block corresponding to that value by choosing a random number to the slots.

If a random value of 3 comes in, I want to place the data in the 3rd if block into the slots I defined.

I can do this correctly with the code you see now, but I don’t think this use creates a clean code.

How should I do this process more properly? Can I use things like creating a database or struct in the domain? Or can I define this data in a different place, not in actions?

I currently use individual slotsets to put each data into the slots. How correct is it in terms of programming if I use it this way?

That question is related to general Python more than Rasa. Maybe you can find better help on Stack Overflow, but I’ll guide you :slight_smile:

It’s bad to stack ifs like that. What if you have 100 elements, each one with 50 properties? You code should be scalable for any number of data and any number of properties, and maybe even each data having different properties. When you see something repetitive like this, you have two choices: for loops and/or functions.

It’s easily achievable to do this using JSON and a for loop.

You can define that data in a JSON file in the same folder as the actions. You can also use an SQL database, Python classes, or whatever you prefer. Let’s stick to JSON for now. Create a file called sayi.json for example with the following format:

{
  "data": [
    {
      "isim": "At",
      "renk": "Kahverengi",
      "bacak": 4,
      etc...
    },
    {
      "isim": "Kus",
      "renk": "Mavi",
      "bacak": 2,
      // etc...
    },
    // etc...
  ]
} 

Then, in your action’s run() method, read that file, transform it into a Python list, and access the sayith element, then set the slots!

Don’t forget to add import json at the top of the actions.py file.

# Initialize the variable
data = []

# Fill `data` with the file
with open('sayi.json') as file:
    data = json.load(json_file)['data']

# Generate a random number between 0 and the number of objects
sayi_number = random.randint(len(data))

# Get the `sayi_number`th object
sayi = data[sayi_number]

dispatcher.utter_message(str(sayi_number))

return [
    SlotSet("hayvan_adi": sayi['isim']),
    SlotSet("hayvan_rengi": sayi['renk']),
    SlotSet("hayvan_bacak": sayi['bacak']),
    # etc...
]

Even better: I suggest that you give the attributes the same names as the slots (or at least be able to deduce one from the other as I’ll do next). If you do that, you won’t even have to write multiple SlotSet()s:

{
  "data": [
    {
      "adi": "At",
      "rengi": "Kahverengi",
      "bacak": 4,
      etc...
    },
    {
      "adi": "Kus",
      "rengi": "Mavi",
      "bacak": 2,
      // etc...
    },
    // etc...
  ]
} 

Then, you can do this:

# Initialize the variable
data = []

# Fill `data` with the file
with open('sayi.json') as file:
    data = json.load(json_file)['data']

# Generate a random number between 0 and the number of objects
sayi_number = random.randint(len(data))

# Get the `sayi_number`th object
sayi = data[sayi_number]

slot_sets = []

# Make a `SlotSet()` for every key-value pair
for key, value in sayi.items():
    slot_name = "hayvan_" + str(key)
    slot_value = value
    slot_sets.append(SlotSet(slot_name, slot_value)

dispatcher.utter_message(str(sayi_number))

return slot_sets

or even:

data = json.load('sayi.json')['data']
sayi_number = random.randint(len(data))
dispatcher.utter_message(str(sayi_number))

return [SlotSet("hayvan_" + str(key), value) for key, value in data[sayi_number].items()]

It’s also doable in one line :slight_smile: But of course, the code will be less readable without any quality/scalability improvements. What I would do is the final code, not less than that. But if you’re still a beginner, the one before that should be good so that you can understand better.

1 Like

Thank you, i needed this :innocent:

1 Like