Superpower your push notifications with AI
Tags: ai, python, gpt3, programming
Published: 2023-05-15 00:30:47

Lately, I've been spending a lot of time thinking about how best to target users in a meaningful way that doesn't feel so spammy - I've come to the conclusion that AI can help me with super, super personalized, almost real time personalization. 

In particular, I want to focus on push notifications - in my experience, our phones are over saturated with notifications. Looking at my screen right now, I have about 56 notifications from different apps and none of them really stand out to me.

Is using AI over engineering? Well, I would say for most companies or apps with a couple of thousand users it's not scalable to handcraft push notifications that are personalised, timely and also have the ability to change certain aspects based on user behavior. 

So let's see how we can do better with AI. For the purpose of this demo, let's pretend we're working for a food delivery app - you know the kind; restaurants, delivery drivers and food orderers in one eco-system. 

Okay, so  let's consider why and when we'd want to send push notifications. I see a few potentials: 
- Big events (sports, holidays, those international something days)
- New restaurants
- Targeting a user based on who they are (dietary requirements, are they traveling? Where do they normally order from? etc)

There's more but let's keep it to these ones for now. 

First up, we're going to start with generic push notifications for restaurants. 

For this, I'm using a subset of Zomato restaurants, pulled from [here](https://www.kaggle.com/datasets/shrutimehta/zomato-restaurants-data?select=zomato.csv) and cleaned for my needs. 

## Data set up

We're going to ingest all the restaurant data, and their details into a vector database - this is what's going to allow us to plug in an LLM eventually, which will create descriptions, push notifications and eventually make decisions on changing pushes and when to send pushes.

[You can find the full code here ](https://gist.github.com/aarushik93/65318d6bbb6b2642001cad77f80e59b0)

But let's focus on some specifics: 

```
Restaurant = {
        "classes": [
            {
                "class": "Restaurant",
                "description": "An MunchMate Restaurant.",
                "moduleConfig": {
                    "text2vec-openai": {
                        "skip": False,
                        "vectorizeClassName": False,
                        "vectorizePropertyName": False
                    }
                },
                "vectorIndexType": "hnsw",
                "vectorizer": "text2vec-openai",
                "properties": [
                    {
                        "name": "description",
                        "dataType": ["text"],
                        "description": "The general description written by an LLM.",
                        "moduleConfig": {
                            "text2vec-openai": {
                                "skip": False,
                                "vectorizePropertyName": False,
                                "vectorizeClassName": False
                            }
                        }
                    },
              // code omitted     
    }
```

Take a look at the Restaurant class, which contains all of the details of the restaurant (or any other entity you want to focus on for your usecase). In particular notice, we use text2vec-openai module to vectorize the description - here you can use any other model and module (plenty of new things coming out). 

The reason I'm only vectorizing description in this example is because that's the only thing I envision doing a semantic search on later down the line. 

## Descriptions

Okay, so next up, we need to write a description for the restaurant. I don't want to do it manually TBH! 

So, let's use our LLM to actually generate a restaurant's description. Here, it depends on your usecase, in particular your CRM and/or marketing strategy on what you want to focus on about the restaurant. 

My prompt is as follows: 

```
    Create a description, for a restaurant with the following details:
    Restaurant Name: {restaurantName}
    Cuisines: {cuisines}
    Delivering now: {isDeliveringNow}
    Table Booking Offered: {hasTableBooking}
    City: {city}

    Stick to the information provided. Do not make up any information about the restaurant in your description.
```

With this, I end up with various descriptions like this: 

```
BJ's Country Buffet is an American and BBQ restaurant located in Albany, offering a range of delicious dishes. With both dine-in and delivery options, you can enjoy the restaurant's offerings from the comfort of your own home. You can also book a table in advance to make sure you have the perfect spot to enjoy their delicious cuisine.
```

 The reason I'm setting up descriptions rather than just creating push notifications directly from the restaurants details is because I want this to become a base for all different types of marketing campaigns, CRM and anything that involves content to get users back into the app.


Now on to the fun stuff.

## Push Notifications For Events

Like we talked about initially, one of the usecases for custom pushes could be specific events. A push crafted for each individual restaurant. 

Again, [you can check out the full code here](https://gist.github.com/aarushik93/65318d6bbb6b2642001cad77f80e59b0) 

I'll walk you through some parts of it. 

```
events = ["valentines day", "super bowl", "international women's day"]
    for e in events:
        generatePrompt = """
          Write a tempting, short push notification, with a short heading for the following new Restaurant:
          Description: {description}.
         Do not make up any information in the push notification
         Target the push towards: {event}
    
        Style:
        Heading:
        Content: 
        """


// code omitted

new_push_properties = {
                "content": push_content,
                "event": e
            }
            new_push_id = get_valid_uuid(uuid4())
            client.data_object.create(
                data_object=new_push_properties,
                class_name="Push",
                uuid=new_push_id
            )
            client.data_object.reference.add(
                from_uuid=restaurant["_additional"]["id"],
                from_property_name="hasPush",
                to_uuid=new_push_id
            )
```


So, this time we've changed our prompt to creating a push notification, based on the description. This is where you can also get a bit more creative: maybe you have a certain style or tone of voice that you want all pushes to sound like. This is where you can also pass examples of those in. 

In this example, I end up with pushes like this: 

Heading: Sweet Valentine's Day!
Content: Satisfy your sweet tooth at Cookie Shoppe!

This is pretty good so far, minimal manual effort - code it once and every time there's a new event, you can have a bunch of pushes for each restaurant. Or maybe every time you have a new restaurant added on a particular event day, an automatic push is generated and sent out - hopefully getting you users to that restaurant. 

Let's take it further and personalise to each individual user. Not just by name, but by information we already have about them. 


## Personalised Push Notifications

Okay so for this step you're going to need information about your users to create a sort of biography about them. For simplicities sake, I've created bios for users in this example. But in reality you can get more creative and collect information about users based on their eating history, you can ask them to input preferences. For other applications, maybe you can think about social logins and asking to collect some information about them from there. 


Let me walk you through some of the specifics: 

First, I've gone ahead and created a User class. Which just contains a name and bio (remember in a real life case this data structure is likely to be more complex). 

```
    user_schema = {
        "classes": [
            {
                "class": "User",
                "description": "A user.",
                "properties": [
                    {
                        "dataType": ["text"],
                        "name": "biography",
                    },
                    {
                        "dataType": ["text"],
                        "name": "name"
                    }
                ]
            }
        ]
    }
```

Next, I've given two users bios. 

```
"biography": "Alex enjoys Mexican food, hates valentines day, loves the superbowl",
        "name": "Alex"


"biography": "Alice is a vegetarian, woman, loves Valentines day and the superbowl.",
        "name": "Alice"
```

Note here, one of the good things about LLMs is that you don't need to be super strict on the structure of bio or what information to include - essentially whatever information you have - pop it in and let the LLM work it's creativity to give some personalized. Some personalization is better than none I say.

The prompt I'm using: 

```
            generatePrompt = """
                 Write a short, targeted, clever, punchy push notification, with a short heading for the following new Restaurant:
                Description: {description}.
                The push notification should appeal to this user, based on their biography, likes and dislikes: {person}.
                Base the push notification on today's event: {event}.
                Use their name.
                Do not make up any information in the push notification. 
                Style:
                Heading:
                Content: 
            """
```

Again, you can be as creative as you want with the prompt!


And I end up with pushes like these: 

```
Heading: Bye Bye V-Day!
Content: Alex, treat yourself to BBQ at BJ's! Enjoy dine-in or delivery.
Heading: Valentine's Day at Austin's!
Content: Alex, forget roses, get BBQ! Order now: Austin's BBQ & Oyster Bar
Heading: Skip the Date Night
Content: Alex, forget V-Day with taco night at El Vaquero!
Heading: Bye Bye Valentines!
Content: Alex, end the day with something sweet at Cookie Shoppe!


Heading: Veg Out Today!
Content: Alice, make Valentine's Day extra special with a delicious feast from Austin's BBQ and Oyster Bar!
Heading: Celebrate V-Day with Alice!
Content: Enjoy Mexican-style vegetarian dishes at El Vaquero Mexican Restaurant in Albany!
Heading: Valentine's Day at Cookie Shoppe!
Content: Alice, satisfy your sweet tooth with our delicious veg options!

```

What I really like about these is it's taking into account differences in each person based on their bios. For example,  Alex doesn't like Valentines day, but Alice does. Or the fact that Alice is vegetarian, but we don't know Alex's dietary requirements so it doesn't focus on that aspect.


Annnd there you have it - few hundred lines of code and now you can have you're own fully personalised push notification builder. 

Take it a step further and you can build out full blow marketing campaigns. 

In my personal work, I'm going to be taking it further and figuring out the tone of voice my users react best to. If it's of interest, let me know and I'll write about that too!