From 47d1add95867461611952aabc11c662e65e64c83 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Thu, 2 Jan 2025 18:49:40 +0300 Subject: [PATCH 01/78] update documentation --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 841b218..1385e27 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ - [Quick Start Guide](#quick-start-guide) - [Basic Usage](#basic-usage) - [Advanced Usage](#advanced-usage) + - [Use With Frameworks](#use-with-frameworks) - [Testing](#testing) - [Contributors](#contributors-) - [License](#license) @@ -78,6 +79,10 @@ $response = DeepseekClient::build($apiKey, 'https://api.deepseek.com/v2', 500) echo 'API Response:'.$response; ``` +## Use With Frameworks + +### [Laravel Deepseek Package](https://github.com/deepseek-php/deepseek-laravel) + --- ## Testing From 2e886f65a5b8fd499238561ba3dd13cd50e538e3 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Thu, 2 Jan 2025 18:55:32 +0300 Subject: [PATCH 02/78] update composer keys --- composer.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/composer.json b/composer.json index 210ec89..4d84a87 100644 --- a/composer.json +++ b/composer.json @@ -6,6 +6,9 @@ "deepseek-php-client", "deepseek-api", "php-deepseek", + "deepseek-coder", + "deepseek-chat", + "deepseek-math", "deepseek-integration", "openai", "sdk", From a9b127f56b623a068d81638f431fc59256717926 Mon Sep 17 00:00:00 2001 From: Omar Alalwi Date: Fri, 3 Jan 2025 08:31:12 +0300 Subject: [PATCH 03/78] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 1385e27..6c1701f 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,7 @@ --- ## Overview -**Deepseek PHP Client** is a robust and community-driven PHP client library for seamless integration with the [Deepseek](https://www.deepseek.com/) API, offering efficient access to advanced AI and data processing capabilities - +**Deepseek PHP Client** is a robust and community-driven PHP client library for seamless integration with the [Deepseek](https://www.deepseek.com/) API. ### Key Features - **Easy Integration:** Simplifies interaction with the Deepseek API using a PHP client. - **Method Chaining:** Supports fluent method chaining for building requests. From 0571779471d3812475840dadc25036f77be92174 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Fri, 17 Jan 2025 17:31:35 +0300 Subject: [PATCH 04/78] feat support temperature option --- .gitignore | 14 ++++++++++++++ README.md | 1 + composer.json | 2 +- src/DeepseekClient.php | 9 +++++++++ src/Enums/Requests/QueryFlags.php | 1 + 5 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c5a6b38 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +build +vendor +tests/TestSupport/temp +tests/temp +composer.lock +phpunit.xml +.env +.phpunit.cache/ +.phpunit.result.cache +.phpunit.cache/test-results +.php-cs-fixer.cache +phpstan.neon +tests/Support/temp/ +.idea/ diff --git a/README.md b/README.md index 6c1701f..0f4424f 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ $response = DeepseekClient::build($apiKey, 'https://api.deepseek.com/v2', 500) ->query('System setup query', 'system') ->query('User input message', 'user') ->withModel(Models::CODER->value) + ->setTemperature(1.5) ->run(); echo 'API Response:'.$response; diff --git a/composer.json b/composer.json index 4d84a87..44a9923 100644 --- a/composer.json +++ b/composer.json @@ -59,7 +59,7 @@ "role": "creator" } ], - "version": "1.0.0.0", + "version": "1.0.2", "require": { "php": "^8.1.0", "php-http/discovery": "^1.20.0", diff --git a/src/DeepseekClient.php b/src/DeepseekClient.php index 33214f1..abf2902 100644 --- a/src/DeepseekClient.php +++ b/src/DeepseekClient.php @@ -43,6 +43,8 @@ class DeepseekClient implements DeepseekClientContract */ protected bool $stream; + protected int $temperature; + /** * Initialize the DeepseekClient with a PSR-compliant HTTP client. * @@ -61,6 +63,7 @@ public function run(): string QueryFlags::MESSAGES->value => $this->queries, QueryFlags::MODEL->value => $this->model, QueryFlags::STREAM->value => $this->stream, + QueryFlags::TEMPERATURE->value => $this->temperature, ]; // Clear queries after sending $this->queries = []; @@ -123,6 +126,12 @@ public function withStream(bool $stream = true): self return $this; } + public function setTemperature(int $temperature): self + { + $this->temperature = $temperature; + return $this; + } + protected function buildQuery(string $content, ?string $role = null): array { return [ diff --git a/src/Enums/Requests/QueryFlags.php b/src/Enums/Requests/QueryFlags.php index fb133d6..b4523f2 100644 --- a/src/Enums/Requests/QueryFlags.php +++ b/src/Enums/Requests/QueryFlags.php @@ -7,4 +7,5 @@ enum QueryFlags: string case MESSAGES = 'messages'; case MODEL = 'model'; case STREAM = 'stream'; + case TEMPERATURE = 'temperature'; } From 0da79fa21fa1630034d0540079408c77f4c1b408 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Fri, 17 Jan 2025 19:36:44 +0300 Subject: [PATCH 05/78] bugfix temprature type --- composer.json | 2 +- src/DeepseekClient.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 44a9923..917d2b8 100644 --- a/composer.json +++ b/composer.json @@ -59,7 +59,7 @@ "role": "creator" } ], - "version": "1.0.2", + "version": "1.0.2.1", "require": { "php": "^8.1.0", "php-http/discovery": "^1.20.0", diff --git a/src/DeepseekClient.php b/src/DeepseekClient.php index abf2902..8ed1b2c 100644 --- a/src/DeepseekClient.php +++ b/src/DeepseekClient.php @@ -43,7 +43,7 @@ class DeepseekClient implements DeepseekClientContract */ protected bool $stream; - protected int $temperature; + protected float $temperature; /** * Initialize the DeepseekClient with a PSR-compliant HTTP client. @@ -126,7 +126,7 @@ public function withStream(bool $stream = true): self return $this; } - public function setTemperature(int $temperature): self + public function setTemperature(float $temperature): self { $this->temperature = $temperature; return $this; From 941542fe1f5d8d97c29aef9bc0349cbd62741e2b Mon Sep 17 00:00:00 2001 From: Omar Alalwi Date: Fri, 17 Jan 2025 19:48:32 +0300 Subject: [PATCH 06/78] Update composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 917d2b8..1c5f46a 100644 --- a/composer.json +++ b/composer.json @@ -59,7 +59,7 @@ "role": "creator" } ], - "version": "1.0.2.1", + "version": "1.0.1", "require": { "php": "^8.1.0", "php-http/discovery": "^1.20.0", From 2795b0a1dca4a2dcc07d89ba6db420bf8322d156 Mon Sep 17 00:00:00 2001 From: moassaad Date: Mon, 20 Jan 2025 17:13:29 +0200 Subject: [PATCH 07/78] create: contract result interface. --- src/Contracts/Models/ResultContract.php | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/Contracts/Models/ResultContract.php diff --git a/src/Contracts/Models/ResultContract.php b/src/Contracts/Models/ResultContract.php new file mode 100644 index 0000000..f591433 --- /dev/null +++ b/src/Contracts/Models/ResultContract.php @@ -0,0 +1,25 @@ + Date: Mon, 20 Jan 2025 17:13:47 +0200 Subject: [PATCH 08/78] create: http state result code. --- src/Enums/Requests/HTTPState.php | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/Enums/Requests/HTTPState.php diff --git a/src/Enums/Requests/HTTPState.php b/src/Enums/Requests/HTTPState.php new file mode 100644 index 0000000..1137cf0 --- /dev/null +++ b/src/Enums/Requests/HTTPState.php @@ -0,0 +1,25 @@ + Date: Mon, 20 Jan 2025 17:14:05 +0200 Subject: [PATCH 09/78] create: result abstruct class model. --- src/Models/ResultAbstract.php | 59 +++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 src/Models/ResultAbstract.php diff --git a/src/Models/ResultAbstract.php b/src/Models/ResultAbstract.php new file mode 100644 index 0000000..3349855 --- /dev/null +++ b/src/Models/ResultAbstract.php @@ -0,0 +1,59 @@ +statusCode = $statusCode; + $this->content = $content; + } + protected function setStatusCode(int $statusCode) + { + $this->statusCode = $statusCode; + return $this; + } + public function getStatusCode(): int + { + return $this->statusCode; + } + protected function setContent(string $content): void + { + $this->content = $content; + } + public function getContent(): string + { + return $this->content; + } + public function setResponse(ResponseInterface $response): static + { + $this->response = $response; + $this->setStatusCode($this->getResponse()->getStatusCode()); + $this->setContent($this->getResponse()->getBody()->getContents()); + return $this; + } + public function getResponse(): ResponseInterface + { + return $this->response; + } + public function isSuccess(): bool + { + return ($this->getStatusCode() === HTTPState::OK->value); + } +} + From c3aaebe763eb159f2ecaa651da336cc8eb872d66 Mon Sep 17 00:00:00 2001 From: moassaad Date: Mon, 20 Jan 2025 17:14:31 +0200 Subject: [PATCH 10/78] create: result models. --- src/Models/BadResult.php | 12 ++++++++++++ src/Models/FailureResult.php | 12 ++++++++++++ src/Models/SuccessResult.php | 12 ++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 src/Models/BadResult.php create mode 100644 src/Models/FailureResult.php create mode 100644 src/Models/SuccessResult.php diff --git a/src/Models/BadResult.php b/src/Models/BadResult.php new file mode 100644 index 0000000..95c207e --- /dev/null +++ b/src/Models/BadResult.php @@ -0,0 +1,12 @@ + Date: Mon, 20 Jan 2025 17:15:32 +0200 Subject: [PATCH 11/78] update: handel result and error massega with models. --- src/DeepseekClient.php | 18 +++++++++++++++++- src/Resources/Resource.php | 29 ++++++++++++++++++++++------- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/DeepseekClient.php b/src/DeepseekClient.php index 8ed1b2c..f2ac21d 100644 --- a/src/DeepseekClient.php +++ b/src/DeepseekClient.php @@ -3,6 +3,7 @@ namespace DeepseekPhp; use DeepseekPhp\Contracts\DeepseekClientContract; +use DeepseekPhp\Contracts\Models\ResultContract; use DeepseekPhp\Enums\Queries\QueryRoles; use DeepseekPhp\Enums\Requests\HeaderFlags; use DeepseekPhp\Enums\Requests\QueryFlags; @@ -45,6 +46,12 @@ class DeepseekClient implements DeepseekClientContract protected float $temperature; + /** + * response result contract + * @var ResultContract + */ + protected ResultContract $result; + /** * Initialize the DeepseekClient with a PSR-compliant HTTP client. * @@ -67,7 +74,8 @@ public function run(): string ]; // Clear queries after sending $this->queries = []; - return (new Resource($this->httpClient))->sendRequest($requestData); + $this->result = (new Resource($this->httpClient))->sendRequest($requestData); + return $this->getResult()->getContent(); } /** @@ -140,4 +148,12 @@ protected function buildQuery(string $content, ?string $role = null): array ]; } + /** + * response result model + * @return \DeepseekPhp\Contracts\Models\ResultContract + */ + public function getResult(): ResultContract + { + return $this->result; + } } diff --git a/src/Resources/Resource.php b/src/Resources/Resource.php index 4e86a50..51e1030 100644 --- a/src/Resources/Resource.php +++ b/src/Resources/Resource.php @@ -4,13 +4,18 @@ namespace DeepseekPhp\Resources; +use DeepseekPhp\Contracts\Models\ResultContract; use DeepseekPhp\Contracts\Resources\ResourceContract; use DeepseekPhp\Enums\Configs\DefaultConfigs; use DeepseekPhp\Enums\Models; use DeepseekPhp\Enums\Data\DataTypes; use DeepseekPhp\Enums\Requests\EndpointSuffixes; use DeepseekPhp\Enums\Requests\QueryFlags; +use DeepseekPhp\Models\BadResult; +use DeepseekPhp\Models\FailureResult; +use DeepseekPhp\Models\SuccessResult; use DeepseekPhp\Traits\Queries\HasQueryParams; +use GuzzleHttp\Exception\BadResponseException; use GuzzleHttp\Exception\GuzzleException; use Psr\Http\Client\ClientInterface; @@ -39,23 +44,33 @@ public function __construct(ClientInterface $client) * Send a request to the API endpoint. * * This method sends a POST request to the API endpoint, including the query data - * and custom headers, and returns the response body as a string. + * and custom headers, and returns the response as a result contract. * * @param array $requestData The data to send in the request. - * @return string The response body. + * @return ResultContract The response result. * - * @throws \RuntimeException If the request fails. */ - public function sendRequest(array $requestData): string + public function sendRequest(array $requestData): ResultContract { try { $response = $this->client->post($this->getEndpointSuffix(), [ 'json' => $this->resolveHeaders($requestData), ]); - return $response->getBody()->getContents(); - } catch (GuzzleException $e) { - throw new \RuntimeException("Deepseek API request failed: " . $e->getMessage()); + return (new SuccessResult())->setResponse($response); + } catch (BadResponseException $badResponse) { + + $response = $badResponse->getResponse(); + return (new BadResult())->setResponse($response); + + } catch (GuzzleException $error) { + + return new FailureResult($error->getCode(), $error->getMessage()); + + } catch (\Exception $error) { + + return new FailureResult($error->getCode(), '{"error":"'.$error->getMessage().'"}'); + } } From 38db594969abf87ea5d72eda63acafd5cd4d3c4c Mon Sep 17 00:00:00 2001 From: moassaad Date: Mon, 20 Jan 2025 17:15:43 +0200 Subject: [PATCH 12/78] create: handel result test. --- tests/HandelResultDeepseekTest.php | 54 ++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 tests/HandelResultDeepseekTest.php diff --git a/tests/HandelResultDeepseekTest.php b/tests/HandelResultDeepseekTest.php new file mode 100644 index 0000000..48a73a9 --- /dev/null +++ b/tests/HandelResultDeepseekTest.php @@ -0,0 +1,54 @@ +apiKey = "valid-api-key"; + $this->expiredApiKey = "expired-api-key"; + } + public function test_ok_response() + { + $deepseek = DeepseekClient::build($this->apiKey) + ->query('Hello Deepseek, how are you today?') + ->setTemperature(1.5); + $response = $deepseek->run(); + $result = $deepseek->getResult(); + + $this->assertNotEmpty($response); + $this->assertEquals(HTTPState::OK->value, $result->getStatusCode()); + } + public function test_can_not_access_with_api_expired_payment() + { + $deepseek = DeepseekClient::build($this->expiredApiKey) + ->query('Hello Deepseek, how are you today?') + ->setTemperature(1.5); + $response = $deepseek->run(); + $result = $deepseek->getResult(); + + $this->assertNotEmpty($response); + if(!$result->isSuccess()) + { + $this->assertEquals(HTTPState::PAYMENT_REQUIRED->value, $result->getStatusCode()); + } + } + public function test_access_with_wrong_api_key() + { + $deepseek = DeepseekClient::build($this->apiKey."wrong-api-key") + ->query('Hello Deepseek, how are you today?') + ->setTemperature(1.5); + $response = $deepseek->run(); + $result = $deepseek->getResult(); + + $this->assertNotEmpty($response); + $this->assertEquals(HTTPState::UNAUTHORIZED->value, $result->getStatusCode()); + } +} From 829ee0ccf602cd0902dd8bc408843ca2a6c49b11 Mon Sep 17 00:00:00 2001 From: Omar Alalwi Date: Tue, 21 Jan 2025 08:39:03 +0300 Subject: [PATCH 13/78] add R1 Models https://github.com/deepseek-ai/DeepSeek-R1 --- src/Enums/Models.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Enums/Models.php b/src/Enums/Models.php index 7ba14c6..8d16077 100644 --- a/src/Enums/Models.php +++ b/src/Enums/Models.php @@ -6,4 +6,6 @@ enum Models: string { case CHAT = 'deepseek-chat'; case CODER = 'deepseek-coder'; + case R1 = 'DeepSeek-R1'; + case R1-Zero = 'DeepSeek-R1-Zero'; } From 98b63b787702721342e00274e0fa3c72a165eaa4 Mon Sep 17 00:00:00 2001 From: obada Date: Fri, 24 Jan 2025 23:24:51 +0300 Subject: [PATCH 14/78] fix: temperature access before initialization bug --- src/Constants/TemperatureValues.php | 15 +++++++++++++++ src/DeepseekClient.php | 12 +++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 src/Constants/TemperatureValues.php diff --git a/src/Constants/TemperatureValues.php b/src/Constants/TemperatureValues.php new file mode 100644 index 0000000..5a6f292 --- /dev/null +++ b/src/Constants/TemperatureValues.php @@ -0,0 +1,15 @@ +httpClient = $httpClient; $this->model = null; $this->stream = false; + $this->temperature = TemperatureValues::GENERAL_CONVERSATION; } public function run(): string From 88b647be0ceac351c0350bec905cf77a2e433db9 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sat, 25 Jan 2025 02:30:23 +0300 Subject: [PATCH 15/78] add temprature enum --- src/Enums/Configs/TemperatureValues.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/Enums/Configs/TemperatureValues.php diff --git a/src/Enums/Configs/TemperatureValues.php b/src/Enums/Configs/TemperatureValues.php new file mode 100644 index 0000000..e7a3f2d --- /dev/null +++ b/src/Enums/Configs/TemperatureValues.php @@ -0,0 +1,15 @@ + Date: Sat, 25 Jan 2025 02:32:00 +0300 Subject: [PATCH 16/78] Delete src/Constants/TemperatureValues.php --- src/Constants/TemperatureValues.php | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 src/Constants/TemperatureValues.php diff --git a/src/Constants/TemperatureValues.php b/src/Constants/TemperatureValues.php deleted file mode 100644 index 5a6f292..0000000 --- a/src/Constants/TemperatureValues.php +++ /dev/null @@ -1,15 +0,0 @@ - Date: Sat, 25 Jan 2025 02:36:43 +0300 Subject: [PATCH 17/78] bugfix with enum --- src/Enums/Configs/TemperatureValues.php | 2 +- src/Enums/Models.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Enums/Configs/TemperatureValues.php b/src/Enums/Configs/TemperatureValues.php index e7a3f2d..c19be88 100644 --- a/src/Enums/Configs/TemperatureValues.php +++ b/src/Enums/Configs/TemperatureValues.php @@ -7,7 +7,7 @@ enum TemperatureValues: string case CODING = "0.0"; case MATH = "0.1"; case DATA_ANALYSIS = "1.0"; - case DATA_CLEANING = "1.1"; // Fixed missing closing quote + case DATA_CLEANING = "1.1";g case GENERAL_CONVERSATION = "1.3"; case TRANSLATION = "1.4"; case CREATIVE_WRITING = "1.5"; diff --git a/src/Enums/Models.php b/src/Enums/Models.php index 8d16077..1bb7bd2 100644 --- a/src/Enums/Models.php +++ b/src/Enums/Models.php @@ -7,5 +7,5 @@ enum Models: string case CHAT = 'deepseek-chat'; case CODER = 'deepseek-coder'; case R1 = 'DeepSeek-R1'; - case R1-Zero = 'DeepSeek-R1-Zero'; + case R1Zero = 'DeepSeek-R1-Zero'; } From 4d9339aaa1aac6b97e692cc6ac2975d45704edbd Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sat, 25 Jan 2025 02:37:22 +0300 Subject: [PATCH 18/78] update --- src/Enums/Configs/TemperatureValues.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Enums/Configs/TemperatureValues.php b/src/Enums/Configs/TemperatureValues.php index c19be88..73fa859 100644 --- a/src/Enums/Configs/TemperatureValues.php +++ b/src/Enums/Configs/TemperatureValues.php @@ -7,7 +7,7 @@ enum TemperatureValues: string case CODING = "0.0"; case MATH = "0.1"; case DATA_ANALYSIS = "1.0"; - case DATA_CLEANING = "1.1";g + case DATA_CLEANING = "1.1"; case GENERAL_CONVERSATION = "1.3"; case TRANSLATION = "1.4"; case CREATIVE_WRITING = "1.5"; From 5cc41fda2189cf160449e56e85727102cb6002d7 Mon Sep 17 00:00:00 2001 From: Omar Alalwi Date: Sat, 25 Jan 2025 02:38:40 +0300 Subject: [PATCH 19/78] Update DeepseekClient.php --- src/DeepseekClient.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DeepseekClient.php b/src/DeepseekClient.php index b132de8..81870b0 100644 --- a/src/DeepseekClient.php +++ b/src/DeepseekClient.php @@ -8,7 +8,7 @@ use DeepseekPhp\Enums\Queries\QueryRoles; use DeepseekPhp\Enums\Requests\QueryFlags; use DeepseekPhp\Enums\Requests\HeaderFlags; -use DeepseekPhp\Constants\TemperatureValues; +use DeepseekPhp\Enums\Configs\TemperatureValues; use DeepseekPhp\Contracts\DeepseekClientContract; use DeepseekPhp\Traits\Resources\{HasChat, HasCoder}; @@ -56,7 +56,7 @@ public function __construct(ClientInterface $httpClient) $this->httpClient = $httpClient; $this->model = null; $this->stream = false; - $this->temperature = TemperatureValues::GENERAL_CONVERSATION; + $this->temperature = (float) TemperatureValues::GENERAL_CONVERSATION->value; } public function run(): string From b245dc8f0d4922f7508343474dc73cb6ff4dd78c Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sat, 25 Jan 2025 02:43:39 +0300 Subject: [PATCH 20/78] bugfix --- src/DeepseekClient.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/DeepseekClient.php b/src/DeepseekClient.php index 844772c..bd5e1f5 100644 --- a/src/DeepseekClient.php +++ b/src/DeepseekClient.php @@ -11,7 +11,6 @@ use DeepseekPhp\Enums\Requests\QueryFlags; use DeepseekPhp\Enums\Requests\HeaderFlags; use DeepseekPhp\Enums\Configs\TemperatureValues; -use DeepseekPhp\Contracts\DeepseekClientContract; use DeepseekPhp\Traits\Resources\{HasChat, HasCoder}; class DeepseekClient implements DeepseekClientContract From 7e2a0ae2a121071000bd8d60df7b2cffd325ca8a Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sat, 25 Jan 2025 02:55:06 +0300 Subject: [PATCH 21/78] change default model to R2 --- README.md | 18 ++++++++++++++++++ composer.json | 4 +++- src/Enums/Configs/DefaultConfigs.php | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0f4424f..6703567 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,24 @@ Thanks to these wonderful people for contributing to this project! 💖
🏆 Contributer + + + Mohammad Asaad +
+ Mohammad Asaad +
+
+ 🏆 Contributer + + + + Opada Alzaiede +
+ Opada Alzaiede +
+
+ 🏆 Contributer + diff --git a/composer.json b/composer.json index 1c5f46a..2b23890 100644 --- a/composer.json +++ b/composer.json @@ -5,6 +5,8 @@ "deepseek", "deepseek-php-client", "deepseek-api", + "DeepSeek-R1", + "DeepSeek-R1-Zero", "php-deepseek", "deepseek-coder", "deepseek-chat", @@ -59,7 +61,7 @@ "role": "creator" } ], - "version": "1.0.1", + "version": "1.0.2", "require": { "php": "^8.1.0", "php-http/discovery": "^1.20.0", diff --git a/src/Enums/Configs/DefaultConfigs.php b/src/Enums/Configs/DefaultConfigs.php index 871cf8d..1d15de8 100644 --- a/src/Enums/Configs/DefaultConfigs.php +++ b/src/Enums/Configs/DefaultConfigs.php @@ -5,7 +5,7 @@ enum DefaultConfigs: string { case BASE_URL = 'https://api.deepseek.com/v3'; - case MODEL = 'deepseek-chat'; + case MODEL = 'DeepSeek-R1'; case TIMEOUT = '30'; case STREAM = 'false'; } From 9830f856e880218332a5acf142cec1db8916880d Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Tue, 28 Jan 2025 02:14:46 +0300 Subject: [PATCH 22/78] Use match expression --- src/Traits/Queries/HasQueryParams.php | 41 ++++++++++----------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/src/Traits/Queries/HasQueryParams.php b/src/Traits/Queries/HasQueryParams.php index 453c7bb..627eb2b 100644 --- a/src/Traits/Queries/HasQueryParams.php +++ b/src/Traits/Queries/HasQueryParams.php @@ -35,24 +35,16 @@ private function getQueryParam(array $query, string $key, $default, string $type */ private function convertValue($value, string $type): mixed { - switch ($type) { - case DataTypes::STRING->value: - return (string) $value; - case DataTypes::INTEGER->value: - return (int) $value; - case DataTypes::FLOAT->value: - return (float) $value; - case DataTypes::ARRAY->value: - return (array) $value; - case DataTypes::OBJECT->value: - return (object) $value; - case DataTypes::BOOL->value: - return (bool) $value; - case DataTypes::JSON->value: - return json_decode((string) $value, true); - default: - return $value; - } + return match ($type) { + DataTypes::STRING->value => (string)$value, + DataTypes::INTEGER->value => (int)$value, + DataTypes::FLOAT->value => (float)$value, + DataTypes::ARRAY->value => (array)$value, + DataTypes::OBJECT->value => (object)$value, + DataTypes::BOOL->value => (bool)$value, + DataTypes::JSON->value => json_decode((string)$value, true), + default => $value, + }; } /** @@ -63,13 +55,10 @@ private function convertValue($value, string $type): mixed */ private function getDefaultForKey(string $key): mixed { - switch ($key) { - case QueryFlags::MODEL->value: - return $this->getDefaultModel(); - case QueryFlags::STREAM->value: - return $this->getDefaultStream(); - default: - return null; - } + return match ($key) { + QueryFlags::MODEL->value => $this->getDefaultModel(), + QueryFlags::STREAM->value => $this->getDefaultStream(), + default => null, + }; } } From cf7cea27c05fe9289aecf75a9bdc91c38ea4cc69 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Tue, 28 Jan 2025 02:17:35 +0300 Subject: [PATCH 23/78] Fix typo --- src/Models/ResultAbstract.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Models/ResultAbstract.php b/src/Models/ResultAbstract.php index 3349855..3b7ae46 100644 --- a/src/Models/ResultAbstract.php +++ b/src/Models/ResultAbstract.php @@ -14,7 +14,7 @@ abstract class ResultAbstract implements ResultContract protected ?int $statusCode; protected ?string $content; /** - * handel response comeing from request + * handel response coming from request * @var ResponseInterface|null */ protected ?ResponseInterface $response; From f6c7de8278c8625431a580d37b0d3648c57133c3 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Tue, 28 Jan 2025 02:22:44 +0300 Subject: [PATCH 24/78] Change namespace to DeepSeekPhp --- src/Contracts/DeepseekClientContract.php | 4 ++-- src/Contracts/Factories/ApiFactoryContract.php | 4 ++-- src/Contracts/Models/ResultContract.php | 2 +- src/Contracts/Resources/ResourceContract.php | 2 +- src/DeepseekClient.php | 18 +++++++++--------- src/Enums/Configs/DefaultConfigs.php | 2 +- src/Enums/Configs/TemperatureValues.php | 2 +- src/Enums/Data/DataTypes.php | 2 +- src/Enums/Queries/QueryRoles.php | 2 +- src/Enums/Requests/EndpointSuffixes.php | 2 +- src/Enums/Requests/HTTPState.php | 2 +- src/Enums/Requests/HeaderFlags.php | 2 +- src/Enums/Requests/QueryFlags.php | 2 +- src/Factories/ApiFactory.php | 8 ++++---- src/Models/BadResult.php | 2 +- src/Models/FailureResult.php | 2 +- src/Models/ResultAbstract.php | 6 +++--- src/Models/SuccessResult.php | 2 +- src/Resources/Chat.php | 2 +- src/Resources/Coder.php | 4 ++-- src/Resources/Resource.php | 2 +- src/Traits/Queries/HasQueryParams.php | 2 +- src/Traits/Resources/HasChat.php | 4 ++-- src/Traits/Resources/HasCoder.php | 4 ++-- tests/DeepseekTest.php | 2 +- tests/HandelResultDeepseekTest.php | 6 +++--- 26 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/Contracts/DeepseekClientContract.php b/src/Contracts/DeepseekClientContract.php index 0106b90..6df9032 100644 --- a/src/Contracts/DeepseekClientContract.php +++ b/src/Contracts/DeepseekClientContract.php @@ -1,8 +1,8 @@ Date: Tue, 28 Jan 2025 22:37:49 +0300 Subject: [PATCH 25/78] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 6703567..4f92771 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,8 @@ echo 'API Response:'.$response; ### [Laravel Deepseek Package](https://github.com/deepseek-php/deepseek-laravel) +### [Symfony Deepseek Package](https://github.com/deepseek-php/deepseek-symfony) + --- ## Testing From b3bd6ddda1836b898743b20d43618274e318f845 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 1 Feb 2025 00:13:50 +0300 Subject: [PATCH 26/78] Remove unnecessary using --- src/Contracts/DeepseekClientContract.php | 2 -- src/DeepseekClient.php | 1 - 2 files changed, 3 deletions(-) diff --git a/src/Contracts/DeepseekClientContract.php b/src/Contracts/DeepseekClientContract.php index 6df9032..1590e45 100644 --- a/src/Contracts/DeepseekClientContract.php +++ b/src/Contracts/DeepseekClientContract.php @@ -2,8 +2,6 @@ namespace DeepSeekPhp\Contracts; -use DeepSeekPhp\DeepseekClient; - interface DeepseekClientContract { public static function build(string $apiKey): self; diff --git a/src/DeepseekClient.php b/src/DeepseekClient.php index e7e66b3..a85d408 100644 --- a/src/DeepseekClient.php +++ b/src/DeepseekClient.php @@ -9,7 +9,6 @@ use DeepSeekPhp\Factories\ApiFactory; use DeepSeekPhp\Enums\Queries\QueryRoles; use DeepSeekPhp\Enums\Requests\QueryFlags; -use DeepSeekPhp\Enums\Requests\HeaderFlags; use DeepSeekPhp\Enums\Configs\TemperatureValues; use DeepSeekPhp\Traits\Resources\{HasChat, HasCoder}; From a2a111d2cb4bda3c64d3ddd3e835b3e9c4f3224c Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 1 Feb 2025 00:19:29 +0300 Subject: [PATCH 27/78] Remove unnecessary return from setStatusCode() --- src/Models/ResultAbstract.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Models/ResultAbstract.php b/src/Models/ResultAbstract.php index b1f4cd8..718cf0e 100644 --- a/src/Models/ResultAbstract.php +++ b/src/Models/ResultAbstract.php @@ -26,7 +26,6 @@ public function __construct(?int $statusCode = null, ?string $content = null) protected function setStatusCode(int $statusCode) { $this->statusCode = $statusCode; - return $this; } public function getStatusCode(): int { From 381ead656a4e4ae6cb8ed4451b819d3730cb0f2b Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sat, 1 Feb 2025 01:00:31 +0300 Subject: [PATCH 28/78] change namespace and adding change logs --- MIGRATION.md | 31 +++ README.md | 180 +++++++++++------- composer.json | 54 ++---- src/Contracts/DeepseekClientContract.php | 4 +- .../Factories/ApiFactoryContract.php | 4 +- src/Contracts/Models/ResultContract.php | 5 +- src/Contracts/Resources/ResourceContract.php | 2 +- src/DeepseekClient.php | 28 +-- src/Enums/Configs/DefaultConfigs.php | 2 +- src/Enums/Configs/TemperatureValues.php | 2 +- src/Enums/Data/DataTypes.php | 2 +- src/Enums/Models.php | 2 +- src/Enums/Queries/QueryRoles.php | 2 +- src/Enums/Requests/EndpointSuffixes.php | 2 +- src/Enums/Requests/HTTPState.php | 2 +- src/Enums/Requests/HeaderFlags.php | 2 +- src/Enums/Requests/QueryFlags.php | 2 +- src/Factories/ApiFactory.php | 8 +- src/Models/BadResult.php | 5 +- src/Models/FailureResult.php | 5 +- src/Models/ResultAbstract.php | 7 +- src/Models/SuccessResult.php | 5 +- src/Resources/Chat.php | 2 +- src/Resources/Coder.php | 4 +- src/Resources/Resource.php | 26 +-- src/Traits/Queries/HasQueryParams.php | 6 +- src/Traits/Resources/HasChat.php | 4 +- src/Traits/Resources/HasCoder.php | 4 +- tests/DeepseekTest.php | 2 +- tests/HandelResultDeepseekTest.php | 12 +- 30 files changed, 233 insertions(+), 183 deletions(-) create mode 100644 MIGRATION.md diff --git a/MIGRATION.md b/MIGRATION.md new file mode 100644 index 0000000..53691e1 --- /dev/null +++ b/MIGRATION.md @@ -0,0 +1,31 @@ +# CHANGELOG + +## [2.x] - 2025-02-01 + +If you are upgrading from a version `1.x` to `2.x`, please perform the following steps: + +### Breaking Changes + +### 1. Namespace Change +- **Old Namespace:** `DeepseekPhp` +- **New Namespace:** `DeepSeek` + +**Action Required:** +Update all imports in your codebase. + +##### Replace: +```php +use DeepseekPhp\DeepseekClient; +``` + +##### With: +```php +use DeepSeek\DeepseekClient; +``` + +### Migration Guide +1. Replace all occurrences of `DeepseekPhp` with `DeepSeek` in your code. +3. Run tests to ensure everything works as expected. + +If you encounter issues, please refer to our documentation or open an issue on GitHub. + diff --git a/README.md b/README.md index 4f92771..a8311b9 100644 --- a/README.md +++ b/README.md @@ -1,85 +1,99 @@

- - Gpdf - +

DeepSeek PHP Client

+

🚀 Community-Driven PHP SDK for DeepSeek AI API Integration

+ +

+ + Latest Version + + + PHP Version + + + License + + + Tests Status + +

-# Deepseek PHP Client - ## Table of Contents -- [Overview](#Overview) - - [Features](#key-Features) -- [Installation](#installation) -- [Quick Start Guide](#quick-start-guide) - - [Basic Usage](#basic-usage) - - [Advanced Usage](#advanced-usage) - - [Use With Frameworks](#use-with-frameworks) -- [Testing](#testing) -- [Contributors](#contributors-) -- [License](#license) +- [✨ Features](#-features) +- [📦 Installation](#-installation) +- [🚀 Quick Start](#-quick-start) + - [Basic Usage](#basic-usage) + - [Advanced Configuration](#advanced-configuration) + - [Framework Integration](#-framework-integration) +- [🆕 Migration Guide](#-migration-guide) +- [📝 Changelog](#-changelog) +- [🧪 Testing](#-testing) +- [🔒 Security](#-security) +- [🤝 Contributors](#-contributors) +- [📄 License](#-license) --- -## Overview -**Deepseek PHP Client** is a robust and community-driven PHP client library for seamless integration with the [Deepseek](https://www.deepseek.com/) API. -### Key Features -- **Easy Integration:** Simplifies interaction with the Deepseek API using a PHP client. -- **Method Chaining:** Supports fluent method chaining for building requests. -- **Customizable:** Allows setting different models, query roles, and streaming options. -- **PSR-18 Compliance:** Utilizes PSR-18 HTTP client for making API requests. + +## ✨ Features + +- **Seamless API Integration**: PHP-first interface for DeepSeek's AI capabilities +- **Fluent Builder Pattern**: Chainable methods for intuitive request building +- **Enterprise Ready**: PSR-18 compliant HTTP client integration +- **Model Flexibility**: Support for multiple DeepSeek models (Coder, Chat, etc.) +- **Streaming Ready**: Built-in support for real-time response handling +- **Framework Friendly**: Laravel & Symfony packages available --- -## Installation +## 📦 Installation -You can install the package via Composer: +Require the package via Composer: ```bash composer require deepseek-php/deepseek-php-client ``` -**Ensure your project meets the following requirements:** -- PHP 8.1 or later +**Requirements**: +- PHP 8.1+ --- -## Quick Start Guide +## 🚀 Quick Start ### Basic Usage -```php -use DeepseekPhp\DeepseekClient; +Get started with just two lines of code: -$apiKey = 'your-api-key'; +```php +use DeepSeek\DeepSeekClient; -$response = DeepseekClient::build($apiKey) - ->query('Hello Deepseek, how are you today?') +$response = DeepSeekClient::build('your-api-key') + ->query('Explain quantum computing in simple terms') ->run(); -echo 'API Response:'.$response; +echo $response; // "Quantum computing uses qubits to..." ``` -**Note**: in easy mode it will take defaults for all configs [Check Default Values](https://github.com/deepseek-php/deepseek-php-client/blob/master/src/Enums/Configs/DefaultConfigs.php) +📌 Defaults used: +- Model: `deepseek-chat` +- Temperature: 0.8 -### Advanced Usage +### Advanced Configuration ```php -use DeepseekPhp\DeepseekClient; -use DeepseekPhp\Enums\Queries\QueryRoles; -use DeepseekPhp\Enums\Models; +use DeepSeek\DeepSeekClient; +use DeepSeek\Enums\Models; -$apiKey = 'your-api-key'; - -$response = DeepseekClient::build($apiKey, 'https://api.deepseek.com/v2', 500) - ->query('System setup query', 'system') - ->query('User input message', 'user') - ->withModel(Models::CODER->value) - ->setTemperature(1.5) +$response = DeepSeekClient::build('your-api-key') + ->withBaseUrl('https://api.deepseek.com/v2') + ->withModel(Models::CODER) + ->withTemperature(1.2) ->run(); echo 'API Response:'.$response; ``` -## Use With Frameworks +### 🛠 Framework Integration ### [Laravel Deepseek Package](https://github.com/deepseek-php/deepseek-laravel) @@ -87,66 +101,92 @@ echo 'API Response:'.$response; --- -## Testing +## 🚧 Migration Guide -tests will come soon . +Upgrading from v1.x? Check our comprehensive [Migration Guide](MIGRATION.md) for breaking changes and upgrade instructions. -## Changelog +--- -See [CHANGELOG](CHANGELOG.md) for recent changes. +## 📝 Changelog -## Contributors ✨ +Detailed release notes available in [CHANGELOG.md](CHANGELOG.md) -Thanks to these wonderful people for contributing to this project! 💖 +--- + +## 🧪 Testing + +```bash +composer test +``` + +Test coverage coming in v2.1. + +--- + +## 🔒 Security + +**Report Vulnerabilities**: to [omaralwi2010@gmail.com](mailto:omaralwi2010@gmail.com) + +--- + +## 🤝 Contributors + +A huge thank you to these amazing people who have contributed to this project! 🎉💖 + -
- Omar AlAlwi + Omar AlAlwi
- Omar AlAlwi + Omar AlAlwi

🏆 Creator
- ayman alhattami + Ayman Alhattami
- ayman alhattami + Ayman Alhattami

- 🏆 Contributer + ⭐ Contributor
- Mohammad Asaad + Mohammad Asaad
- Mohammad Asaad + Mohammad Asaad

- 🏆 Contributer + ⭐ Contributor
- Opada Alzaiede + Opada Alzaiede
- Opada Alzaiede + Opada Alzaiede

- 🏆 Contributer + ⭐ Contributor +
+ + Hisham Abdullah +
+ Hisham Abdullah +
+
+ ⭐ Contributor
-Want to contribute? Check out the [contributing guidelines](./CONTRIBUTING.md) and submit a pull request! 🚀 - -## Security +**Want to contribute?** Check out the [contributing guidelines](./CONTRIBUTING.md) and submit a pull request! 🚀 -If you discover any security-related issues, please email creator : `omaralwi2010@gmail.com`. +--- -## License +## 📄 License -The MIT License (MIT). See [LICENSE](LICENSE.md) for more information. +This package is open-source software licensed under the [MIT License](LICENSE.md). diff --git a/composer.json b/composer.json index 2b23890..7e39749 100644 --- a/composer.json +++ b/composer.json @@ -3,48 +3,32 @@ "description": "deepseek PHP client is a robust and community-driven PHP client library for seamless integration with the Deepseek API, offering efficient access to advanced AI and data processing capabilities.", "keywords": [ "deepseek", - "deepseek-php-client", - "deepseek-api", - "DeepSeek-R1", - "DeepSeek-R1-Zero", - "php-deepseek", - "deepseek-coder", - "deepseek-chat", - "deepseek-math", - "deepseek-integration", - "openai", + "ai", "sdk", - "codex", - "GPT-3", - "DALL-E", "api", + "php", "client", - "deepseek-sdk", + "llm", + "nlp", + "openai", + "qwen", + "machine-learning", "php-sdk", - "php-ai", - "ai-for-php", "ai-sdk", "ai-api", - "natural", - "language", - "processing", - "deepseek-php-library", - "deepseek-client", "natural-language-processing", - "ai-integration", - "machine-learning", - "php-machine-learning", - "php-iot", - "nlp", - "data-processing", - "deep-learning", - "deepseek-library", - "php-library", "api-integration", "php-api-client", "deepseek-ai", - "php-openai-alternative", - "ai-client-library" + "ai-client-library", + "text-generation", + "generative-ai", + "api-wrapper", + "rest-client", + "developer-tools", + "php-ai-integration", + "deepseek-api", + "openai-alternative" ], "homepage": "https://github.com/deepseek-php/deepseek-php-client", "license": "MIT", @@ -61,7 +45,7 @@ "role": "creator" } ], - "version": "1.0.2", + "version": "2.0.0", "require": { "php": "^8.1.0", "php-http/discovery": "^1.20.0", @@ -86,12 +70,12 @@ }, "autoload": { "psr-4": { - "DeepseekPhp\\": "src/" + "DeepSeek\\": "src/" } }, "autoload-dev": { "psr-4": { - "DeepseekPhp\\Tests\\": "tests/" + "DeepSeek\\Tests\\": "tests/" } }, "minimum-stability": "dev", diff --git a/src/Contracts/DeepseekClientContract.php b/src/Contracts/DeepseekClientContract.php index 6df9032..3e5316e 100644 --- a/src/Contracts/DeepseekClientContract.php +++ b/src/Contracts/DeepseekClientContract.php @@ -1,8 +1,8 @@ apiKey) + $deepseek = DeepSeekClient::build($this->apiKey) ->query('Hello Deepseek, how are you today?') ->setTemperature(1.5); $response = $deepseek->run(); @@ -28,7 +28,7 @@ public function test_ok_response() } public function test_can_not_access_with_api_expired_payment() { - $deepseek = DeepseekClient::build($this->expiredApiKey) + $deepseek = DeepSeekClient::build($this->expiredApiKey) ->query('Hello Deepseek, how are you today?') ->setTemperature(1.5); $response = $deepseek->run(); @@ -42,7 +42,7 @@ public function test_can_not_access_with_api_expired_payment() } public function test_access_with_wrong_api_key() { - $deepseek = DeepseekClient::build($this->apiKey."wrong-api-key") + $deepseek = DeepSeekClient::build($this->apiKey."wrong-api-key") ->query('Hello Deepseek, how are you today?') ->setTemperature(1.5); $response = $deepseek->run(); From f91945ca0cd2e7da7e1766085c45b3e612d53d0d Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sat, 1 Feb 2025 01:06:46 +0300 Subject: [PATCH 29/78] update doc --- MIGRATION.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index 53691e1..ccb5cb4 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -15,12 +15,12 @@ Update all imports in your codebase. ##### Replace: ```php -use DeepseekPhp\DeepseekClient; +use DeepseekPhp\Someclass; ``` ##### With: ```php -use DeepSeek\DeepseekClient; +use DeepSeek\Someclass; ``` ### Migration Guide From 5087ae6c99a2edc8bb5efa634dfb99b4138cfcac Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sat, 1 Feb 2025 01:24:24 +0300 Subject: [PATCH 30/78] bugfix --- src/{DeepseekClient.php => DeepSeekClient.php} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/{DeepseekClient.php => DeepSeekClient.php} (98%) diff --git a/src/DeepseekClient.php b/src/DeepSeekClient.php similarity index 98% rename from src/DeepseekClient.php rename to src/DeepSeekClient.php index 184c23d..19d58df 100644 --- a/src/DeepseekClient.php +++ b/src/DeepSeekClient.php @@ -13,7 +13,7 @@ use DeepSeek\Enums\Configs\TemperatureValues; use DeepSeek\Traits\Resources\{HasChat, HasCoder}; -class DeepseekClient implements DeepseekClientContract +class DeepSeekClient implements DeepseekClientContract { use HasChat, HasCoder; From 66a3aa6070023e935b635c5700da28e88be691d2 Mon Sep 17 00:00:00 2001 From: Omar Alalwi Date: Sat, 1 Feb 2025 01:26:25 +0300 Subject: [PATCH 31/78] Update composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7e39749..2946e66 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "role": "creator" } ], - "version": "2.0.0", + "version": "2.0.1", "require": { "php": "^8.1.0", "php-http/discovery": "^1.20.0", From a0c246e06b3191ed4bfb27ef550911887513d03b Mon Sep 17 00:00:00 2001 From: Omar Alalwi Date: Sat, 1 Feb 2025 01:27:43 +0300 Subject: [PATCH 32/78] Update composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 2946e66..7e39749 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "role": "creator" } ], - "version": "2.0.1", + "version": "2.0.0", "require": { "php": "^8.1.0", "php-http/discovery": "^1.20.0", From 21ab962c30eb0b56ddaf65e79c04d5b8af30fbfb Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sat, 1 Feb 2025 01:33:22 +0300 Subject: [PATCH 33/78] clean up --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a8311b9..a1bdab9 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ $response = DeepSeekClient::build('your-api-key') ->query('Explain quantum computing in simple terms') ->run(); -echo $response; // "Quantum computing uses qubits to..." +echo $response; ``` 📌 Defaults used: From e4fbe56bf96dfbe7d69ffd3b34f0a13d9f6c01f4 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sat, 1 Feb 2025 03:18:46 +0300 Subject: [PATCH 34/78] feat / test cases --- composer.json | 3 ++- tests/DeepseekTest.php | 9 --------- tests/Helpers/TestCase.php | 23 +++++++++++++++++++++++ tests/Integration/ApiIntegrationTest.php | 21 +++++++++++++++++++++ tests/Pest.php | 5 +++++ tests/Unit/DeepSeekClientTest.php | 24 ++++++++++++++++++++++++ 6 files changed, 75 insertions(+), 10 deletions(-) delete mode 100644 tests/DeepseekTest.php create mode 100644 tests/Helpers/TestCase.php create mode 100644 tests/Integration/ApiIntegrationTest.php create mode 100644 tests/Pest.php create mode 100644 tests/Unit/DeepSeekClientTest.php diff --git a/composer.json b/composer.json index 7e39749..864db28 100644 --- a/composer.json +++ b/composer.json @@ -61,7 +61,7 @@ "laravel/pint": "^1.18.1", "mockery/mockery": "^1.6.12", "nunomaduro/collision": "^7.11.0|^8.5.0", - "pestphp/pest": "^2.36.0|^3.5.0", + "pestphp/pest": "^3.7", "pestphp/pest-plugin-arch": "^2.7|^3.0", "pestphp/pest-plugin-type-coverage": "^2.8.7|^3.1.0", "phpstan/phpstan": "^1.12.7", @@ -96,6 +96,7 @@ "config": { "sort-packages": true, "preferred-install": "dist", + "optimize-autoloader": true, "allow-plugins": { "pestphp/pest-plugin": true, "php-http/discovery": true diff --git a/tests/DeepseekTest.php b/tests/DeepseekTest.php deleted file mode 100644 index a8a7141..0000000 --- a/tests/DeepseekTest.php +++ /dev/null @@ -1,9 +0,0 @@ - $handlerStack]); + } + + protected function createDeepSeekClient($apiKey, $httpClient = null) + { + return new DeepSeekClient($apiKey, $httpClient); + } +} diff --git a/tests/Integration/ApiIntegrationTest.php b/tests/Integration/ApiIntegrationTest.php new file mode 100644 index 0000000..02f980f --- /dev/null +++ b/tests/Integration/ApiIntegrationTest.php @@ -0,0 +1,21 @@ +client = new DeepSeekClient(getenv('DEEPSEEK_API_KEY')); +}); + +it('fetches data from the API', function () { + $response = $this->client->get('/some-endpoint'); + expect($response)->toBeArray(); + expect($response)->toHaveKey('data'); +}); diff --git a/tests/Pest.php b/tests/Pest.php new file mode 100644 index 0000000..a04204d --- /dev/null +++ b/tests/Pest.php @@ -0,0 +1,5 @@ +in('Unit', 'Integration'); diff --git a/tests/Unit/DeepSeekClientTest.php b/tests/Unit/DeepSeekClientTest.php new file mode 100644 index 0000000..8f2476c --- /dev/null +++ b/tests/Unit/DeepSeekClientTest.php @@ -0,0 +1,24 @@ +mockHandler = new MockHandler(); + $this->httpClient = new HttpClient(['handler' => HandlerStack::create($this->mockHandler)]); + $this->client = new DeepSeekClient('test-api-key', $this->httpClient); +}); + +it('can set API key', function () { + expect($this->client->getApiKey())->toBe('test-api-key'); +}); + +it('makes a GET request successfully', function () { + $this->mockHandler->append(new \GuzzleHttp\Psr7\Response(200, [], '{"data": "success"}')); + + $response = $this->client->get('/endpoint'); + expect($response)->toBeArray(); + expect($response['data'])->toBe('success'); +}); From a83d60607e2057d37cde01d6c2e458950dec57ea Mon Sep 17 00:00:00 2001 From: moassaad Date: Sat, 1 Feb 2025 20:11:52 +0200 Subject: [PATCH 35/78] update: add set result function. --- src/DeepseekClient.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/DeepseekClient.php b/src/DeepseekClient.php index bd5e1f5..cb31090 100644 --- a/src/DeepseekClient.php +++ b/src/DeepseekClient.php @@ -76,7 +76,7 @@ public function run(): string ]; // Clear queries after sending $this->queries = []; - $this->result = (new Resource($this->httpClient))->sendRequest($requestData); + $this->setResult((new Resource($this->httpClient))->sendRequest($requestData)); return $this->getResult()->getContent(); } @@ -150,6 +150,17 @@ protected function buildQuery(string $content, ?string $role = null): array ]; } + /** + * set result model + * @param \DeepseekPhp\Contracts\Models\ResultContract $result + * @return self The current instance for method chaining. + */ + public function setResult(ResultContract $result) + { + $this->result = $result; + return $this; + } + /** * response result model * @return \DeepseekPhp\Contracts\Models\ResultContract From 914a0e093e135ad793d82a661c57adc9a3a8ad24 Mon Sep 17 00:00:00 2001 From: moassaad Date: Sat, 1 Feb 2025 20:12:40 +0200 Subject: [PATCH 36/78] update: fix handel response result. --- src/Traits/Resources/HasChat.php | 3 ++- src/Traits/Resources/HasCoder.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Traits/Resources/HasChat.php b/src/Traits/Resources/HasChat.php index 29ae330..1ba8dd7 100644 --- a/src/Traits/Resources/HasChat.php +++ b/src/Traits/Resources/HasChat.php @@ -19,6 +19,7 @@ public function chat(): string 'stream' => $this->stream, ]; $this->queries = []; - return (new Chat($this->httpClient))->sendRequest($requestData); + $this->setResult((new Chat($this->httpClient))->sendRequest($requestData)); + return $this->getResult()->getContent(); } } diff --git a/src/Traits/Resources/HasCoder.php b/src/Traits/Resources/HasCoder.php index 600b92b..041677e 100644 --- a/src/Traits/Resources/HasCoder.php +++ b/src/Traits/Resources/HasCoder.php @@ -19,6 +19,7 @@ public function code(): string 'stream' => $this->stream, ]; $this->queries = []; - return (new Coder($this->httpClient))->sendRequest($requestData); + $this->setResult((new Coder($this->httpClient))->sendRequest($requestData)); + return $this->getResult()->getContent(); } } From 00745a8d7c69d5018cd4c92e986060dccc77a6f2 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sun, 2 Feb 2025 00:53:15 +0300 Subject: [PATCH 37/78] fix xml file --- README.md | 3 +++ composer.json | 4 ++-- tests/Feature/ExampleTest.php | 5 +++++ tests/TestCase.php | 10 ++++++++++ tests/Unit/DeepSeekClientTest.php | 23 +++-------------------- tests/Unit/ExampleTest.php | 5 +++++ 6 files changed, 28 insertions(+), 22 deletions(-) create mode 100644 tests/Feature/ExampleTest.php create mode 100644 tests/TestCase.php create mode 100644 tests/Unit/ExampleTest.php diff --git a/README.md b/README.md index a1bdab9..b2201ec 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,9 @@ Detailed release notes available in [CHANGELOG.md](CHANGELOG.md) ```bash composer test + +./vendor/bin/pest + ``` Test coverage coming in v2.1. diff --git a/composer.json b/composer.json index 864db28..fd9edea 100644 --- a/composer.json +++ b/composer.json @@ -61,7 +61,7 @@ "laravel/pint": "^1.18.1", "mockery/mockery": "^1.6.12", "nunomaduro/collision": "^7.11.0|^8.5.0", - "pestphp/pest": "^3.7", + "pestphp/pest": "^2.36", "pestphp/pest-plugin-arch": "^2.7|^3.0", "pestphp/pest-plugin-type-coverage": "^2.8.7|^3.1.0", "phpstan/phpstan": "^1.12.7", @@ -75,7 +75,7 @@ }, "autoload-dev": { "psr-4": { - "DeepSeek\\Tests\\": "tests/" + "Tests\\": "tests/" } }, "minimum-stability": "dev", diff --git a/tests/Feature/ExampleTest.php b/tests/Feature/ExampleTest.php new file mode 100644 index 0000000..61cd84c --- /dev/null +++ b/tests/Feature/ExampleTest.php @@ -0,0 +1,5 @@ +toBeTrue(); +}); diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..cfb05b6 --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,10 @@ +mockHandler = new MockHandler(); - $this->httpClient = new HttpClient(['handler' => HandlerStack::create($this->mockHandler)]); - $this->client = new DeepSeekClient('test-api-key', $this->httpClient); -}); - -it('can set API key', function () { - expect($this->client->getApiKey())->toBe('test-api-key'); -}); - -it('makes a GET request successfully', function () { - $this->mockHandler->append(new \GuzzleHttp\Psr7\Response(200, [], '{"data": "success"}')); - - $response = $this->client->get('/endpoint'); - expect($response)->toBeArray(); - expect($response['data'])->toBe('success'); + expect($result)->toBe(3); }); diff --git a/tests/Unit/ExampleTest.php b/tests/Unit/ExampleTest.php new file mode 100644 index 0000000..61cd84c --- /dev/null +++ b/tests/Unit/ExampleTest.php @@ -0,0 +1,5 @@ +toBeTrue(); +}); From 879ef902a31e21a5830c0481ce579f4eeceae812 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sun, 2 Feb 2025 00:56:16 +0300 Subject: [PATCH 38/78] fix xml file --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index b2201ec..b63d2e0 100644 --- a/README.md +++ b/README.md @@ -117,9 +117,8 @@ Detailed release notes available in [CHANGELOG.md](CHANGELOG.md) ```bash composer test - +OR ./vendor/bin/pest - ``` Test coverage coming in v2.1. From 1358ad607257276549ad64e6eb17d78e0ef55015 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sun, 2 Feb 2025 01:03:26 +0300 Subject: [PATCH 39/78] update --- tests/Helpers/TestCase.php | 23 ----------------------- tests/Integration/ApiIntegrationTest.php | 21 --------------------- tests/Unit/DeepSeekClientTest.php | 7 ------- tests/Unit/ExampleTest.php | 5 ----- 4 files changed, 56 deletions(-) delete mode 100644 tests/Helpers/TestCase.php delete mode 100644 tests/Integration/ApiIntegrationTest.php delete mode 100644 tests/Unit/DeepSeekClientTest.php delete mode 100644 tests/Unit/ExampleTest.php diff --git a/tests/Helpers/TestCase.php b/tests/Helpers/TestCase.php deleted file mode 100644 index 785915f..0000000 --- a/tests/Helpers/TestCase.php +++ /dev/null @@ -1,23 +0,0 @@ - $handlerStack]); - } - - protected function createDeepSeekClient($apiKey, $httpClient = null) - { - return new DeepSeekClient($apiKey, $httpClient); - } -} diff --git a/tests/Integration/ApiIntegrationTest.php b/tests/Integration/ApiIntegrationTest.php deleted file mode 100644 index 02f980f..0000000 --- a/tests/Integration/ApiIntegrationTest.php +++ /dev/null @@ -1,21 +0,0 @@ -client = new DeepSeekClient(getenv('DEEPSEEK_API_KEY')); -}); - -it('fetches data from the API', function () { - $response = $this->client->get('/some-endpoint'); - expect($response)->toBeArray(); - expect($response)->toHaveKey('data'); -}); diff --git a/tests/Unit/DeepSeekClientTest.php b/tests/Unit/DeepSeekClientTest.php deleted file mode 100644 index 11bae6e..0000000 --- a/tests/Unit/DeepSeekClientTest.php +++ /dev/null @@ -1,7 +0,0 @@ -toBe(3); -}); diff --git a/tests/Unit/ExampleTest.php b/tests/Unit/ExampleTest.php deleted file mode 100644 index 61cd84c..0000000 --- a/tests/Unit/ExampleTest.php +++ /dev/null @@ -1,5 +0,0 @@ -toBeTrue(); -}); From 6e9e5f98f3196bab6626845a139990dfa223533e Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sun, 2 Feb 2025 01:34:47 +0300 Subject: [PATCH 40/78] clean up --- tests/{ => Feature}/HandelResultDeepseekTest.php | 6 +++--- tests/Pest.php | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) rename tests/{ => Feature}/HandelResultDeepseekTest.php (97%) diff --git a/tests/HandelResultDeepseekTest.php b/tests/Feature/HandelResultDeepseekTest.php similarity index 97% rename from tests/HandelResultDeepseekTest.php rename to tests/Feature/HandelResultDeepseekTest.php index 18a9007..9b2ab44 100644 --- a/tests/HandelResultDeepseekTest.php +++ b/tests/Feature/HandelResultDeepseekTest.php @@ -1,10 +1,10 @@ setTemperature(1.5); $response = $deepseek->run(); $result = $deepseek->getResult(); - + $this->assertNotEmpty($response); $this->assertEquals(HTTPState::UNAUTHORIZED->value, $result->getStatusCode()); } diff --git a/tests/Pest.php b/tests/Pest.php index a04204d..7ea77fb 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,5 +1,3 @@ in('Unit', 'Integration'); + // From b748ed4fa376e2852ce66c8b8e87d751f99c24fe Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Fri, 7 Feb 2025 02:53:25 +0300 Subject: [PATCH 41/78] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b63d2e0..05f3298 100644 --- a/README.md +++ b/README.md @@ -175,9 +175,9 @@ A huge thank you to these amazing people who have contributed to this project! - Hisham Abdullah + Hisham Bin Ateya
- Hisham Abdullah + Hisham Bin Ateya

⭐ Contributor From 1029a471de74a9422aae8b62138e48bafe6b3ebd Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sat, 8 Feb 2025 04:35:04 +0300 Subject: [PATCH 42/78] feat / list available models --- README.md | 13 +++++++++++++ src/DeepSeekClient.php | 21 ++++++++++++++++++++- src/Enums/Requests/EndpointSuffixes.php | 1 + src/Resources/Resource.php | 17 ++++++++++------- 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 05f3298..3cf2f27 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ - [🚀 Quick Start](#-quick-start) - [Basic Usage](#basic-usage) - [Advanced Configuration](#advanced-configuration) + - [Get Models List](#get-models-list) - [Framework Integration](#-framework-integration) - [🆕 Migration Guide](#-migration-guide) - [📝 Changelog](#-changelog) @@ -93,6 +94,18 @@ $response = DeepSeekClient::build('your-api-key') echo 'API Response:'.$response; ``` +### Get Models List + +```php +use DeepSeek\DeepSeekClient; + +$response = DeepSeekClient::build('your-api-key') + ->getModelsList() + ->run(); + +echo $response; // {"object":"list","data":[{"id":"deepseek-chat","object":"model","owned_by":"deepseek"},{"id":"deepseek-reasoner","object":"model","owned_by":"deepseek"}]} +``` + ### 🛠 Framework Integration ### [Laravel Deepseek Package](https://github.com/deepseek-php/deepseek-laravel) diff --git a/src/DeepSeekClient.php b/src/DeepSeekClient.php index 882a8ec..3b3dad2 100644 --- a/src/DeepSeekClient.php +++ b/src/DeepSeekClient.php @@ -4,6 +4,7 @@ use DeepSeek\Contracts\DeepseekClientContract; use DeepSeek\Contracts\Models\ResultContract; +use DeepSeek\Enums\Requests\EndpointSuffixes; use DeepSeek\Resources\Resource; use Psr\Http\Client\ClientInterface; use DeepSeek\Factories\ApiFactory; @@ -53,6 +54,10 @@ class DeepSeekClient implements DeepseekClientContract */ protected ResultContract $result; + protected string $requestMethod; + + protected ?string $endpointSuffixes; + /** * Initialize the DeepSeekClient with a PSR-compliant HTTP client. * @@ -63,6 +68,8 @@ public function __construct(ClientInterface $httpClient) $this->httpClient = $httpClient; $this->model = null; $this->stream = false; + $this->requestMethod = 'POST'; + $this->endpointSuffixes = EndpointSuffixes::CHAT->value; $this->temperature = (float) TemperatureValues::GENERAL_CONVERSATION->value; } @@ -76,7 +83,7 @@ public function run(): string ]; // Clear queries after sending $this->queries = []; - $this->setResult((new Resource($this->httpClient))->sendRequest($requestData)); + $this->setResult((new Resource($this->httpClient, $this->endpointSuffixes))->sendRequest($requestData, $this->requestMethod)); return $this->getResult()->getContent(); } @@ -112,6 +119,18 @@ public function query(string $content, ?string $role = null): self return $this; } + /** + * get list of available models .. + * + * @return self The current instance for method chaining. + */ + public function getModelsList(): self + { + $this->endpointSuffixes = EndpointSuffixes::MODELS_LIST->value; + $this->requestMethod = 'GET'; + return $this; + } + /** * Set the model to be used for API requests. * diff --git a/src/Enums/Requests/EndpointSuffixes.php b/src/Enums/Requests/EndpointSuffixes.php index 43dc3dd..f903d43 100644 --- a/src/Enums/Requests/EndpointSuffixes.php +++ b/src/Enums/Requests/EndpointSuffixes.php @@ -5,4 +5,5 @@ enum EndpointSuffixes: string { case CHAT = '/chat/completions'; + case MODELS_LIST = '/models'; } diff --git a/src/Resources/Resource.php b/src/Resources/Resource.php index a3075cf..ea2740a 100644 --- a/src/Resources/Resource.php +++ b/src/Resources/Resource.php @@ -30,14 +30,17 @@ class Resource implements ResourceContract */ protected ClientInterface $client; + protected ?string $endpointSuffixes; + /** * Initialize the Resource with a Guzzle HTTP client. * * @param ClientInterface $client The HTTP client instance for making requests. */ - public function __construct(ClientInterface $client) + public function __construct(ClientInterface $client, ?string $endpointSuffixes = null) { $this->client = $client; + $this->endpointSuffixes = $endpointSuffixes ?: EndpointSuffixes::CHAT->value; } /** @@ -47,13 +50,13 @@ public function __construct(ClientInterface $client) * and custom headers, and returns the response as a result contract. * * @param array $requestData The data to send in the request. + * @param string|null $requestMethod method of request Get or POST. * @return ResultContract The response result. - * */ - public function sendRequest(array $requestData): ResultContract + public function sendRequest(array $requestData, ?string $requestMethod = 'POST'): ResultContract { try { - $response = $this->client->post($this->getEndpointSuffix(), [ + $response = $this->client->{$requestMethod}($this->getEndpointSuffix(), [ 'json' => $this->resolveHeaders($requestData), ]); @@ -62,9 +65,9 @@ public function sendRequest(array $requestData): ResultContract $response = $badResponse->getResponse(); return (new BadResult())->setResponse($response); - + } catch (GuzzleException $error) { - + return new FailureResult($error->getCode(), $error->getMessage()); } catch (\Exception $error) { @@ -119,7 +122,7 @@ public function prepareCustomHeaderParams(array $query): array */ public function getEndpointSuffix(): string { - return EndpointSuffixes::CHAT->value; + return $this->endpointSuffixes; } /** From 3c145cdcc684681ac189c5c741e7a3182d84978b Mon Sep 17 00:00:00 2001 From: Omar Alalwi Date: Sat, 8 Feb 2025 08:06:53 +0300 Subject: [PATCH 43/78] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3cf2f27..c5823ba 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ use DeepSeek\Enums\Models; $response = DeepSeekClient::build('your-api-key') ->withBaseUrl('https://api.deepseek.com/v2') - ->withModel(Models::CODER) + ->withModel(Models::CODER->value) ->withTemperature(1.2) ->run(); From 321cfefe2978cc96439f3656deb2cabe02b62467 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 8 Feb 2025 09:14:37 +0300 Subject: [PATCH 44/78] Replace PHP unit test with PEST test --- tests/Feature/DeepSeekClient.php | 52 +++++++++++++++++++++ tests/Feature/HandelResultDeepseekTest.php | 54 ---------------------- 2 files changed, 52 insertions(+), 54 deletions(-) create mode 100644 tests/Feature/DeepSeekClient.php delete mode 100644 tests/Feature/HandelResultDeepseekTest.php diff --git a/tests/Feature/DeepSeekClient.php b/tests/Feature/DeepSeekClient.php new file mode 100644 index 0000000..a0866e0 --- /dev/null +++ b/tests/Feature/DeepSeekClient.php @@ -0,0 +1,52 @@ +query('Hello DeepSeek, how are you today?') + ->setTemperature(1.5); + + // Act + $response = $client->run(); + $result = $client->getResult(); + + // Assert + expect($response)->not->toBeEmpty($response) + ->and($result->getStatusCode())->toEqual(HTTPState::OK->value); +}); + +test('Run query with valid API Key & insufficient balance should return 402', function () { + // Arrange + $apiKey = "insufficient-balance-api-key"; + $client = DeepSeekClient::build($apiKey) + ->query('Hello DeepSeek, how are you today?') + ->setTemperature(1.5); + + // Act + $response = $client->run(); + $result = $client->getResult(); + + // Assert + expect($response)->not->toBeEmpty($response) + ->and($result->getStatusCode())->toEqual(HTTPState::PAYMENT_REQUIRED->value); +}); + +test('Run query with invalid API key should return 401', function () { + // Arrange + $apiKey = "insufficient-balance-api-key"; + $client = DeepSeekClient::build($apiKey) + ->query('Hello DeepSeek, how are you today?') + ->setTemperature(1.5); + + // Act + $response = $client->run(); + $result = $client->getResult(); + + // Assert + expect($response)->not->toBeEmpty($response) + ->and($result->getStatusCode())->toEqual(HTTPState::UNAUTHORIZED->value); +}); diff --git a/tests/Feature/HandelResultDeepseekTest.php b/tests/Feature/HandelResultDeepseekTest.php deleted file mode 100644 index 9b2ab44..0000000 --- a/tests/Feature/HandelResultDeepseekTest.php +++ /dev/null @@ -1,54 +0,0 @@ -apiKey = "valid-api-key"; - $this->expiredApiKey = "expired-api-key"; - } - public function test_ok_response() - { - $deepseek = DeepSeekClient::build($this->apiKey) - ->query('Hello Deepseek, how are you today?') - ->setTemperature(1.5); - $response = $deepseek->run(); - $result = $deepseek->getResult(); - - $this->assertNotEmpty($response); - $this->assertEquals(HTTPState::OK->value, $result->getStatusCode()); - } - public function test_can_not_access_with_api_expired_payment() - { - $deepseek = DeepSeekClient::build($this->expiredApiKey) - ->query('Hello Deepseek, how are you today?') - ->setTemperature(1.5); - $response = $deepseek->run(); - $result = $deepseek->getResult(); - - $this->assertNotEmpty($response); - if(!$result->isSuccess()) - { - $this->assertEquals(HTTPState::PAYMENT_REQUIRED->value, $result->getStatusCode()); - } - } - public function test_access_with_wrong_api_key() - { - $deepseek = DeepSeekClient::build($this->apiKey."wrong-api-key") - ->query('Hello Deepseek, how are you today?') - ->setTemperature(1.5); - $response = $deepseek->run(); - $result = $deepseek->getResult(); - - $this->assertNotEmpty($response); - $this->assertEquals(HTTPState::UNAUTHORIZED->value, $result->getStatusCode()); - } -} From 10eb95e791804215702b641d6aa13ca4060b49ed Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sun, 9 Feb 2025 03:28:00 +0300 Subject: [PATCH 45/78] enhance client contract --- ...{DeepseekClientContract.php => ClientContract.php} | 6 ++++-- src/DeepSeekClient.php | 11 +++++------ 2 files changed, 9 insertions(+), 8 deletions(-) rename src/Contracts/{DeepseekClientContract.php => ClientContract.php} (52%) diff --git a/src/Contracts/DeepseekClientContract.php b/src/Contracts/ClientContract.php similarity index 52% rename from src/Contracts/DeepseekClientContract.php rename to src/Contracts/ClientContract.php index 7ea06b9..12172e3 100644 --- a/src/Contracts/DeepseekClientContract.php +++ b/src/Contracts/ClientContract.php @@ -2,11 +2,13 @@ namespace DeepSeek\Contracts; -interface DeepseekClientContract +interface ClientContract { - public static function build(string $apiKey): self; public function run(): string; + public static function build(string $apiKey, ?string $baseUrl = null, ?int $timeout = null): self; public function query(string $content, ?string $role = "user"): self; + public function getModelsList(): self; public function withModel(?string $model = null): self; public function withStream(bool $stream = true): self; + public function buildQuery(string $content, ?string $role = null): array; } diff --git a/src/DeepSeekClient.php b/src/DeepSeekClient.php index 3b3dad2..f78d8e5 100644 --- a/src/DeepSeekClient.php +++ b/src/DeepSeekClient.php @@ -2,7 +2,7 @@ namespace DeepSeek; -use DeepSeek\Contracts\DeepseekClientContract; +use DeepSeek\Contracts\ClientContract; use DeepSeek\Contracts\Models\ResultContract; use DeepSeek\Enums\Requests\EndpointSuffixes; use DeepSeek\Resources\Resource; @@ -10,11 +10,10 @@ use DeepSeek\Factories\ApiFactory; use DeepSeek\Enums\Queries\QueryRoles; use DeepSeek\Enums\Requests\QueryFlags; -use DeepSeek\Enums\Requests\HeaderFlags; use DeepSeek\Enums\Configs\TemperatureValues; use DeepSeek\Traits\Resources\{HasChat, HasCoder}; -class DeepSeekClient implements DeepseekClientContract +class DeepSeekClient implements ClientContract { use HasChat, HasCoder; @@ -113,14 +112,14 @@ public static function build(string $apiKey, ?string $baseUrl = null, ?int $time * @param string|null $role * @return self The current instance for method chaining. */ - public function query(string $content, ?string $role = null): self + public function query(string $content, ?string $role = "user"): self { $this->queries[] = $this->buildQuery($content, $role); return $this; } /** - * get list of available models .. + * get list of available models . * * @return self The current instance for method chaining. */ @@ -161,7 +160,7 @@ public function setTemperature(float $temperature): self return $this; } - protected function buildQuery(string $content, ?string $role = null): array + public function buildQuery(string $content, ?string $role = null): array { return [ 'role' => $role ?: QueryRoles::USER->value, From c3651b906a36b0dab26e644a4ab69a2eb4347623 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sun, 9 Feb 2025 03:34:11 +0300 Subject: [PATCH 46/78] update version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index fd9edea..69b83d7 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "role": "creator" } ], - "version": "2.0.0", + "version": "2.0.1", "require": { "php": "^8.1.0", "php-http/discovery": "^1.20.0", From 70d3bce2a9f9947a96a5f4a74cbd79c73968eb9a Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sun, 9 Feb 2025 03:50:33 +0300 Subject: [PATCH 47/78] initilize tests --- ...pSeekClient.php => DeepSeekClientTest.php} | 0 tests/Pest.php | 44 ++++++++++++++++++- tests/Unit/ExampleTest.php | 5 +++ 3 files changed, 48 insertions(+), 1 deletion(-) rename tests/Feature/{DeepSeekClient.php => DeepSeekClientTest.php} (100%) create mode 100644 tests/Unit/ExampleTest.php diff --git a/tests/Feature/DeepSeekClient.php b/tests/Feature/DeepSeekClientTest.php similarity index 100% rename from tests/Feature/DeepSeekClient.php rename to tests/Feature/DeepSeekClientTest.php diff --git a/tests/Pest.php b/tests/Pest.php index 7ea77fb..5949c61 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,3 +1,45 @@ in('Feature'); + +/* +|-------------------------------------------------------------------------- +| Expectations +|-------------------------------------------------------------------------- +| +| When you're writing tests, you often need to check that values meet certain conditions. The +| "expect()" function gives you access to a set of "expectations" methods that you can use +| to assert different things. Of course, you may extend the Expectation API at any time. +| +*/ + +expect()->extend('toBeOne', function () { + return $this->toBe(1); +}); + +/* +|-------------------------------------------------------------------------- +| Functions +|-------------------------------------------------------------------------- +| +| While Pest is very powerful out-of-the-box, you may have some testing code specific to your +| project that you don't want to repeat in every file. Here you can also expose helpers as +| global functions to help you to reduce the number of lines of code in your test files. +| +*/ + +function something() +{ + // .. +} diff --git a/tests/Unit/ExampleTest.php b/tests/Unit/ExampleTest.php new file mode 100644 index 0000000..61cd84c --- /dev/null +++ b/tests/Unit/ExampleTest.php @@ -0,0 +1,5 @@ +toBeTrue(); +}); From 37057a82314e23a9d5891aca5359df35f5ba6ace Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sun, 9 Feb 2025 03:52:03 +0300 Subject: [PATCH 48/78] update doc --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index c5823ba..55603d8 100644 --- a/README.md +++ b/README.md @@ -129,8 +129,6 @@ Detailed release notes available in [CHANGELOG.md](CHANGELOG.md) ## 🧪 Testing ```bash -composer test -OR ./vendor/bin/pest ``` From 6913fbea50f55059563abc08ead2b4a938d38cfb Mon Sep 17 00:00:00 2001 From: Vinchan Date: Tue, 18 Feb 2025 11:20:09 +0800 Subject: [PATCH 49/78] feat(*):Add Chinese README --- README-CN.md | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 README-CN.md diff --git a/README-CN.md b/README-CN.md new file mode 100644 index 0000000..26dd190 --- /dev/null +++ b/README-CN.md @@ -0,0 +1,205 @@ +

+

DeepSeek PHP Client

+

🚀 社区驱动的 PHP SDK,用于 DeepSeek AI 接口集成

+ +

+ + Latest Version + + + PHP Version + + + License + + + Tests Status + +

+

+ +## 目录 +- [✨ 特性](#-特性) +- [📦 安装](#-安装) +- [🚀 快速入门](#-快速入门) + - [基本用法](#基本用法) + - [高级配置](#高级配置) + - [获取模型列表](#获取模型列表) + - [框架集成](#-框架集成) +- [🆕 迁移指南](#-迁移指南) +- [📝 更新日志](#-更新日志) +- [🧪 测试](#-测试) +- [🔒 安全](#-安全) +- [🤝 贡献者](#-贡献者) +- [📄 许可](#-许可) + +--- + +## ✨ 特性 + +- **无缝 API 集成**: DeepSeek AI 功能的 PHP 优先接口 +- **构建器模式**: 直观的链接请求构建方法 +- **企业级别**: 符合 PSR-18 规范 +- **模型灵活性**: 支持多种 DeepSeek 模型(Coder、Chat 等) +- **流式传输**: 内置对实时响应处理的支持 +- **框架友好**: 提供 Laravel 和 Symfony 包 + +--- + +## 📦 安装 + +通过 Composer 安装: + +```bash +composer require deepseek-php/deepseek-php-client +``` + +**要求**: +- PHP 8.1+ + +--- + +## 🚀 快速入门 + +### 基本用法 + +只需两行代码即可开始: + +```php +use DeepSeek\DeepSeekClient; + +$response = DeepSeekClient::build('your-api-key') + ->query('Explain quantum computing in simple terms') + ->run(); + +echo $response; +``` + +📌 默认配置: +- Model: `deepseek-chat` +- Temperature: 0.8 + +### 高级配置 + +```php +use DeepSeek\DeepSeekClient; +use DeepSeek\Enums\Models; + +$response = DeepSeekClient::build('your-api-key') + ->withBaseUrl('https://api.deepseek.com/v2') + ->withModel(Models::CODER->value) + ->withTemperature(1.2) + ->run(); + +echo 'API Response:'.$response; +``` + +### 获取模型列表 + +```php +use DeepSeek\DeepSeekClient; + +$response = DeepSeekClient::build('your-api-key') + ->getModelsList() + ->run(); + +echo $response; // {"object":"list","data":[{"id":"deepseek-chat","object":"model","owned_by":"deepseek"},{"id":"deepseek-reasoner","object":"model","owned_by":"deepseek"}]} +``` + +### 🛠 框架集成 + +### [Laravel Deepseek Package](https://github.com/deepseek-php/deepseek-laravel) + +### [Symfony Deepseek Package](https://github.com/deepseek-php/deepseek-symfony) + +--- + +## 🚧 迁移指南 + +从 v1.x 升级?请查看我们全面的 [迁移指南](MIGRATION.md) 了解重大变更和升级说明。 + +--- + +## 📝 更新日志 + +详细的发布说明可在 [CHANGELOG.md](CHANGELOG.md) 查看。 + +--- + +## 🧪 测试 + +```bash +./vendor/bin/pest +``` + +测试覆盖范围涵盖 v2.1。 + +--- + +## 🔒 安全 + +**报告漏洞**: [omaralwi2010@gmail.com](mailto:omaralwi2010@gmail.com) + +--- + +## 🤝 贡献者 + +非常感谢为这个项目做出贡献的人! 🎉💖 + + + + + + + + + +
+ + Omar AlAlwi +
+ Omar AlAlwi +
+
+ 🏆 Creator +
+ + Ayman Alhattami +
+ Ayman Alhattami +
+
+ ⭐ Contributor +
+ + Mohammad Asaad +
+ Mohammad Asaad +
+
+ ⭐ Contributor +
+ + Opada Alzaiede +
+ Opada Alzaiede +
+
+ ⭐ Contributor +
+ + Hisham Bin Ateya +
+ Hisham Bin Ateya +
+
+ ⭐ Contributor +
+ +**想要贡献?** 查看 [contributing guidelines](./CONTRIBUTING.md) 并提交拉取请求! 🚀 + +--- + +## 📄 许可 + +基于 [MIT License](LICENSE.md) 开源协议。 From 52a652b78090d43879b73eb4df28d512a67683c4 Mon Sep 17 00:00:00 2001 From: Omar Alalwi Date: Wed, 19 Feb 2025 19:46:38 +0300 Subject: [PATCH 50/78] Update README.md --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index 55603d8..d45142e 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,25 @@ Detailed release notes available in [CHANGELOG.md](CHANGELOG.md) Test coverage coming in v2.1. +--- +
+ +# 🐘✨ **DeepSeek PHP Community** ✨🐘 + +Click the button bellow or [join here](https://t.me/deepseek_php_community) to be part of our growing community! + +[![Join Telegram](https://img.shields.io/badge/Join-Telegram-blue?style=for-the-badge&logo=telegram)](https://t.me/deepseek_php_community) + +
+ +### **Channel Structure** 🏗️ +- 🗨️ **General** - Daily chatter +- 💡 **Ideas & Suggestions** - Shape the community's future +- 📢 **Announcements & News** - Official updates & news +- 🚀 **Releases & Updates** - Version tracking & migration support +- 🐞 **Issues & Bug Reports** - Collective problem-solving +- 🤝 **Pull Requests** - Code collaboration & reviews + --- ## 🔒 Security From dea86c50b3c4bc805588e39499e1014b73cee2b3 Mon Sep 17 00:00:00 2001 From: Omar Alalwi Date: Wed, 19 Feb 2025 19:47:36 +0300 Subject: [PATCH 51/78] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d45142e..c340dc0 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ Detailed release notes available in [CHANGELOG.md](CHANGELOG.md) Test coverage coming in v2.1. --- -
+
# 🐘✨ **DeepSeek PHP Community** ✨🐘 @@ -143,7 +143,6 @@ Click the button bellow or [join here](https://t.me/deepseek_php_community) to b [![Join Telegram](https://img.shields.io/badge/Join-Telegram-blue?style=for-the-badge&logo=telegram)](https://t.me/deepseek_php_community) -
### **Channel Structure** 🏗️ - 🗨️ **General** - Daily chatter @@ -153,6 +152,8 @@ Click the button bellow or [join here](https://t.me/deepseek_php_community) to b - 🐞 **Issues & Bug Reports** - Collective problem-solving - 🤝 **Pull Requests** - Code collaboration & reviews +
+ --- ## 🔒 Security From 1599c4d840975a7666ff03419ec7fe34c3e85eac Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sat, 22 Feb 2025 05:53:07 +0300 Subject: [PATCH 52/78] support many http clients --- README.md | 27 +++++--- composer.json | 10 ++- src/DeepSeekClient.php | 7 +- src/Enums/Requests/ClientTypes.php | 10 +++ src/Factories/ApiFactory.php | 104 ++++++++++++----------------- src/Resources/Resource.php | 65 +++++++++--------- 6 files changed, 116 insertions(+), 107 deletions(-) create mode 100644 src/Enums/Requests/ClientTypes.php diff --git a/README.md b/README.md index c340dc0..79775c3 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ - [🚀 Quick Start](#-quick-start) - [Basic Usage](#basic-usage) - [Advanced Configuration](#advanced-configuration) + - [Use with Symfony HttpClient](#use-with-symfony-httpclient) - [Get Models List](#get-models-list) - [Framework Integration](#-framework-integration) - [🆕 Migration Guide](#-migration-guide) @@ -37,12 +38,13 @@ ## ✨ Features -- **Seamless API Integration**: PHP-first interface for DeepSeek's AI capabilities -- **Fluent Builder Pattern**: Chainable methods for intuitive request building -- **Enterprise Ready**: PSR-18 compliant HTTP client integration -- **Model Flexibility**: Support for multiple DeepSeek models (Coder, Chat, etc.) -- **Streaming Ready**: Built-in support for real-time response handling -- **Framework Friendly**: Laravel & Symfony packages available +- **Seamless API Integration**: PHP-first interface for DeepSeek's AI capabilities. +- **Fluent Builder Pattern**: Chainable methods for intuitive request building. +- **Enterprise Ready**: PSR-18 compliant HTTP client integration. +- **Model Flexibility**: Support for multiple DeepSeek models (Coder, Chat, etc.). +- **Streaming Ready**: Built-in support for real-time response handling. +- **Many Http Clients**: easy to use `Guzzle http client` (default) , or `symfony http client`. +- **Framework Friendly**: Laravel & Symfony packages available. --- @@ -94,6 +96,17 @@ $response = DeepSeekClient::build('your-api-key') echo 'API Response:'.$response; ``` +### Use with Symfony HttpClient +the package already built with `symfony Http client`, if you need to use package with `symfony` Http Client , it is easy to achieve that, just pass `clientType:'symfony'` with `build` function. + +ex with symfony: + +```php +$response = DeepSeekClient::build('your-api-key', clientType:'symfony') + ->query('Explain quantum computing in simple terms') + ->run(); +``` + ### Get Models List ```php @@ -110,8 +123,6 @@ echo $response; // {"object":"list","data":[{"id":"deepseek-chat","object":"mode ### [Laravel Deepseek Package](https://github.com/deepseek-php/deepseek-laravel) -### [Symfony Deepseek Package](https://github.com/deepseek-php/deepseek-symfony) - --- ## 🚧 Migration Guide diff --git a/composer.json b/composer.json index 69b83d7..83f33d9 100644 --- a/composer.json +++ b/composer.json @@ -7,11 +7,15 @@ "sdk", "api", "php", + "symfony", "client", "llm", "nlp", "openai", - "qwen", + "symfony-deepseek", + "deepseek-symfony", + "symfony-http-client", + "symfony-client", "machine-learning", "php-sdk", "ai-sdk", @@ -48,12 +52,14 @@ "version": "2.0.1", "require": { "php": "^8.1.0", + "nyholm/psr7": "^1.8", "php-http/discovery": "^1.20.0", "php-http/multipart-stream-builder": "^1.4.2", "psr/http-client": "^1.0.3", "psr/http-client-implementation": "^1.0.1", "psr/http-factory-implementation": "*", - "psr/http-message": "^1.1.0|^2.0.0" + "psr/http-message": "^1.1.0|^2.0.0", + "symfony/http-client": "^7.2" }, "require-dev": { "guzzlehttp/guzzle": "^7.9.2", diff --git a/src/DeepSeekClient.php b/src/DeepSeekClient.php index f78d8e5..a8d7f01 100644 --- a/src/DeepSeekClient.php +++ b/src/DeepSeekClient.php @@ -4,6 +4,7 @@ use DeepSeek\Contracts\ClientContract; use DeepSeek\Contracts\Models\ResultContract; +use DeepSeek\Enums\Requests\ClientTypes; use DeepSeek\Enums\Requests\EndpointSuffixes; use DeepSeek\Resources\Resource; use Psr\Http\Client\ClientInterface; @@ -94,13 +95,15 @@ public function run(): string * @param int|null $timeout The timeout duration for requests in seconds (optional). * @return self A new instance of the DeepSeekClient. */ - public static function build(string $apiKey, ?string $baseUrl = null, ?int $timeout = null): self + public static function build(string $apiKey, ?string $baseUrl = null, ?int $timeout = null, ?string $clientType = null): self { + $clientType = $clientType ?? ClientTypes::GUZZLE->value; + $httpClient = ApiFactory::build() ->setBaseUri($baseUrl) ->setTimeout($timeout) ->setKey($apiKey) - ->run(); + ->run($clientType); return new self($httpClient); } diff --git a/src/Enums/Requests/ClientTypes.php b/src/Enums/Requests/ClientTypes.php new file mode 100644 index 0000000..fbc01d9 --- /dev/null +++ b/src/Enums/Requests/ClientTypes.php @@ -0,0 +1,10 @@ +baseUrl = $baseUrl ? trim($baseUrl) : DefaultConfigs::BASE_URL->value; return $this; } - /** - * Set the API key for authentication. - * - * @param string $apiKey The API key to set. - * @return self The instance of the self for method chaining. - */ public function setKey(string $apiKey): self { $this->apiKey = trim($apiKey); return $this; } - /** - * Set the timeout for the API request. - * - * If no timeout is provided, the default timeout value from the configuration is used. - * - * @param int|null $timeout The timeout value in seconds (optional). - * @return self The instance of the self for method chaining. - */ public function setTimeout(?int $timeout = null): self { $this->timeout = $timeout ?: (int)DefaultConfigs::TIMEOUT->value; return $this; } - /** - * Build and return the Guzzle Client instance. - * - * This method creates and configures a new Guzzle HTTP client instance - * using the provided base URL, timeout, and headers. - * - * @return Client A Guzzle client instance configured for the API. - */ - public function run(): Client + public function initialize(): self { - $clientConfig = [ + if (!isset($this->baseUrl)) { + $this->setBaseUri(); + } + + if (!isset($this->apiKey)) { + throw new RuntimeException('API key must be set using setKey() before initialization.'); + } + + if (!isset($this->timeout)) { + $this->setTimeout(); + } + + $this->clientConfig = [ HeaderFlags::BASE_URL->value => $this->baseUrl, HeaderFlags::TIMEOUT->value => $this->timeout, HeaderFlags::HEADERS->value => [ HeaderFlags::AUTHORIZATION->value => 'Bearer ' . $this->apiKey, - HeaderFlags::CONTENT_TYPE->value => "application/json", + HeaderFlags::CONTENT_TYPE->value => 'application/json', ], ]; - return new Client($clientConfig); + return $this; + } + + public function run(?string $clientType = null): ClientInterface + { + $clientType = $clientType ?? ClientTypes::GUZZLE->value; + + if (!isset($this->clientConfig)) { + $this->initialize(); + } + + switch (strtolower($clientType)) { + case ClientTypes::GUZZLE->value: + return new Client($this->clientConfig); + case ClientTypes::SYMFONY->value: + $symfonyClient = HttpClient::create($this->clientConfig); + return new Psr18Client($symfonyClient); + default: + throw new InvalidArgumentException("Unsupported client type: {$clientType}"); + } } } diff --git a/src/Resources/Resource.php b/src/Resources/Resource.php index ea2740a..65ed2fe 100644 --- a/src/Resources/Resource.php +++ b/src/Resources/Resource.php @@ -18,62 +18,57 @@ use GuzzleHttp\Exception\BadResponseException; use GuzzleHttp\Exception\GuzzleException; use Psr\Http\Client\ClientInterface; +use Psr\Http\Message\RequestFactoryInterface; +use Psr\Http\Message\StreamFactoryInterface; +use Nyholm\Psr7\Factory\Psr17Factory; class Resource implements ResourceContract { use HasQueryParams; - /** - * HTTP client for making requests. - * - * @var ClientInterface - */ protected ClientInterface $client; - protected ?string $endpointSuffixes; - - /** - * Initialize the Resource with a Guzzle HTTP client. - * - * @param ClientInterface $client The HTTP client instance for making requests. - */ - public function __construct(ClientInterface $client, ?string $endpointSuffixes = null) - { + protected RequestFactoryInterface $requestFactory; + protected StreamFactoryInterface $streamFactory; + + public function __construct( + ClientInterface $client, + ?string $endpointSuffixes = null, + ?RequestFactoryInterface $requestFactory = null, + ?StreamFactoryInterface $streamFactory = null + ) { $this->client = $client; $this->endpointSuffixes = $endpointSuffixes ?: EndpointSuffixes::CHAT->value; + $this->requestFactory = $requestFactory ?: new Psr17Factory(); + $this->streamFactory = $streamFactory ?: new Psr17Factory(); } - /** - * Send a request to the API endpoint. - * - * This method sends a POST request to the API endpoint, including the query data - * and custom headers, and returns the response as a result contract. - * - * @param array $requestData The data to send in the request. - * @param string|null $requestMethod method of request Get or POST. - * @return ResultContract The response result. - */ public function sendRequest(array $requestData, ?string $requestMethod = 'POST'): ResultContract { try { - $response = $this->client->{$requestMethod}($this->getEndpointSuffix(), [ - 'json' => $this->resolveHeaders($requestData), - ]); + $request = $this->requestFactory->createRequest( + $requestMethod, + $this->getEndpointSuffix() + ); + + if ($requestMethod === 'POST') { + $request = $request + ->withHeader('Content-Type', 'application/json') + ->withBody( + $this->streamFactory->createStream( + json_encode($this->resolveHeaders($requestData)) + )); + } + + $response = $this->client->sendRequest($request); return (new SuccessResult())->setResponse($response); } catch (BadResponseException $badResponse) { - - $response = $badResponse->getResponse(); - return (new BadResult())->setResponse($response); - + return (new BadResult())->setResponse($badResponse->getResponse()); } catch (GuzzleException $error) { - return new FailureResult($error->getCode(), $error->getMessage()); - } catch (\Exception $error) { - return new FailureResult($error->getCode(), '{"error":"'.$error->getMessage().'"}'); - } } From cd1c6c04cf4174167e71d168d3d3733989a13210 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sat, 22 Feb 2025 05:57:02 +0300 Subject: [PATCH 53/78] clean up --- src/Contracts/Factories/ApiFactoryContract.php | 3 ++- src/Factories/ApiFactory.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Contracts/Factories/ApiFactoryContract.php b/src/Contracts/Factories/ApiFactoryContract.php index 80c9c53..9732d59 100644 --- a/src/Contracts/Factories/ApiFactoryContract.php +++ b/src/Contracts/Factories/ApiFactoryContract.php @@ -4,6 +4,7 @@ use DeepSeek\Factories\ApiFactory; use GuzzleHttp\Client; +use Psr\Http\Client\ClientInterface; interface ApiFactoryContract { @@ -43,5 +44,5 @@ public function setTimeout(?int $timeout = null): ApiFactory; * * @return Client */ - public function run(): Client; + public function run(?string $clientType = null): ClientInterface; } diff --git a/src/Factories/ApiFactory.php b/src/Factories/ApiFactory.php index 3330682..60980ba 100644 --- a/src/Factories/ApiFactory.php +++ b/src/Factories/ApiFactory.php @@ -13,7 +13,7 @@ use RuntimeException; use InvalidArgumentException; -final class ApiFactory +final class ApiFactory implements ApiFactoryContract { protected string $apiKey; protected string $baseUrl; From 7df84a2583dd3965ce68403c2f4596d861f7ab87 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sat, 22 Feb 2025 05:57:27 +0300 Subject: [PATCH 54/78] clean up --- src/Contracts/Factories/ApiFactoryContract.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Contracts/Factories/ApiFactoryContract.php b/src/Contracts/Factories/ApiFactoryContract.php index 9732d59..7799e7e 100644 --- a/src/Contracts/Factories/ApiFactoryContract.php +++ b/src/Contracts/Factories/ApiFactoryContract.php @@ -40,9 +40,9 @@ public function setKey(string $apiKey): ApiFactory; public function setTimeout(?int $timeout = null): ApiFactory; /** - * Build and return the Guzzle Client instance. + * Build and return http Client instance. * - * @return Client + * @return ClientInterface */ public function run(?string $clientType = null): ClientInterface; } From 67a9e559895e8b678ba94b2df89acb94494f9c10 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sat, 22 Feb 2025 06:00:59 +0300 Subject: [PATCH 55/78] clean up --- src/Factories/ApiFactory.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Factories/ApiFactory.php b/src/Factories/ApiFactory.php index 60980ba..0a38466 100644 --- a/src/Factories/ApiFactory.php +++ b/src/Factories/ApiFactory.php @@ -77,14 +77,10 @@ public function run(?string $clientType = null): ClientInterface $this->initialize(); } - switch (strtolower($clientType)) { - case ClientTypes::GUZZLE->value: - return new Client($this->clientConfig); - case ClientTypes::SYMFONY->value: - $symfonyClient = HttpClient::create($this->clientConfig); - return new Psr18Client($symfonyClient); - default: - throw new InvalidArgumentException("Unsupported client type: {$clientType}"); - } + return match (strtolower($clientType)) { + ClientTypes::GUZZLE->value => new Client($this->clientConfig), + ClientTypes::SYMFONY->value => new Psr18Client(HttpClient::create($this->clientConfig)), + default => throw new InvalidArgumentException("Unsupported client type: {$clientType}") + }; } } From 930665ec819def24ef442a3ae0f083fa2f5f16c8 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sat, 22 Feb 2025 06:17:49 +0300 Subject: [PATCH 56/78] update doc --- README.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 79775c3..a2ddb9e 100644 --- a/README.md +++ b/README.md @@ -87,9 +87,11 @@ echo $response; use DeepSeek\DeepSeekClient; use DeepSeek\Enums\Models; -$response = DeepSeekClient::build('your-api-key') - ->withBaseUrl('https://api.deepseek.com/v2') +$client = DeepSeekClient::build(apiKey:'your-api-key', baseUrl:'https://api.deepseek.com/v3', timeout:30, clientType:'guzzle'); + +$response = $client ->withModel(Models::CODER->value) + ->withStream() ->withTemperature(1.2) ->run(); @@ -102,9 +104,13 @@ the package already built with `symfony Http client`, if you need to use packag ex with symfony: ```php -$response = DeepSeekClient::build('your-api-key', clientType:'symfony') - ->query('Explain quantum computing in simple terms') - ->run(); +// with defaults baseUrl and timeout +$client = DeepSeekClient::build('your-api-key', clientType:'symfony') +// with customization +$client = DeepSeekClient::build(apiKey:'your-api-key', baseUrl:'https://api.deepseek.com/v3', timeout:30, 'symfony'); + +$client->query('Explain quantum computing in simple terms') + ->run(); ``` ### Get Models List From 5e7a48231a1567941b23efbeb9da9691803cfe93 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sat, 22 Feb 2025 06:18:55 +0300 Subject: [PATCH 57/78] update version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 83f33d9..4b7b927 100644 --- a/composer.json +++ b/composer.json @@ -49,7 +49,7 @@ "role": "creator" } ], - "version": "2.0.1", + "version": "2.0.2", "require": { "php": "^8.1.0", "nyholm/psr7": "^1.8", From 26653268b462d827705aa9c71cd31d1e7b6b2278 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sat, 22 Feb 2025 06:32:09 +0300 Subject: [PATCH 58/78] Add Arabic documentation --- README-AR.md | 252 +++++++++++++++++++++++++++++++++++++++++++++++++++ README-CN.md | 36 +++++++- README.md | 9 ++ 3 files changed, 292 insertions(+), 5 deletions(-) create mode 100644 README-AR.md diff --git a/README-AR.md b/README-AR.md new file mode 100644 index 0000000..c8918c7 --- /dev/null +++ b/README-AR.md @@ -0,0 +1,252 @@ + +

+

عميل DeepSeek PHP

+

🚀 حزمة SDK لـ PHP مدعومة من المجتمع لتكامل واجهة برمجة التطبيقات الذكية DeepSeek

+ +

+ + أحدث إصدار + + + نسخة PHP + + + الرخصة + + + حالة الاختبارات + +

+

+ +## فهرس المحتويات +- [✨ المميزات](#-المميزات) +- [📦 التثبيت](#-التثبيت) +- [🚀 البداية السريعة](#-البداية-السريعة) + - [الاستخدام الأساسي](#الاستخدام-الأساسي) + - [التكوين المتقدم](#التكوين-المتقدم) + - [الاستخدام مع عميل HTTP من Symfony](#الاستخدام-مع-عميل-http-من-symfony) + - [الحصول على قائمة النماذج](#الحصول-على-قائمة-النماذج) + - [تكامل مع الأطر](#-تكامل-مع-الأطر) +- [🆕 دليل الترحيل](#-دليل-الترحيل) +- [📝 سجل التغييرات](#-سجل-التغييرات) +- [🧪 الاختبارات](#-الاختبارات) +- [🔒 الأمان](#-الأمان) +- [🤝 المساهمين](#-المساهمين) +- [📄 الرخصة](#-الرخصة) + +--- + +## ✨ المميزات + +- **تكامل API سلس**: واجهة تعتمد على PHP لميزات الذكاء الاصطناعي في DeepSeek. +- **نمط الباني السلس**: أساليب قابلة للسلسلة لبناء الطلبات بطريقة بديهية. +- **جاهز للمؤسسات**: تكامل مع عميل HTTP متوافق مع PSR-18. +- **مرونة النماذج**: دعم لعدة نماذج من DeepSeek (Coder, Chat, وغيرها). +- **جاهز للبث**: دعم مدمج للتعامل مع الردود في الوقت الفعلي. +- **العديد من عملاء HTTP**: يمكنك استخدام عميل `Guzzle http client` (افتراضي) أو `symfony http client` بسهولة. +- **متوافق مع الأطر**: حزم Laravel و Symfony متاحة. + +--- + +## 📦 التثبيت + +قم بتثبيت الحزمة عبر Composer: + +```bash +composer require deepseek-php/deepseek-php-client +``` + +**المتطلبات**: +- PHP 8.1+ + +--- + +## 🚀 البداية السريعة + +### الاستخدام الأساسي + +ابدأ مع سطرين من الكود فقط: + +```php +use DeepSeek\DeepSeekClient; + +$response = DeepSeekClient::build('your-api-key') + ->query('Explain quantum computing in simple terms') + ->run(); + +echo $response; +``` + +📌 الإعدادات الافتراضية المستخدمة: +- النموذج: `deepseek-chat` +- الحرارة: 0.8 + +### التكوين المتقدم + +```php +use DeepSeek\DeepSeekClient; +use DeepSeek\Enums\Models; + +$client = DeepSeekClient::build(apiKey:'your-api-key', baseUrl:'https://api.deepseek.com/v3', timeout:30, clientType:'guzzle'); + +$response = $client + ->withModel(Models::CODER->value) + ->withStream() + ->withTemperature(1.2) + ->run(); + +echo 'API Response:'.$response; +``` + +### الاستخدام مع عميل HTTP من Symfony +الحزمة مبنية مسبقاً مع `symfony Http client`، فإذا كنت بحاجة إلى استخدامها مع عميل HTTP الخاص بـ Symfony، فيمكن تحقيق ذلك بسهولة عن طريق تمرير `clientType:'symfony'` إلى دالة `build`. + +مثال باستخدام Symfony: + +```php +// مع القيم الافتراضية للـ baseUrl و timeout +$client = DeepSeekClient::build('your-api-key', clientType:'symfony') +// مع التخصيص +$client = DeepSeekClient::build(apiKey:'your-api-key', baseUrl:'https://api.deepseek.com/v3', timeout:30, 'symfony'); + +$client->query('Explain quantum computing in simple terms') + ->run(); +``` + +### الحصول على قائمة النماذج + +```php +use DeepSeek\DeepSeekClient; + +$response = DeepSeekClient::build('your-api-key') + ->getModelsList() + ->run(); + +echo $response; // {"object":"list","data":[{"id":"deepseek-chat","object":"model","owned_by":"deepseek"},{"id":"deepseek-reasoner","object":"model","owned_by":"deepseek"}]} +``` + +### 🛠 تكامل مع الأطر + +### [حزمة Deepseek لـ Laravel](https://github.com/deepseek-php/deepseek-laravel) + +--- + +## 🚧 دليل الترحيل + +هل تقوم بالترقية من الإصدار v1.x؟ اطلع على دليل الترحيل الشامل الخاص بنا للتغييرات الجذرية وتعليمات الترقية. + +--- + +## 📝 سجل التغييرات + +ملاحظات الإصدار التفصيلية متوفرة في [CHANGELOG.md](CHANGELOG.md) + +--- + +## 🧪 الاختبارات + +```bash +./vendor/bin/pest +``` + +تغطية الاختبارات ستتوفر في الإصدار v2.1. + +--- +
+ +# 🐘✨ **مجتمع DeepSeek PHP** ✨🐘 + +انقر على الزر أدناه أو [انضم هنا](https://t.me/deepseek_php_community) لتكون جزءًا من مجتمعنا المتنامي! + +[![Join Telegram](https://img.shields.io/badge/Join-Telegram-blue?style=for-the-badge&logo=telegram)](https://t.me/deepseek_php_community) + + +### **هيكل القناة** 🏗️ +- 🗨️ **عام** - دردشة يومية +- 💡 **الأفكار والاقتراحات** - تشكيل مستقبل المجتمع +- 📢 **الإعلانات والأخبار** - التحديثات والأخبار الرسمية +- 🚀 **الإصدارات والتحديثات** - تتبع الإصدارات ودعم الترحيل +- 🐞 **المشاكل وتقارير الأخطاء** - حل مشكلات جماعي +- 🤝 **طلبات السحب** - التعاون والمراجعة البرمجية + +
+ +--- + +## 🔒 الأمان + +**الإبلاغ عن الثغرات**: إلى [omaralwi2010@gmail.com](mailto:omaralwi2010@gmail.com) + +--- + +## 🤝 المساهمين + +شكراً جزيلاً لهؤلاء الأشخاص المذهلين الذين ساهموا في هذا المشروع! 🎉💖 + + + + + + + + + + +
+ + Omar AlAlwi +
+ Omar AlAlwi +
+
+ 🏆 المُنشئ +
+ + Ayman Alhattami +
+ Ayman Alhattami +
+
+ ⭐ مساهم +
+ + Mohammad Asaad +
+ Mohammad Asaad +
+
+ ⭐ مساهم +
+ + Opada Alzaiede +
+ Opada Alzaiede +
+
+ ⭐ مساهم +
+ + Hisham Bin Ateya +
+ Hisham Bin Ateya +
+
+ ⭐ مساهم +
+ + Vinchan +
+ Vinchan +
+
+ ⭐ مساهم +
+ +**هل ترغب في المساهمة؟** اطلع على [إرشادات المساهمة](./CONTRIBUTING.md) وقدم طلب سحب! 🚀 + +--- + +## 📄 الرخصة + +هذه الحزمة هي برنامج مفتوح المصدر مرخص بموجب [رخصة MIT](LICENSE.md). diff --git a/README-CN.md b/README-CN.md index 26dd190..530833e 100644 --- a/README-CN.md +++ b/README-CN.md @@ -23,7 +23,8 @@ - [📦 安装](#-安装) - [🚀 快速入门](#-快速入门) - [基本用法](#基本用法) - - [高级配置](#高级配置) + - [高级配置](#advanced-configuration) + - [Use with Symfony HttpClient](#use-with-symfony-httpclient) - [获取模型列表](#获取模型列表) - [框架集成](#-框架集成) - [🆕 迁移指南](#-迁移指南) @@ -79,21 +80,38 @@ echo $response; - Model: `deepseek-chat` - Temperature: 0.8 -### 高级配置 +### Advanced Configuration ```php use DeepSeek\DeepSeekClient; use DeepSeek\Enums\Models; -$response = DeepSeekClient::build('your-api-key') - ->withBaseUrl('https://api.deepseek.com/v2') +$client = DeepSeekClient::build(apiKey:'your-api-key', baseUrl:'https://api.deepseek.com/v3', timeout:30, clientType:'guzzle'); + +$response = $client ->withModel(Models::CODER->value) + ->withStream() ->withTemperature(1.2) ->run(); echo 'API Response:'.$response; ``` +### Use with Symfony HttpClient +the package already built with `symfony Http client`, if you need to use package with `symfony` Http Client , it is easy to achieve that, just pass `clientType:'symfony'` with `build` function. + +ex with symfony: + +```php +// with defaults baseUrl and timeout +$client = DeepSeekClient::build('your-api-key', clientType:'symfony') +// with customization +$client = DeepSeekClient::build(apiKey:'your-api-key', baseUrl:'https://api.deepseek.com/v3', timeout:30, 'symfony'); + +$client->query('Explain quantum computing in simple terms') + ->run(); +``` + ### 获取模型列表 ```php @@ -110,7 +128,6 @@ echo $response; // {"object":"list","data":[{"id":"deepseek-chat","object":"mode ### [Laravel Deepseek Package](https://github.com/deepseek-php/deepseek-laravel) -### [Symfony Deepseek Package](https://github.com/deepseek-php/deepseek-symfony) --- @@ -193,6 +210,15 @@ echo $response; // {"object":"list","data":[{"id":"deepseek-chat","object":"mode
⭐ Contributor + + + 陈文锋 +
+ 陈文锋 +
+
+ ⭐ Contributor + diff --git a/README.md b/README.md index a2ddb9e..9be3a07 100644 --- a/README.md +++ b/README.md @@ -230,6 +230,15 @@ A huge thank you to these amazing people who have contributed to this project!
⭐ Contributor + + + Vinchan +
+ Vinchan +
+
+ ⭐ Contributor + From 05e4331afcd4a2c35c84a01db6a36870979772e6 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sat, 22 Feb 2025 06:55:46 +0300 Subject: [PATCH 59/78] update doc --- README-AR.md | 3 +++ README-CN.md | 3 +++ README.md | 3 +++ 3 files changed, 9 insertions(+) diff --git a/README-AR.md b/README-AR.md index c8918c7..5cf564e 100644 --- a/README-AR.md +++ b/README-AR.md @@ -17,6 +17,9 @@ حالة الاختبارات

+ +[الإنجليزية](README.md) | [الصينية](README-CN.md) +

## فهرس المحتويات diff --git a/README-CN.md b/README-CN.md index 530833e..8ef7f67 100644 --- a/README-CN.md +++ b/README-CN.md @@ -16,6 +16,9 @@ Tests Status

+ +[EN](README.md) | [AR](README-AR.md) +

## 目录 diff --git a/README.md b/README.md index 9be3a07..2edb83d 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,9 @@ Tests Status

+ +[AR](README-AR.md) | [CN](README-CN.md) +

## Table of Contents From d645985c4da57bd17d0f8a8a9386313a8a8815bf Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Sat, 22 Feb 2025 07:00:28 +0300 Subject: [PATCH 60/78] update doc --- README-AR.md | 2 +- README-CN.md | 2 +- README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README-AR.md b/README-AR.md index 5cf564e..8b6ce37 100644 --- a/README-AR.md +++ b/README-AR.md @@ -111,7 +111,7 @@ echo 'API Response:'.$response; // مع القيم الافتراضية للـ baseUrl و timeout $client = DeepSeekClient::build('your-api-key', clientType:'symfony') // مع التخصيص -$client = DeepSeekClient::build(apiKey:'your-api-key', baseUrl:'https://api.deepseek.com/v3', timeout:30, 'symfony'); +$client = DeepSeekClient::build(apiKey:'your-api-key', baseUrl:'https://api.deepseek.com/v3', timeout:30, clientType:'symfony'); $client->query('Explain quantum computing in simple terms') ->run(); diff --git a/README-CN.md b/README-CN.md index 8ef7f67..8977cf9 100644 --- a/README-CN.md +++ b/README-CN.md @@ -109,7 +109,7 @@ ex with symfony: // with defaults baseUrl and timeout $client = DeepSeekClient::build('your-api-key', clientType:'symfony') // with customization -$client = DeepSeekClient::build(apiKey:'your-api-key', baseUrl:'https://api.deepseek.com/v3', timeout:30, 'symfony'); +$client = DeepSeekClient::build(apiKey:'your-api-key', baseUrl:'https://api.deepseek.com/v3', timeout:30, clientType:'symfony'); $client->query('Explain quantum computing in simple terms') ->run(); diff --git a/README.md b/README.md index 2edb83d..1ec6776 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ ex with symfony: // with defaults baseUrl and timeout $client = DeepSeekClient::build('your-api-key', clientType:'symfony') // with customization -$client = DeepSeekClient::build(apiKey:'your-api-key', baseUrl:'https://api.deepseek.com/v3', timeout:30, 'symfony'); +$client = DeepSeekClient::build(apiKey:'your-api-key', baseUrl:'https://api.deepseek.com/v3', timeout:30, clientType:'symfony'); $client->query('Explain quantum computing in simple terms') ->run(); From 52117612cbfcd1de9ea67d599c555282925dd835 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Mon, 24 Feb 2025 02:49:45 +0300 Subject: [PATCH 61/78] fix symfony client Compatibility --- composer.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index 4b7b927..b3d0459 100644 --- a/composer.json +++ b/composer.json @@ -49,17 +49,17 @@ "role": "creator" } ], - "version": "2.0.2", + "version": "2.0.3", "require": { "php": "^8.1.0", "nyholm/psr7": "^1.8", "php-http/discovery": "^1.20.0", "php-http/multipart-stream-builder": "^1.4.2", "psr/http-client": "^1.0.3", - "psr/http-client-implementation": "^1.0.1", + "psr/http-client-implementation": "1.0", "psr/http-factory-implementation": "*", "psr/http-message": "^1.1.0|^2.0.0", - "symfony/http-client": "^7.2" + "symfony/http-client": "^6.4" }, "require-dev": { "guzzlehttp/guzzle": "^7.9.2", @@ -68,8 +68,8 @@ "mockery/mockery": "^1.6.12", "nunomaduro/collision": "^7.11.0|^8.5.0", "pestphp/pest": "^2.36", - "pestphp/pest-plugin-arch": "^2.7|^3.0", - "pestphp/pest-plugin-type-coverage": "^2.8.7|^3.1.0", + "pestphp/pest-plugin-arch": "^2.7", + "pestphp/pest-plugin-type-coverage": "^2.8.7", "phpstan/phpstan": "^1.12.7", "roave/security-advisories": "dev-latest", "symfony/var-dumper": "^6.4.11|^7.1.5" @@ -108,4 +108,4 @@ "php-http/discovery": true } } -} +} \ No newline at end of file From 6d7dbbac71e6aae08f575e304b52fded877ba620 Mon Sep 17 00:00:00 2001 From: moassaad Date: Tue, 4 Mar 2025 23:03:17 +0200 Subject: [PATCH 62/78] update: add case (assistant, tool) role. --- src/Enums/Queries/QueryRoles.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Enums/Queries/QueryRoles.php b/src/Enums/Queries/QueryRoles.php index 4659084..a23925c 100644 --- a/src/Enums/Queries/QueryRoles.php +++ b/src/Enums/Queries/QueryRoles.php @@ -6,4 +6,6 @@ enum QueryRoles: string { case USER = 'user'; case SYSTEM = 'system'; + case ASSISTANT = 'assistant'; + case TOOL = 'tool'; } From ef5514f56adc842cf62728dc2d496ddf784a7947 Mon Sep 17 00:00:00 2001 From: moassaad Date: Tue, 4 Mar 2025 23:03:37 +0200 Subject: [PATCH 63/78] update: add case tools flag. --- src/Enums/Requests/QueryFlags.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Enums/Requests/QueryFlags.php b/src/Enums/Requests/QueryFlags.php index 19c1cdd..0e2b49a 100644 --- a/src/Enums/Requests/QueryFlags.php +++ b/src/Enums/Requests/QueryFlags.php @@ -8,4 +8,5 @@ enum QueryFlags: string case MODEL = 'model'; case STREAM = 'stream'; case TEMPERATURE = 'temperature'; + case TOOLS = 'tools'; } From 21b5dbc4f185912beae1933cca819fe7bf31fc4b Mon Sep 17 00:00:00 2001 From: moassaad Date: Tue, 4 Mar 2025 23:03:56 +0200 Subject: [PATCH 64/78] create: trait tools function calling for using in deepseek client. --- src/Traits/Client/HasToolsFunctionCalling.php | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 src/Traits/Client/HasToolsFunctionCalling.php diff --git a/src/Traits/Client/HasToolsFunctionCalling.php b/src/Traits/Client/HasToolsFunctionCalling.php new file mode 100644 index 0000000..97d53fc --- /dev/null +++ b/src/Traits/Client/HasToolsFunctionCalling.php @@ -0,0 +1,66 @@ +tools = $tools; + return $this; + } + + /** + * Add a query tool calls to the accumulated queries list. + * + * @param array $toolCalls The tool calls generated by the model, such as function calls. + * @param string $content + * @param string|null $role + * @return self The current instance for method chaining. + */ + public function queryToolCall(array $toolCalls, string $content, ?string $role = null): self + { + $this->queries[] = $this->buildToolCallQuery($toolCalls, $content, $role); + return $this; + } + + public function buildToolCallQuery(array $toolCalls, string $content, ?string $role = null): array + { + $query = [ + 'role' => $role ?: QueryRoles::ASSISTANT->value, + 'tool_calls' => $toolCalls, + 'content' => $content, + ]; + return $query; + } + + /** + * Add a query tool to the accumulated queries list. + * + * @param string $toolCallId + * @param string $content + * @param string|null $role + * @return self The current instance for method chaining. + */ + public function queryTool(string $toolCallId, string $content , ?string $role = null): self + { + $this->queries[] = $this->buildToolQuery($toolCallId, $content, $role); + return $this; + } + + public function buildToolQuery(string $toolCallId, string $content, ?string $role): array + { + $query = [ + 'role' => $role ?: QueryRoles::TOOL->value, + 'tool_call_id' => $toolCallId, + 'content' => $content, + ]; + return $query; + } +} From ade67b33f3de29b751cedcd7a885d38bb55591d3 Mon Sep 17 00:00:00 2001 From: moassaad Date: Tue, 4 Mar 2025 23:04:08 +0200 Subject: [PATCH 65/78] update: add tool property and reset query function. --- src/DeepSeekClient.php | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/DeepSeekClient.php b/src/DeepSeekClient.php index a8d7f01..1c0cb58 100644 --- a/src/DeepSeekClient.php +++ b/src/DeepSeekClient.php @@ -13,10 +13,12 @@ use DeepSeek\Enums\Requests\QueryFlags; use DeepSeek\Enums\Configs\TemperatureValues; use DeepSeek\Traits\Resources\{HasChat, HasCoder}; +use DeepSeek\Traits\Client\HasToolsFunctionCalling; class DeepSeekClient implements ClientContract { use HasChat, HasCoder; + use HasToolsFunctionCalling; /** * PSR-18 HTTP client for making requests. @@ -58,6 +60,12 @@ class DeepSeekClient implements ClientContract protected ?string $endpointSuffixes; + /** + * Array of tools for using function calling. + * @var array|null $tools + */ + protected ?array $tools; + /** * Initialize the DeepSeekClient with a PSR-compliant HTTP client. * @@ -71,6 +79,7 @@ public function __construct(ClientInterface $httpClient) $this->requestMethod = 'POST'; $this->endpointSuffixes = EndpointSuffixes::CHAT->value; $this->temperature = (float) TemperatureValues::GENERAL_CONVERSATION->value; + $this->tools = null; } public function run(): string @@ -80,9 +89,9 @@ public function run(): string QueryFlags::MODEL->value => $this->model, QueryFlags::STREAM->value => $this->stream, QueryFlags::TEMPERATURE->value => $this->temperature, + QueryFlags::TOOLS->value => $this->tools, ]; - // Clear queries after sending - $this->queries = []; + $this->setResult((new Resource($this->httpClient, $this->endpointSuffixes))->sendRequest($requestData, $this->requestMethod)); return $this->getResult()->getContent(); } @@ -120,6 +129,17 @@ public function query(string $content, ?string $role = "user"): self $this->queries[] = $this->buildQuery($content, $role); return $this; } + + /** + * Reset a queries list to empty. + * + * @return self The current instance for method chaining. + */ + public function resetQuery() + { + $this->query = []; + return $this; + } /** * get list of available models . @@ -173,7 +193,7 @@ public function buildQuery(string $content, ?string $role = null): array /** * set result model - * @param \DeepseekPhp\Contracts\Models\ResultContract $result + * @param \DeepSeek\Contracts\Models\ResultContract $result * @return self The current instance for method chaining. */ public function setResult(ResultContract $result) From 8b41e4421907119267896713c3e3c5a94ee64f35 Mon Sep 17 00:00:00 2001 From: moassaad Date: Tue, 4 Mar 2025 23:04:18 +0200 Subject: [PATCH 66/78] create: fake response class to using in test mock. --- .../Feature/ClientDependency/FakeResponse.php | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 tests/Feature/ClientDependency/FakeResponse.php diff --git a/tests/Feature/ClientDependency/FakeResponse.php b/tests/Feature/ClientDependency/FakeResponse.php new file mode 100644 index 0000000..3b1b725 --- /dev/null +++ b/tests/Feature/ClientDependency/FakeResponse.php @@ -0,0 +1,69 @@ + Date: Tue, 4 Mar 2025 23:04:29 +0200 Subject: [PATCH 67/78] create: test function calling. --- tests/Feature/FunctionCallingTest.php | 155 ++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 tests/Feature/FunctionCallingTest.php diff --git a/tests/Feature/FunctionCallingTest.php b/tests/Feature/FunctionCallingTest.php new file mode 100644 index 0000000..6efae8f --- /dev/null +++ b/tests/Feature/FunctionCallingTest.php @@ -0,0 +1,155 @@ + ["temperature"=> 22, "condition" => "Sunny"], + "gharbia" => ["temperature"=> 23, "condition" => "Sunny"], + "sharkia" => ["temperature"=> 24, "condition" => "Sunny"], + "beheira" => ["temperature"=> 21, "condition" => "Sunny"], + default => "not found city name." + }; + return json_encode($city); +} + +test('Test function calling with fake responses.', function () { + // Arrange + $fake = new FakeResponse(); + + /** @var DeepSeekClient&LegacyMockInterface&MockInterface */ + $mockClient = Mockery::mock(DeepSeekClient::class); + + $mockClient->shouldReceive('build')->andReturn($mockClient); + $mockClient->shouldReceive('setTools')->andReturn($mockClient); + $mockClient->shouldReceive('query')->andReturn($mockClient); + $mockClient->shouldReceive('run')->once()->andReturn($fake->toolFunctionCalling()); + + // Act + $response = $mockClient::build('your-api-key') + ->query('What is the weather like in Cairo?') + ->setTools([ + [ + "type" => "function", + "function" => [ + "name" => "get_weather", + "description" => "Get the current weather in a given city", + "parameters" => [ + "type" => "object", + "properties" => [ + "city" => [ + "type" => "string", + "description" => "The city name", + ], + ], + "required" => ["city"], + ], + ], + ], + ] + )->run(); + + // Assert + expect($fake->toolFunctionCalling())->toEqual($response); + + //------------------------------------------ + + // Arrange + $response = json_decode($response, true); + $message = $response['choices'][0]['message']; + + $firstFunction = $message['tool_calls'][0]; + if ($firstFunction['function']['name'] == "get_weather") + { + $weather_data = get_weather($firstFunction['function']['arguments']['city']); + } + + $mockClient->shouldReceive('queryCallTool')->andReturn($mockClient); + $mockClient->shouldReceive('queryTool')->andReturn($mockClient); + $mockClient->shouldReceive('run')->andReturn($fake->resultToolFunctionCalling()); + + // Act + $response2 = $mockClient->queryCallTool( + $message['tool_calls'], + $message['content'], + $message['role'] + )->queryTool( + $firstFunction['id'], + $weather_data, + 'tool' + )->run(); + + // Assert + expect($fake->resultToolFunctionCalling())->toEqual($response2); +}); + +test('Test function calling use base data with real responses.', function () { + // Arrange + $client = DeepSeekClient::build('your-api-key') + ->query('What is the weather like in Cairo?') + ->setTools([ + [ + "type" => "function", + "function" => [ + "name" => "get_weather", + "description" => "Get the current weather in a given city", + "parameters" => [ + "type" => "object", + "properties" => [ + "city" => [ + "type" => "string", + "description" => "The city name", + ], + ], + "required" => ["city"], + ], + ], + ], + ] + ); + + // Act + $response = $client->run(); + $result = $client->getResult(); + + // Assert + expect($response)->not()->toBeEmpty($response) + ->and($result->getStatusCode())->toEqual(HTTPState::OK->value); + + //----------------------------------------------------------------- + + // Arrange + $response = json_decode($response, true); + $message = $response['choices'][0]['message']; + $firstFunction = $message['tool_calls'][0]; + if ($firstFunction['function']['name'] == "get_weather") + { + $weather_data = get_weather($firstFunction['function']['arguments']['city']); + } + + $response2 = $client->queryToolCall( + $message['tool_calls'], + $message['content'], + $message['role'] + )->queryTool( + $firstFunction['id'], + $weather_data, + 'tool' + ); + + // Act + $response2 = $response2->run(); + $result2 = $client->getResult(); + + // Assert + expect($response2)->not()->toBeEmpty($response2) + ->and($result2->getStatusCode())->toEqual(HTTPState::OK->value); +}); From 2a0040f39938a7c778c53a6e4158d5c59e1cf102 Mon Sep 17 00:00:00 2001 From: moassaad Date: Mon, 10 Mar 2025 22:41:15 +0200 Subject: [PATCH 68/78] fix: reset queries function. --- src/DeepSeekClient.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DeepSeekClient.php b/src/DeepSeekClient.php index 1c0cb58..93c989d 100644 --- a/src/DeepSeekClient.php +++ b/src/DeepSeekClient.php @@ -135,9 +135,9 @@ public function query(string $content, ?string $role = "user"): self * * @return self The current instance for method chaining. */ - public function resetQuery() + public function resetQueries() { - $this->query = []; + $this->queries = []; return $this; } From 218ea3f0ef05025d586cd980c7fdbe119c981ab5 Mon Sep 17 00:00:00 2001 From: moassaad Date: Sat, 22 Mar 2025 00:46:19 +0200 Subject: [PATCH 69/78] update: edit test real responses. --- tests/Feature/FunctionCallingTest.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/Feature/FunctionCallingTest.php b/tests/Feature/FunctionCallingTest.php index 6efae8f..041e153 100644 --- a/tests/Feature/FunctionCallingTest.php +++ b/tests/Feature/FunctionCallingTest.php @@ -128,14 +128,16 @@ function get_weather($city) // Arrange $response = json_decode($response, true); + $message = $response['choices'][0]['message']; $firstFunction = $message['tool_calls'][0]; if ($firstFunction['function']['name'] == "get_weather") { - $weather_data = get_weather($firstFunction['function']['arguments']['city']); + $args = json_decode($firstFunction['function']['arguments'], true); + $weather_data = get_weather($args['city']); } - $response2 = $client->queryToolCall( + $client2 = $client->queryToolCall( $message['tool_calls'], $message['content'], $message['role'] @@ -146,8 +148,8 @@ function get_weather($city) ); // Act - $response2 = $response2->run(); - $result2 = $client->getResult(); + $response2 = $client2->run(); + $result2 = $client2->getResult(); // Assert expect($response2)->not()->toBeEmpty($response2) From f5642d65ad12b267fd7ddeaeeab723de09e7a443 Mon Sep 17 00:00:00 2001 From: Kenneth Gerald Hamilton <29099829+kghamilton89@users.noreply.github.com> Date: Sat, 5 Apr 2025 15:00:07 +0200 Subject: [PATCH 70/78] update docs to correct `setTemperature` parameter --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ec6776..a8c4db2 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ $client = DeepSeekClient::build(apiKey:'your-api-key', baseUrl:'https://api.deep $response = $client ->withModel(Models::CODER->value) ->withStream() - ->withTemperature(1.2) + ->setTemperature(1.2) ->run(); echo 'API Response:'.$response; From 2091d51a06ab805e53b482ae4de02c8dcad08232 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Thu, 12 Jun 2025 01:50:33 +0300 Subject: [PATCH 71/78] Docs / add function calilng docs --- README-AR.md | 14 ++- README-CN.md | 33 ++++++- README.md | 10 ++ docs/FUNCTION-CALLING.md | 192 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 243 insertions(+), 6 deletions(-) create mode 100644 docs/FUNCTION-CALLING.md diff --git a/README-AR.md b/README-AR.md index 8b6ce37..83163f9 100644 --- a/README-AR.md +++ b/README-AR.md @@ -1,4 +1,3 @@ -

عميل DeepSeek PHP

🚀 حزمة SDK لـ PHP مدعومة من المجتمع لتكامل واجهة برمجة التطبيقات الذكية DeepSeek

@@ -30,6 +29,7 @@ - [التكوين المتقدم](#التكوين-المتقدم) - [الاستخدام مع عميل HTTP من Symfony](#الاستخدام-مع-عميل-http-من-symfony) - [الحصول على قائمة النماذج](#الحصول-على-قائمة-النماذج) + - [استدعاء الدوال](#استدعاء-الدوال) - [تكامل مع الأطر](#-تكامل-مع-الأطر) - [🆕 دليل الترحيل](#-دليل-الترحيل) - [📝 سجل التغييرات](#-سجل-التغييرات) @@ -97,6 +97,7 @@ $response = $client ->withModel(Models::CODER->value) ->withStream() ->withTemperature(1.2) + ->query('Explain quantum computing in simple terms') ->run(); echo 'API Response:'.$response; @@ -129,6 +130,17 @@ $response = DeepSeekClient::build('your-api-key') echo $response; // {"object":"list","data":[{"id":"deepseek-chat","object":"model","owned_by":"deepseek"},{"id":"deepseek-reasoner","object":"model","owned_by":"deepseek"}]} ``` +### استدعاء الدوال + +يتيح **استدعاء الدوال** للنموذج استدعاء أدوات خارجية لتعزيز قدراته. +يمكنك الرجوع إلى الوثائق الخاصة باستدعاء الدوال في الملف: +[FUNCTION-CALLING.md](docs/FUNCTION-CALLING.md) + +--- + +هل ترغب في أن أضع النسخ الثلاث (الإنجليزية + العربية + الصينية) ضمن ملف Markdown موحد؟ + + ### 🛠 تكامل مع الأطر ### [حزمة Deepseek لـ Laravel](https://github.com/deepseek-php/deepseek-laravel) diff --git a/README-CN.md b/README-CN.md index 8977cf9..df859b4 100644 --- a/README-CN.md +++ b/README-CN.md @@ -25,11 +25,12 @@ - [✨ 特性](#-特性) - [📦 安装](#-安装) - [🚀 快速入门](#-快速入门) - - [基本用法](#基本用法) - - [高级配置](#advanced-configuration) - - [Use with Symfony HttpClient](#use-with-symfony-httpclient) - - [获取模型列表](#获取模型列表) - - [框架集成](#-框架集成) + - [基本用法](#基本用法) + - [高级配置](#高级配置) + - [使用 Symfony HttpClient](#使用-symfony-httpclient) + - [获取模型列表](#获取模型列表) + - [函数调用](#函数调用) + - [框架集成](#-框架集成) - [🆕 迁移指南](#-迁移指南) - [📝 更新日志](#-更新日志) - [🧪 测试](#-测试) @@ -95,6 +96,7 @@ $response = $client ->withModel(Models::CODER->value) ->withStream() ->withTemperature(1.2) + ->query('Explain quantum computing in simple terms') ->run(); echo 'API Response:'.$response; @@ -127,11 +129,32 @@ $response = DeepSeekClient::build('your-api-key') echo $response; // {"object":"list","data":[{"id":"deepseek-chat","object":"model","owned_by":"deepseek"},{"id":"deepseek-reasoner","object":"model","owned_by":"deepseek"}]} ``` +### 函数调用 + +**函数调用**允许模型调用外部工具以增强其功能。 +你可以在文档中查看有关函数调用的详细信息: +[FUNCTION-CALLING.md](docs/FUNCTION-CALLING.md) + + ### 🛠 框架集成 ### [Laravel Deepseek Package](https://github.com/deepseek-php/deepseek-laravel) +# 🐘✨ **DeepSeek PHP Community** ✨🐘 + +Click the button bellow or [join here](https://t.me/deepseek_php_community) to be part of our growing community! + +[![Join Telegram](https://img.shields.io/badge/Join-Telegram-blue?style=for-the-badge&logo=telegram)](https://t.me/deepseek_php_community) + +### **Channel Structure** 🏗️ +- 🗨️ **General** - Daily chatter +- 💡 **Ideas & Suggestions** - Shape the community's future +- 📢 **Announcements & News** - Official updates & news +- 🚀 **Releases & Updates** - Version tracking & migration support +- 🐞 **Issues & Bug Reports** - Collective problem-solving +- 🤝 **Pull Requests** - Code collaboration & reviews + --- ## 🚧 迁移指南 diff --git a/README.md b/README.md index a8c4db2..7ed8c3e 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ - [Advanced Configuration](#advanced-configuration) - [Use with Symfony HttpClient](#use-with-symfony-httpclient) - [Get Models List](#get-models-list) + - [Function Calling](#function-calling) - [Framework Integration](#-framework-integration) - [🆕 Migration Guide](#-migration-guide) - [📝 Changelog](#-changelog) @@ -96,6 +97,7 @@ $response = $client ->withModel(Models::CODER->value) ->withStream() ->setTemperature(1.2) + ->query('Explain quantum computing in simple terms') ->run(); echo 'API Response:'.$response; @@ -128,6 +130,14 @@ $response = DeepSeekClient::build('your-api-key') echo $response; // {"object":"list","data":[{"id":"deepseek-chat","object":"model","owned_by":"deepseek"},{"id":"deepseek-reasoner","object":"model","owned_by":"deepseek"}]} ``` + +### Function Calling + +Function Calling allows the model to call external tools to enhance its capabilities.[[1]](https://api-docs.deepseek.com/guides/function_calling) + +You Can check the documentation for function calling in [FUNCTION-CALLING.md](docs/FUNCTION-CALLING.md) + + ### 🛠 Framework Integration ### [Laravel Deepseek Package](https://github.com/deepseek-php/deepseek-laravel) diff --git a/docs/FUNCTION-CALLING.md b/docs/FUNCTION-CALLING.md new file mode 100644 index 0000000..4d115cf --- /dev/null +++ b/docs/FUNCTION-CALLING.md @@ -0,0 +1,192 @@ +## Function Calling + +Function Calling allows the model to call external tools to enhance its capabilities.[[1]](https://api-docs.deepseek.com/guides/function_calling) + +#### 1. Define the tools used by the model and pass them with each message passed to the model, Receive query messages from the end user and pass them to the model with the defined tools. +- example function `get_weather($city)`. +```php +function get_weather($city) +{ + $city = strtolower($city); + $city = match($city){ + "cairo" => ["temperature"=> 22, "condition" => "Sunny"], + "gharbia" => ["temperature"=> 23, "condition" => "Sunny"], + "sharkia" => ["temperature"=> 24, "condition" => "Sunny"], + "beheira" => ["temperature"=> 21, "condition" => "Sunny"], + default => "not found city name." + }; + return json_encode($city); +} +``` +The user requests the weather in Cairo. +```php +$client = DeepSeekClient::build('your-api-key') + ->query('What is the weather like in Cairo?') + ->setTools([ + [ + "type" => "function", + "function" => [ + "name" => "get_weather", + "description" => "Get the current weather in a given city", + "parameters" => [ + "type" => "object", + "properties" => [ + "city" => [ + "type" => "string", + "description" => "The city name", + ], + ], + "required" => ["city"], + ], + ], + ], + ] +); + +$response = $client->run(); + +``` + +Output response like. +```json +{ + "id": "chat_12345", + "object": "chat.completion", + "created": 1677654321, + "model": "deepseek-chat", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": null, + "tool_calls": [ + { + "id": "call_12345", + "type": "function", + "function": { + "name": "get_weather", + "arguments": "{\"city\": \"Cairo\"}" + } + } + ] + }, + "finish_reason": "tool_calls" + } + ] +} +``` + +#### 2. Receive the response and check if it has called one or more tools to execute it in the system ,And execute the tool called by the model. +The deepseek api responds to the system and requests the execution of the tool responsible for fetching the weather status. +```php + +$response = $client->run(); + +$response = json_decode($response, true); +$message = $response['choices'][0]['message']; +$firstFunction = $message['tool_calls'][0]; +if ($firstFunction['function']['name'] == "get_weather") +{ + $weather_data = get_weather($firstFunction['function']['arguments']['city']); +} + +``` + +#### 3. Coordinate the results and send the previous response with the results of the executed tools. +Formats the response, and sends it back to the form. +```php +$response2 = $client->queryToolCall( + $message['tool_calls'], + $message['content'], + $message['role'] + )->queryTool( + $firstFunction['id'], + $weather_data +); +``` + +Request like +```json +{ + "messages": [ + { + "role": "user", + "content": "What is the weather like in Cairo?" + }, + { + "content": "What is the weather like in Cairo?", + "tool_calls": [ + { + "id": "930c60df-3ec75f81e00e", + "type": "function", + "function": { + "name": "get_weather", + "arguments": { + "city": "Cairo" + } + } + } + ], + "role": "assistant" + }, + { + "role": "tool", + "tool_call_id": "930c60df-3ec75f81e00e", + "content": "{\"temperature\":22,\"condition\":\"Sunny\"}" + } + ], + "model": "deepseek-chat", + "stream": false, + "temperature": 1.3, + "tools": [ + { + "type": "function", + "function": { + "name": "get_weather", + "description": "Get the current weather in a given city", + "parameters": { + "type": "object", + "properties": { + "city": { + "type": "string", + "description": "The city name" + } + }, + "required": [ + "city" + ] + } + } + } + ] +} +``` + +#### 4. Receive the final response from the model and pass it to the end user. +The deepseek api responds with the final response, which is the weather status according to the data passed to it in the example. +```php + +$response2 = $response2->run(); +echo $response2; +``` +Output response like :- +```json +{ + "id": "chat_67890", + "object": "chat.completion", + "created": 1677654322, + "model": "deepseek-chat", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "The weather in Cairo is 22℃." + }, + "finish_reason": "stop" + } + ] +} +``` + From 844e4f718a220dcee2d46e332e9a9a4f0c420d33 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Thu, 12 Jun 2025 01:56:30 +0300 Subject: [PATCH 72/78] update version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b3d0459..5f03fd6 100644 --- a/composer.json +++ b/composer.json @@ -49,7 +49,7 @@ "role": "creator" } ], - "version": "2.0.3", + "version": "2.0.4", "require": { "php": "^8.1.0", "nyholm/psr7": "^1.8", From fa02d9a5b22d55ddbf1093f8c260936e7e181fee Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Wed, 16 Jul 2025 22:51:04 +0300 Subject: [PATCH 73/78] update bardes --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7ed8c3e..0a59cec 100644 --- a/README.md +++ b/README.md @@ -6,17 +6,19 @@ Latest Version + + Total Downloads + PHP Version License - - Tests Status + + GitHub Stars -

- + [AR](README-AR.md) | [CN](README-CN.md)

From 1f078c7b507b7f587caf82476af65b087194fe02 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Wed, 16 Jul 2025 23:02:11 +0300 Subject: [PATCH 74/78] update badges --- README-AR.md | 15 +++++++++------ README-CN.md | 19 +++++++++++-------- README.md | 2 +- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/README-AR.md b/README-AR.md index 83163f9..10905a9 100644 --- a/README-AR.md +++ b/README-AR.md @@ -1,19 +1,22 @@

-

عميل DeepSeek PHP

-

🚀 حزمة SDK لـ PHP مدعومة من المجتمع لتكامل واجهة برمجة التطبيقات الذكية DeepSeek

+

عميل DeepSeek بلغة PHP

+

🚀 حزمة PHP مفتوحة المصدر ومدعومة من المجتمع للتكامل مع واجهة DeepSeek API

أحدث إصدار + + إجمالي التحميلات + - نسخة PHP + إصدار PHP - الرخصة + الترخيص - - حالة الاختبارات + + النجوم على GitHub

diff --git a/README-CN.md b/README-CN.md index df859b4..ebd7e19 100644 --- a/README-CN.md +++ b/README-CN.md @@ -1,19 +1,22 @@

-

DeepSeek PHP Client

-

🚀 社区驱动的 PHP SDK,用于 DeepSeek AI 接口集成

- +

DeepSeek PHP 客户端

+

🚀 由社区驱动的 PHP SDK,用于集成 DeepSeek AI API

+

- Latest Version + 最新版本 + + + 总下载次数 - PHP Version + PHP 版本 - License + 许可证 - - Tests Status + + GitHub 收藏数

diff --git a/README.md b/README.md index 0a59cec..c70c40f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

DeepSeek PHP Client

-

🚀 Community-Driven PHP SDK for DeepSeek AI API Integration

+

🚀 Community-Driven PHP Client for DeepSeek AI API Integration

From c0d27f605cf0f747cdced9cb6806f2227994d726 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Wed, 16 Jul 2025 23:56:11 +0300 Subject: [PATCH 75/78] feat / support pass max tokens option --- README-AR.md | 1 + README-CN.md | 1 + README.md | 1 + src/DeepSeekClient.php | 11 +++++++++++ src/Enums/Configs/TemperatureValues.php | 1 + src/Enums/Requests/QueryFlags.php | 1 + 6 files changed, 16 insertions(+) diff --git a/README-AR.md b/README-AR.md index 10905a9..8e9ad5a 100644 --- a/README-AR.md +++ b/README-AR.md @@ -100,6 +100,7 @@ $response = $client ->withModel(Models::CODER->value) ->withStream() ->withTemperature(1.2) + ->setMaxTokens(8192) ->query('Explain quantum computing in simple terms') ->run(); diff --git a/README-CN.md b/README-CN.md index ebd7e19..b93bb99 100644 --- a/README-CN.md +++ b/README-CN.md @@ -99,6 +99,7 @@ $response = $client ->withModel(Models::CODER->value) ->withStream() ->withTemperature(1.2) + ->setMaxTokens(8192) ->query('Explain quantum computing in simple terms') ->run(); diff --git a/README.md b/README.md index c70c40f..6ec9b7e 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,7 @@ $response = $client ->withModel(Models::CODER->value) ->withStream() ->setTemperature(1.2) + ->setMaxTokens(8192) ->query('Explain quantum computing in simple terms') ->run(); diff --git a/src/DeepSeekClient.php b/src/DeepSeekClient.php index 93c989d..63592a1 100644 --- a/src/DeepSeekClient.php +++ b/src/DeepSeekClient.php @@ -49,6 +49,7 @@ class DeepSeekClient implements ClientContract protected bool $stream; protected float $temperature; + protected int $maxTokens; /** * response result contract @@ -79,6 +80,7 @@ public function __construct(ClientInterface $httpClient) $this->requestMethod = 'POST'; $this->endpointSuffixes = EndpointSuffixes::CHAT->value; $this->temperature = (float) TemperatureValues::GENERAL_CONVERSATION->value; + $this->maxTokens = (int) TemperatureValues::MAX_TOKENS->value; $this->tools = null; } @@ -89,9 +91,12 @@ public function run(): string QueryFlags::MODEL->value => $this->model, QueryFlags::STREAM->value => $this->stream, QueryFlags::TEMPERATURE->value => $this->temperature, + QueryFlags::MAX_TOKENS->value => $this->maxTokens, QueryFlags::TOOLS->value => $this->tools, ]; + \Log::info(['debug info: this is $requestData :' => $requestData ]); + $this->setResult((new Resource($this->httpClient, $this->endpointSuffixes))->sendRequest($requestData, $this->requestMethod)); return $this->getResult()->getContent(); } @@ -183,6 +188,12 @@ public function setTemperature(float $temperature): self return $this; } + public function setMaxTokens(int $maxTokens): self + { + $this->maxTokens = $maxTokens; + return $this; + } + public function buildQuery(string $content, ?string $role = null): array { return [ diff --git a/src/Enums/Configs/TemperatureValues.php b/src/Enums/Configs/TemperatureValues.php index 12c21b1..b9b9a93 100644 --- a/src/Enums/Configs/TemperatureValues.php +++ b/src/Enums/Configs/TemperatureValues.php @@ -12,4 +12,5 @@ enum TemperatureValues: string case TRANSLATION = "1.4"; case CREATIVE_WRITING = "1.5"; case POETRY = "1.6"; + case MAX_TOKENS = "4096"; } diff --git a/src/Enums/Requests/QueryFlags.php b/src/Enums/Requests/QueryFlags.php index 0e2b49a..2b4b557 100644 --- a/src/Enums/Requests/QueryFlags.php +++ b/src/Enums/Requests/QueryFlags.php @@ -8,5 +8,6 @@ enum QueryFlags: string case MODEL = 'model'; case STREAM = 'stream'; case TEMPERATURE = 'temperature'; + case MAX_TOKENS = 'max_tokens'; case TOOLS = 'tools'; } From ab01fa544cbbd0225fa46c5500b4dcc4125679b8 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Thu, 17 Jul 2025 00:03:22 +0300 Subject: [PATCH 76/78] clean u p --- composer.json | 4 ++-- src/DeepSeekClient.php | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 5f03fd6..20f2766 100644 --- a/composer.json +++ b/composer.json @@ -47,9 +47,9 @@ "name": "Omar Alalwi", "email": "omaralwi2010@gmail.com", "role": "creator" - } + }g ], - "version": "2.0.4", + "version": "2.0.5", "require": { "php": "^8.1.0", "nyholm/psr7": "^1.8", diff --git a/src/DeepSeekClient.php b/src/DeepSeekClient.php index 63592a1..c44d0cd 100644 --- a/src/DeepSeekClient.php +++ b/src/DeepSeekClient.php @@ -95,8 +95,6 @@ public function run(): string QueryFlags::TOOLS->value => $this->tools, ]; - \Log::info(['debug info: this is $requestData :' => $requestData ]); - $this->setResult((new Resource($this->httpClient, $this->endpointSuffixes))->sendRequest($requestData, $this->requestMethod)); return $this->getResult()->getContent(); } From dde2965ef938b365e6b24e41c29d88e29b29c521 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Thu, 17 Jul 2025 00:03:37 +0300 Subject: [PATCH 77/78] clean up --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 20f2766..e4a48f2 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,7 @@ "name": "Omar Alalwi", "email": "omaralwi2010@gmail.com", "role": "creator" - }g + } ], "version": "2.0.5", "require": { From 0dc68a2ce8ee8997ee76b15eba3d8ec8501300c4 Mon Sep 17 00:00:00 2001 From: omaralalwi Date: Thu, 17 Jul 2025 00:44:05 +0300 Subject: [PATCH 78/78] feat / support response format option --- README-AR.md | 39 +++++++++++++++++++++-- README-CN.md | 38 +++++++++++++++++++++-- README.md | 41 +++++++++++++++++++++++-- composer.json | 2 +- src/DeepSeekClient.php | 11 +++++++ src/Enums/Configs/TemperatureValues.php | 1 + src/Enums/Requests/QueryFlags.php | 1 + 7 files changed, 125 insertions(+), 8 deletions(-) diff --git a/README-AR.md b/README-AR.md index 8e9ad5a..cccbfc0 100644 --- a/README-AR.md +++ b/README-AR.md @@ -22,14 +22,13 @@ [الإنجليزية](README.md) | [الصينية](README-CN.md) -

- ## فهرس المحتويات - [✨ المميزات](#-المميزات) - [📦 التثبيت](#-التثبيت) - [🚀 البداية السريعة](#-البداية-السريعة) - [الاستخدام الأساسي](#الاستخدام-الأساسي) - [التكوين المتقدم](#التكوين-المتقدم) + - [تحذير هام عند استخدام وضع JSON](#-متطلب-وضع-json-في-deepseek) - [الاستخدام مع عميل HTTP من Symfony](#الاستخدام-مع-عميل-http-من-symfony) - [الحصول على قائمة النماذج](#الحصول-على-قائمة-النماذج) - [استدعاء الدوال](#استدعاء-الدوال) @@ -101,12 +100,48 @@ $response = $client ->withStream() ->withTemperature(1.2) ->setMaxTokens(8192) + ->setResponseFormat('text') ->query('Explain quantum computing in simple terms') ->run(); echo 'API Response:'.$response; ``` + +## ⚠️ متطلب وضع JSON في DeepSeek + +عند استخدام: + +```php +->setResponseFormat('json_object') +``` + +يجب أن يحتوي الـ برومبت على **كلمة "json"** بشكل واضح. + +وإلا سيتم رفض الطلب من قبل وترجع رسالة الخطأ التالية: + +> `"Prompt must contain the word 'json' in some form to use 'response_format' of type 'json_object'"` + +--- + +### 🚫 استخدام غير صحيح + +```php +->setResponseFormat('json_object') +->query('اشرح الحوسبة الكمومية بطريقة مبسطة') +``` + +### ✅ استخدام صحيح + +```php +->setResponseFormat('json_object') +->query('أجب بصيغة JSON صحيحة. اشرح الحوسبة الكمومية بطريقة مبسطة.') +``` + +> ✅ **نصيحة**: للحصول على أفضل النتائج، قم أيضًا بإعطاء مثال على صيغة JSON في الرسالة. + +--- + ### الاستخدام مع عميل HTTP من Symfony الحزمة مبنية مسبقاً مع `symfony Http client`، فإذا كنت بحاجة إلى استخدامها مع عميل HTTP الخاص بـ Symfony، فيمكن تحقيق ذلك بسهولة عن طريق تمرير `clientType:'symfony'` إلى دالة `build`. diff --git a/README-CN.md b/README-CN.md index b93bb99..0458b5c 100644 --- a/README-CN.md +++ b/README-CN.md @@ -22,14 +22,13 @@ [EN](README.md) | [AR](README-AR.md) -

- ## 目录 - [✨ 特性](#-特性) - [📦 安装](#-安装) - [🚀 快速入门](#-快速入门) - [基本用法](#基本用法) - [高级配置](#高级配置) + - [使用 JSON 模式的重要警告](#-deepseek-json-模式使用要求) - [使用 Symfony HttpClient](#使用-symfony-httpclient) - [获取模型列表](#获取模型列表) - [函数调用](#函数调用) @@ -100,12 +99,47 @@ $response = $client ->withStream() ->withTemperature(1.2) ->setMaxTokens(8192) + ->setResponseFormat('text') ->query('Explain quantum computing in simple terms') ->run(); echo 'API Response:'.$response; ``` + +## ⚠️ DeepSeek JSON 模式使用要求 + +当使用: + +```php +->setResponseFormat('json_object') +``` + +你的提示语(prompt)**必须包含 "json" 这个词**,否则 API 会返回以下错误: + +> `"Prompt must contain the word 'json' in some form to use 'response_format' of type 'json_object'"` + +--- + +### 🚫 错误示例 + +```php +->setResponseFormat('json_object') +->query('用简单的语言解释量子计算') +``` + +### ✅ 正确示例 + +```php +->setResponseFormat('json_object') +->query('请以有效的 JSON 格式回答,并用简单语言解释量子计算。') +``` + +> ✅ **建议**:为了获得更好的结果,最好也在提示中提供一个 JSON 示例,并强调 “只返回 JSON”。 + + +--- + ### Use with Symfony HttpClient the package already built with `symfony Http client`, if you need to use package with `symfony` Http Client , it is easy to achieve that, just pass `clientType:'symfony'` with `build` function. diff --git a/README.md b/README.md index 6ec9b7e..262f8ca 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,9 @@
GitHub Stars - -[AR](README-AR.md) | [CN](README-CN.md) +

-

+[AR](README-AR.md) | [CN](README-CN.md) ## Table of Contents - [✨ Features](#-features) @@ -29,6 +28,7 @@ - [🚀 Quick Start](#-quick-start) - [Basic Usage](#basic-usage) - [Advanced Configuration](#advanced-configuration) + - [important warning with json mode](#-deepseek-json-mode-requirement) - [Use with Symfony HttpClient](#use-with-symfony-httpclient) - [Get Models List](#get-models-list) - [Function Calling](#function-calling) @@ -100,12 +100,47 @@ $response = $client ->withStream() ->setTemperature(1.2) ->setMaxTokens(8192) + ->setResponseFormat('text') // or "json_object" with careful . ->query('Explain quantum computing in simple terms') ->run(); echo 'API Response:'.$response; ``` +## ⚠️ DeepSeek JSON Mode Requirement + +When using: + +```php +->setResponseFormat('json_object') +``` + +Your prompt **must contain the word `"json"`** in some form. Otherwise, the API will reject the request with the following error: + +> `"Prompt must contain the word 'json' in some form to use 'response_format' of type 'json_object'"` + +--- + +### 🚫 Incorrect Usage + +```php +->setResponseFormat('json_object') +->query('Explain quantum computing in simple terms') +``` + +### ✅ Correct Usage + +```php +->setResponseFormat('json_object') +->query('Respond in valid JSON format. Explain quantum computing in simple terms.') +``` + +> ✅ **Tip**: For best results, also provide a JSON example or explicitly say: +> *"Respond only in valid JSON."* + + +--- + ### Use with Symfony HttpClient the package already built with `symfony Http client`, if you need to use package with `symfony` Http Client , it is easy to achieve that, just pass `clientType:'symfony'` with `build` function. diff --git a/composer.json b/composer.json index e4a48f2..e9e0a67 100644 --- a/composer.json +++ b/composer.json @@ -49,7 +49,7 @@ "role": "creator" } ], - "version": "2.0.5", + "version": "2.0.6", "require": { "php": "^8.1.0", "nyholm/psr7": "^1.8", diff --git a/src/DeepSeekClient.php b/src/DeepSeekClient.php index c44d0cd..62e39f5 100644 --- a/src/DeepSeekClient.php +++ b/src/DeepSeekClient.php @@ -50,6 +50,7 @@ class DeepSeekClient implements ClientContract protected float $temperature; protected int $maxTokens; + protected string $responseFormatType; /** * response result contract @@ -81,6 +82,7 @@ public function __construct(ClientInterface $httpClient) $this->endpointSuffixes = EndpointSuffixes::CHAT->value; $this->temperature = (float) TemperatureValues::GENERAL_CONVERSATION->value; $this->maxTokens = (int) TemperatureValues::MAX_TOKENS->value; + $this->responseFormatType = TemperatureValues::RESPONSE_FORMAT_TYPE->value; $this->tools = null; } @@ -93,6 +95,9 @@ public function run(): string QueryFlags::TEMPERATURE->value => $this->temperature, QueryFlags::MAX_TOKENS->value => $this->maxTokens, QueryFlags::TOOLS->value => $this->tools, + QueryFlags::RESPONSE_FORMAT->value => [ + 'type' => $this->responseFormatType + ], ]; $this->setResult((new Resource($this->httpClient, $this->endpointSuffixes))->sendRequest($requestData, $this->requestMethod)); @@ -192,6 +197,12 @@ public function setMaxTokens(int $maxTokens): self return $this; } + public function setResponseFormat(string $type): self + { + $this->responseFormatType = $type; + return $this; + } + public function buildQuery(string $content, ?string $role = null): array { return [ diff --git a/src/Enums/Configs/TemperatureValues.php b/src/Enums/Configs/TemperatureValues.php index b9b9a93..c09d315 100644 --- a/src/Enums/Configs/TemperatureValues.php +++ b/src/Enums/Configs/TemperatureValues.php @@ -13,4 +13,5 @@ enum TemperatureValues: string case CREATIVE_WRITING = "1.5"; case POETRY = "1.6"; case MAX_TOKENS = "4096"; + case RESPONSE_FORMAT_TYPE = "text"; } diff --git a/src/Enums/Requests/QueryFlags.php b/src/Enums/Requests/QueryFlags.php index 2b4b557..29e2586 100644 --- a/src/Enums/Requests/QueryFlags.php +++ b/src/Enums/Requests/QueryFlags.php @@ -10,4 +10,5 @@ enum QueryFlags: string case TEMPERATURE = 'temperature'; case MAX_TOKENS = 'max_tokens'; case TOOLS = 'tools'; + case RESPONSE_FORMAT = 'response_format'; }