OpenAI ChatGPT APIをPHPで実装する

- PHP 8.2.12
- "guzzlehttp/guzzle": "^7.9"

OpenAI APIをPHPにて実装してみます。

HTTPクライアントはguzzleを使用します。Laravelでのシステムにて利用することを想定しています。

APIキーは、**OPENAI_API_KEY**という名前で環境変数に入れてあります。**phpdotenv**を使ってます。

```bash
$ composer require guzzlehttp/guzzle
$ composer require vlucas/phpdotenv
```

### 通常パターン

```php:chatgpt1.php
<?php
require __DIR__.'/vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Dotenv\Dotenv;

$dotenv = Dotenv::createImmutable(__DIR__);
$dotenv->load();

$url = 'https://api.openai.com/v1/chat/completions';
$user = '富士山の高さを教えてください。'; // ユーザープロンプト
$system = '英語で答えてください。'; // システムプロンプト

$client = new Client();

$data = [
    'model' => 'gpt-4o-mini',
    'messages' => [
        ['role' => 'user', 'content' => $user],
        ['role' => 'system', 'content' => $system]
    ]
];

$response = $client->post($url, [
    'headers' => [
        'Authorization' => 'Bearer '.$_ENV['OPENAI_API_KEY'],
        'Content-Type'  => 'application/json',
    ],
    'json' => $data,
]);

$answer = json_decode($response->getBody()->getContents(), true);
print($answer['choices'][0]['message']['content']);
```
```bash:実行
$ php ./chatgpt1.php
Mount Fuji has a height of 3,776 meters (12,389 feet).
```

### 画像を添付するパターン

```php:chatgpt2.php
<?php
require __DIR__.'/vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Dotenv\Dotenv;

$dotenv = Dotenv::createImmutable(__DIR__);
$dotenv->load();

$url = 'https://api.openai.com/v1/chat/completions';
$user = 'この画像が何の画像か推測して答えてください'; // ユーザープロンプト
$imageFile = __DIR__.'/book.jpg';

function encodeImageFile($filePath) {
    $types = ['jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'png' => 'image/png'];
    $info = pathinfo($filePath);
    $type = $types[strtolower($info['extension'])];
    return'data:'.$type.';base64, '.base64_encode(file_get_contents($filePath));
}

$client = new Client();

$data = [
    'model' => 'gpt-4o-mini',
    'messages' => [['role' => 'user', 'content' => [
        ['type' => 'text', 'text' => $user],
        ['type' => 'image_url', 'image_url' => ['url' => encodeImageFile($imageFile)]]
    ]]],
];

$response = $client->post($url, [
    'headers' => [
        'Authorization' => 'Bearer '.$_ENV['OPENAI_API_KEY'],
        'Content-Type'  => 'application/json',
    ],
    'json' => $data
]);

$answer = json_decode($response->getBody()->getContents(), true);
print($answer['choices'][0]['message']['content']);
```
```bash:実行
$ php ./chatgpt2.php
この画像はおそらく、日本のマンガや小説の表紙デザインです。「成瀬は天下を取りにいく」というタイトルが書かれており、野球のユニフォ
ームを着たキャラクターが描かれています。おそらく、成瀬というキャラクターの成長や挑戦をテーマにした物語かもしれません。作者は宮島 未奈さんで、出版元は新潮社です。
```

### Stream で実行

レスポンス中の ```data:``` の扱いがわからず今回はただ削除しちゃってます。
```$chunk = json_decode(str_replace('data: ', '', $data[$i]), true);```

```php:chatgpt3.php
<?php
require __DIR__.'/vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Dotenv\Dotenv;

$dotenv = Dotenv::createImmutable(__DIR__);
$dotenv->load();

$url = 'https://api.openai.com/v1/chat/completions';
$user = '富士山の高さを教えてください。'; // ユーザープロンプト
$system = '関西弁で答えてください。'; // システムプロンプト

$client = new Client();

$data = [
    'model' => 'gpt-4o-mini',
    'messages' => [
        ['role' => 'user', 'content' => $user],
        ['role' => 'system', 'content' => $system]
    ],
    'stream' => true
];

$response = $client->post($url, [
    'headers' => [
        'Authorization' => 'Bearer '.$_ENV['OPENAI_API_KEY'],
        'Content-Type'  => 'application/json',
    ],
    'json' => $data,
    'stream' => true
]);

$body = $response->getBody();
$buf = '';
while (!$body->eof()) {
    $buf .= $body->read(1024);
    $data = explode("\n", $buf);
    for ($i = 0; $i < count($data); ++$i) {
        if ($i == count($data) - 1) {
            $buf = $data[$i];
        } else {
            $chunk = json_decode(str_replace('data: ', '', $data[$i]), true);
            if ($chunk != null && $chunk['choices'][0]['finish_reason'] == null) {
                print($chunk['choices'][0]['delta']['content']);
            }
        }
    }
    flush();
}
```

```bash:実行
$ php ./chatgpt3.php
富士山の高さは、約3,776メートルやで！日本一の山やから、めっちゃ有名やな。登る人も多いし、ほんまにきれいな山やな。
```

### 紹介

次はAssistants APIをやってみたいと思います。

OpenAI API, ChatGPTの組み込みサンプルを紹介しています。
ご興味あればみてみてください。

https://develop.sankosc.co.jp/chatgptdemo/