Usecase
of GPT

In my day-to-day at Rangle.io, we're knee-deep in design systems, and as part of our knowledge-sharing culture, we produce tons of insightful blog posts. However, keeping up with all of the content can feel daunting. I was thinking this could be a good use case for Chat GPT's API - it seemed like the perfect tool to create concise summaries of our blog posts to help me (and others) keep up to date with blog posts.

I already had access to Chat GPT's API from a side project I was dabbling in. It was a Python project with the necessary setup, making it the perfect launchpad for this new experiment.

The first step was to gather all the blog post URLs. Rangle.io employs a robust CMS named Sanity. Looking at the API for Sanity and Rangle's site I found the list of all the blog posts in one of the API requests.

import requests
import json

res = requests.get('https://d367if72.api.sanity.io/v2021-10-21/data/query/production?query=*%5B_type%20%3D%3D%20%22blogPost%22%0A%20%26%26%20!(_id%20in%20path(%27drafts.**%27))%20%26%26%20%22ds%22%20in%20topicTags%5B%5D-%3E.id%5D%20%7C%20order(publishDate%20desc)%5B0...99%5D%0A%7B%0A%20%20%22id%22%3A%20_id%2C%0A%20%20blogTitle%2C%0A%20%20publishDate%2C%0A%20%20summary%2C%0A%20%20slug%2C%0A%7D%0A%0A')
with open('blogPosts.json', 'w') as file:
  json.dump(res.json(), file)

This query looks like gibberish but by putting it through a URL decoder you get an easier-to-read query

https://d367if72.api.sanity.io/v2021-10-21/data/query/production?query=*[_type == "blogPost"
 && !(_id in path('drafts.**')) && "ds" in topicTags[]->.id] | order(publishDate desc)[0...99]
{
  "id": _id,
  blogTitle,
  publishDate,
  summary,
  slug,
}

Having compiled the list of all blog post pages, we now scrape the HTML pages rather than navigating through Sanity's API.

With Beautiful Soup, I parsed the text from the HTML, effectively preparing the data for Chat GPT.

import requests
import json
from bs4 import BeautifulSoup

with open('blogPosts.json') as json_file:
  blogPosts = json.load(json_file)['result']

for blogPost in blogPosts:
  print('scraping blog post %s'%blogPost['slug'])
  res = requests.get('https://rangle.io/blog/%s'%blogPost['slug'])
  soup = BeautifulSoup(res.text, 'html.parser')
  with open('blogPosts/%s.txt'%blogPost['slug'], 'w') as outfile:
    for p in soup.find('article').find_all('p'):
      outfile.write(p.text + '\n')

Then fed each article into Chat GPT, storing the returned responses. I initially considered having GPT output the data in JSON format (which can be unreliable), so in the interest of a more reliable structure, I opted for lists.

import requests
import json
import os

context = '''
convert the content into point form
each point should have enough context to be understood and useful
each point should provide a piece of wisdom or insight
be very informative and to the point
do not use any filler words
'''

texts = []
for filename in os.listdir('blogPosts'):
  with open('blogPosts/%s'%filename) as file:
    name = filename.split('.')[0]
    texts.append({'title':name,'text':file.read()})

summaries = []
for text in texts:
  try:
    data = {
      'model':'gpt-3.5-turbo',
      'messages':[
        {
          'role':"system",
          'content': context
        },
        {
          'role':"user",
          'content': text['text'] # the content of the blog post
        }
      ]
    }
    config = {
      'headers': {
        'Authorization': f'Bearer {apiKey}',
      },
    }

    response = requests.post('https://api.openai.com/v1/chat/completions', json=data, headers=config['headers'])
    summary = response.json()['choices'][0]['message']['content']
    summaries.append(summary)
    # add to a file text
    with open('summaries.txt', 'a') as file:
      file.write(summary)
  except:
    print('error')

Looking at the responses, some of the summaries were more like advice than summaries. This sparked the idea of a "Guru" bot - a kind of AI that provides random advice on Design System related topics.

Next was to format the data to be useable for the site, basically transforming the text into a JSON object with arrays of summaries via find and replace operations.

With the data all set, I initialized a Vite TypeScript project, implementing a feature that randomizes the piece of content to display. This way, each visit offers a fresh piece of summarized knowledge with a link out to the related blog post.

Published on: 2023-06-04