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
⭐ 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 接口集成
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## 目录
+- [✨ 特性](#-特性)
+- [📦 安装](#-安装)
+- [🚀 快速入门](#-快速入门)
+ - [基本用法](#基本用法)
+ - [高级配置](#高级配置)
+ - [获取模型列表](#获取模型列表)
+ - [框架集成](#-框架集成)
+- [🆕 迁移指南](#-迁移指南)
+- [📝 更新日志](#-更新日志)
+- [🧪 测试](#-测试)
+- [🔒 安全](#-安全)
+- [🤝 贡献者](#-贡献者)
+- [📄 许可](#-许可)
+
+---
+
+## ✨ 特性
+
+- **无缝 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)
+
+---
+
+## 🤝 贡献者
+
+非常感谢为这个项目做出贡献的人! 🎉💖
+
+
+
+**想要贡献?** 查看 [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!
+
+[](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
[](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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## فهرس المحتويات
+- [✨ المميزات](#-المميزات)
+- [📦 التثبيت](#-التثبيت)
+- [🚀 البداية السريعة](#-البداية-السريعة)
+ - [الاستخدام الأساسي](#الاستخدام-الأساسي)
+ - [التكوين المتقدم](#التكوين-المتقدم)
+ - [الاستخدام مع عميل 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) لتكون جزءًا من مجتمعنا المتنامي!
+
+[](https://t.me/deepseek_php_community)
+
+
+### **هيكل القناة** 🏗️
+- 🗨️ **عام** - دردشة يومية
+- 💡 **الأفكار والاقتراحات** - تشكيل مستقبل المجتمع
+- 📢 **الإعلانات والأخبار** - التحديثات والأخبار الرسمية
+- 🚀 **الإصدارات والتحديثات** - تتبع الإصدارات ودعم الترحيل
+- 🐞 **المشاكل وتقارير الأخطاء** - حل مشكلات جماعي
+- 🤝 **طلبات السحب** - التعاون والمراجعة البرمجية
+
+
+
+---
+
+## 🔒 الأمان
+
+**الإبلاغ عن الثغرات**: إلى [omaralwi2010@gmail.com](mailto:omaralwi2010@gmail.com)
+
+---
+
+## 🤝 المساهمين
+
+شكراً جزيلاً لهؤلاء الأشخاص المذهلين الذين ساهموا في هذا المشروع! 🎉💖
+
+
+
+**هل ترغب في المساهمة؟** اطلع على [إرشادات المساهمة](./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
+
+
+ ⭐ 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 @@
+
+[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 @@
+
+[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!
+
+[](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 @@
+
+
+
-
-
+
+
-
-
+
[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
+
+
+
-
+
-
+
-
-
+
+
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
+
-
+
+
+
+
-
+
-
+
-
-
+
+
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 @@
-
-[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';
}