From f07e454b6c9f4faea303f076d312a8c9de82a722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Sat, 4 Mar 2023 00:05:23 +0100 Subject: [PATCH 1/4] Allows to change the HTTP client in the factory --- src/OpenAI.php | 5 +++-- tests/OpenAI.php | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/OpenAI.php b/src/OpenAI.php index 83e3357b..b518dc20 100644 --- a/src/OpenAI.php +++ b/src/OpenAI.php @@ -8,13 +8,14 @@ use OpenAI\ValueObjects\ApiKey; use OpenAI\ValueObjects\Transporter\BaseUri; use OpenAI\ValueObjects\Transporter\Headers; +use Psr\Http\Client\ClientInterface; final class OpenAI { /** * Creates a new Open AI Client with the given API token. */ - public static function client(string $apiKey, string $organization = null): Client + public static function client(string $apiKey, string $organization = null, ClientInterface $client = null): Client { $apiKey = ApiKey::from($apiKey); @@ -26,7 +27,7 @@ public static function client(string $apiKey, string $organization = null): Clie $headers = $headers->withOrganization($organization); } - $client = new GuzzleClient(); + $client ??= new GuzzleClient(); $transporter = new HttpTransporter($client, $baseUri, $headers); diff --git a/tests/OpenAI.php b/tests/OpenAI.php index dd1a601d..842fb37a 100644 --- a/tests/OpenAI.php +++ b/tests/OpenAI.php @@ -1,6 +1,9 @@ toBeInstanceOf(Client::class); }); + +it('accepts a custom http client', function () { + $client = new class implements ClientInterface { + public function sendRequest(RequestInterface $request): ResponseInterface { + throw new \LogicException('Not implemented'); + } + }; + + $openAI = OpenAI::client('foo', client: ); + + expect($openAI)->toBeInstanceOf(Client::class); +}); From 8f997098cf8a8ae5022397151a7305dbfbfa18b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Sat, 4 Mar 2023 21:24:50 +0100 Subject: [PATCH 2/4] feat: replace default guzzle http client by any psr/http-client-implementation --- composer.json | 6 +++++- src/OpenAI.php | 7 ++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index f460efc3..03c5e54d 100644 --- a/composer.json +++ b/composer.json @@ -11,9 +11,10 @@ ], "require": { "php": "^8.1.0", - "guzzlehttp/guzzle": "^7.5.0" + "psr/http-client-implementation": "1.0" }, "require-dev": { + "guzzlehttp/guzzle": "^7.5.0", "laravel/pint": "^1.6.0", "nunomaduro/collision": "^7.0.5", "pestphp/pest": "^2.0.0", @@ -23,6 +24,9 @@ "rector/rector": "^0.14.8", "symfony/var-dumper": "^6.2.7" }, + "suggest": { + "guzzlehttp/guzzle": "^7.5.0" + }, "autoload": { "psr-4": { "OpenAI\\": "src/" diff --git a/src/OpenAI.php b/src/OpenAI.php index b518dc20..3c420b69 100644 --- a/src/OpenAI.php +++ b/src/OpenAI.php @@ -27,7 +27,12 @@ public static function client(string $apiKey, string $organization = null, Clien $headers = $headers->withOrganization($organization); } - $client ??= new GuzzleClient(); + if (null === $client) { + if (!class_exists(GuzzleClient::class)) { + throw new \LogicException('Guzzle is not installed. Try running "composer require guzzlehttp/guzzle" or pass a PSR-18 client.'); + } + $client = new GuzzleClient(); + } $transporter = new HttpTransporter($client, $baseUri, $headers); From e309266c764d677b842163ff403540c9d48ec481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Fri, 10 Mar 2023 10:33:48 +0100 Subject: [PATCH 3/4] Use php-http/discovery --- composer.json | 8 ++++---- src/OpenAI.php | 9 ++------- tests/OpenAI.php | 10 ++++++---- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/composer.json b/composer.json index 03c5e54d..bc6c49af 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,8 @@ ], "require": { "php": "^8.1.0", + "guzzlehttp/psr7": "^2.4.4", + "php-http/discovery": "^1.14", "psr/http-client-implementation": "1.0" }, "require-dev": { @@ -24,9 +26,6 @@ "rector/rector": "^0.14.8", "symfony/var-dumper": "^6.2.7" }, - "suggest": { - "guzzlehttp/guzzle": "^7.5.0" - }, "autoload": { "psr-4": { "OpenAI\\": "src/" @@ -46,7 +45,8 @@ "sort-packages": true, "preferred-install": "dist", "allow-plugins": { - "pestphp/pest-plugin": true + "pestphp/pest-plugin": true, + "php-http/discovery": false } }, "scripts": { diff --git a/src/OpenAI.php b/src/OpenAI.php index 3c420b69..5f9422bf 100644 --- a/src/OpenAI.php +++ b/src/OpenAI.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use GuzzleHttp\Client as GuzzleClient; +use Http\Discovery\Psr18ClientDiscovery; use OpenAI\Client; use OpenAI\Transporters\HttpTransporter; use OpenAI\ValueObjects\ApiKey; @@ -27,12 +27,7 @@ public static function client(string $apiKey, string $organization = null, Clien $headers = $headers->withOrganization($organization); } - if (null === $client) { - if (!class_exists(GuzzleClient::class)) { - throw new \LogicException('Guzzle is not installed. Try running "composer require guzzlehttp/guzzle" or pass a PSR-18 client.'); - } - $client = new GuzzleClient(); - } + $client ??= Psr18ClientDiscovery::find(); $transporter = new HttpTransporter($client, $baseUri, $headers); diff --git a/tests/OpenAI.php b/tests/OpenAI.php index 842fb37a..b41d9494 100644 --- a/tests/OpenAI.php +++ b/tests/OpenAI.php @@ -1,9 +1,9 @@ toBeInstanceOf(Client::class); }); From b1e9d7b16bb3de62eeb2b132e58edbc5f0010ced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Fri, 10 Mar 2023 12:39:24 +0100 Subject: [PATCH 4/4] Improve test --- composer.json | 2 +- tests/Arch.php | 1 + tests/OpenAI.php | 26 ++++++++++++++------------ 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/composer.json b/composer.json index bc6c49af..5db0e3cc 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ "php": "^8.1.0", "guzzlehttp/psr7": "^2.4.4", "php-http/discovery": "^1.14", - "psr/http-client-implementation": "1.0" + "psr/http-client-implementation": "^1.0" }, "require-dev": { "guzzlehttp/guzzle": "^7.5.0", diff --git a/tests/Arch.php b/tests/Arch.php index e01e7cd3..cc853640 100644 --- a/tests/Arch.php +++ b/tests/Arch.php @@ -33,6 +33,7 @@ ]); test('openai')->expect('OpenAI')->toOnlyUse([ + 'Http\Discovery\Psr18ClientDiscovery', 'Psr\Http\Client', 'GuzzleHttp\Client', 'GuzzleHttp\Psr7', diff --git a/tests/OpenAI.php b/tests/OpenAI.php index b41d9494..5455f293 100644 --- a/tests/OpenAI.php +++ b/tests/OpenAI.php @@ -1,9 +1,10 @@ $handlerStack]); $openAI = OpenAI::client('foo', client: $client); + $response = $openAI->completions()->create([ + 'model' => 'text-davinci-003', + 'prompt' => 'Say this is a test', + ]); - expect($openAI)->toBeInstanceOf(Client::class); + expect($response->id)->toBe('test-id'); });