Skip to content
This repository was archived by the owner on Jul 16, 2025. It is now read-only.

Commit 95b21cb

Browse files
committed
refactor: remove visitor infavor of single converter class
1 parent 9271a5b commit 95b21cb

22 files changed

+281
-194
lines changed

.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,4 @@ PINECONE_HOST=
4141
RUN_EXPENSIVE_EXAMPLES=false
4242

4343
# For using Gemini
44-
GOOGLE_API_KEY=
44+
GOOGLE_API_KEY=

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ LLM Chain categorizes two main types of models: **Language Models** and **Embedd
3838
Language Models, like GPT, Claude and Llama, as essential centerpiece of LLM applications
3939
and Embeddings Models as supporting models to provide vector representations of text.
4040

41-
Those models are provided by different **platforms**, like OpenAI, Azure, Replicate, and others.
41+
Those models are provided by different **platforms**, like OpenAI, Azure, Google, Replicate, and others.
4242

4343
#### Example Instantiation
4444

@@ -63,6 +63,7 @@ $embeddings = new Embeddings();
6363
* [OpenAI's GPT](https://platform.openai.com/docs/models/overview) with [OpenAI](https://platform.openai.com/docs/overview) and [Azure](https://learn.microsoft.com/azure/ai-services/openai/concepts/models) as Platform
6464
* [Anthropic's Claude](https://www.anthropic.com/claude) with [Anthropic](https://www.anthropic.com/) as Platform
6565
* [Meta's Llama](https://www.llama.com/) with [Ollama](https://ollama.com/) and [Replicate](https://replicate.com/) as Platform
66+
* [Google's Gemini](https://gemini.google.com/) with [Google](https://ai.google.dev/) as Platform
6667
* [Google's Gemini](https://gemini.google.com/) with [OpenRouter](https://www.openrouter.com/) as Platform
6768
* [DeepSeek's R1](https://www.deepseek.com/) with [OpenRouter](https://www.openrouter.com/) as Platform
6869
* Embeddings Models

examples/chat-gemini-google.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
use PhpLlm\LlmChain\Bridge\Google\GoogleModel;
3+
use PhpLlm\LlmChain\Bridge\Google\Gemini;
44
use PhpLlm\LlmChain\Bridge\Google\PlatformFactory;
55
use PhpLlm\LlmChain\Chain;
66
use PhpLlm\LlmChain\Model\Message\Message;
@@ -16,7 +16,7 @@
1616
}
1717

1818
$platform = PlatformFactory::create($_ENV['GOOGLE_API_KEY']);
19-
$llm = new GoogleModel(GoogleModel::GEMINI_2_FLASH);
19+
$llm = new Gemini(Gemini::GEMINI_2_FLASH);
2020

2121
$chain = new Chain($platform, $llm);
2222
$messages = new MessageBag(
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
use PhpLlm\LlmChain\Bridge\Google\Gemini;
4+
use PhpLlm\LlmChain\Bridge\Google\PlatformFactory;
5+
use PhpLlm\LlmChain\Chain;
6+
use PhpLlm\LlmChain\Model\Message\Content\Image;
7+
use PhpLlm\LlmChain\Model\Message\Message;
8+
use PhpLlm\LlmChain\Model\Message\MessageBag;
9+
use Symfony\Component\Dotenv\Dotenv;
10+
11+
require_once dirname(__DIR__).'/vendor/autoload.php';
12+
(new Dotenv())->loadEnv(dirname(__DIR__).'/.env');
13+
14+
if (empty($_ENV['GOOGLE_API_KEY'])) {
15+
echo 'Please set the GOOGLE_API_KEY environment variable.'.PHP_EOL;
16+
exit(1);
17+
}
18+
19+
$platform = PlatformFactory::create($_ENV['GOOGLE_API_KEY']);
20+
$llm = new Gemini(Gemini::GEMINI_1_5_FLASH);
21+
22+
$chain = new Chain($platform, $llm);
23+
$messages = new MessageBag(
24+
Message::forSystem('You are an image analyzer bot that helps identify the content of images.'),
25+
Message::ofUser(
26+
'Describe the image as a comedian would do it.',
27+
new Image(dirname(__DIR__).'/tests/Fixture/image.jpg'),
28+
),
29+
);
30+
$response = $chain->call($messages);
31+
32+
echo $response->getContent().PHP_EOL;

examples/stream-google-gemini.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
use PhpLlm\LlmChain\Bridge\Google\Gemini;
4+
use PhpLlm\LlmChain\Bridge\Google\PlatformFactory;
5+
use PhpLlm\LlmChain\Chain;
6+
use PhpLlm\LlmChain\Model\Message\Message;
7+
use PhpLlm\LlmChain\Model\Message\MessageBag;
8+
use Symfony\Component\Dotenv\Dotenv;
9+
10+
require_once dirname(__DIR__).'/vendor/autoload.php';
11+
(new Dotenv())->loadEnv(dirname(__DIR__).'/.env');
12+
13+
if (empty($_ENV['GOOGLE_API_KEY'])) {
14+
echo 'Please set the GOOGLE_API_KEY environment variable.'.PHP_EOL;
15+
exit(1);
16+
}
17+
18+
$platform = PlatformFactory::create($_ENV['GOOGLE_API_KEY']);
19+
$llm = new Gemini(Gemini::GEMINI_2_FLASH);
20+
21+
$chain = new Chain($platform, $llm);
22+
$messages = new MessageBag(
23+
Message::forSystem('You are a funny clown that entertains people.'),
24+
Message::ofUser('What is the purpose of an ant?'),
25+
);
26+
$response = $chain->call($messages, [
27+
'stream' => true, // enable streaming of response text
28+
]);
29+
30+
foreach ($response->getContent() as $word) {
31+
echo $word;
32+
}
33+
echo PHP_EOL;

src/Bridge/Google/GoogleModel.php renamed to src/Bridge/Google/Gemini.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use PhpLlm\LlmChain\Model\LanguageModel;
88

9-
final readonly class GoogleModel implements LanguageModel
9+
final readonly class Gemini implements LanguageModel
1010
{
1111
public const GEMINI_2_FLASH = 'gemini-2.0-flash';
1212
public const GEMINI_2_PRO = 'gemini-2.0-pro-exp-02-05';
@@ -35,12 +35,12 @@ public function getOptions(): array
3535

3636
public function supportsAudioInput(): bool
3737
{
38-
return false; // it does, but implementation here is still open; in_array($this->version, [self::GEMINI_2_FLASH, self::GEMINI_2_PRO, self::GEMINI_1_5_FLASH], true);
38+
return false; // it does, but implementation here is still open
3939
}
4040

4141
public function supportsImageInput(): bool
4242
{
43-
return false; // it does, but implementation here is still open;in_array($this->version, [self::GEMINI_2_FLASH, self::GEMINI_2_PRO, self::GEMINI_2_FLASH_LITE, self::GEMINI_2_FLASH_THINKING, self::GEMINI_1_5_FLASH], true);
43+
return true;
4444
}
4545

4646
public function supportsStreaming(): bool
@@ -50,11 +50,11 @@ public function supportsStreaming(): bool
5050

5151
public function supportsStructuredOutput(): bool
5252
{
53-
return false;
53+
return false; // it does, but implementation here is still open
5454
}
5555

5656
public function supportsToolCalling(): bool
5757
{
58-
return false;
58+
return false; // it does, but implementation here is still open
5959
}
6060
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpLlm\LlmChain\Bridge\Google;
6+
7+
use PhpLlm\LlmChain\Model\Message\AssistantMessage;
8+
use PhpLlm\LlmChain\Model\Message\Content\Image;
9+
use PhpLlm\LlmChain\Model\Message\Content\Text;
10+
use PhpLlm\LlmChain\Model\Message\MessageBagInterface;
11+
use PhpLlm\LlmChain\Model\Message\MessageInterface;
12+
use PhpLlm\LlmChain\Model\Message\Role;
13+
use PhpLlm\LlmChain\Model\Message\UserMessage;
14+
15+
use function Symfony\Component\String\u;
16+
17+
final class GooglePromptConverter
18+
{
19+
/**
20+
* @return array{
21+
* contents: list<array{
22+
* role: 'model'|'user',
23+
* parts: list<array{inline_data?: array{mime_type: string, data: string}|array{text: string}}>
24+
* }>,
25+
* system_instruction?: array{parts: array{text: string}}
26+
* }
27+
*/
28+
public function convertToPrompt(MessageBagInterface $bag): array
29+
{
30+
$body = ['contents' => []];
31+
32+
$systemMessage = $bag->getSystemMessage();
33+
if (null !== $systemMessage) {
34+
$body['system_instruction'] = [
35+
'parts' => ['text' => $systemMessage->content],
36+
];
37+
}
38+
39+
foreach ($bag->withoutSystemMessage()->getMessages() as $message) {
40+
$body['contents'][] = [
41+
'role' => $message->getRole()->equals(Role::Assistant) ? 'model' : 'user',
42+
'parts' => $this->convertMessage($message),
43+
];
44+
}
45+
46+
return $body;
47+
}
48+
49+
/**
50+
* @return list<array{inline_data?: array{mime_type: string, data: string}|array{text: string}}>
51+
*/
52+
private function convertMessage(MessageInterface $message): array
53+
{
54+
if ($message instanceof AssistantMessage) {
55+
return [['text' => $message->content]];
56+
}
57+
58+
if ($message instanceof UserMessage) {
59+
$parts = [];
60+
foreach ($message->content as $content) {
61+
if ($content instanceof Text) {
62+
$parts[] = ['text' => $content->text];
63+
}
64+
if ($content instanceof Image) {
65+
$parts[] = ['inline_data' => [
66+
'mime_type' => u($content->url)->after('data:')->before(';')->toString(),
67+
'data' => u($content->url)->after('base64,')->toString(),
68+
]];
69+
}
70+
}
71+
72+
return $parts;
73+
}
74+
75+
return [];
76+
}
77+
}

src/Bridge/Google/GoogleRequestBodyProducer.php

Lines changed: 0 additions & 97 deletions
This file was deleted.

0 commit comments

Comments
 (0)