Mission Chai

🎯 Ace your technical interviews with Chai (and the magic of spaced repetition ✨)

Google’s recruiting process for software engineers typically involves several rounds for testing your coding aptitude. You’ve heard the advice again and again: to ace these technical interview you need a solid foundation in Data Structures and Algorithms problems.

During my time at university I managed to do pretty well on the Algorithms course I took - in this article I’ll walk you through how I did it, in the hopes that I can help you ace your technical interviews. These techniques can be applied to learning pretty much anything!

To learn the nitty-gritty concepts we will be using a method called spaced repitition, which makes use of a phenomenon called the spacing effect, which describes how our brains learn more effectively when we space out our learning over time. It’s a brilliant technique and has been written about at length by many people who know better than me. For now, all I will say is that effective use of flashcards can feel like magic for remembering.

Setup:

  1. pip install chaipy and pip install supermemo2
  2. Get the Chai app.
  3. Sign in to Chai Developer Platform .
  4. Scroll to the bottom and get your “Developer Unique ID” and “Developer Key”.

Next, I’ll show you how to make a class which holds our flashcards.

from supermemo2 import SMTwo

class Flashcard:
    def __init__(self, question, answer):
        self.question = question
        self.answer = answer
        self.review = None

    def update_review(self, quality):
        """ Take the user's input to set the flashcard 'easiness'. """
        quality = int(quality)
        if self.review is None: # i.e. not yet reviewed
            self.review = SMTwo.first_review(quality)
            return self.review
        self.review = self.review.review(quality)
        return self.review

    def __lt__(self, other):
        """ Use the magic 'less-than' method to help us sort the flashcards. """
        if self.review is None:
            return True
        if other.review is None:
            return False
        if self.review.review_date == other.review.review_date:
            return self.review.easiness < other.review.easiness
        return self.review.review_date < other.review.review_date

    def __repr__(self):
        """ Giving our Flashcard a printable output can be helpful
            in the development process. """
        return f"{self.question}, {self.answer}, {self.review}"

So there we have it! This class will hold our questions, answers and the SMTwo object to calculate our spaced repetition.

Next, we’re going to make a simple enum to help us keep track of where we are in the process of going through a flashcard.

from enum import Enum, auto

class MessageType(Enum):
    QUESTION = auto()
    # In our example, we don't care about the user's answer.
    # ANSWER = auto()
    QUALITY = auto()

These will come in handy in our next step, where we will be using the chaipy package.

from chai_py import ChaiBot, Update

class Bot(ChaiBot):
    def setup(self):
        self.logger.info("Setting up...")
        self.flashcards = [
                Flashcard("What is a heap?", "The (binary) heap is an arraythat we can view as a nearly complete binary tree. Each node of the tree corresponds to an element of the array. The tree is filled on all levels except sometimes the lowest, which is filled starting from the left."),
                Flashcard("What is the max-heap property?", "For every node i other than the root A[parent(i)] >= A[i]"),
                ]
        self.previous_messagetype = None

    async def on_message(self, update: Update) -> str:
        if self.previous_messagetype is MessageType.QUESTION:
            self.previous_messagetype = MessageType.QUALITY
            return f"Answer: {self.flashcards[0].answer}\n\nHow easy was this? (1-5)"
        if self.previous_messagetype is MessageType.QUALITY:
            self.flashcards[0].update_review(update.latest_message.text)
            print(self.flashcards[0].review)
            self.flashcards.sort() # This is where __lt__ comes in handy!
        self.previous_messagetype = MessageType.QUESTION
        return self.flashcards[0].question

And you’re done! Now, we’re going to test out our flashcards. Open up your Python terminal and run the following:

from chai_py import TRoom
troom = TRoom([Bot()])
troom.chat()

Deploying to the mobile app: - Here’s the fun part. Now, you will be able to access your flashcards from anywhere, so long as you have your phone and an internet connection. This is the really valuable part of using Chai, so I’m excited to share this with you!

from chai_py import Metadata, package, upload_and_deploy, wait_for_deployment
from chai_py import share_bot, set_auth
from starter_bot import Bot
DEVELOPER_UID = None # Fill these in using the values from https://chai.ml/dev
DEVELOPER_KEY = None # Fill these in using the values from https://chai.ml/dev

set_auth(DEVELOPER_UID, DEVELOPER_KEY)
BOT_IMAGE_URL = "https://images.unsplash.com/photo-1566039263025-caf125cd0994?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1000&q=80"

package(
    Metadata(
        name="CLRS Flashcards 🧠🤑💯",
        image_url=BOT_IMAGE_URL,
        color="f1a2b3",
        description="'The secret to getting ahead is getting started.' – Mark Twain.",
        input_class=Bot,
     ),
    requirements=["supermemo2"],
)

bot_uid = upload_and_deploy(
    "_package.zip"
)

wait_for_deployment(bot_uid)
share_bot(bot_uid)

Next steps:

  • You could use regex to evaluate the user’s answer nicely and compare it to the stored answer.
  • You’ll inevitably end up with a huge list of flashcards. Move these into a separate file and import them in.
  • You could improve shuffling of the flashcards. Now, when you go through all your existing flashcards you get stuck on one.
  • You can include images in your flashcards. Chai allows Markdown syntax, so you simply need a URL for your image and you’re good to go: e.g. Flashcard(question="How would you construct a recurrence tree for T(n) = n^2?", answer="![](https://i.imgur.com/bRNWawz.png)")

Helpful resources:

GitHub repo of the code from this article: https://github.com/christie-cb/chai-flashcards


22 days ago

Christie-Carol Beauchamp