Creative Tect 4: Project 2-Chatbot

In this project, I am planning to make a chatbot that helps you decide what to eat for today. It is always difficult for me to choose what to eat and I hope there will be a bot that can recommend something to eat. At the beginning of the project, while I haven ’t planned what characteristics or UI might have, I want to first explore how to connect my bot with API.





Connecting API


First, I choose mealAPI for the resource and import this as an html/json link. I want people to have two options, one for the random selection of the meal, and one you could select by category. So fetch this two function from the mealAPI:


import os

import discord

import aiohttp

from discord.ui import View, Select

intents = discord.Intents.default()

intents.message_content = True

client = discord.Client(intents=intents)

async def get_random_recipe():

  url = "https://www.themealdb.com/api/json/v1/1/random.php "

  async with aiohttp.ClientSession() as session:

    async with session.get(url) as response:

      if response.status == 200:

        data = await response.json()

        return data['meals '][0] if data['meals '] else None

      else:

        return None

async def get_categories():

  url = "https://www.themealdb.com/api/json/v1/1/list.php?c=list "

  async with aiohttp.ClientSession() as session:

    async with session.get(url) as response:

      if response.status == 200:

        data = await response.json()

        return [category['strCategory '] for category in data['meals ']]

      else:

        return None

Then, as I said there would be two functions, I would provide two buttons for people to click. When I type in “What to eat ”or @ the bot, it would automatically come out the two buttons.

  if message.content.startswith("What to eat?"):

    our_view = MyCustomView()

    await message.channel.send("I am here to recommend you some recipes for today!", view=our_view)

  if client.user in message.mentions:

    our_view = MyCustomView()

    await message.channel.send("Thanks for mentioning Luka ", view=our_view )

Set up class and buttons


The first one is the random select function. Basically, if people clicked the button I set up, it would automatically give you a random recipe, including the name of the dish, how to cook it and the image of it.

class MyCustomView(View):

  def __init__(self):

    super().__init__()

  @discord.ui.button(label="Random Recipe ")

  async def button_callback(self, interaction, button):

    meal_data = await get_random_recipe()

    if meal_data:

      name = meal_data['strMeal ']

      image = meal_data['strMealThumb ']

      instructions = meal_data['strInstructions ']

      response_message = f "**Name:** {name}\n**Image:** {image}\n**Instructions:** {instructions}"

    else:

      response_message = "Oops! Something went wrong while fetching the random recipe."

    

    await interaction.response.send_message(response_message)

After setting up this button, the result would be like this:

The second option would be, selecting the category for the recipe, after click this button, a drop down menu would pop up, that using the category fetched in the API:

@discord.ui.button(label="Select Category ")

async def button_callback2(self, interaction, button):

  categories = await get_categories()

  if categories:

    select = CustomSelect(options=[discord.SelectOption(label=category) for category in categories])

    self.clear_items()

    self.add_item(select)

    await interaction.response.send_message("Select a category:", view=self)

  else:

    await interaction.response.send_message("Oops! Something went wrong while fetching the categories.")

The result would look like this:

However, for the first week, I was still having trouble fetching a random meal inside the category. I might have to revisit the API json to check up what exactly the functions were called, and I am not sure if they could still provide a random mean inside the category.

Further development

In this case, I cannot fix the problem of the drop down and I was interested in connecting the bot to the API again, so I changed my direction to add another API. In this case, I want to shape the conversation with the bot like, the users who are rude customers that the bot wants to satisfy them.

During the conversation, if the users are not satisfied with the first recommendation, to let angry customers cool down, the bot will recommend a cocktail for them. So I tried to connect the cocktail api.

async def get_random_cocktail():

  url = "https://www.thecocktaildb.com/api/json/v1/1/random.php "

  async with aiohttp.ClientSession() as session:

    async with session.get(url) as response:

      if response.status == 200:

        data = await response.json()

        return data['drinks '][0] if data['drinks '] else None

      else:

        return None

After fetching the data from the API, I started to write down the conversation and the reaction I mentioned before:

follow_up_view = FollowUpView()

    follow_up_message = await interaction.followup.send("Did you satisfy with my recommendation?", view=follow_up_view)

    # Update the follow-up view with the message reference for callback

    follow_up_view.message_reference = follow_up_message.to_reference()

class FollowUpView(discord.ui.View):

  def __init__(self):

    super().__init__()

  @discord.ui.button(label="Yes ")

  async def yes_button_callback(self, interaction, button):

    await interaction.response.send_message("Great to hear!")

  @discord.ui.button(label="Not at all! I don 't like your recommendation!", emoji="😡")  # Add the angry emoji

  async def no_button_callback(self, interaction, button):

    cocktail_data = await get_random_cocktail()

    if cocktail_data:

      name = cocktail_data['strDrink ']

      image = cocktail_data['strDrinkThumb ']

      response_message = f "To show my apology, please try this cocktail:\n**Name:** {name}\n**Image:** {image}"

    else:

      response_message = "Oops! Something went wrong while fetching the random cocktail."

    # Send the cocktail recommendation as a new message

    await interaction.response.send_message(response_message)

And this is what the conversation looks like:

After this, I would like to add one more conversation , like  the customer was still not satisfied with the result and felt angry constantly, the bot got angry too and refused service. Here is the follow up conversation:

 cocktail_follow_up_view = CocktailFollowUpView()

    cocktail_follow_up_message = await interaction.followup.send(

      "Are you satisfied with my cocktail recommendation?", view=cocktail_follow_up_view

    )

    # Update the cocktail follow-up view with the message reference for callback

    cocktail_follow_up_view.message_reference = cocktail_follow_up_message.to_reference()

class CocktailFollowUpView(discord.ui.View):

  def __init__(self):

    super().__init__()

  @discord.ui.button(label="Yes! I feel better ")

  async def yes_button_callback(self, interaction, button):

    await interaction.response.send_message("I 'm glad you feel better!")

  @discord.ui.button(label="😠😠No you are not doing a proper job ")

  async def no_button_callback(self, interaction, button):

    await interaction.response.send_message("I 'm a bit upset now, and I may not be able to assist you further. Find another bot! ")

The conversation would look like this:

Since I was having the idea before knowing how to draw a decision tree, I feel like it ’s quite hard to turn it into decision tree format. Also, the conversations and options are not complex, so I just keep the format as follow up questions.




Video documentation



https://youtube.com/shorts/UeP8uhwNsgo