Usage Laravel and ChatGPT "Function calling"
Tags: tutorial, beginners, laravel, chatgpt
Published: 2023-06-19 00:28:41

Recently, OpenAI released an update for ChatGPT, introducing new features that allow developers to describe language model functions - gpt-4-0613 and gpt-3.5-turbo-0613. These features enable the generation of JSON objects containing arguments to run these functions based on user input.

Let's explore an example of this new feature. You can use it to obtain information about an IP address, previous orders, information from your FAQ, weather forecast, or any other desired information.

To demonstrate how it works, we will use the `openai-php/client` library. Firstly, create an Artisan command by running the following command:

```bash
php artisan make:command ChatFunction
```

Update the `ChatFunction` class as follows:

```php
namespace App\Console\Commands;

use Illuminate\Console\Command;
use OpenAI\Client;

class ChatFunction extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'app:chat-function';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Invoke a chat function with OpenAI language model.';

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $client = new Client(config('openai.api_key'));

        $response = $client->chat()->create([
            'model'    => 'gpt-3.5-turbo-0613',
            'messages' => [
                ['role' => 'user', 'content' => 'What do you know about IP address 12.175.87.227?'],
            ],
        ]);

        $answer = $response->choices[0]->message->content;

        $this->info("OpenAI response: $answer");
    }
}
```

If we ask AI for information about a specific IP address, it may respond with something like, "I'm sorry, but I cannot provide information about specific IP addresses."

To fix this, let's specify the function in our request.

```php
namespace App\Console\Commands;

use Illuminate\Console\Command;

class ChatFunction extends Command
{
    public function handle()
    {
        $client = \OpenAI::factory()
            ->withApiKey(config('openai.api_key'))
            ->make();

        $response = $client->chat()->create([
            'model'     => 'gpt-3.5-turbo-0613',
            'messages'  => [
                ['role' => 'user', 'content' => 'What do you know about IP 12.175.87.227 ?'],
            ],
            'functions' => [
                [
                    'name'        => 'about_ip',
                    'description' => 'Get information about the IP address',
                    'parameters'  => [
                        'type'       => 'object',
                        'properties' => [
                            'ip' => [
                                'type'        => 'string',
                                'description' => 'IP address v4',
                            ],
                        ],
                        'required'   => ['ip'],
                    ],
                ],
            ],
        ]);

        // As we can see, we now have a proposal to call a function on our side and there are arguments:  
        $name = $response->choices[0]->message->functionCall->name; // ip_info  
        $arguments = $response->choices[0]->message->functionCall->arguments; // {\n "ip": "12.175.87.227" }  
    }
}
```
Now we have prepared data such as the name of the function to be called and its arguments. I believe that an excellent solution for performing such tasks is to use the [Sajya package](https://sajya.github.io/), which simplifies working with JSON-RPC both in the console and as an API. Therefore, let's create a simple class using this package:

Command to create a new procedure called "AboutIp" using Laravel's artisan CLI:

```bash
php artisan make:procedure AboutIp
```

Now, let's add a useful action to it:

```php 
namespace App\Http\Procedures;  
  
use Illuminate\Support\Collection;  
use Illuminate\Support\Facades\Http;  
use Sajya\Server\Procedure;  
  
class AboutIp extends Procedure  
{  
    /**  
     * The name of the procedure that is used for referencing.  
     * 
     * @var string  
     */  
    public static string $name = 'about';  
  
    /**  
     * Execute the procedure.  
     * 
     * @param string $ip  
     * @return Collection  
     */  
    public function ip(string $ip): Collection  
    {  
        return Http::get('http://ip-api.com/json/' . $ip)->collect();  
    }  
}
```

This "about_ip" procedure will simply receive an IP address, fetch information from another API, and return it to the user.

Let's go back to the console command and add a method to create and call the Remote Procedure Call (RPC):

```php
protected function callRPC(string $method, ?string $params = null): ?string
{
    $app = new App([
        \App\Http\Procedures\AboutIp::class,
    ], '_');

    $response = $app->terminate(json_encode([
        'jsonrpc' => '2.0',
        'method'  => $method,
        'params'  => json_decode($params, true),
        'id'      => 1,
    ]));

    return json_encode($response, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
}
```

If we call it just by its name and arguments, we won't receive a human response. To obtain that, we need to refer back to ChatGPT:

```php
/**
 * Execute the console command.
 */
public function handle()
{
    $client = \OpenAI::factory()
        ->withApiKey(config('openai.api_key'))
        ->make();

    $response = $client->chat()->create([
        'model'     => 'gpt-3.5-turbo-0613',
        'messages'  => [
            ['role' => 'user', 'content' => 'What do you know about IP 12.175.87.227 ?'],
        ],
        'functions' => [
            [
                'name'        => 'about_ip',
                'description' => 'Get information about the IP address',
                'parameters'  => [
                    'type'       => 'object',
                    'properties' => [
                        'ip' => [
                            'type'        => 'string',
                            'description' => 'IP address v4',
                        ],
                    ],
                    'required'   => ['ip'],
                ],
            ],
        ],
    ]);

    // As we can see, we now have a proposal to call a function on our side and there are arguments:
    $name = $response->choices[0]->message->functionCall->name; // ip_info
    $arguments = $response->choices[0]->message->functionCall->arguments; // {\n "ip": "12.175.87.227" }


    $functionResult = $this->callRPC($name, $arguments);

    // Again we turn to ChatGPT, but this time we add the response from the function:
    $response = $client->chat()->create([
        'model'     => 'gpt-3.5-turbo-0613',
        'messages'  => [
            ['role' => 'user', 'content' => 'What do you know about IP 12.175.87.227 ?'],
            ['role' => 'function', 'name' => $name, 'content' => $functionResult],
        ],
        'functions' => [
            [
                'name'        => 'about_ip',
                'description' => 'Get information about the IP address',
                'parameters'  => [
                    'type'       => 'object',
                    'properties' => [
                        'ip' => [
                            'type'        => 'string',
                            'description' => 'IP address v4',
                        ],
                    ],
                    'required'   => ['ip'],
                ],
            ],
        ],
    ]);

    $response->choices[0]->message->content;

    // The IP address 12.175.87.227 is located in San Diego, California, United States.
    // The postal code is 92110.
    // The latitude and longitude coordinates are 32.7616 and -117.2058 respectively.
    // The timezone of this location is America/Los_Angeles.
    // The ISP (Internet Service Provider) is AT&T Services, Inc.
    // The organization associated with this IP address is Coffman Specialties.
    // The Autonomous System (AS) number is AS7018 AT&T Services, Inc.
}
```
Now we got a human response and used the ChatGPT "features" to enrich the actual information.