Skip to content

Commit

Permalink
Merge pull request #34 from aydinfatih/beta
Browse files Browse the repository at this point in the history
feat: Added Structured Output feature for Beta
  • Loading branch information
aydinfatih authored Sep 28, 2024
2 parents 5757f93 + 09f9903 commit a53ff72
Show file tree
Hide file tree
Showing 42 changed files with 566 additions and 45 deletions.
113 changes: 112 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
- [Text-and-image Input](#text-and-image-input)
- [Multi-turn Conversations (Chat)](#multi-turn-conversations-chat)
- [Stream Generate Content](#stream-generate-content)
- [Structured Output](#structured-output)
- [Count tokens](#count-tokens)
- [Configuration](#configuration)
- [Embedding Resource](#embedding-resource)
Expand Down Expand Up @@ -67,8 +68,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 All @@ -78,7 +99,7 @@ $yourApiKey = getenv('YOUR_API_KEY');

$client = Gemini::factory()
->withApiKey($yourApiKey)
->withBaseUrl('https://generativelanguage.example.com/v1') // default: https://generativelanguage.googleapis.com/v1/
->withBaseUrl('https://generativelanguage.example.com/v1beta') // default: https://generativelanguage.googleapis.com/v1beta/
->withHttpHeader('X-My-Header', 'foo')
->withQueryParam('my-param', 'bar')
->withHttpClient(new \GuzzleHttp\Client([])) // default: HTTP client found using PSR-18 HTTP Client Discovery
Expand Down Expand Up @@ -155,6 +176,56 @@ foreach ($stream as $response) {
}
```

#### Structured Output

```php
$result = $client
->geminiFlash()
->withGenerationConfig(
generationConfig: new GenerationConfig(
responseMimeType: ResponseMimeType::APPLICATION_JSON,
responseSchema: new Schema(
type: DataType::ARRAY,
items: new Schema(
type: DataType::OBJECT,
properties: [
"recipe_name" => new Schema(type: DataType::STRING),
"cooking_time_in_minutes" => new Schema(type: DataType::INTEGER)
]
)
)
)
)
->generateContent("List 5 popular cookie recipes with cooking time");


$result->json();

//[
// {
// +"cooking_time_in_minutes": 10,
// +"recipe_name": "Chocolate Chip Cookies",
// },
// {
// +"cooking_time_in_minutes": 12,
// +"recipe_name": "Oatmeal Raisin Cookies",
// },
// {
// +"cooking_time_in_minutes": 10,
// +"recipe_name": "Peanut Butter Cookies",
// },
// {
// +"cooking_time_in_minutes": 10,
// +"recipe_name": "Snickerdoodles",
// },
// {
// +"cooking_time_in_minutes": 12,
// +"recipe_name": "Sugar Cookies",
// },
// ]

```

#### Count tokens
When using long prompts, it might be useful to count tokens before sending any content to the model.

Expand Down Expand Up @@ -231,6 +302,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;
}
2 changes: 1 addition & 1 deletion src/Data/Blob.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
/**
* Raw media bytes.
*
* https://ai.google.dev/api/rest/v1/Content#blob
* https://ai.google.dev/api/rest/v1beta/Content#blob
*/
final class Blob implements Arrayable
{
Expand Down
2 changes: 1 addition & 1 deletion src/Data/Candidate.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
/**
* A response candidate generated from the model.
*
* https://ai.google.dev/api/rest/v1/GenerateContentResponse#candidate
* https://ai.google.dev/api/rest/v1beta/GenerateContentResponse#candidate
*/
final class Candidate implements Arrayable
{
Expand Down
2 changes: 1 addition & 1 deletion src/Data/CitationMetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/**
* A collection of source attributions for a piece of content.
*
* https://ai.google.dev/api/rest/v1/GenerateContentResponse#citationmetadata
* https://ai.google.dev/api/rest/v1beta/GenerateContentResponse#citationmetadata
*/
final class CitationMetadata implements Arrayable
{
Expand Down
2 changes: 1 addition & 1 deletion src/Data/CitationSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/**
* A citation to a source for a portion of a specific response.
*
* https://ai.google.dev/api/rest/v1/GenerateContentResponse#citationsource
* https://ai.google.dev/api/rest/v1beta/GenerateContentResponse#citationsource
*/
final class CitationSource implements Arrayable
{
Expand Down
2 changes: 1 addition & 1 deletion src/Data/Content.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* A Content includes a role field designating the producer of the Content and a parts
* field containing multi-part data that contains the content of the message turn.
*
* https://ai.google.dev/api/rest/v1/Content
* https://ai.google.dev/api/rest/v1beta/Content
*/
final class Content implements Arrayable
{
Expand Down
2 changes: 1 addition & 1 deletion src/Data/ContentEmbedding.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/**
* A list of floats representing an embedding.
*
* https://ai.google.dev/api/rest/v1/ContentEmbedding
* https://ai.google.dev/api/rest/v1beta/ContentEmbedding
*/
final class ContentEmbedding implements Arrayable
{
Expand Down
19 changes: 19 additions & 0 deletions src/Data/DataFormat.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Gemini\Data;

enum DataFormat: string
{
// for Number
case FLOAT = 'float';
case DOUBLE = 'double';

// for Integer
case INT32 = 'int32';
case INT64 = 'int64';

// for String
case ENUM = 'enum';
}
39 changes: 30 additions & 9 deletions src/Data/GenerationConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
namespace Gemini\Data;

use Gemini\Contracts\Arrayable;
use Gemini\Enums\ResponseMimeType;

/**
* Configuration options for model generation and outputs.
*
* https://ai.google.dev/api/rest/v1/GenerationConfig
* https://ai.google.dev/api/rest/v1beta/GenerationConfig
*/
final class GenerationConfig implements Arrayable
{
Expand All @@ -20,6 +21,12 @@ final class GenerationConfig implements Arrayable
* @param float|null $temperature Controls the randomness of the output.
* @param float|null $topP The maximum cumulative probability of tokens to consider when sampling.
* @param int|null $topK The maximum number of tokens to consider when sampling.
* @param ResponseMimeType|null $responseMimeType MIME type of the generated candidate text.
* @param Schema|null $responseSchema Output schema of the generated candidate text.
* @param float|null $presencePenalty Presence penalty applied to the next token's logprobs if the token has already been seen in the response.
* @param float|null $frequencyPenalty Frequency penalty applied to the next token's logprobs, multiplied by the number of times each token has been seen in the respponse so far.
* @param bool|null $responseLogprobs If true, export the logprobs results in response.
* @param int|null $logprobs Only valid if responseLogprobs=True. This sets the number of top logprobs to return at each decoding step in the Candidate.logprobs_result.
*/
public function __construct(
public readonly int $candidateCount = 1,
Expand All @@ -28,17 +35,31 @@ public function __construct(
public readonly ?float $temperature = null,
public readonly ?float $topP = null,
public readonly ?int $topK = null,
public readonly ?ResponseMimeType $responseMimeType = ResponseMimeType::TEXT_PLAIN,
public readonly ?Schema $responseSchema = null,
public readonly ?float $presencePenalty = null,
public readonly ?float $frequencyPenalty = null,
public readonly ?bool $responseLogprobs = null,
public readonly ?int $logprobs = null,
) {}

public function toArray(): array
{
return [
'candidateCount' => $this->candidateCount,
'stopSequences' => $this->stopSequences,
'maxOutputTokens' => $this->maxOutputTokens,
'temperature' => $this->temperature,
'topP' => $this->topP,
'topK' => $this->topK,
];
return array_filter(
array: [
'candidateCount' => $this->candidateCount,
'stopSequences' => $this->stopSequences,
'maxOutputTokens' => $this->maxOutputTokens,
'temperature' => $this->temperature,
'topP' => $this->topP,
'topK' => $this->topK,
'responseMimeType' => $this->responseMimeType?->value,
'responseSchema' => $this->responseSchema?->toArray(),
'presencePenalty' => $this->presencePenalty,
'frequencyPenalty' => $this->frequencyPenalty,
'responseLogprobs' => $this->responseLogprobs,
'logprobs' => $this->logprobs,
]
);
}
}
2 changes: 1 addition & 1 deletion src/Data/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/**
* Information about a Generative Language Model.
*
* https://ai.google.dev/api/rest/v1/models#resource:-model
* https://ai.google.dev/api/rest/v1beta/models#resource:-model
*/
final class Model implements Arrayable
{
Expand Down
2 changes: 1 addition & 1 deletion src/Data/PromptFeedback.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
/**
* A set of the feedback metadata the prompt specified in GenerateContentRequest.content.
*
* https://ai.google.dev/api/rest/v1/GenerateContentResponse#promptfeedback
* https://ai.google.dev/api/rest/v1beta/GenerateContentResponse#promptfeedback
*/
final class PromptFeedback implements Arrayable
{
Expand Down
2 changes: 1 addition & 1 deletion src/Data/SafetyRating.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* for a piece of content. Content is classified for safety across a number of harm categories
* and the probability of the harm classification is included here.
*
* https://ai.google.dev/api/rest/v1/GenerateContentResponse#safetyrating
* https://ai.google.dev/api/rest/v1beta/GenerateContentResponse#safetyrating
*/
final class SafetyRating implements Arrayable
{
Expand Down
2 changes: 1 addition & 1 deletion src/Data/SafetySetting.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
/**
* Safety setting, affecting the safety-blocking behavior.
*
* https://ai.google.dev/api/rest/v1/SafetySetting
* https://ai.google.dev/api/rest/v1beta/SafetySetting
*/
final class SafetySetting implements Arrayable
{
Expand Down
Loading

0 comments on commit a53ff72

Please sign in to comment.