Skip to content

Commit

Permalink
feat: chat + message store
Browse files Browse the repository at this point in the history
  • Loading branch information
chr-hertel committed Feb 6, 2025
1 parent 06e52f1 commit 9910b6c
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 1 deletion.
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"symfony/dotenv": "^6.4 || ^7.1",
"symfony/event-dispatcher": "^6.4 || ^7.1",
"symfony/finder": "^6.4 || ^7.1",
"symfony/http-foundation": "^6.4 || ^7.1",
"symfony/process": "^6.4 || ^7.1",
"symfony/var-dumper": "^6.4 || ^7.1"
},
Expand All @@ -50,7 +51,8 @@
"mongodb/mongodb": "For using MongoDB Atlas as retrieval vector store.",
"probots-io/pinecone-php": "For using the Pinecone as retrieval vector store.",
"symfony/css-selector": "For using the YouTube transcription tool.",
"symfony/dom-crawler": "For using the YouTube transcription tool."
"symfony/dom-crawler": "For using the YouTube transcription tool.",
"symfony/http-foundation": "For using the SessionStore as message store."
},
"autoload": {
"psr-4": {
Expand Down
34 changes: 34 additions & 0 deletions examples/persistent-chat.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

use PhpLlm\LlmChain\Bridge\OpenAI\GPT;
use PhpLlm\LlmChain\Bridge\OpenAI\PlatformFactory;
use PhpLlm\LlmChain\Chain;
use PhpLlm\LlmChain\Chat;
use PhpLlm\LlmChain\Chat\MessageStore\InMemoryStore;
use PhpLlm\LlmChain\Model\Message\Message;
use PhpLlm\LlmChain\Model\Message\MessageBag;
use Symfony\Component\Dotenv\Dotenv;

require_once dirname(__DIR__).'/vendor/autoload.php';
(new Dotenv())->loadEnv(dirname(__DIR__).'/.env');

if (empty($_ENV['OPENAI_API_KEY'])) {
echo 'Please set the OPENAI_API_KEY environment variable.'.PHP_EOL;
exit(1);
}

$platform = PlatformFactory::create($_ENV['OPENAI_API_KEY']);
$llm = new GPT(GPT::GPT_4O_MINI);

$chain = new Chain($platform, $llm);
$chat = new Chat($chain, new InMemoryStore());

$messages = new MessageBag(
Message::forSystem('You are a helpful assistant. You only answer with short sentences.'),
);

$chat->start($messages);
$chat->submit(Message::ofUser('My name is Christopher.'));
$message = $chat->submit(Message::ofUser('What is my name?'));

echo $message->content.PHP_EOL;
44 changes: 44 additions & 0 deletions src/Chat.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace PhpLlm\LlmChain;

use PhpLlm\LlmChain\Chat\MessageStoreInterface;
use PhpLlm\LlmChain\Model\Message\AssistantMessage;
use PhpLlm\LlmChain\Model\Message\Message;
use PhpLlm\LlmChain\Model\Message\MessageBag;
use PhpLlm\LlmChain\Model\Message\UserMessage;
use PhpLlm\LlmChain\Model\Response\TextResponse;

final readonly class Chat implements ChatInterface
{
public function __construct(
private ChainInterface $chain,
private MessageStoreInterface $store,
) {
}

public function start(MessageBag $messages): void
{
$this->store->clear();
$this->store->save($messages);
}

public function submit(UserMessage $message): AssistantMessage
{
$messages = $this->store->load();

$messages->add($message);
$response = $this->chain->call($messages);

assert($response instanceof TextResponse);

$assistantMessage = Message::ofAssistant($response->getContent());
$messages->add($assistantMessage);

$this->store->save($messages);

return $assistantMessage;
}
}
28 changes: 28 additions & 0 deletions src/Chat/MessageStore/InMemoryStore.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace PhpLlm\LlmChain\Chat\MessageStore;

use PhpLlm\LlmChain\Chat\MessageStoreInterface;
use PhpLlm\LlmChain\Model\Message\MessageBag;

final class InMemoryStore implements MessageStoreInterface
{
private MessageBag $messages;

public function save(MessageBag $messages): void
{
$this->messages = $messages;
}

public function load(): MessageBag
{
return $this->messages ?? new MessageBag();
}

public function clear(): void
{
$this->messages = new MessageBag();
}
}
37 changes: 37 additions & 0 deletions src/Chat/MessageStore/SessionStore.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace PhpLlm\LlmChain\Chat\MessageStore;

use PhpLlm\LlmChain\Chat\MessageStoreInterface;
use PhpLlm\LlmChain\Model\Message\MessageBag;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionInterface;

final readonly class SessionStore implements MessageStoreInterface
{
private SessionInterface $session;

public function __construct(
RequestStack $requestStack,
private string $sessionKey = 'messages',
) {
$this->session = $requestStack->getSession();
}

public function save(MessageBag $messages): void
{
$this->session->set($this->sessionKey, $messages);
}

public function load(): MessageBag
{
return $this->session->get($this->sessionKey, new MessageBag());
}

public function clear(): void
{
$this->session->remove($this->sessionKey);
}
}
16 changes: 16 additions & 0 deletions src/Chat/MessageStoreInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace PhpLlm\LlmChain\Chat;

use PhpLlm\LlmChain\Model\Message\MessageBag;

interface MessageStoreInterface
{
public function save(MessageBag $messages): void;

public function load(): MessageBag;

public function clear(): void;
}
16 changes: 16 additions & 0 deletions src/ChatInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace PhpLlm\LlmChain;

use PhpLlm\LlmChain\Model\Message\AssistantMessage;
use PhpLlm\LlmChain\Model\Message\MessageBag;
use PhpLlm\LlmChain\Model\Message\UserMessage;

interface ChatInterface
{
public function start(MessageBag $messages): void;

public function submit(UserMessage $message): AssistantMessage;
}

0 comments on commit 9910b6c

Please sign in to comment.