PHP/Laravelで使える！？OpenAI APIクライアント

## 背景
もう随分前から生成AI/LLM/ChatGPTあたりの話題が尽きない今日このごろ。
弊社運営のSaaSにもGPTが導入されたりして、結果、お問い合わせが増加していると聞いています。
先日、ふとLaravel Newsのブログ記事などを眺めて居たのですが、やはりというべきか、最近になってGPT関連の記事が複数掲載されていました。PHP/Laravel界隈も例に漏れず、という所のようです。
私も、今更ながらキャッチアップをばと、PHPerの端くれとして、
PHP/LaravelからOpenAI APIを利用する実装を試してみました。

## 事前準備

* Laravel sailで開発環境を構築
    * `curl -s "https://laravel.build/example-app" | bash`
* OpenAI APIを利用するため、OpenAIへのSignUpと、APIキーの払出
    * https://openai.com/ にアクセスしてSign Up
    * https://platform.openai.com/account/billing/payment-methods でクレカ登録
    * https://platform.openai.com/account/api-keys で `Create new secret key`
    * https://platform.openai.com/docs/api-reference でAPIドキュメント確認

## OpenAIで紹介されているクライアント

OpenAI内の下記ページにて、様々な言語のクライアントが紹介されています。

[Libraries - OpenAI API](https://platform.openai.com/docs/libraries/community-libraries)

PHPは、現時点で3つほど紹介されています。

* [openai-php clinet by openai-php](https://github.com/openai-php/client) ★2.9k (clinetは恐らくtypoなので、後ほど報告したい)
* [orhanerday/open-ai by orhanerday](https://github.com/orhanerday/open-ai) ★1.8k
* [tectalic/openai by tectalic](https://github.com/tectalichq/public-openai-client-php) ★283

ひとまずStarが多い `openai-php/client`を利用してみることにしました。


## OpenAI APIクライアント[openai-php/client](https://github.com/openai-php/client)を利用してみる

とにかくREADMEに従ってパッケージをインストールします。

```bash
$ sail composer require openai-php/client
```

（自分の場合はサクッとインストールできました）

tinkerで、READMEに含まれるサンプルコードを実行してみます。

```bash
sail tinker
```
```php

$yourApiKey = 'sk..........';
$client = OpenAI::client($yourApiKey);
$result = $client->completions()->create([
    'model' => 'text-davinci-003',
    'prompt' => 'PHP is',
]);

// 以下、実行結果
= OpenAI\Responses\Completions\CreateResponse {#6243
    +id: "cmpl-7b4h2GpCqrnYmheiqb5uZrQxxxxxx",
    +object: "text_completion",
    +created: 1689070532,
    +model: "text-davinci-003",
    +choices: [
      OpenAI\Responses\Completions\CreateResponseChoice {#6228
        +text: " an acronym that refer to the programming language "Hypertext Preprocessor." It is",
        +index: 0,
        +logprobs: null,
        +finishReason: "length",
      },
    ],
    +usage: OpenAI\Responses\Completions\CreateResponseUsage {#6224
      +promptTokens: 3,
      +completionTokens: 16,
      +totalTokens: 19,
    },
  }

```

サクッと結果を得られました。

とはいえ想像通りではありますが、かなりシンプルなAPIクライアントですね。

なんと、こちらの `openai-php/client` ですが、Laravelに特化したパッケージがあるのに気づきました。

[openai-php/laravel](https://github.com/openai-php/laravel)

## Laravelで[openai-php/laravel](https://github.com/openai-php/laravel)を使ったAPIを作成してみる 


折角なので、`text-davinci-003` ではなく、GPT3.5とchat APIを使ってみたいと思います。


### 実装

何はともあれ、まずはパッケージのインストール


```bash
$ sail composer require openai-php/laravel
```

configファイルを生成
```bash
$ sail artisan vendor:publish --provider="OpenAI\Laravel\ServiceProvider"
```

.envに `OPENAI_API_KEY` の変数名でOpenAIのSecret Keyを追記

```.env
.
.
.
OPENAI_API_KEY=sk-...
```

クセで再起動しました（不要かも）

```bash
$ sail restart
```

Controllerを作成
```bash
$ sail artisan make:controller ChatController
```


Controllerに、OpenAI APIへの問い合わせやレスポンスを記述

```php:./app/Http/Controllers/ChatController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use OpenAI\Laravel\Facades\OpenAI;

class ChatController extends Controller
{
    /**
     * Undocumented function
     *
     * @param Request $request
     * @return void
     */
    public function index(Request $request)
    {
        // TODO: バリデーション
        $messages = $request->messages;

        $result = OpenAI::chat()->create([
            'model' => 'gpt-3.5-turbo',
            'messages' => $messages,
        ]);

        return response()->json(['message' => $result->choices[0]->message->content]);
    }
}

```


Routesに追加 
（今回は省略しましたが、ローカル環境以外では、認証が必須となるかと思います）

```php:./routes/api.php
<?php

use App\Http\Controllers\ChatController;
use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "api" middleware group. Make something great!
|
*/

Route::post('/chat', [ChatController::class, 'index']);

```


大変簡易ではありますが、以上です。

クライアントの初期化をProviderに任せるような実装のようです。
[aws/aws-sdk-php](https://packagist.org/packages/aws/aws-sdk-php)に対する[aws/aws-sdk-php-laravel](https://packagist.org/packages/aws/aws-sdk-php-laravel) と同じような形ですね。

### APIを叩く

カラオケで一緒に歌ってくれそうなプロンプトを用意しました。

```bash:curlコマンド
curl -X POST -H "Content-Type: application/json" -d '{"messages":[{"role":"system","content":"あなたは影山ヒロノブです"},{"role":"user","content":"立ち上がれ気高く舞え"}]}' http://0.0.0.0:80/api/chat
```

```json:結果
{
	"message": "立ち上がれ気高く舞え\n\n影山ヒロノブよ、立ち上がりなさい\n気高さと闘志を胸に秘めて\n輝く未来のために戦い続けよ\n立ち上がれ、気高く舞え",
}
```

想定とは異なる方向で「影山ヒロノブがかっこいい」歌をうたってくれました。
影山ヒロノブが「かっこいい歌」をうたってくれるのかと思っていたので正直おどろきましたが、
ありがとうGPT。カラオケに行く友達がいない僕でもGPTとは友達となれた気がしたので、ひとまず成功です。

（なにせ知識が浅いので、自分の設定したパラメータやプロンプトがイマイチだったのかもしれません。）
（怖いので実際に友達かどうかは聞かないことにしました。）

## さいごに

本格的にプロダクトにOpenAI APIを導入するとなると、色々な課題があります。

今回はLaravel上で動くものを実装しましたが、
実際に既存のアプリケーションに入れるとすると、他エンドポイントと比較してレスポンスが非常遅いものになることが想定されます。
チャットAPIのためだけにタイムアウトを伸ばすよりは、FaaS等を利用したマイクロなサービスとして実装すべきかもしれない、と思いました。
（そして、その場合はLaravelは使用されないでしょう）

しかしながら、非常に少ないコード量で、かつ躓くことなく実装できたことを踏まえると、
例えば「既存の資産を活かしたクローズドなプロトタイプ」等を作成するには結構良いかもしれないな、と感じました。

また、今回は素直に(?)OpenAIのAPIを利用しましたが、リージョンや利用制限等を考慮すると、
（特に受託開発では）AzureのOpenAI Serviceの方が都合の良いケースも多い気もしています。
そちらにも対応できそうな気がするので、そのうち実際に試してみたいと考えています。
また、他にも色々なGPT/生成AI関連のパッケージがあるので、それらも試してみたいと思いました。

### メモ：PHPならこのあたりを試してみたい

https://github.com/orhanerday/open-ai
https://github.com/elastic/elasticsearch-chatgpt-php
https://github.com/kambo-1st/llama-cpp-php
https://github.com/blinq-dev/laravel-synth
https://github.com/yllw-digital/laravel-chatgpt-mock-api