Skip to content

Commit dfc28dc

Browse files
authored
Merge pull request #38 from deepseek-php/support-many-http-clients
support many http clients (Guzzle & Symfony)
2 parents dea86c5 + 5e7a482 commit dfc28dc

File tree

7 files changed

+124
-112
lines changed

7 files changed

+124
-112
lines changed

README.md

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
- [🚀 Quick Start](#-quick-start)
2525
- [Basic Usage](#basic-usage)
2626
- [Advanced Configuration](#advanced-configuration)
27+
- [Use with Symfony HttpClient](#use-with-symfony-httpclient)
2728
- [Get Models List](#get-models-list)
2829
- [Framework Integration](#-framework-integration)
2930
- [🆕 Migration Guide](#-migration-guide)
@@ -37,12 +38,13 @@
3738

3839
## ✨ Features
3940

40-
- **Seamless API Integration**: PHP-first interface for DeepSeek's AI capabilities
41-
- **Fluent Builder Pattern**: Chainable methods for intuitive request building
42-
- **Enterprise Ready**: PSR-18 compliant HTTP client integration
43-
- **Model Flexibility**: Support for multiple DeepSeek models (Coder, Chat, etc.)
44-
- **Streaming Ready**: Built-in support for real-time response handling
45-
- **Framework Friendly**: Laravel & Symfony packages available
41+
- **Seamless API Integration**: PHP-first interface for DeepSeek's AI capabilities.
42+
- **Fluent Builder Pattern**: Chainable methods for intuitive request building.
43+
- **Enterprise Ready**: PSR-18 compliant HTTP client integration.
44+
- **Model Flexibility**: Support for multiple DeepSeek models (Coder, Chat, etc.).
45+
- **Streaming Ready**: Built-in support for real-time response handling.
46+
- **Many Http Clients**: easy to use `Guzzle http client` (default) , or `symfony http client`.
47+
- **Framework Friendly**: Laravel & Symfony packages available.
4648

4749
---
4850

@@ -85,15 +87,32 @@ echo $response;
8587
use DeepSeek\DeepSeekClient;
8688
use DeepSeek\Enums\Models;
8789

88-
$response = DeepSeekClient::build('your-api-key')
89-
->withBaseUrl('https://api.deepseek.com/v2')
90+
$client = DeepSeekClient::build(apiKey:'your-api-key', baseUrl:'https://api.deepseek.com/v3', timeout:30, clientType:'guzzle');
91+
92+
$response = $client
9093
->withModel(Models::CODER->value)
94+
->withStream()
9195
->withTemperature(1.2)
9296
->run();
9397

9498
echo 'API Response:'.$response;
9599
```
96100

101+
### Use with Symfony HttpClient
102+
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.
103+
104+
ex with symfony:
105+
106+
```php
107+
// with defaults baseUrl and timeout
108+
$client = DeepSeekClient::build('your-api-key', clientType:'symfony')
109+
// with customization
110+
$client = DeepSeekClient::build(apiKey:'your-api-key', baseUrl:'https://api.deepseek.com/v3', timeout:30, 'symfony');
111+
112+
$client->query('Explain quantum computing in simple terms')
113+
->run();
114+
```
115+
97116
### Get Models List
98117

99118
```php
@@ -110,8 +129,6 @@ echo $response; // {"object":"list","data":[{"id":"deepseek-chat","object":"mode
110129

111130
### [Laravel Deepseek Package](https://github.com/deepseek-php/deepseek-laravel)
112131

113-
### [Symfony Deepseek Package](https://github.com/deepseek-php/deepseek-symfony)
114-
115132
---
116133

117134
## 🚧 Migration Guide

composer.json

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,15 @@
77
"sdk",
88
"api",
99
"php",
10+
"symfony",
1011
"client",
1112
"llm",
1213
"nlp",
1314
"openai",
14-
"qwen",
15+
"symfony-deepseek",
16+
"deepseek-symfony",
17+
"symfony-http-client",
18+
"symfony-client",
1519
"machine-learning",
1620
"php-sdk",
1721
"ai-sdk",
@@ -45,15 +49,17 @@
4549
"role": "creator"
4650
}
4751
],
48-
"version": "2.0.1",
52+
"version": "2.0.2",
4953
"require": {
5054
"php": "^8.1.0",
55+
"nyholm/psr7": "^1.8",
5156
"php-http/discovery": "^1.20.0",
5257
"php-http/multipart-stream-builder": "^1.4.2",
5358
"psr/http-client": "^1.0.3",
5459
"psr/http-client-implementation": "^1.0.1",
5560
"psr/http-factory-implementation": "*",
56-
"psr/http-message": "^1.1.0|^2.0.0"
61+
"psr/http-message": "^1.1.0|^2.0.0",
62+
"symfony/http-client": "^7.2"
5763
},
5864
"require-dev": {
5965
"guzzlehttp/guzzle": "^7.9.2",

src/Contracts/Factories/ApiFactoryContract.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use DeepSeek\Factories\ApiFactory;
66
use GuzzleHttp\Client;
7+
use Psr\Http\Client\ClientInterface;
78

89
interface ApiFactoryContract
910
{
@@ -39,9 +40,9 @@ public function setKey(string $apiKey): ApiFactory;
3940
public function setTimeout(?int $timeout = null): ApiFactory;
4041

4142
/**
42-
* Build and return the Guzzle Client instance.
43+
* Build and return http Client instance.
4344
*
44-
* @return Client
45+
* @return ClientInterface
4546
*/
46-
public function run(): Client;
47+
public function run(?string $clientType = null): ClientInterface;
4748
}

src/DeepSeekClient.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use DeepSeek\Contracts\ClientContract;
66
use DeepSeek\Contracts\Models\ResultContract;
7+
use DeepSeek\Enums\Requests\ClientTypes;
78
use DeepSeek\Enums\Requests\EndpointSuffixes;
89
use DeepSeek\Resources\Resource;
910
use Psr\Http\Client\ClientInterface;
@@ -94,13 +95,15 @@ public function run(): string
9495
* @param int|null $timeout The timeout duration for requests in seconds (optional).
9596
* @return self A new instance of the DeepSeekClient.
9697
*/
97-
public static function build(string $apiKey, ?string $baseUrl = null, ?int $timeout = null): self
98+
public static function build(string $apiKey, ?string $baseUrl = null, ?int $timeout = null, ?string $clientType = null): self
9899
{
100+
$clientType = $clientType ?? ClientTypes::GUZZLE->value;
101+
99102
$httpClient = ApiFactory::build()
100103
->setBaseUri($baseUrl)
101104
->setTimeout($timeout)
102105
->setKey($apiKey)
103-
->run();
106+
->run($clientType);
104107

105108
return new self($httpClient);
106109
}

src/Enums/Requests/ClientTypes.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace DeepSeek\Enums\Requests;
4+
5+
enum ClientTypes: string
6+
{
7+
case GUZZLE = 'guzzle';
8+
case SYMFONY = 'symfony';
9+
10+
}

src/Factories/ApiFactory.php

Lines changed: 39 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,103 +4,83 @@
44

55
use DeepSeek\Contracts\Factories\ApiFactoryContract;
66
use DeepSeek\Enums\Configs\DefaultConfigs;
7+
use DeepSeek\Enums\Requests\ClientTypes;
78
use DeepSeek\Enums\Requests\HeaderFlags;
89
use GuzzleHttp\Client;
10+
use Psr\Http\Client\ClientInterface;
11+
use Symfony\Component\HttpClient\HttpClient;
12+
use Symfony\Component\HttpClient\Psr18Client;
13+
use RuntimeException;
14+
use InvalidArgumentException;
915

1016
final class ApiFactory implements ApiFactoryContract
1117
{
12-
/**
13-
* The API key for authentication.
14-
*
15-
* @var string
16-
*/
1718
protected string $apiKey;
18-
19-
/**
20-
* The base URL for the API.
21-
*
22-
* @var string
23-
*/
2419
protected string $baseUrl;
25-
26-
/**
27-
* The timeout value for the API request in seconds.
28-
*
29-
* @var int
30-
*/
3120
protected int $timeout;
21+
protected array $clientConfig;
3222

33-
/**
34-
* Returns an instance of the ApiFactory.
35-
*
36-
* This is a static factory method that creates a new instance of the class.
37-
*
38-
* @return self A new instance of the ApiFactory.
39-
*/
4023
public static function build(): self
4124
{
42-
return new self;
25+
return new self();
4326
}
4427

45-
/**
46-
* Set the base URL for the API.
47-
*
48-
* If no URL is provided, the default base URL from the configuration is used.
49-
*
50-
* @param string|null $baseUrl The base URL to set (optional).
51-
* @return self The instance of the self for method chaining.
52-
*/
5328
public function setBaseUri(?string $baseUrl = null): self
5429
{
5530
$this->baseUrl = $baseUrl ? trim($baseUrl) : DefaultConfigs::BASE_URL->value;
5631
return $this;
5732
}
5833

59-
/**
60-
* Set the API key for authentication.
61-
*
62-
* @param string $apiKey The API key to set.
63-
* @return self The instance of the self for method chaining.
64-
*/
6534
public function setKey(string $apiKey): self
6635
{
6736
$this->apiKey = trim($apiKey);
6837
return $this;
6938
}
7039

71-
/**
72-
* Set the timeout for the API request.
73-
*
74-
* If no timeout is provided, the default timeout value from the configuration is used.
75-
*
76-
* @param int|null $timeout The timeout value in seconds (optional).
77-
* @return self The instance of the self for method chaining.
78-
*/
7940
public function setTimeout(?int $timeout = null): self
8041
{
8142
$this->timeout = $timeout ?: (int)DefaultConfigs::TIMEOUT->value;
8243
return $this;
8344
}
8445

85-
/**
86-
* Build and return the Guzzle Client instance.
87-
*
88-
* This method creates and configures a new Guzzle HTTP client instance
89-
* using the provided base URL, timeout, and headers.
90-
*
91-
* @return Client A Guzzle client instance configured for the API.
92-
*/
93-
public function run(): Client
46+
public function initialize(): self
9447
{
95-
$clientConfig = [
48+
if (!isset($this->baseUrl)) {
49+
$this->setBaseUri();
50+
}
51+
52+
if (!isset($this->apiKey)) {
53+
throw new RuntimeException('API key must be set using setKey() before initialization.');
54+
}
55+
56+
if (!isset($this->timeout)) {
57+
$this->setTimeout();
58+
}
59+
60+
$this->clientConfig = [
9661
HeaderFlags::BASE_URL->value => $this->baseUrl,
9762
HeaderFlags::TIMEOUT->value => $this->timeout,
9863
HeaderFlags::HEADERS->value => [
9964
HeaderFlags::AUTHORIZATION->value => 'Bearer ' . $this->apiKey,
100-
HeaderFlags::CONTENT_TYPE->value => "application/json",
65+
HeaderFlags::CONTENT_TYPE->value => 'application/json',
10166
],
10267
];
10368

104-
return new Client($clientConfig);
69+
return $this;
70+
}
71+
72+
public function run(?string $clientType = null): ClientInterface
73+
{
74+
$clientType = $clientType ?? ClientTypes::GUZZLE->value;
75+
76+
if (!isset($this->clientConfig)) {
77+
$this->initialize();
78+
}
79+
80+
return match (strtolower($clientType)) {
81+
ClientTypes::GUZZLE->value => new Client($this->clientConfig),
82+
ClientTypes::SYMFONY->value => new Psr18Client(HttpClient::create($this->clientConfig)),
83+
default => throw new InvalidArgumentException("Unsupported client type: {$clientType}")
84+
};
10585
}
10686
}

0 commit comments

Comments
 (0)