Content Generation

Children

Related:


Intro: Simple Emails

An english explanation can often get the API started on what to write, although implicit domains and whatnot will give it some level of guessing what you want.

For instance, you can feed in a task explanation:

The following email explains two things:
1) The writer, Andy, is going to miss work.
2) The receiver, Betty, is Andy's boss and can email if anything needs to be done.

From: [EOP]

and it'll fill in what it thinks should come next as well as guess the response!

Andy
To: Betty
Subject: [email protected]
Hi Betty,
I am going to be out of the office on Thursday and Friday this week.
The reason is that I have to attend a conference in the city.
I will be back on Monday.
If anything urgent comes up, please email me.
Andy

From: Betty
To: Andy
Subject: Re: [email protected]
Hi Andy,
No problem.
I will let you know if anything urgent comes up.
I hope you have a good time at the conference.
Betty

Ads

One of the most immediately viable uses of GPT-3 is content marketing.
This section uses the code at https://gist.github.com/brockmanmatt/7593226da604f8827825ef405df2b0fd and https://gist.github.com/markketai/b537f0bd10e0190980b96ebaf05620b0 to create simple ads.

Background:

As many people are finding out, while GPT-3 is great at generating content off of the implicit relations in the neural network, it doesn't actually understand anything. GPT generation ends up being a factor of the current model, the way the model is primed with the prompt, and the quality of the data that it's being primed with. It seems to be the case that the hardest part of GPT-3 is actually in the last bit; hooking up a datasource to GPT-3 in order to optimize your context-stuffing.

Initial Exploration

(see https://gist.github.com/brockmanmatt/7593226da604f8827825ef405df2b0fd)

Figuring out Temperature and Descriptions

For this section, I use a query method which is a wrapper around the GPT3 API to easily call and get back single results. It lets me set up default api-parameters to call the Davinci model at temperature .25 requesting up to 150 tokens and stopping at "\n\n", but can be modified by passing the optional argument "myKwargs".

def query(prompt, myKwargs = {}):
  """wrapper for the API to save the prompt and the result"""

  #arguments to send the API
  kwargs = {"engine":"davinci", "temperature":.25, "max_tokens":150, "stop":"\n\n"}

  for kwarg in myKwargs:
    kwargs[kwarg] = myKwargs[kwarg]

  r = openai.Completion.create(prompt=prompt, **kwargs)["choices"][0]["text"].strip()
  return r

Google Search Ads are divided into heads (the part in blue, up to 3 30-character blurbs) and the description (up to 2 90 character blurbs). To initially test how well GPT-3 can generate these ads, we can give it a couple examples. I just took a single ad that was targeted at a couple different audiences to let GPT-3 pick up on what it means for an ad to be targeted towards an audience. Here, the few-shot examples contain a product, an audience, and a description, and by feeding GPT a subsequent product and audience it'll guess what the description is supposed to be.

defaultAdsPrompt = """the following are google headlines for an ad campaign:
Product: Bikes
Audience: Bikes for  Price-sensitive shoppers
Description: Low prices and huge selection. Free and fast delivery. Order online today!

Product: Bikes
Audience:  Large groups looking for bike rentals
Description: Stylish bikes. Make your experience memorable. Reserve online in minutes!

Product: Bikes
Topic: Locals interested in purchasing a bike
Description: Our friendly staff will help you find the perfect bike. Visit our store today!

Product: {}
Audience: {}
Description:"""

product = "Apple Pies"
audience = "Kids"
query(defaultAdsPrompt.format(product, audience), myKwargs= {"stop":"\n"})

Now, we want to see what this looks like when GPT-3 tries to pattern match to it. One of the first things I want to try is what effect temperature has on it. Remember, the way GPT-3 works is it's constantly predicting the probabilities of the next token that'll occur; at low temperature it selects the most probable next-token. At higher temperature, it selects less-probable next tokens. What I do then is I'll run the prompt through a range of temperatures to see how the behavior changes; generally higher temperature is more creative, but it can stray from the desired format.

audience = "Local Convenience Stores"

for temp in range(1,10):
  print(temp)
  print(query(defaultAdsPrompt.format(product, audience), myKwargs= {"stop":"\n", "temperature":.1*temp}))

The output of this is as follows:

1
Fresh baked pies. Delicious.
2
Delicious pies. Fresh from the oven. Visit our store today!
3
Delicious pies. Fresh from the oven.
4
Delicious pies. Fresh and hot. Order online today!
5
Hot Apple Pies for sale. Fresh out of the oven.
6
Fresh apple pies. Enjoy hot or cold.
7
In-store delivery available. Ask about our catering service.
8
Best apple pies in the area. We bake fresh all day. Our pies are perfect!
9
Our  pies have a fresh, homemade taste. Order today!

We can see the low-temperature results are similar, and as the temperature passes .5 the results really start to vary.

Adding in Headlines

So now we want to add in headlines. We can add headlines to the descriptions as well (and promotions for fun) to really see what GPT-3 can do when we let it loose. We'll structure the few-shot examples the same way as before.

defaultAdsPrompt = """the following are google headlines for an ad campaign:
Product: Betty's Bikes
Audience: Bikes for  Price-sensitive shoppers
Promo: 15% off all bikes in august
Headline:Betty's Beach Bikes - 15% Off All Bikes in August
Description: Low prices and huge selection. Free and fast delivery. Order online today!

Product: Betty's Bikes
Audience: Large groups looking for bike rentals
Promo: 20% off rentals for 3+
Headline:Betty's Bike Rentals - 20% Off Rentals for 3 or More
Description: Stylish bikes. Make your experience memorable. Reserve online in minutes!

Product: Betty's Bikes
Audience: Locals interested in purchasing a bike
Promo: None
Headline: Buy a Bike at Betty's - Affordable Stylish Bikes
Description: Our friendly staff will help you find the perfect bike. Visit our store today!

Product: {}
Audience: {}
Promo: {}
Headline:"""

Now, we want to go ahead and run our range off temperatures again.

product = "Apple Pies"
audience = "Schools"
promo = "None"

for temp in range(1,10):
  print(temp)
  print(query(defaultAdsPrompt.format(product, audience, promo), myKwargs= {"temperature":.1*temp}))

Again, we can see the low-temperature examples aren't very creative, but as we increase the temperature the variance increases.

1
Apple Pies for Schools
Description: Apple pies are a delicious treat for any school. Order today!
2
Apple Pies for Schools
Description: Betty's Apple Pies are the perfect treat for your school. Order today!
3
Apple Pies for Schools - Betty's Pies
Description: Betty's Pies are the best. Try them today!
4
Apple Pies: A Delicious and Healthy Snack
Description: Apple pies are a delicious and healthy snack. Order today for your school!
5
Apple Pies for School Lunches
Description: Betty's Pies are great for school lunches. Buy in bulk and save!
6
Apple Pies - Fresh Baked and Ready to Go
Description: We deliver fresh apple pies to school cafeterias. Call today to place an order!
7
Betty's Apple Pies for School Fundraisers
Description: Betty's pies are the perfect fundraiser for schools. Call us today!
8
Betty's Apple Pies are Perfect for School Lunches
Description: Betty's freshly baked organic apple pies are low in calories and high in nutrients.
9
Pies for Schools
Description: Pyromaniac Bakeries makes it easy for schools to order custom-made apple pies

So far, these have been static few-shot examples. However, GPT-3 can do so much more with a more flexible prompt design.

Dynamic Examples

(code from https://gist.github.com/markketai/b537f0bd10e0190980b96ebaf05620b0)

As we've found with context-stuffing, we want to make sure that we include as much explicit information in the few-shots as possible. To be able to do that, we'll want to be able to dynamically generate our few-shot examples.

Here, we'll also change up how we're querying the GPT-3 API. Rather than simply take one generation for each query, we'll leverage the "n" parameter of the API (see api-parameters). This helps with costs as well as seeing variability of a single query without changing temperature. It helps with cost because OpenAI charges for the number of tokens in the prompt as well as the total number of generated tokens; if we were to run a prompt of size 900 with a 100 token max_length 10x, we'd get charged 10,000 tokens. On the other hand, using n=10 instead we'd get charged once for the 900 and then 10x the 100 completions for a total of 1900 tokens, 1/5 the cost!

We'll first re-write our query wrapper. As you can see, instead of selection r["choices"][0] we'll return all choices (each of the n completions is stored in the array of choices).

def query(prompt, myKwargs = {}):
  """  Wrapper for the gpt-3 API  """
  #arguments to send the API
  kwargs = {  "engine":"davinci",  "temperature":.25,  "max_tokens":150,  "stop":"\n\n", }

  for kwarg in myKwargs:
    kwargs[kwarg] = myKwargs[kwarg]

  r = openai.Completion.create(prompt=prompt, **kwargs)
  return r

Now instead of hard coding in the examples, we'll make the examples into an array and select them. For this, we'll select examples randomly; you can see context-stuffing for different ways of selecting examples. So here's a quick set of labeled ads we can make:

myAds = [
    {
      "company":"None",
      "audience":"Beachgoers, Elderly",
      "tone":"Neutral",
      "promo": "None",
      "keywords": "Bikes, Low Prices",
      "product":"bikes",
      "background":"We rent bikes that people can use to go to the beach with. Good for old and young alike",
      "AdSense Headline":"Low Priced Beach Bikes | Great for the beach",
      "Final Description": "We have low prices and a huge selection. Great way to stay fit with a bike ride on the beach!"
    },
    {
      "company": "Betty's Bikes",
      "audience":"Large groups",
      "tone": "Brief",
      "promo": "20% off rentals for 3 or more people",
      "keywords": "Syle, Experience, Rentals",
      "product":"bikes",
      "background":"Betty's Bikes rents bikes that people can use to go to the beach with. Good for old and young alike",
      "AdSense Headline":"Betty's Bike Rentals | 20% Off Rentals for 3 or More",
      "Final Description": "Stylish bikes. Make your experience memorable. Reserve group deals online in minutes!",
    },
    {
      "company":"Jimbo's Backpacks",
      "audience":"School kids",
      "tone": "Urgent",
      "promo": "15% Off All Backpacks",
      "keywords": "Customer Service, Local, Backpacks",
      "product":"backpacks",
      "background":"Jimbo's backpacks has sold backpacks for years. Our backpacks are locally sourced. With school approaching, everyone wants a bike. Great customer service.",
      "AdSense Headline": "Great backpacks for School | Coolest Backpacks in Town | While supplies last",
      "Final Description": "Hey kids, need the coolest backpack that fits you well? Our professional backpack pickers can help you prepare for the new school year. Backpacks are flying off the shelves, get yours before they're gone.",
    },
    {
      "company":"Donovan's Flowers",
      "audience":"Boyfriends",
      "tone":"Witty",
      "promo":"Free shipping on orders over $100",
      "keywords":"Fresh, Flowers, Quick, Valentines",
      "product":"valentines flowers",
      "background":"Donovan's flowers sells flowers. You need flowers? We got them. We have fast delivery.",
      "AdSense Headline":"Donovan's Flowers | Last Minute Flowers",
      "Final Description": "Hey Boyfriends! Valentines day is approaching! Make up for slacking off this year by giving your loved one our signature valentines flowers. Delivered so fast, she won't know you forgot again this year.",
    },
]

We have 4 examples to choose from, so we can build a method to randomly select 2 of them for each time we call the API. In reality, you'll want to experiment with different methods of selecting the examples rather than randomly (again, context-stuffing), how different temperatures impact the output, and most importantly, what labeled examples you have (and how well they're labelled). We'l also only include the fields of the examples which we have parameters for from the input; e.g. if we don't have an "audience" field, it'll ignore that from the examples.

def buildPrompt(someRequest, temperature=.5, verbose=False):
  """
  take a dict someRequest which has any of the below keys in it.
  """
  if verbose:
      print("Recieved Request: {}".format(someRequest))

  #removed keywords
  possibleKeys = ["company", "audience", "tone", "promo", "product", "background"]
  targetKeys = []
  for key in possibleKeys:
    if key in someRequest:
        if someRequest[key] not in ["None","none", ""]:
            targetKeys.append(key)

  if verbose:
      print("currentKeys: {}".format(targetKeys))

  examples = []
  if len(examples) < 3:
    newExamples = random.sample(myAds, 3-len(examples))
  prompt = "Our new advertising team came up with the following ad campaigns for Google Search based on the provided Ad information.\n\n"
  for example in newExamples:
    for key in targetKeys:
      if key == "company":
        prompt += "Company Name: {}\nAd information:".format(example[key].strip())
      else:
        prompt += " The ad's {} is {}.".format(key, example[key])
    prompt += "\n"
    for key in ["AdSense Headline", "Final Description"]:
      prompt += "{}: {}\n".format(key, example[key])

    prompt += "\n"

  if verbose:
      print(prompt)

  for key in targetKeys:
      if key == "company":
        prompt += "Company Name: {}\nAd Information:".format(someRequest[key].strip())
      else:
        prompt += " The ad's {} is {}.".format(key, someRequest[key].strip())
  prompt += "\n"
  prompt += """AdSense Headline:"""

  results = query(prompt, myKwargs={"temperature":temperature, "n": 6, "frequency_penalty":.2, "stop":["\n\n", "AdSense"]})
  outputs = []
  for i in range(len(results["choices"])):
      current = results["choices"][i]["text"]
      sections = current.split("\nFinal Description: ")
      if len(sections) == 2:
          output = ""
          # output += "EXAMPLE:<br>"
          heads = sections[0][:90]
          newDescription = sections[1]
          if len(sections[1]) > 177:
              newDescription = sections[1][:177] + "..."
          descriptions  = "{}".format(newDescription)

          outputs.append({"heads":heads, "descriptions":descriptions})

  return(outputs)

Now, we can see what this looks like to get our n=6 ads back!

newAds = buildPrompt({ "company":"markket.ai", "audience":"everyone",  "background":"we use AI to make ads"})

Our function returns an array of 6 dicts, each of which have descriptions and headlines.

[{'descriptions': 'Our AI is the best in the business. We have a new technology that can create the best ads online.',
  'heads': ' AI Powered Advertising | Best Ads Online'},
 {'descriptions': "We'll make ads for you! Try it free",
  'heads': " AI Powered Ads | We'll make ads for you | Try it free"},
 {'descriptions': "We use AI to make ads. Whether it's for a small business or a large one, we can make the ads for you.",
  'heads': ' AI-generated ads | Get your ads done in minutes'},
 {'descriptions': 'We use AI to make ads. We can make ads based on your audience.\nAds by Markket.ai',
  'heads': ' AI Powered Ads'},
 {'descriptions': 'We use AI to make ads. Our AI is trained to make ads that are better than what humans can make. We are the future of advertising.\nAds were served on google search for a period o...',
  'heads': ' AI Makes Ads | Better Ads for Everyone'},
 {'descriptions': 'We use AI to create amazing ads. Want to know more? Check out our blog to learn more about how we use AI to create better ads.\nAds were shown with the following demographics:',
  'heads': ' AI Powered Ad Creation | The Future of Ads'}]

Now here's a question: What happens when you include generated ads back in the pool of possible examples? How does this influence possible generations? Using GPT outputs can really improve how well GPT responds to prompts. These are important areas of research. If you'd like to help us work on developing this technology, apply for a job with us today at https://markket.ai/jobs!

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License