diff --git a/README.md b/README.md index bd954b3..c19e273 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,32 @@ print $chat->sendMessage('in Go'); // This code will print "Hello World!" to the standard output. ``` +### Chat Session with History + +```php +use GeminiAPI\Laravel\Facades\Gemini; + +$history = [ + [ + 'message' => 'Hello World in PHP', + 'role' => 'user', + ], + [ + 'message' => << 'model', + ], +]; +$chat = Gemini::startChat($history); + +print $chat->sendMessage('in Go'); +// fmt.Println("Hello World!") +// This code will print "Hello World!" to the standard output. +``` + ### Tokens counting ```php diff --git a/composer.json b/composer.json index f5b36dc..73b1aab 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ ], "require": { "php": "^8.1", - "gemini-api-php/client": "^1.1", + "gemini-api-php/client": "^1.2", "illuminate/support": "^9.0 || ^10.0 || ^11.0", "psr/container": "^1.0 || ^2.0", "psr/http-client": "^1.0" diff --git a/src/ChatSession.php b/src/ChatSession.php index b01702d..3ed100c 100644 --- a/src/ChatSession.php +++ b/src/ChatSession.php @@ -5,6 +5,7 @@ namespace GeminiAPI\Laravel; use GeminiAPI\ChatSession as ApiChatSession; +use GeminiAPI\Resources\Content; use GeminiAPI\Resources\Parts\TextPart; use Psr\Http\Client\ClientExceptionInterface; @@ -24,4 +25,21 @@ public function sendMessage(string $text): string ->sendMessage(new TextPart($text)) ->text(); } + + /** + * @return array + */ + public function history(): array + { + return array_map( + static fn (Content $content): array => [ + 'message' => $content->parts[0] instanceof TextPart ? $content->parts[0]->text : '', + 'role' => $content->role->value, + ], + $this->chatSession->history(), + ); + } } diff --git a/src/Gemini.php b/src/Gemini.php index 527ba24..524147b 100644 --- a/src/Gemini.php +++ b/src/Gemini.php @@ -7,14 +7,26 @@ use GeminiAPI\ClientInterface; use GeminiAPI\Enums\MimeType; use GeminiAPI\Enums\ModelName; +use GeminiAPI\Enums\Role; use GeminiAPI\Laravel\Contracts\GeminiContract; use GeminiAPI\Laravel\Exceptions\InvalidArgumentException; use GeminiAPI\Laravel\Exceptions\InvalidMimeType; +use GeminiAPI\Resources\Content; use GeminiAPI\Resources\Model; use GeminiAPI\Resources\Parts\ImagePart; use GeminiAPI\Resources\Parts\TextPart; use Psr\Http\Client\ClientExceptionInterface; +use function array_map; +use function base64_encode; +use function file_get_contents; +use function in_array; +use function is_file; +use function is_null; +use function is_readable; +use function is_string; +use function sprintf; + class Gemini implements GeminiContract { public function __construct( @@ -114,12 +126,38 @@ public function generateTextUsingImage( return $response->text(); } - public function startChat(): ChatSession + /** + * @param array $history + * + * @throws InvalidArgumentException + */ + public function startChat(array $history = []): ChatSession { $chatSession = $this->client ->generativeModel(ModelName::GeminiPro) ->startChat(); + if (! empty($history)) { + $contents = array_map( + static function (array $message): Content { + if (empty($message['message']) || empty($message['role'])) { + throw new InvalidArgumentException('Invalid message in the chat history'); + } + + if (! is_string($message['message']) || ! in_array($message['role'], ['user', 'model'], true)) { + throw new InvalidArgumentException('Invalid message in the chat history'); + } + + return Content::text($message['message'], Role::from($message['role'])); + }, + $history, + ); + $chatSession = $chatSession->withHistory($contents); + } + return new ChatSession($chatSession); }