GPT technology can transform the way developers work, making it possible to write code and develop features much faster than before. This is, of course, also true for ecommerce specifically. With the power of GPTs, we can now build advanced chatbots and interfaces for the Shopify platform more quickly and efficiently than ever.

In this tutorial, we will look at the functionality of OpenAI assistants and how they can be leveraged to build chatbots that interact with Shopify data. I will use the function calling capabilities of the OpenAI Assistant API and walk you through the run-step process that executes a function that extracts the needed Shopify data. Specifically, we are going to cover

  1. OpenAI Assistant Use Cases
  2. How OpenAI Assistants Work
  3. How to Extract Shopify Data with Assistant Function Calling
  4. Decoding OpenAI Assistant Run Steps
đź’ˇ
By the end of this tutorial, you will know how to use OpenAI Assistants with the Shopify API and build simple ecommerce chatbots capable of fetching customer data with function calling.

OpenAI Assistant Use Cases

OpenAI Assistants can transform various business functions, including customer support, ecommerce, marketing, and data analysis. Leveraging OpenAI Assistants and Agentic systems can bring several benefits, such as automating administrative tasks, saving time, and minimizing human error. They can analyze large datasets, generate reports, and highlight key findings, optimizing various business functions.

Here are some practical applications:

1. Customer Support

By handling simple inquiries, OpenAI Assistants can reduce wait times for customers seeking help or information. Immediate engagement can lead to improved customer satisfaction and loyalty. For businesses, it means their human employees can focus on more complex queries, optimizing the overall efficiency of the support team.

2. Product Discovery

OpenAI Assistants can act as personal shopping assistants, asking users questions about their preferences and using those responses to recommend products that meet their needs. This personalization enhances the shopping experience and can lead to increased sales.

3. Lead Magnets

OpenAI Assistants can engage website visitors through interactive conversations, quizzes, or questionnaires, making the data collection process more engaging and less intrusive. This information can create more personalized and targeted marketing campaigns, improving conversion rates and building a more refined customer profile.

4. Funnels

In marketing and sales, guiding a potential customer through the various stages of the buying process is key to healthy conversion rates. OpenAI Assistants can qualify leads by asking questions and providing information or resources relevant to each stage of the funnel. This process helps nurture leads more effectively and move them closer to making a purchase.

5. Workflow Automation

Administrative tasks and repetitive processes can consume a significant amount of time for businesses. OpenAI Assistants can automate these tasks, such as scheduling appointments, updating records, or retrieving specific information, freeing employees to focus on more strategic activities.

6. Data Analysis

OpenAI Assistants can assist in analyzing data, generating reports, and highlighting key findings. This capability enables businesses to make informed decisions more quickly and efficiently, leveraging the power of their data to drive growth and profitability.

How OpenAI Assistants Work

OpenAI Assistants work by engaging with users through threads. They can be programmed with specific instructions to fine-tune their personality and abilities, making them versatile for various tasks. These tasks could range from interpreting code to retrieving knowledge, all facilitated by OpenAI's hosted tools or custom tools you can create and host yourself.

Threads are persistent and store the history of messages, allowing for continuous conversations. Once a Thread is created, it's simply a matter of appending new messages as users interact with the assistant.

The OpenAI Assistant Flow

OpenAI Assistants can work with files introduced at the creation stage or during ongoing conversations within Threads. Additionally, when utilizing specific tools, assistants can create new files, such as images or spreadsheets.

Let's get our hands dirty and see how we set up an assistant capable of doing basic function calling to help a customer with an order inquiry.

The Colab Notebook

The Colab notebook for this tutorial is available here.

Environment Setup

To get started, we need to pip install some necessary Python packages. These packages include python-dotenv which will be used to handle our environment variables, openai, and ShopifyAPI for interacting with the Shopify platform.

!pip install -qU python-dotenv openai ShopifyAPI

This will quietly (without verbose messages) update and install these packages, a crucial first step. Then, we will load the OpenAI API key from the environment file.

import os
from dotenv import load_dotenv
load_dotenv()

from openai import OpenAI
client = OpenAI()

Connecting to Shopify

First, we must set up a Shopify client to interact with the Shopify API. I will use the function I've used in earlier tutorials for this. Then, I define a function that extracts order information from the GraphQL API:

import shopify, time, json

def shopify_client(merchant, token):
    """
    Initialize a Shopify GraphQL client.
    """
    api_session = shopify.Session(merchant, '2023-10', token)
    shopify.ShopifyResource.activate_session(api_session)
    client = shopify.GraphQL()
    return client

def query_customer_by_email(customer_email):
    """
    Query customer data by email from Shopify.
    """
    # 'your_shopify_store.myshopify.com'
    merchant = os.getenv('SHOPIFY_MERCHANT')
    # 'your_shopify_access_token'
    token = os.getenv('SHOPIFY_TOKEN') 
    # Initialize the Shopify GraphQL client
    client = shopify_client(merchant, token)

    query = f"""
    {{
      customers(first: 1, query: "email:'{customer_email}'") {{
        edges {{
          node {{
            id
            firstName
            lastName
            email
            orders(first: 3) {{
              edges {{
                node {{
                  id
                  createdAt
                  currentSubtotalLineItemsQuantity
                  lineItems(first: 5) {{
                    edges {{
                      node {{
                        id
                        title
                        variantTitle
                        quantity
                      }}
                    }}
                  }}
                }}
              }}
            }}
          }}
        }}
      }}
    }}
    """

    # Execute the query
    result = client.execute(query)

    # Process the result as needed
    return result

Here, I define the two functions needed for extracting the data: shopify_client, which sets up a connection to Shopify using a merchant's URL and API token, and query_customer_by_email, which queries Shopify for customer data based on their email address. By calling query_customer_by_email with a customer's email, we retrieve detailed customer and order information.

Setting Up The Shopify Assistant

We will now see how the OpenAI Assistant function calls work and connect an assistant to the Shopify API to fetch some data. To connect the assistant to Shopify, we need to specify the tools the assistant will have at its disposal. In this case, it's only one function, which is integrated into our assistant's capabilities to allow it to fetch information about a customer's orders. This function is defined within the list tools, and it outlines the specific external function query_customer_by_email that our assistant can call upon when needed:

tools=[
    {
        "type": "function",
        "function": {
            "name": "query_customer_by_email",
            "description": "Get the orders for a customer given a customer email",
            "parameters": {
                "type": "object",
                "properties": {
                    "email": {"type": "string", "description": "The email of the customer"}
                },
                "required": ["email"]
            }
        }
    }
]

This configuration not only specifies the function's name but also describes its purpose: to retrieve orders for a customer using their email address. It details the parameters required for the function to execute, in this case, the customer's email address, and marks it as a required field.

This assistant is designed to function as a sales chatbot, offering help to customers by answering questions about their orders and, if necessary, asking for additional information:

prompt="""You are an e-commerce sales chatbot helping customers
        answer questions about their orders. If needed, ask for 
        additional information from the customer"""

assistant = client.beta.assistants.create(
  instructions=prompt,
  model="gpt-4-0125-preview",
  name="Ecom Customer Support Assistant",
  tools=tools,
)

Here, I'm using the client.beta.assistants.create method to set up an ecommerce assistant. I provide it with a set of instructions that outlines its role as a support entity within an e-commerce environment. The assistant uses the gpt-4-0125-preview model, and the name parameter identifies our assistant as the "Ecom Customer Support Assistant," clarifying its purpose.

Most importantly, we integrate the previously defined tools array into our assistant's setup. This array includes the query_customer_by_email function, which allows the assistant to fetch order details directly from Shopify based on customer email addresses. This integration signifies a crucial step towards creating a dynamic and interactive assistant capable of handling specific customer inquiries by accessing real-time data from external systems.

Running The Assistant

Then, we add the customer's message to the conversation thread and execute the assistant's response mechanism. This involves creating a new thread for the dialogue, posting a message as if it were from a customer, and initiating a run where the assistant processes the message. Here's how this is done:

thread = client.beta.threads.create()

message = client.beta.threads.messages.create(
  thread_id=thread.id,
  role="user",
  content="I'm looking to get an overview of my orders"
)

run = client.beta.threads.runs.create(
  thread_id=thread.id,
  assistant_id=assistant.id,
)

Here, we first create a new thread for the dialogue. Then, we simulate a customer's inquiry about their orders by posting a message to this thread. Lastly, by initiating a run, we prompt the assistant to process the message and prepare a response. This sequence effectively sets up the interaction, leveraging the assistant's capabilities to provide meaningful support to the customer.

Displaying Conversations

To display the messages resulting from the run step, we use a specific function designed to organize and print the conversation for easy reading. This function, print_conversationtakes the messages object, sorts the messages by their creation time, and prints each one with a timestamp, the role of the sender (Assistant or User), and the message text:

from datetime import datetime

def print_conversation(messages_object):
    # Sort messages by their creation time
    sorted_messages = sorted(messages_object.data, key=lambda x: x.created_at)

    # Iterate through the sorted messages and print them
    for msg in sorted_messages:
        # Convert timestamp to readable format
        timestamp = datetime.utcfromtimestamp(msg.created_at).strftime('%Y-%m-%d %H:%M:%S')
        role = "Assistant" if msg.role == 'assistant' else "User"
        text = msg.content[0].text.value if msg.content else "No text content"
        print(f"{timestamp} [{role}]: {text}")

This function enhances the readability of the conversation by clearly distinguishing between user and assistant messages, providing a structured overview of the interaction timeline. It's a useful tool for debugging and presentation, allowing developers and users alike to follow the dialogue's flow easily.

Retrieving the results from the run provides a straightforward example of the interaction between the user and the assistant, illustrating how the assistant handles queries and requests for additional information to provide specific assistance. Here is the exact conversation:

  • 2024-02-13 16:08:03 [User]: "I'm looking to get an overview of my orders"
  • 2024-02-13 16:09:42 [Assistant]: "Sure, I can help with that. Could you please provide me with your email address? This will allow me to look up your order history."

This dialogue showcases the assistant's ability to understand the user's request and its protocol for gathering the necessary information to fulfill that request. By asking for the user's email address, the assistant demonstrates a logical step toward accessing personalized order details, emphasizing its role in facilitating a user-friendly and efficient support experience.

Executing The Run Steps

To retrieve order details for a customer named John Doe from my Shopify account, I input his email into the assistant with the following command:

message = client.beta.threads.messages.create(
  thread_id=thread.id,
  role="user",
  content="my email address is john@rabbitpromotion.com"
)

This step is necessary to look up John Doe's order information using the assistant.

After waiting a bit, the status of the run changes to "requires_action." This status indicates that the assistant needs additional action to proceed, typically meaning it's ready to use the arguments provided by the user to execute a function. To check the run status and confirm it's in this state, you can retrieve the run details and examine the status like this:

run = client.beta.threads.runs.retrieve(
  thread_id=thread.id,
  run_id=run.id
)

print(run.status)

When the status is "requires_action," it signals that we can move forward with extracting the arguments provided by the user—in this case, John Doe's email address—and then execute the query_customer_by_email function to fetch the relevant data from Shopify on behalf of the Assistant.

To extract the arguments from the run when it reaches the "requires_action" status, you can access the necessary information by navigating through its required_action attribute. This allows you to identify the specific tool call (in this case, our function call to query_customer_by_email) and then extract the customer's email address from the arguments:

tool_call = run.required_action.submit_tool_outputs.tool_calls[0]
customer_email = json.loads(tool_call.function.arguments)['email']

This navigates to the first tool call within the required_action of the run. It then parses the arguments of the function call, which are in JSON format, to extract the email field. This field contains the email address provided by the user, which, in our scenario, is John Doe's email "john@rabbitpromotion.com". With the email address successfully extracted, you're set to execute the function with this argument to retrieve John Doe's order details from Shopify.

The final step involves using the extracted customer email to fetch their information from Shopify and then submitting this information back to the assistant as tool outputs:

customer_info = query_customer_by_email(customer_email)
tool_outputs = []
tool_outputs.append(
      {
            "tool_call_id": tool_call.id,
            "output": customer_info,
      })
run = client.beta.threads.runs.submit_tool_outputs(
    thread_id=thread.id,
    run_id=run.id,
    tool_outputs=tool_outputs
)

This will fetch the customer's order information using the query_customer_by_email function with the extracted email. It then prepares a list of tool outputs, including the tool_call_id and the fetched customer_info, and submits these outputs to the assistant. This action allows the assistant to use the provided information in its conversation with the user.

Once the run is complete and the tool outputs are submitted, we can retrieve and display the conversation's messages:

messages = client.beta.threads.messages.list(
  thread_id=thread.id
)

print_conversation(messages)

This results in a conversation that flows as follows:

  • 2024-02-13 16:08:03 [User]: "I'm looking to get an overview of my orders"
  • 2024-02-13 16:09:42 [Assistant]: "Sure, I can help with that. Could you please provide me with your email address? This will allow me to look up your order history."
  • 2024-02-13 16:10:59 [User]: "my email address is john@rabbitpromotion.com"
  • 2024-02-13 16:14:30 [Assistant]: "It looks like you have one order in your history with us. Here are the details of your order:
    • Order ID: 5449412444328
    • Order Date: January 2, 2024
    • Items Ordered:
      • Product: ADIDAS | CLASSIC BACKPACK | LEGEND INK MULTICOLOUR
      • Variant: OS / blue
      • Quantity: 1"

This exchange effectively demonstrates how the assistant can fetch specific customer data from Shopify and convey this information to the user, providing a tailored and informative response based on the user's request.

Share this post