Tutorials

Using OpenAPI definitions with LLMs through GPTScript tools

May 9, 2024 by grant linville

OpenAPI is a common format for describing APIs. Many apps and services will come with an OpenAPI definition file that describes the endpoints and operations that are available. Each operation consists of a path on the server, an HTTP method (such as GET or POST), and sometimes parameters or a request body.

One feature that was recently added to GPTScript allows you to provide an OpenAPI definition file to GPTScript, as though it were a normal tool file. Internally, GPTScript will generate a tool for each operation in the OpenAPI definition, and when the large language model calls that tool, GPTScript will make the correct HTTP request to the server, and return the contents of the response body to the LLM. This makes it easy to interact with APIs using LLMs like GPT-4. This tutorial will demonstrate how to use this feature.

The Definition

This is the OpenAPI definition file that we will use:

# petstore.yaml
openapi: "3.0.0"
info:
  version: 1.0.0
  title: Swagger Petstore
  license:
    name: MIT
servers:
  - url: http://127.0.0.1:5000
paths:
  /pets:
    get:
      summary: List all pets
      operationId: listPets
      tags:
        - pets
      parameters:
        - name: limit
          in: query
          description: How many items to return at one time (max 100)
          required: false
          schema:
            type: integer
            maximum: 100
            format: int32
      responses:
        '200':
          description: A paged array of pets
          headers:
            x-next:
              description: A link to the next page of responses
              schema:
                type: string
          content:
            application/json:    
              schema:
                $ref: "#/components/schemas/Pets"
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
    post:
      summary: Create a pet
      operationId: createPets
      tags:
        - pets
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Pet'
        required: true
      responses:
        '201':
          description: Null response
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
  /pets/{petId}:
    get:
      summary: Info for a specific pet
      operationId: showPetById
      tags:
        - pets
      parameters:
        - name: petId
          in: path
          required: true
          description: The id of the pet to retrieve
          schema:
            type: string
      responses:
        '200':
          description: Expected response to a valid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Pet"
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
components:
  schemas:
    Pet:
      type: object
      required:
        - id
        - name
      properties:
        id:
          type: integer
          format: int64
        name:
          type: string
        tag:
          type: string
    Pets:
      type: array
      maxItems: 100
      items:
        $ref: "#/components/schemas/Pet"
    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: integer
          format: int32
        message:
          type: string

This is adapted from the Swagger Petstore example.

This file defines two paths and three operations. Create this file on your system and name it "petstore.yaml".

The Server

Here is a small Python Flask app that serves this API:

# app.py
from flask import Flask, request, jsonify
app = Flask(__name__)

# Mock data for demonstration purposes
pets = [
    {"id": 1, "name": "Rex", "tag": "dog"},
    {"id": 2, "name": "Mittens", "tag": "cat"}
]

@app.route('/pets', methods=['GET'])
def list_pets():
    limit = request.args.get('limit', default=100, type=int)
    return jsonify(pets[:limit])

@app.route('/pets', methods=['POST'])
def create_pet():
    new_pet = request.json
    pets.append(new_pet)  # Simple storage for demonstration, would typically save to a database
    return jsonify({}), 201

@app.route('/pets/<int:petId>', methods=['GET'])
def show_pet_by_id(petId):
    pet = next((pet for pet in pets if pet['id'] == petId), None)
    if pet:
        return jsonify(pet)
    else:
        return jsonify({"code": 404, "message": "Pet not found"}), 404

# Error handling for the API
@app.errorhandler(404)
def not_found(error):
    return jsonify({"code": 404, "message": "Not found"}), 404

@app.errorhandler(500)
def internal_error(error):
    return jsonify({"code": 500, "message": "Internal server error"}), 500

if __name__ == '__main__':
    app.run(debug=True)

Create this file on your system and name it "app.py". If you do not have Flask installed, you can install it by
running "pip install flask" (or "pip3 install flask", depending on how Python is installed on your system).

Start the server by running "flask run" in the directory containing the app.py file. The server will start on http://localhost:5000.

Using the API in GPTScript

Now we will use GPTScript to interact with this API. Export the environment variable OPENAI_API_KEY with your OpenAI key if you have not done so already. Next, let’s write a small script to test this out:

# petstore.gpt
tools: ./petstore.yaml

List all the pets.

Save this file and call it "petstore.gpt". It should be in the same directory as the petstore.yaml OpenAPI definition.
Then, run the script with "gptscript petstore.gpt". Your output should look something like this:

The pets are:
1. Rex (dog)
2. Mittens (cat)

This shows that GPTScript made the correct API call to list the pets. Now let’s ask it to add a new pet with ID 3, and then list all the pets again:

# petstore.gpt
tools: ./petstore.yaml

Only make one function call at a time.
Add a new pet with ID 3. His name is Mark and he is a Lizard. After you do that, list all the pets.

The output should look something like this:

The pets listed are:
1. Rex (Dog)
2. Mittens (Cat)
3. Mark (Lizard)

The only operation we have not used yet is the "showPetById" operation. Let’s try it:

# petstore.gpt
tools: ./petstore.yaml

Which pet has ID 3?

The output should look something like this:

The pet with ID 3 is named Mark and has the tag "Lizard".

That brings us to the end of this tutorial. For more details about using OpenAPI definitions with GPTScript, see
the docs. If you’d like more information about using OpenAPI with Acorn, we also hosted a livestream where we discussed it in more detail, which I’ve embedded below.

<iframe width=”560″ height=”315″ src=”https://www.youtube.com/embed/FvIdZbun1KM?si=33svLqMoacPB7I2n” title=”YouTube video player” frameborder=”0″ allow=”accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share” referrerpolicy=”strict-origin-when-cross-origin” allowfullscreen></iframe>

Related Articles