Skip to content

Instantly share code, notes, and snippets.

@raghubetina
Last active May 11, 2023 03:35
Show Gist options
  • Save raghubetina/e9c872c1d286e81dad66949af5bcbe27 to your computer and use it in GitHub Desktop.
Save raghubetina/e9c872c1d286e81dad66949af5bcbe27 to your computer and use it in GitHub Desktop.
OpenAI Demo Notes

Follow along

If you want to follow along, set up a new workspace using the base-ruby template repository.

The API tokens for this project can be found in the corresponding Canvas assignment.

HTTP Requests

So far, we've been using our browser's address bar, <a> tags, and <form> tags to visit URLs.

More formally, what we've been doing is: placing HTTP requests. There are also many other ways to place HTTP requests — we've already seen one, in Ruby's URI.open() method.

An HTTP request is actually comprised of more things than just the URL where the resource is located at. When we place a request, we specify:

  1. A request line. E.g.:

    GET /fortunes/aries HTTP/1.1
    

    The first part is known as the HTTP method, a.k.a. HTTP verb. Then comes the URL, and finally comes the version of the HTTP protocol being used.

    The browser's address bar can only use the GET HTTP verb, which makes sense because the best practice is to use GET to say that you're trying to read the resource located at the specified URL. When we're doing our normal browsing, we're usually reading things (and not creating, updating, or deleting).

    For the rest of the CRUD operations, best practice is to use:

    • POST → creating
    • PATCH → updating
    • DELETE → deleting

    <a> elements can also only place GET requests, like the browser's address bar. However, <form> elements have the ability to place POST requests if you add the method="post" attribute to the opening <form> tag. In fact, most <form>s use POST, since the job of most forms is to create information.

    PATCH and DELETE are, oddly, not possible in plain HTML. Later on, we'll use JavaScript to achieve that. For now, we'll use POST for updating and stick with GET for deleting.

  2. A set of header fields allow us to specify things like our user agent (e.g. what browser we're using), authentication information, and more.

  3. A body (optional). This is where we can supply information along with our request, like image uploads or other form input data.

Read more about HTTP requests here.

Hoppscotch

  • Visit https://hoppscotch.io/
  • Try making a GET request to a JSON API:
  • Try making GET requests to JSON APIs that require authentication via query string parameters:
  • Try placing a GET to the URL of a regular HTML page, like "https://wikipedia.org". (You will need to check "Proxy" in the dialog that appears the first time.) You will get back the HTML source code of the page. Hoppscotch is really just a special browser built for exploring APIs.
  • There are many advantages of using a tool like Hoppscotch, which is built specifically for exploring APIs, over using your browser's address bar to place these requests:
    • It indents and formats the JSON responses.
    • You can use POST, PATCH, DELETE, and any other HTTP verbs; not just GET.
    • You can include headers in your request, which many APIs require for authentication (as opposed to just sticking your token in a query string parameter).
    • You can sign up for an account and save the requests you are making, for future reference.
  • For example, try placing a request to the following:
    • Verb: POST
    • URL: https://api.twilio.com/2010-04-01/Accounts/REPLACE_WITH_YOUR_TWILIO_ACCOUNT_SID/Messages
    • Body tab:
      • Switch Content Type to application/x-www-form-urlencoded.
      • Add three key-value pairs:
        • From => +19876543210 (replace with our Twilio sending number)
        • To => +13129876543 (replace with your own phone number, to receive the SMS)
        • Body => Hello from Hoppscotch!
    • Authorization tab:
      • Switch Authorization Type to Basic Auth.
      • Username => paste our Twilio account SID
      • Password => paste our Twilio API token
    • Then click "Send". You should receive a text!

I learned how to fill out those fields by exploring the API documentation, looking at the examples, and lots of trial and error. But once I got a message to successfully send from Hoppscotch, I knew I would be good to go in Ruby!

http.rb gem

Once I've explored an API by reading the docs and using Hoppscotch to make sure I can successfully place the requests, I then turn to translating the requests into Ruby.

Ruby's built in URI.open() method is a super-convenient way to get started placing HTTP requests, but it's sort of like your browser's address bar; it can only place GET requests.

Instead, let's use the wonderful http.rb gem, which makes it easy to place any kind of request.

First, let's install the gem. At a Terminal prompt:

gem install http

In a Ruby script:

require "http"

p HTTP.get("https://api.exchangerate.host/convert?from=USD&to=EUR")

This returns the body of that page as a String. Then, we can use the JSON.parse() method to convert that String into a much more useful Hash:

require "http"

raw_response = HTTP.get("https://api.exchangerate.host/convert?from=USD&to=EUR")

parsed_response = JSON.parse(raw_response)

info_hash = parsed_response.fetch("info")

result = info_hash.fetch("rate")

p result

The nice thing is that we can place more involved requests with HTTP. Let's place the same request that we did above using Hoppscotch to send an SMS with Twilio:

require "http"

response = HTTP.
  basic_auth(
    {
      :user => ENV.fetch("TWILIO_ACCOUNT_SID"),
      :pass => ENV.fetch("TWILIO_AUTH_TOKEN")
    }
  ).
  post(
    "https://api.twilio.com/2010-04-01/Accounts/AC28922e0822d827ee29834fe1dc6f681e/Messages", 
    :form => {
      "From" => ENV.fetch("TWILIO_SENDING_NUMBER"),
      "To" => "+13129876543",  # Put your own phone number here if you want to see it in action
      "Body" => "Hello from http.rb!"
    }
  )

p response.to_s

Be sure that you have the needed environment variables.

API clients

As we can see, once we've done our homework by reading the API docs, experimenting with Hoppscotch, and figuring out the URLs, parameters, and authentication — then actually using the API from Ruby is pretty straightforward. Doing the homework and figuring out what we want to do is, as usual, the hard part.

But, for most popular APIs, it gets even more straightforward — someone has usually written a gem to interact with the raw URLs and parameters for us. For example, Twilio have themselves written and shared a Ruby gem called twilio-ruby. Let's try it out:

Make sure we have the gem installed:

gem install twilio-ruby

In a Ruby script:

require "twilio-ruby"

# Create an instance of the Twilio Client and authenticate with your API key
twilio_client = Twilio::REST::Client.new(ENV.fetch("TWILIO_ACCOUNT_SID"), ENV.fetch("TWILIO_AUTH_TOKEN"))

# Craft your SMS as a Hash literal with three keys
sms_info = {
  :from => ENV.fetch("TWILIO_SENDING_NUMBER"),
  :to => "+19876543210", # Put your own phone number here if you want to see it in action
  :body => "Hello from twilio-ruby!"
}

# Send your SMS!
twilio_client.api.account.messages.create(**sms_info)

ruby-openai

For interacting with the OpenAI API, we're going to skip directly to using an API client.

Make sure we have the gem installed:

gem install ruby-openai

In a Ruby script:

require "openai"

openai_client = OpenAI::Client.new(
  access_token: ENV.fetch("OPENAI_TOKEN"),
  request_timeout: 240 # Optional parameter; increases the number of seconds before a request times out
)

response = openai_client.chat(
    parameters: {
        model: "gpt-3.5-turbo", # Required. I recommend using gpt-3.5-turbo while developing, because it's a LOT cheaper than gpt-4
        messages: [
          { role: "system", content: "You are a helpful assistant that talks like Shakespeare." },
          { role: "user", content: "Hello!"}
        ],
        temperature: 0.7,
    }
)

p response.fetch("choices").at(0)

Keep the conversation going

You can keep the conversation going by adding GPT's previous response to the messages array, as well as the next user prompt. Then re-submit the request for the next chat response!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment