Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 23 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

![Grok PHP Client](assets/images/grok-client.png)

**A lightweight, framework-agnostic PHP client for interacting with Grok AI APIs.**
**A lightweight, framework-agnostic PHP client for interacting with Grok AI APIs.**
Supports **PHP 8.2+**, built with **OOP best practices**, and **fully type-safe**.

[![Latest Version](https://img.shields.io/packagist/v/grok-php/client)](https://packagist.org/packages/grok-php/client)
Expand All @@ -22,6 +22,7 @@ Supports **PHP 8.2+**, built with **OOP best practices**, and **fully type-safe*
- [Advanced Configuration](#advanced-configuration)
- [Available Grok AI Models](#available-grok-ai-models)
- [Streaming Responses](#streaming-responses)
- [Response format](#response-format)
- [Error Handling](#error-handling)
- [Testing](#testing)
- [Security](#security)
Expand All @@ -34,10 +35,10 @@ Supports **PHP 8.2+**, built with **OOP best practices**, and **fully type-safe*

![Grok PHP Client Demo](assets/images/demo.gif)

- **Easy Integration** – Seamlessly connects with Grok AI APIs.
- **Modern PHP Features** – Utilizes PHP 8.2+ features like enums and traits.
- **Framework Agnostic** – Works with any PHP project, CLI scripts, or web applications.
- **Streaming Support** – Built-in support for real-time responses.
- **Easy Integration** – Seamlessly connects with Grok AI APIs.
- **Modern PHP Features** – Utilizes PHP 8.2+ features like enums and traits.
- **Framework Agnostic** – Works with any PHP project, CLI scripts, or web applications.
- **Streaming Support** – Built-in support for real-time responses.
- **Lightweight & Efficient** – Optimized with PSR-4 autoloading and minimal dependencies.

---
Expand Down Expand Up @@ -139,7 +140,7 @@ $messages = [
// Custom API settings
$options = new ChatOptions(
model: Model::GROK_2_LATEST,
temperature: 1.2,
temperature: 1.2,
stream: false
);

Expand All @@ -151,8 +152,8 @@ echo "AI Says: " . $response['choices'][0]['message']['content'];

## **Available Grok AI Models**

Grok AI offers multiple models optimized for different use cases.
These models are available in the `Model` enum inside our package:
Grok AI offers multiple models optimized for different use cases.
These models are available in the `Model` enum inside our package:
📄 `src/Enums/Model.php`

| Model Enum | API Model Name | Description |
Expand All @@ -172,7 +173,7 @@ These models are available in the `Model` enum inside our package:

## **Streaming Responses**

The Grok API supports streaming responses for real-time interaction.
The Grok API supports streaming responses for real-time interaction.
Enable it by setting `stream: true`:

```php
Expand All @@ -183,9 +184,20 @@ Streaming can be useful for chatbots, real-time applications, and CLI assistants

---

## **Response format**

The Grok API supports setting a response format, also refered to structured outputs, for the `grok-2-1212` model.

```php
$options = new ChatOptions(model: Model::GROK_2_1212, temperature: 0.7, stream: false, responseFormat: ['type' => 'json_object']);
$response = $client->chat($messages, $options);
```

---

## **Error Handling**

This package includes built-in error handling with a dedicated exception class.
This package includes built-in error handling with a dedicated exception class.
Common errors and their messages:

| Error Type | HTTP Code | Message |
Expand Down Expand Up @@ -221,7 +233,7 @@ vendor/bin/phpunit

## **Security**

If you discover a security vulnerability, please report it via email:
If you discover a security vulnerability, please report it via email:
📩 [thefeqy@gmail.com](mailto:thefeqy@gmail.com)

---
Expand Down
1 change: 1 addition & 0 deletions src/Clients/GrokClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public function chat(array $messages, ChatOptions $options): array
'messages' => $messages,
'temperature' => $options->temperature,
'stream' => $options->stream,
'response_format' => $options->responseFormat,
]);
}

Expand Down
7 changes: 6 additions & 1 deletion src/Config/ChatOptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,21 @@ class ChatOptions

public bool $stream;

public ?array $responseFormat;

public function __construct(
?Model $model = null,
?float $temperature = null,
?bool $stream = null
?bool $stream = null,
?array $responseFormat = null
) {

$this->model = $model ?: Model::tryFrom(DefaultConfig::MODEL->value) ?: Model::GROK_2;

$this->temperature = $temperature ?? (float) DefaultConfig::TEMPERATURE->value;

$this->stream = $stream ?? filter_var(DefaultConfig::STREAMING->value, FILTER_VALIDATE_BOOLEAN);

$this->responseFormat = $responseFormat ? (array) $responseFormat : null;
}
}
4 changes: 2 additions & 2 deletions src/Testing/ClientFake.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class ClientFake
*
* @throws JsonException
*/
public static function fakeSuccessResponse(): Response
public static function fakeSuccessResponse(?array $data = null): Response
{
return new Response(200, ['Content-Type' => 'application/json'], json_encode([
'id' => '7c51076a-e4cc-4855-8dbe-66c26818e35f',
Expand All @@ -24,7 +24,7 @@ public static function fakeSuccessResponse(): Response
'index' => 0,
'message' => [
'role' => 'assistant',
'content' => json_encode([
'content' => json_encode($data ?? [
'framework_name' => 'Laravel',
'release_date' => '2011',
'programming_language' => 'PHP',
Expand Down
26 changes: 26 additions & 0 deletions tests/Feature/GrokClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,30 @@ public function test_chat_request_returns_response(): void
$this->assertSame('2011', $decodedContent['release_date']);
$this->assertSame('PHP', $decodedContent['programming_language']);
}

public function test_chat_request_returns_response_in_specific_format(): void
{
$this->client->setHttpClient(new Client(['handler' => HandlerStack::create(new MockHandler([
ClientFake::fakeSuccessResponse([
'name' => 'Taylor',
'city' => 'Little Rock'
]),
]))]));

$messages = [
['role' => 'system', 'content' => 'You are a helpful assistant.'],
['role' => 'user', 'content' => 'Return a json object with a random name (string) and random city (string).'],
];

$options = new ChatOptions(model: Model::GROK_2_1212, temperature: 0.7, stream: false, responseFormat: ['type' => 'json_object']);
$response = $this->client->chat($messages, $options);
$content = $response['choices'][0]['message']['content'];
$decodedContent = json_decode($response['choices'][0]['message']['content'], true, 512, JSON_THROW_ON_ERROR);

$this->assertJson($content);
$this->assertArrayHasKey('name', $decodedContent);
$this->assertArrayHasKey('city', $decodedContent);
$this->assertSame('Taylor', $decodedContent['name']);
$this->assertSame('Little Rock', $decodedContent['city']);
}
}