Skip to content

Commit

Permalink
Merge pull request #33 from aydinfatih/main
Browse files Browse the repository at this point in the history
feat: Add batchEmbedContents method to embeddingModel
  • Loading branch information
aydinfatih authored Sep 28, 2024
2 parents 5757f93 + ca170bf commit d329f9c
Show file tree
Hide file tree
Showing 9 changed files with 324 additions and 0 deletions.
60 changes: 60 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,28 @@ $yourApiKey = getenv('YOUR_API_KEY');
$client = Gemini::client($yourApiKey);

$result = $client->geminiPro()->generateContent('Hello');
$result->text(); // Hello! How can I assist you today?

// Custom Model
$result = $client->geminiPro()->generativeModel(model: 'models/gemini-1.5-flash-001');
$result->text(); // Hello! How can I assist you today?


// Enum usage
$result = $client->geminiPro()->generativeModel(model: ModelType::GEMINI_FLASH);
$result->text(); // Hello! How can I assist you today?


// Enum method usage
$result = $client->geminiPro()->generativeModel(
model: ModelType::generateGeminiModel(
variation: ModelVariation::FLASH,
generation: 1.5,
version: "002"
), // models/gemini-1.5-flash-002
);
$result->text(); // Hello! How can I assist you today?

```

If necessary, it is possible to configure and create a separate client.
Expand Down Expand Up @@ -231,6 +251,46 @@ print_r($response->embedding->values);
//]
```

```php
$response = $client
->embeddingModel()
->batchEmbedContents("Bu bir testtir", "Deneme123");

print_r($response->embeddings);
// [
// [0] => Gemini\Data\ContentEmbedding Object
// (
// [values] => Array
// (
// [0] => 0.035855837
// [1] => -0.049537655
// [2] => -0.06834927
// [3] => -0.010445258
// [4] => 0.044641383
// [5] => 0.031156342
// [6] => -0.007810312
// [7] => -0.0106866965
// ...
// ),
// ),
// [1] => Gemini\Data\ContentEmbedding Object
// (
// [values] => Array
// (
// [0] => 0.035855837
// [1] => -0.049537655
// [2] => -0.06834927
// [3] => -0.010445258
// [4] => 0.044641383
// [5] => 0.031156342
// [6] => -0.007810312
// [7] => -0.0106866965
// ...
// ),
// ),
// ]
```

### Models

#### List Models
Expand Down
11 changes: 11 additions & 0 deletions src/Contracts/Resources/EmbeddingModalContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
use Gemini\Data\Blob;
use Gemini\Data\Content;
use Gemini\Enums\TaskType;
use Gemini\Requests\GenerativeModel\EmbedContentRequest;
use Gemini\Responses\GenerativeModel\BatchEmbedContentsResponse;
use Gemini\Responses\GenerativeModel\EmbedContentResponse;

interface EmbeddingModalContract
Expand All @@ -15,4 +17,13 @@ interface EmbeddingModalContract
* @param string|Blob|array<string|Blob>|Content $content
*/
public function embedContent(string|Blob|array|Content $content, ?TaskType $taskType = null, ?string $title = null): EmbedContentResponse;

/**
* Generates multiple embedding vectors from the input Content which consists of a batch of strings represented as EmbedContentRequest objects.
*
* @see https://ai.google.dev/api/embeddings#method:-models.batchembedcontents
*
* @param string|Blob|array<string|Blob>|Content|EmbedContentRequest ...$parts
*/
public function batchEmbedContents(string|Blob|array|Content|EmbedContentRequest ...$parts): BatchEmbedContentsResponse;
}
58 changes: 58 additions & 0 deletions src/Requests/GenerativeModel/BatchEmbedContentRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

namespace Gemini\Requests\GenerativeModel;

use Gemini\Concerns\HasContents;
use Gemini\Data\Blob;
use Gemini\Data\Content;
use Gemini\Enums\Method;
use Gemini\Foundation\Request;
use Gemini\Requests\Concerns\HasJsonBody;

class BatchEmbedContentRequest extends Request
{
use HasContents;
use HasJsonBody;

protected Method $method = Method::POST;

/**
* @param string $model The model's resource name. This serves as an ID for the Model to use.
* @param array<string|Blob|array<string|Blob>|Content|EmbedContentRequest> $parts
*/
public function __construct(
protected readonly string $model,
protected readonly array $parts,
) {}

public function resolveEndpoint(): string
{
return "{$this->model}:batchEmbedContents";
}

/**
* Default body
*
* @return array<string, mixed>
*/
protected function defaultBody(): array
{
return [
'requests' => array_map(
fn (EmbedContentRequest|string|Blob|array|Content $part) => [
'model' => $this->model,
...match (true) {
$part instanceof EmbedContentRequest => $part->body(),
default => (new EmbedContentRequest(
model: $this->model,
part: $part
))->body(),
},
],
$this->parts
),
];
}
}
22 changes: 22 additions & 0 deletions src/Resources/EmbeddingModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
use Gemini\Data\Content;
use Gemini\Enums\ModelType;
use Gemini\Enums\TaskType;
use Gemini\Requests\GenerativeModel\BatchEmbedContentRequest;
use Gemini\Requests\GenerativeModel\EmbedContentRequest;
use Gemini\Responses\GenerativeModel\BatchEmbedContentsResponse;
use Gemini\Responses\GenerativeModel\EmbedContentResponse;
use Gemini\Transporters\DTOs\ResponseDTO;

Expand Down Expand Up @@ -49,4 +51,24 @@ public function embedContent(string|Blob|array|Content $content, ?TaskType $task

return EmbedContentResponse::from($response->data());
}

/**
* Generates multiple embedding vectors from the input Content which consists of a batch of strings represented as EmbedContentRequest objects.
*
* @see https://ai.google.dev/api/embeddings#method:-models.batchembedcontents
*
* @param string|Blob|array<string|Blob>|Content|EmbedContentRequest ...$parts
*/
public function batchEmbedContents(string|Blob|array|Content|EmbedContentRequest ...$parts): BatchEmbedContentsResponse
{
/** @var ResponseDTO<array{ embeddings: array{ array{ values: array<float> } } }> $response */
$response = $this->transporter->request(
request: new BatchEmbedContentRequest(
model: $this->model,
parts: $parts
)
);

return BatchEmbedContentsResponse::from($response->data());
}
}
49 changes: 49 additions & 0 deletions src/Responses/GenerativeModel/BatchEmbedContentsResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace Gemini\Responses\GenerativeModel;

use Gemini\Contracts\ResponseContract;
use Gemini\Data\ContentEmbedding;
use Gemini\Testing\Responses\Concerns\Fakeable;

/**
* https://ai.google.dev/api/rest/v1/models/embedContent#response-body
*/
final class BatchEmbedContentsResponse implements ResponseContract
{
use Fakeable;

/**
* @param array<ContentEmbedding> $embeddings
*/
private function __construct(
public readonly array $embeddings,
) {}

/**
* @param array{ embeddings: array{ array{ values: array<float> } } } $attributes
*/
public static function from(array $attributes): self
{
$embeddings = array_map(
static fn (array $embedding): ContentEmbedding => ContentEmbedding::from($embedding),
$attributes['embeddings'],
);

return new self(
embeddings: $embeddings
);
}

public function toArray(): array
{
return [
'embeddings' => array_map(
static fn (ContentEmbedding $embedding): array => $embedding->toArray(),
$this->embeddings
),
];
}
}
14 changes: 14 additions & 0 deletions src/Testing/Resources/EmbeddingModelTestResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
use Gemini\Data\Blob;
use Gemini\Data\Content;
use Gemini\Enums\TaskType;
use Gemini\Requests\GenerativeModel\EmbedContentRequest;
use Gemini\Resources\EmbeddingModel;
use Gemini\Responses\GenerativeModel\BatchEmbedContentsResponse;
use Gemini\Responses\GenerativeModel\EmbedContentResponse;
use Gemini\Testing\Resources\Concerns\Testable;

Expand All @@ -25,4 +27,16 @@ public function embedContent(Blob|Content|array|string $content, ?TaskType $task
{
return $this->record(method: __FUNCTION__, args: func_get_args(), model: $this->model);
}

/**
* Generates multiple embedding vectors from the input Content which consists of a batch of strings represented as EmbedContentRequest objects.
*
* @see https://ai.google.dev/api/embeddings#method:-models.batchembedcontents
*
* @param string|Blob|array<string|Blob>|Content|EmbedContentRequest ...$parts
*/
public function batchEmbedContents(string|Blob|array|Content|EmbedContentRequest ...$parts): BatchEmbedContentsResponse
{
return $this->record(method: __FUNCTION__, args: func_get_args(), model: $this->model);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace Gemini\Testing\Responses\Fixtures\GenerativeModel;

final class BatchEmbedContentsResponseFixture
{
public const ATTRIBUTES = [
'embeddings' => [
[
'values' => [
0.008624583,
-0.030451821,
-0.042496547,
-0.029230341,
0.05486475,
0.006694871,
0.004025645,
],
],
[
'values' => [
0.008624583,
-0.030451821,
-0.042496547,
-0.029230341,
0.05486475,
0.006694871,
0.004025645,
],
],
],
];
}
13 changes: 13 additions & 0 deletions tests/Resources/EmbeddingModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use Gemini\Data\ContentEmbedding;
use Gemini\Enums\Method;
use Gemini\Enums\ModelType;
use Gemini\Responses\GenerativeModel\BatchEmbedContentsResponse;
use Gemini\Responses\GenerativeModel\EmbedContentResponse;

test('embed content', function () {
Expand All @@ -16,6 +17,18 @@
->embedding->toBeInstanceOf(ContentEmbedding::class)
->embedding->values->toBeArray()->toHaveCount(7);
});
test('batch embed contents', function () {
$modelType = ModelType::EMBEDDING;
$client = mockClient(method: Method::POST, endpoint: "{$modelType->value}:batchEmbedContents", response: BatchEmbedContentsResponse::fake());

$result = $client->embeddingModel()->batchEmbedContents('Test', 'Test2');

expect($result)
->toBeInstanceOf(BatchEmbedContentsResponse::class)
->embeddings->toBeArray()->toHaveCount(2)
->embeddings->each->toBeInstanceOf(ContentEmbedding::class)
->embeddings->each(fn ($embeddingModel) => $embeddingModel->values->toBeArray()->toHaveCount(7));
});

test('embed content for custom model', function () {
$modelType = 'models/gemini-1.0-pro-001';
Expand Down
62 changes: 62 additions & 0 deletions tests/Responses/GenerativeModel/BatchEmbedContentsResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

use Gemini\Data\ContentEmbedding;
use Gemini\Responses\GenerativeModel\BatchEmbedContentsResponse;

test('from', function () {
$response = BatchEmbedContentsResponse::from(BatchEmbedContentsResponse::fake()->toArray());

expect($response)
->toBeInstanceOf(BatchEmbedContentsResponse::class)
->embeddings->each->toBeInstanceOf(ContentEmbedding::class)
->embeddings->each(fn ($embeddingModel) => $embeddingModel->values->toBeArray()->toMatchArray([
0.008624583,
-0.030451821,
-0.042496547,
-0.029230341,
0.05486475,
0.006694871,
0.004025645,
]));
});

test('fake', function () {
$response = BatchEmbedContentsResponse::fake();

expect($response)
->toBeInstanceOf(BatchEmbedContentsResponse::class)
->embeddings->each->toBeInstanceOf(ContentEmbedding::class)
->embeddings->each(fn ($embeddingModel) => $embeddingModel->values->toBeArray()->toMatchArray([
0.008624583,
-0.030451821,
-0.042496547,
-0.029230341,
0.05486475,
0.006694871,
0.004025645,
]));
});

test('to array', function () {
$attributes = BatchEmbedContentsResponse::fake()->toArray();
$response = BatchEmbedContentsResponse::from($attributes);

expect($response->toArray())
->toBeArray()->toBe($attributes);
});

test('fake with override', function () {
$response = BatchEmbedContentsResponse::fake([
'embeddings' => [
[
'values' => [
0,
],
],
],
]);
expect($response)
->embeddings->{0}->values->toBeArray()->toMatchArray([
0,
]);
});

0 comments on commit d329f9c

Please sign in to comment.