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
52 changes: 40 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ _This library is not developed or endorsed by Google._
- [Tokens counting](#tokens-counting)
- [Listing models](#listing-models)
- [Advanced Usages](#advanced-usages)
- [Using Beta version](#using-beta-version)
- [Safety Settings and Generation Configuration](#safety-settings-and-generation-configuration)
- [Using your own HTTP client](#using-your-own-http-client)
- [Using your own HTTP client for streaming responses](#using-your-own-http-client-for-streaming-responses)
Expand All @@ -52,10 +53,11 @@ you need to allow `php-http/discovery` composer plugin or install a PSR-18 compa

```php
use GeminiAPI\Client;
use GeminiAPI\Resources\ModelName;
use GeminiAPI\Resources\Parts\TextPart;

$client = new Client('GEMINI_API_KEY');
$response = $client->geminiPro()->generateContent(
$response = $client->generativeModel(ModelName::GEMINI_PRO)->generateContent(
new TextPart('PHP in less than 100 chars'),
);

Expand All @@ -71,11 +73,12 @@ print $response->text();
```php
use GeminiAPI\Client;
use GeminiAPI\Enums\MimeType;
use GeminiAPI\Resources\ModelName;
use GeminiAPI\Resources\Parts\ImagePart;
use GeminiAPI\Resources\Parts\TextPart;

$client = new Client('GEMINI_API_KEY');
$response = $client->geminiProVision()->generateContent(
$response = $client->generativeModel(ModelName::GEMINI_PRO)->generateContent(
new TextPart('Explain what is in the image'),
new ImagePart(
MimeType::IMAGE_JPEG,
Expand All @@ -94,10 +97,11 @@ print $response->text();

```php
use GeminiAPI\Client;
use GeminiAPI\Resources\ModelName;
use GeminiAPI\Resources\Parts\TextPart;

$client = new Client('GEMINI_API_KEY');
$chat = $client->geminiPro()->startChat();
$chat = $client->generativeModel(ModelName::GEMINI_PRO)->startChat();

$response = $chat->sendMessage(new TextPart('Hello World in PHP'));
print $response->text();
Expand Down Expand Up @@ -132,6 +136,7 @@ This code will print "Hello World!" to the standard output.
use GeminiAPI\Client;
use GeminiAPI\Enums\Role;
use GeminiAPI\Resources\Content;
use GeminiAPI\Resources\ModelName;
use GeminiAPI\Resources\Parts\TextPart;

$history = [
Expand All @@ -149,7 +154,7 @@ $history = [
];

$client = new Client('GEMINI_API_KEY');
$chat = $client->geminiPro()
$chat = $client->generativeModel(ModelName::GEMINI_PRO)
->startChat()
->withHistory($history);

Expand Down Expand Up @@ -179,6 +184,7 @@ Long responses may be broken into separate responses, and you can start receivin

```php
use GeminiAPI\Client;
use GeminiAPI\Resources\ModelName;
use GeminiAPI\Resources\Parts\TextPart;
use GeminiAPI\Responses\GenerateContentResponse;

Expand All @@ -191,7 +197,7 @@ $callback = function (GenerateContentResponse $response): void {
};

$client = new Client('GEMINI_API_KEY');
$client->geminiPro()->generateContentStream(
$client->generativeModel(ModelName::GEMINI_PRO)->generateContentStream(
$callback,
[new TextPart('PHP in less than 100 chars')],
);
Expand All @@ -209,6 +215,7 @@ $client->geminiPro()->generateContentStream(
use GeminiAPI\Client;
use GeminiAPI\Enums\Role;
use GeminiAPI\Resources\Content;
use GeminiAPI\Resources\ModelName;
use GeminiAPI\Resources\Parts\TextPart;
use GeminiAPI\Responses\GenerateContentResponse;

Expand All @@ -235,7 +242,7 @@ $callback = function (GenerateContentResponse $response): void {
};

$client = new Client('GEMINI_API_KEY');
$chat = $client->geminiPro()
$chat = $client->generativeModel(ModelName::GEMINI_PRO)
->startChat()
->withHistory($history);

Expand All @@ -261,11 +268,11 @@ This code will print "Hello World!" to the standard output.

```php
use GeminiAPI\Client;
use GeminiAPI\Enums\ModelName;
use GeminiAPI\Resources\ModelName;
use GeminiAPI\Resources\Parts\TextPart;

$client = new Client('GEMINI_API_KEY');
$response = $client->embeddingModel(ModelName::Embedding)
$response = $client->embeddingModel(ModelName::EMBEDDING_001)
->embedContent(
new TextPart('PHP in less than 100 chars'),
);
Expand All @@ -282,10 +289,11 @@ print_r($response->embedding->values);

```php
use GeminiAPI\Client;
use GeminiAPI\Resources\ModelName;
use GeminiAPI\Resources\Parts\TextPart;

$client = new Client('GEMINI_API_KEY');
$response = $client->geminiPro()->countTokens(
$response = $client->generativeModel(ModelName::GEMINI_PRO)->countTokens(
new TextPart('PHP in less than 100 chars'),
);

Expand Down Expand Up @@ -322,13 +330,31 @@ print_r($response->models);

### Advanced Usages

#### Using Beta version

```php
use GeminiAPI\Client;
use GeminiAPI\Resources\ModelName;
use GeminiAPI\Resources\Parts\TextPart;

$client = (new Client('GEMINI_API_KEY'))
->withV1BetaVersion();
$response = $client->generativeModel(ModelName::GEMINI_PRO)->countTokens(
new TextPart('PHP in less than 100 chars'),
);

print $response->totalTokens;
// 10
```

#### Safety Settings and Generation Configuration

```php
use GeminiAPI\Client;
use GeminiAPI\Enums\HarmCategory;
use GeminiAPI\Enums\HarmBlockThreshold;
use GeminiAPI\GenerationConfig;
use GeminiAPI\Resources\ModelName;
use GeminiAPI\Resources\Parts\TextPart;
use GeminiAPI\SafetySetting;

Expand All @@ -345,7 +371,7 @@ $generationConfig = (new GenerationConfig())
->withStopSequences(['STOP']);

$client = new Client('GEMINI_API_KEY');
$response = $client->geminiPro()
$response = $client->generativeModel(ModelName::GEMINI_PRO)
->withAddedSafetySetting($safetySetting)
->withGenerationConfig($generationConfig)
->generateContent(
Expand All @@ -357,6 +383,7 @@ $response = $client->geminiPro()

```php
use GeminiAPI\Client as GeminiClient;
use GeminiAPI\Resources\ModelName;
use GeminiAPI\Resources\Parts\TextPart;
use GuzzleHttp\Client as GuzzleClient;

Expand All @@ -365,7 +392,7 @@ $guzzle = new GuzzleClient([
]);

$client = new GeminiClient('GEMINI_API_KEY', $guzzle);
$response = $client->geminiPro()->generateContent(
$response = $client->generativeModel(ModelName::GEMINI_PRO)->generateContent(
new TextPart('PHP in less than 100 chars')
);
```
Expand All @@ -388,6 +415,7 @@ You can also pass the headers you want to be used in the requests.

```php
use GeminiAPI\Client;
use GeminiAPI\Resources\ModelName;
use GeminiAPI\Resources\Parts\TextPart;
use GeminiAPI\Responses\GenerateContentResponse;

Expand All @@ -402,7 +430,7 @@ $client = new Client('GEMINI_API_KEY');
$client->withRequestHeaders([
'User-Agent' => 'My Gemini-backed app'
])
->geminiPro()
->generativeModel(ModelName::GEMINI_PRO)
->generateContentStream(
$callback,
[new TextPart('PHP in less than 100 chars')],
Expand Down
4 changes: 2 additions & 2 deletions src/ChatSession.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public function sendMessage(PartInterface ...$parts): GenerateContentResponse
->withGenerationConfig($config)
->generateContentWithContents($this->history);

if(!empty($response->candidates)) {
if (!empty($response->candidates)) {
$parts = $response->candidates[0]->content->parts;
$this->history[] = new Content($parts, Role::Model);
}
Expand All @@ -58,7 +58,7 @@ public function sendMessageStream(

$parts = [];
$partsCollectorCallback = function (GenerateContentResponse $response) use ($callback, &$parts) {
if(!empty($response->candidates)) {
if (!empty($response->candidates)) {
array_push($parts, ...$response->parts());
}

Expand Down
36 changes: 31 additions & 5 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
class Client implements GeminiClientInterface
{
private string $baseUrl = 'https://generativelanguage.googleapis.com';
private string $version = GeminiClientInterface::API_VERSION_V1;

/**
* @var array<string, string|string[]>
Expand Down Expand Up @@ -87,15 +88,15 @@ public function geminiProFlash1_5(): GenerativeModel
}


public function generativeModel(ModelName $modelName): GenerativeModel
public function generativeModel(ModelName|string $modelName): GenerativeModel
{
return new GenerativeModel(
$this,
$modelName,
);
}

public function embeddingModel(ModelName $modelName): EmbeddingModel
public function embeddingModel(ModelName|string $modelName): EmbeddingModel
{
return new EmbeddingModel(
$this,
Expand Down Expand Up @@ -163,7 +164,7 @@ public function generateContentStream(
}
}

curl_setopt($ch, CURLOPT_URL, "{$this->baseUrl}/v1/{$request->getOperation()}");
curl_setopt($ch, CURLOPT_URL, $this->getRequestUrl($request));
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($request));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headerLines);
Expand Down Expand Up @@ -214,6 +215,19 @@ public function withBaseUrl(string $baseUrl): self
return $clone;
}

public function withV1BetaVersion(): self
{
return $this->withVersion(GeminiClientInterface::API_VERSION_V1_BETA);
}

public function withVersion(string $version): self
{
$clone = clone $this;
$clone->version = $version;

return $clone;
}

/**
* @param array<string, string|string[]> $headers
* @return self
Expand Down Expand Up @@ -241,6 +255,16 @@ private function getRequestHeaders(): array
];
}

private function getRequestUrl(RequestInterface $request): string
{
return sprintf(
'%s/%s/%s',
$this->baseUrl,
$this->version,
$request->getOperation(),
);
}

/**
* @throws ClientExceptionInterface
*/
Expand All @@ -250,9 +274,11 @@ private function doRequest(RequestInterface $request): string
throw new RuntimeException('Missing client or factory for Gemini API operation');
}

$uri = "{$this->baseUrl}/v1/{$request->getOperation()}";
$httpRequest = $this->requestFactory
->createRequest($request->getHttpMethod(), $uri);
->createRequest(
$request->getHttpMethod(),
$this->getRequestUrl($request),
);

foreach ($this->getRequestHeaders() as $name => $value) {
$httpRequest = $httpRequest->withAddedHeader($name, $value);
Expand Down
6 changes: 4 additions & 2 deletions src/ClientInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@
interface ClientInterface
{
public const API_KEY_HEADER_NAME = 'x-goog-api-key';
public const API_VERSION_V1 = 'v1';
public const API_VERSION_V1_BETA = 'v1beta';

public function countTokens(CountTokensRequest $request): CountTokensResponse;
public function generateContent(GenerateContentRequest $request): GenerateContentResponse;
public function embedContent(EmbedContentRequest $request): EmbedContentResponse;
public function generativeModel(ModelName $modelName): GenerativeModel;
public function embeddingModel(ModelName $modelName): EmbeddingModel;
public function generativeModel(ModelName|string $modelName): GenerativeModel;
public function embeddingModel(ModelName|string $modelName): EmbeddingModel;
public function listModels(): ListModelsResponse;
public function withBaseUrl(string $baseUrl): self;

Expand Down
2 changes: 1 addition & 1 deletion src/EmbeddingModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class EmbeddingModel

public function __construct(
private readonly Client $client,
public readonly ModelName $modelName,
public readonly ModelName|string $modelName,
) {
}

Expand Down
3 changes: 3 additions & 0 deletions src/Enums/ModelName.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

namespace GeminiAPI\Enums;

/**
* @deprecated Use constants from GeminiAPI\Resources\ModelName instead
*/
enum ModelName: string
{
case Default = 'models/text-bison-001';
Expand Down
3 changes: 1 addition & 2 deletions src/GenerativeModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace GeminiAPI;

use BadMethodCallException;
use CurlHandle;
use GeminiAPI\Enums\ModelName;
use GeminiAPI\Enums\Role;
Expand All @@ -29,7 +28,7 @@ class GenerativeModel

public function __construct(
private readonly Client $client,
public readonly ModelName $modelName,
public readonly ModelName|string $modelName,
) {
}

Expand Down
Loading
Loading