diff --git a/src/Contracts/DeepseekClientContract.php b/src/Contracts/DeepseekClientContract.php index 7ea06b9..c0044bb 100644 --- a/src/Contracts/DeepseekClientContract.php +++ b/src/Contracts/DeepseekClientContract.php @@ -2,9 +2,11 @@ namespace DeepSeek\Contracts; +use DeepSeek\DeepSeekClientOptions; + interface DeepseekClientContract { - public static function build(string $apiKey): self; + public static function build(DeepSeekClientOptions $options): self; public function run(): string; public function query(string $content, ?string $role = "user"): self; public function withModel(?string $model = null): self; diff --git a/src/Contracts/Factories/ApiFactoryContract.php b/src/Contracts/Factories/ApiFactoryContract.php deleted file mode 100644 index 80c9c53..0000000 --- a/src/Contracts/Factories/ApiFactoryContract.php +++ /dev/null @@ -1,47 +0,0 @@ -httpClient = $httpClient; - $this->model = null; - $this->stream = false; - $this->temperature = (float) TemperatureValues::GENERAL_CONVERSATION->value; - } - - public function run(): string - { - $requestData = [ - QueryFlags::MESSAGES->value => $this->queries, - QueryFlags::MODEL->value => $this->model, - QueryFlags::STREAM->value => $this->stream, - QueryFlags::TEMPERATURE->value => $this->temperature, - ]; - // Clear queries after sending - $this->queries = []; - $this->result = (new Resource($this->httpClient))->sendRequest($requestData); - return $this->getResult()->getContent(); + $this->clientOptions = $options ?? new DeepSeekClientOptions(); + $this->queryOptions = new DeepSeekQueryOptions(); } /** - * Create a new DeepSeekClient instance with the given API key. + * Create a new DeepSeekClient instance with a given options. * - * @param string $apiKey The API key for authentication. - * @param string|null $baseUrl The base URL for the API (optional). - * @param int|null $timeout The timeout duration for requests in seconds (optional). + * @param DeepSeekClientOptions $options A client options. * @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(DeepSeekClientOptions $options): self { - $httpClient = ApiFactory::build() - ->setBaseUri($baseUrl) - ->setTimeout($timeout) - ->setKey($apiKey) - ->run(); + $httpClient = DefaultHttpClientFactory::getInstance()->createClient("DeepSeekClient"); - return new self($httpClient); + $httpClient->baseAddress = DefaultConfigs::BASE_URL->value; + $httpClient->timeout = $options->timeout ?? (int)DefaultConfigs::TIMEOUT->value; + $httpClient->headers = [ + HeaderFlags::AUTHORIZATION->value => 'Bearer ' . $options->apiKey, + HeaderFlags::CONTENT_TYPE->value => "application/json", + ]; + + return new self($httpClient, $options); } /** @@ -106,56 +52,72 @@ 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"): IDeepSeekQuery { - $this->queries[] = $this->buildQuery($content, $role); + $this->query[] = [ + 'role' => $role, + 'content' => $content + ]; + return $this; } /** * Set the model to be used for API requests. * - * @param string|null $model The model name (optional). + * @param string $model The model name (optional). * @return self The current instance for method chaining. */ - public function withModel(?string $model = null): self + public function withModel(string $model): IDeepSeekQuery { - $this->model = $model; + $this->queryOptions->model = $model; + return $this; } /** * Enable or disable streaming for API responses. * - * @param bool $stream Whether to enable streaming (default: true). + * @param bool $stream Whether to enable streaming. * @return self The current instance for method chaining. */ - public function withStream(bool $stream = true): self + public function withStream(bool $stream): IDeepSeekQuery { - $this->stream = $stream; + $this->queryOptions->stream = $stream; + return $this; } - public function setTemperature(float $temperature): self + public function withTemperature(float $temperature): IDeepSeekQuery { - $this->temperature = $temperature; + $this->queryOptions->temperature = $temperature; + return $this; } - protected function buildQuery(string $content, ?string $role = null): array + public function run(): ResultContract { - return [ - 'role' => $role ?: QueryRoles::USER->value, - 'content' => $content - ]; + $queryRunner = new DeepSeekQueryRunner($this->httpClient, $this->getQueryOptions()); + $result = $queryRunner->run($this->query); + + // Clear queries after sending + $this->query = []; + + return $result; } - /** - * response result model - * @return \DeepSeek\Contracts\Models\ResultContract - */ - public function getResult(): ResultContract + public function getClientOptions(): DeepSeekClientOptions + { + return $this->clientOptions; + } + + public function getHttpClient(): HttpClient + { + return $this->httpClient; + } + + public function getQueryOptions(): DeepSeekQueryOptions { - return $this->result; + return $this->queryOptions; } } diff --git a/src/DeepSeekClientOptions.php b/src/DeepSeekClientOptions.php new file mode 100644 index 0000000..e536a0e --- /dev/null +++ b/src/DeepSeekClientOptions.php @@ -0,0 +1,17 @@ +timeout = (int)DefaultConfigs::TIMEOUT->value; + } + + public int $timeout; + + public string $apiKey; +} \ No newline at end of file diff --git a/src/DeepSeekQueryOptions.php b/src/DeepSeekQueryOptions.php new file mode 100644 index 0000000..7df62c7 --- /dev/null +++ b/src/DeepSeekQueryOptions.php @@ -0,0 +1,21 @@ +model = null; + $this->stream = true; + $this->temperature = (float)TemperatureValues::GENERAL_CONVERSATION->value; + } + + public ?string $model; + + public bool $stream; + + public float $temperature; +} \ No newline at end of file diff --git a/src/DeepSeekQueryRunner.php b/src/DeepSeekQueryRunner.php new file mode 100644 index 0000000..4717fd2 --- /dev/null +++ b/src/DeepSeekQueryRunner.php @@ -0,0 +1,32 @@ +httpClient = $httpClient; + $this->queryOptions = $queryOptions; + } + + public function run(array $query): ResultContract + { + $requestData = [ + QueryFlags::MESSAGES->value => $query, + QueryFlags::MODEL->value => $this->queryOptions->model, + QueryFlags::STREAM->value => $this->queryOptions->stream, + QueryFlags::TEMPERATURE->value => $this->queryOptions->temperature + ]; + + return (new Resource($this->httpClient->getInternalClient()))->sendRequest($requestData); + } +} \ No newline at end of file diff --git a/src/Factories/ApiFactory.php b/src/Factories/ApiFactory.php deleted file mode 100644 index d3b9c99..0000000 --- a/src/Factories/ApiFactory.php +++ /dev/null @@ -1,106 +0,0 @@ -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 - { - $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", - ], - ]; - - return new Client($clientConfig); - } -} diff --git a/src/Http/HttpClient.php b/src/Http/HttpClient.php new file mode 100644 index 0000000..ac9eb3f --- /dev/null +++ b/src/Http/HttpClient.php @@ -0,0 +1,38 @@ +headers = []; + } + + public string $baseAddress; + + public int $timeout; + + public array $headers; + + public function getInternalClient() : ClientInterface { + if (isNull($this->client)) { + $clientConfig = [ + HeaderFlags::BASE_URL->value => $this->baseAddress, + HeaderFlags::TIMEOUT->value => $this->timeout, + HeaderFlags::HEADERS->value => $this->headers + ]; + + $this->client = new Client($clientConfig); + } + + return $this->client; + } +} \ No newline at end of file diff --git a/src/Http/HttpClientFactory.php b/src/Http/HttpClientFactory.php new file mode 100644 index 0000000..b588b6c --- /dev/null +++ b/src/Http/HttpClientFactory.php @@ -0,0 +1,13 @@ +baseAddress = $baseAddress; + + return $client; + } +} \ No newline at end of file diff --git a/src/IDeepSeekClient.php b/src/IDeepSeekClient.php new file mode 100644 index 0000000..015d130 --- /dev/null +++ b/src/IDeepSeekClient.php @@ -0,0 +1,12 @@ +clientOptions = new DeepSeekClientOptions(); + } + + protected string $apiKey; + protected string $expiredApiKey; protected function setUp():void { $this->apiKey = "valid-api-key"; @@ -17,38 +26,41 @@ protected function setUp():void } 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->clientOptions->apiKey = $this->apiKey; - $this->assertNotEmpty($response); + $query = DeepSeekClient::build($this->clientOptions) + ->query('Hello DeepSeek, how are you today?') + ->withTemperature(1.5); + + $result = $query->run(); + + $this->assertNotEmpty($result); $this->assertEquals(HTTPState::OK->value, $result->getStatusCode()); } public function test_can_not_access_with_api_expired_payment() { - $deepseek = DeepSeekClient::build($this->expiredApiKey) + $this->clientOptions->apiKey = $this->expiredApiKey; + + $query = DeepSeekClient::build($this->clientOptions) ->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()); - } + ->withTemperature(1.5); + + $result = $query->run(); + + $this->assertNotEmpty($result); + $this->assertEquals(HTTPState::PAYMENT_REQUIRED->value, $result->getStatusCode()); } public function test_access_with_wrong_api_key() { - $deepseek = DeepSeekClient::build($this->apiKey."wrong-api-key") + $this->clientOptions->apiKey = "wrong-api-key"; + + $query = DeepSeekClient::build($this->clientOptions) ->query('Hello Deepseek, how are you today?') - ->setTemperature(1.5); - $response = $deepseek->run(); - $result = $deepseek->getResult(); + ->withTemperature(1.5); + + $result = $query->run(); - $this->assertNotEmpty($response); + $this->assertNotEmpty($result); $this->assertEquals(HTTPState::UNAUTHORIZED->value, $result->getStatusCode()); } }