Search code examples
javascriptchatgpt-api

chatGPT API function calling


I am trying to set up function calling for a recent project i had been working on but i cant seem to get it to work

I've looked for documentation and only found YouTube videos that were not great at explaining it. I've tried to run various examples, but nothing is working for me. This is what I have: the base communication with the API works, but the function calling isn't returning anything. If anyone could help, it would be much appreciated.

<!DOCTYPE html>
<html>


<head>

    <script>
        function sendRequest() {

            // API endpoint URL
            const apiUrl = 'https://api.openai.com/v1/chat/completions';

            // Your API key
            const apiKey = 'API_Key';

            // Get the user input
            const userInput = document.getElementById('userInput').value;


            async function lookupTime() {
                fetch("http://worldtimeapi.org/api/timezone/America/Chicago")
                    .then(response => response.json())
                    .then(data => {
                        const currentTime = new Date(data.datetime);
                        const timeString = currentTime.toLocaleTimeString();
                        console.log(timeString);
                        Current_Time = timeString;
                    })
                    .catch(error => {
                        console.error("Error fetching time:", error);
                    });
            }

            // Request payload
            const payload = {
                model: 'gpt-3.5-turbo-0613',
                messages: [{
                    role: 'system',
                    content: 'be a helpfull assistant'
                }, {
                    role: 'user',
                    content: userInput
                }],
                functions: [{
                    name: "lookupTime",
                    description: "get the current time",
                    parameters: {
                        type: "object", // specify that the parameter is an object
                        properties: {
                            TimeInput: {
                                type: "string", // specify the parameter type as a string
                                description: "The Current_Time variable"
                            }
                        },
                        required: ["TimeInput"] // specify that the location parameter is required
                    }
                }],

                max_tokens: 100,
                temperature: 0.7
            };

            // Make the API call
            fetch(apiUrl, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Authorization': `Bearer ${apiKey}`
                    },
                    body: JSON.stringify(payload)
                })
                .then(response => response.json())
                .then(data => {
                    // Handle the response
                    console.log(data);

                    // Show the response in the output element
                    const outputElement = document.getElementById('output');
                    outputElement.textContent = data.choices[0].message.content;
                })
                .catch(error => {
                    // Handle any errors
                    console.error(error);
                });
        }
    </script>
</head>

<body>
    <input type="text" id="userInput" placeholder="Type your message...">
    <button onclick="sendRequest()">Send Request</button>
    <div id="output"></div>


</body>

</html>

It outputs the following information without a text response:

(finish_reason: "function_call", index: 0, message: content: null, function_call: arguments: "{\n "TimeInput": "Current_Time"\n}", name: "lookupTime").

However, it doesn't actually call the function. If I were to ask it a question, it correctly outputs the desired text, and the content field is populated.


Solution

  • Your code contains two problems:

    1. the code does not handle the case where GPT wants to call the function you specified. In this case, the response does not contain the "content" attribute, so you get a runtime error.
    2. the function signature of the lookupTime function does not make sense (to me) and does not match the definition of your JavaScript implementation. The actual function takes no arguments, but the signature you give GPT describes an argument.

    I have corrected your code and changed it a bit so that it does a useful job. However, the implementation is still more than incomplete and lacks any serious error handling etc.

    The new lookupTime function expects a city as an argument and returns the time for that city. Note that it only accepts the few cities that match the names in the Americas region for the timezone database (e.g. Phoenix).

    async function lookupTime(city) {
       try {
          const response = await fetch(`http://worldtimeapi.org/api/timezone/America/${city}`);
          const data = await response.json();
          const currentTime = new Date(data.datetime);
          const timeString = currentTime.toLocaleTimeString();
          console.log(timeString);
          return timeString;
       }
       catch (error) {
          console.error("Error fetching time:", error);
       }
    }
    

    The function signature that is made available to GPT is then changed to reflect the new argument:

    async function sendRequest() {
        const apiUrl = 'https://api.openai.com/v1/chat/completions';
        const apiKey = 'YOUR API KEY';
        const userInput = document.getElementById('userInput').value;
    
        let payload = {
           model: 'gpt-3.5-turbo-0613',
             messages: [{
                role: 'system',
                content: 'You are a helpful assistant.'
             }, {
                role: 'user',
                content: userInput
             }],
             functions: [{
                name: "lookupTime",
                description: "get the current time",
                parameters: {
                   type: "object",
                   properties: {
                      city: {
                         type: "string",
                         description: "The city for which the current time is to be retrieved."
                      }
                   },
                required: ["city"]
             }
           }],
    
           max_tokens: 100,
           temperature: 0.7
        };
    

    And finally, we need to change the handling of communication with GPT. First, we need to send an initial request. Then we need to respond to the response from GPT. If it wants to call a function, we must interpret that response, call the function, and then call GPT again with (a) the previous messages and (b) a new message containing the response to the function call. Only then will GPT know the result and return the expected response.

    So, we need to call the API twice. The easiest way is to move the API call to a function chatWithGpt and allow this function to call itself recursively:

        async function chatWithGpt() {
           console.log(payload);
           const response = await fetch(apiUrl, {
              method: 'POST',
              headers: {
                 'Content-Type': 'application/json',
                 'Authorization': `Bearer ${apiKey}`
              },
              body: JSON.stringify(payload)
           });
    
           const data = await response.json();
           console.log(data);
           const choice = data.choices[0];
    
           if (choice.finish_reason === 'function_call' && choice.message.function_call.name === 'lookupTime') {
              const arguments = JSON.parse(choice.message.function_call.arguments);
              const timeString = await lookupTime(arguments.city);
              payload.messages.push({
                    role: "function",
                    name: "lookupTime",
                    content: JSON.stringify({ time: timeString })
              });
              return chatWithGpt();
           }
           else {
              const outputElement = document.getElementById('output');
              outputElement.textContent = data.choices[0].message.content;
           }
        }
        try {
           chatWithGpt();
        }
        catch (error) {
           console.error(error);
        }
     }
    

    For better reproducibility I changed the temperature to 0. Then you will receive the following answers to the given Questions:

    Q: What time is it in Phoenix?

    A: The current time in Phoenix is 02:11:08.

    And it is even smart to call the function to get context information:

    Q: Do I need a flashlight out in Phoenix now?

    A: Based on the current time in Phoenix (02:13 AM), it is nighttime. If you are planning to go outside, it is recommended to have a flashlight with you for better visibility in the dark.

    For further explanations I recommend reading the blog entry of OpenAI regarding the new function API as well as the API documentation.