ChatGPT Multi Turn Chat

ChatGPT Multi Turn Chat using Apex

Before diving into ChatGPT multi turn chat capabilities, let’s review what we’ve covered so far. In a previous post, we talked about ChatGPT Salesforce integration using Apex, as well as Google Gemini Salesforce integration, also using Apex. These integrations involved making API calls that allowed for single exchanges with GPT models—meaning we would send one question or command and receive one answer back. However, when interacting with ChatGPT, we often engage in longer discussions, where the AI takes into account our previous exchanges to provide more relevant responses. This process, where past interactions are used to improve the conversation, is called multi-turn conversation/chat.. Now, let’s explore how we can implement this feature through an API to achieve more dynamic and context-aware interactions.

ChatGPT Single Turn Chat

Let take an Example. I want ChatGPT to create a Story of a Magic Horse but in a one line and respond like poetry from late 1700s. So if I hit the GPT API, my request body would be like this:

Single Turn Request Body

{
  "model": "gpt-4-turbo-preview",
  "messages": [
    {
      "role": "system",
      "content": "Give Response in Poetry like its 1700s"
    },
    {
      "role": "user",
      "content": "Create a story about magic horse with wings in one line"
    }
  ]
}

To explain the above code, content given using User Role is the actual query I want ChatGPT to solve. The content given using System Role is my meta-instruction that guides the AI’s behavior. If you are confused what are these Roles, check my detailed post on ChatGPT Roles in AI Conversations.

Single Turn Response

You’ll receive response something similar to this structure:

"choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "message": {
        "content": "In realms where dreams and night do merge, there flies a steed with wings, enchantments surge.",
        "role": "assistant"
      },
      "logprobs": null
    }
]

Now if you see, response that came in from the GPT has a Role ‘Assistant’. Any response that comes in from the AI Model is logged under assistant role. This is Single Turn Chat/Conversation in ChatGPT AI Models.

ChatGPT Multi Turn Chat

Now, for ChatGPT Multi Turn Chat, we will add the response from our Single Turn Response to the request body in our next API hit. Check this code below.

Multi Turn Request Body

Second Request Body:
{
  "model": "gpt-4-turbo-preview",
  "messages": [
    {
      "role": "system",
      "content": "Give Response in Poetry like its 1700s"
    },
    {
      "role": "user",
      "content": "Create a story about magic horse with wings in one line"
    },
    {
      "role": "assistant",
      "content": "In realms of yore, a steed with wings enchanted took to flight, through azure skies and dreams ignighted."
    }
  ]
}

See how the new content added has Assistant Role. This Assistant Role will tell our AI model that this content was given by the AI model previously.

Now we have our previous conversation in our request body. All we need to add to request is our next query. Let’s tell the AI model to replace the Magic Horse with Magic Rabbit. Let’s add this to our Request Body.

{
  "model": "gpt-4-turbo-preview",
  "messages": [
    {
      "role": "system",
      "content": "Give Response in Poetry like its 1700s"
    },
    {
      "role": "user",
      "content": "Create a story about magic horse with wings in one line"
    },
    {
      "role": "assistant",
      "content": "In realms of yore, a steed with wings enchanted took to flight, through azure skies and dreams ignighted."
    },
    {
      "role": "user",
      "content": "Replace Horse with Rabbit"
    }
  ]
}

Now, we’ll receive a response that is based on our previous conversation. AI will tell us a story in a way we asked it originally but now with Rabbit as the magic animal. Check the below response.

"choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "message": {
        "content": "In realms where dreams and night do merge, there hops a rabbit with wings, enchantment's surge.",
        "role": "assistant"
      },
      "logprobs": null
    }
]

Now I hope you understood the basic logic that goes behind the ChatGPT Multi Turn Chat. Now let build this via Apex.

ChatGPT Multi Turn Chat using Apex

Apex Class

// ChatGPT Multi Turn Chat
public class ChatGPTMultiTurnConversation {
   private static List<ChatMessage> chatHistory = new List<ChatMessage>();
   private class ChatMessage {
       String role;
       String content;
       public ChatMessage(String role, String content) {
           this.role = role;
           this.content = content;
       }
   }
 public static void makeOpenAICallout(List<ChatMessage> chat) {
       String ENDPOINT_URL = 'https://api.openai.com/v1/chat/completions?';
       String API_KEY = 'API_KEY';
       HttpRequest request = new HttpRequest();
       request.setEndpoint(ENDPOINT_URL);
       request.setMethod('POST');
       request.setHeader('Content-Type', 'application/json');
       request.setHeader('Authorization', 'Bearer ' + API_KEY);
       request.setTimeout(120000);
       Map<String, Object> requestBody = new Map<String, Object>{
           'messages' => chat,
           'model' => 'gpt-4-turbo-preview'
       };
       request.setBody(JSON.serialize(requestBody));
       system.debug('Requst MAP-'+JSON.serialize(requestBody));
       try {
           Http http = new Http();
           HttpResponse response = http.send(request);
           if (response.getStatusCode() == 200) {
               handleOpenAIResponse(response.getBody());
               System.debug('Updated Chat History: ' + JSON.serialize(chatHistory));
           } else {
               System.debug('Error--'+response.getBody());
           }
       } catch (Exception e) {
           System.debug('Error: '+ e.getMessage());
       }
   }
  
   private static void handleOpenAIResponse(String responseBody) {
       Map<String, Object> responseMap = (Map<String, Object>) JSON.deserializeUntyped(responseBody);
       if (responseMap.containsKey('choices')) {
           List<Object> choices = (List<Object>) responseMap.get('choices');
           if (!choices.isEmpty()) {
               Map<String, Object> choice = (Map<String, Object>) choices.get(0);
               Map<String, Object> message = (Map<String, Object>) choice.get('message');
               String outSOQL = (String) message.get('content');
               chatHistory.add(new ChatMessage('assistant', outSOQL));
           }
       }     
   }
  
   public static void AddQueryAndCallout(String query, String queryTwo) {
       chatHistory.add(new ChatMessage('system', 'Give Response in Poetry like its 1700s'));
       chatHistory.add(new ChatMessage('user', query));
       //First API Callout using first Query
       makeOpenAICallout(chatHistory);
       //Second API Callout using second query
       chatHistory.add(new ChatMessage('user', queryTwo));
       makeOpenAICallout(chatHistory);
   }
}

For the sake of this example, I will pass both my queries to our code. Our code will

  1. Hit API with the first Query.
  2. Fetch the Response from AI Model and add that response to Request body.
  3. Hit API with second Query.

To Run this Code, open Anonymous Window and use below line:

ChatGPT Multi Turn Chat
ChatGPTMultiTurnConversation.AddQueryAndCallout('Create a story about magic horse with wings in one line','Replace Horse with Rabbit');

Here’s how our code will process the execution.

First Request Body:
{
  "model": "gpt-4-turbo-preview",
  "messages": [
    {
      "role": "system",
      "content": "Give Response in Poetry like its 1700s"
    },
    {
      "role": "user",
      "content": "Create a story about magic horse with wings in one line"
    }
  ]
}

First Query Chat History:
[
  {
    "role": "system",
    "content": "Give Response in Poetry like its 1700s"
  },
  {
    "role": "user",
    "content": "Create a story about magic horse with wings in one line"
  },
  {
    "role": "assistant",
    "content": "In realms of yore, a steed with wings enchanted took to flight, through azure skies and dreams ignighted."
  }
]

Second Request Body:
{
  "model": "gpt-4-turbo-preview",
  "messages": [
    {
      "role": "system",
      "content": "Give Response in Poetry like its 1700s"
    },
    {
      "role": "user",
      "content": "Create a story about magic horse with wings in one line"
    },
    {
      "role": "assistant",
      "content": "In realms of yore, a steed with wings enchanted took to flight, through azure skies and dreams ignighted."
    },
    {
      "role": "user",
      "content": "Replace Horse with Rabbit"
    }
  ]
}

Second Query Chat History:
[
  {
    "role": "system",
    "content": "Give Response in Poetry like its 1700s"
  },
  {
    "role": "user",
    "content": "Create a story about magic horse with wings in one line"
  },
  {
    "role": "assistant",
    "content": "In realms of yore, a steed with wings enchanted took to flight, through azure skies and dreams ignighted."
  },
  {
    "role": "user",
    "content": "Replace Horse with Rabit"
  },
  {
    "role": "assistant",
    "content": "In realms of yore, a rabbit with wings enchanted took to flight, through azure skies and dreams ignited."
  }

I hope ChatGPT Multi Turn Chat code is easy enough to understand. If you have any queries or suggestions, please reach out to me via LinkedIn, Kamal Thakur. Please check Official ChatGPT Documentation for any additional information.

Share: