Skip to content

Commit

Permalink
Add raw data support for user-defined custom logic. (#8)
Browse files Browse the repository at this point in the history
* Add raw data support for user-defined custom logic.

* Tests updated.

* Missing types added.
  • Loading branch information
halilcosdu committed Apr 27, 2024
1 parent 495e138 commit 0eb9e17
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 28 deletions.
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,29 @@ ChatBot::updateThread('Hi', $id); /* Continue the conversation */
ChatBot::deleteThread($id); /* Delete the thread */
```
### Raw Data - Not Saved to Database
#### You can use the following methods to interact with the OpenAI API directly.
```php
public function createThreadAsRaw(string $subject)
public function listThreadMessagesAsRaw(string $remoteThreadId)
public function updateThreadAsRaw(string $remoteThreadId, array $data) /* $data = ['role' => 'user or assistant', 'content' => 'Hello'] */
public function deleteThreadAsRaw(string $remoteThreadId)
public function threadAsRaw(string $threadId)
public function messageAsRaw(string $threadId, string $messageId)
public function modifyMessageAsRaw(string $threadId, string $messageId, array $parameters)
```
```php
ChatBot::createThreadAsRaw(string $subject);
ChatBot::listThreadMessagesAsRaw(string $remoteThreadId);
ChatBot::updateThreadAsRaw(string $remoteThreadId, array $data);
ChatBot::deleteThreadAsRaw(string $remoteThreadId);
ChatBot::threadAsRaw(string $threadId);
ChatBot::messageAsRaw(string $threadId, string $messageId);
ChatBot::modifyMessageAsRaw(string $threadId, string $messageId, array $parameters);
```
## Testing
```bash
Expand Down
43 changes: 42 additions & 1 deletion src/ChatBot.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@
namespace HalilCosdu\ChatBot;

use HalilCosdu\ChatBot\Services\ChatBotService;
use HalilCosdu\ChatBot\Services\OpenAI\RawService;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use OpenAI\Responses\Threads\Messages\ThreadMessageListResponse;
use OpenAI\Responses\Threads\Messages\ThreadMessageResponse;
use OpenAI\Responses\Threads\ThreadDeleteResponse;
use OpenAI\Responses\Threads\ThreadResponse;

readonly class ChatBot
{
public function __construct(private ChatBotService $chatBotService)
public function __construct(private ChatBotService $chatBotService, private RawService $rawService)
{
//
}
Expand Down Expand Up @@ -38,4 +43,40 @@ public function deleteThread(int $id, mixed $ownerId = null): void
{
$this->chatBotService->delete($id, $ownerId);
}

public function createThreadAsRaw(string $subject): ThreadResponse
{
return $this->rawService->createThreadAsRaw($subject);
}

public function threadAsRaw(string $threadId): ThreadResponse
{
return $this->rawService->threadAsRaw($threadId);
}

public function messageAsRaw($threadId, $messageId): ThreadMessageResponse
{
return $this->rawService->messageAsRaw($threadId, $messageId);
}

public function modifyMessageAsRaw(string $threadId, string $messageId, array $parameters): ThreadMessageResponse
{
return $this->rawService->modifyMessageAsRaw($threadId, $messageId, $parameters);
}

public function listThreadMessagesAsRaw(string $remoteThreadId): ThreadMessageListResponse
{
return $this->rawService->listThreadMessagesAsRaw($remoteThreadId);

}

public function updateThreadAsRaw(string $remoteThreadId, array $data): ThreadResponse
{
return $this->rawService->updateThreadAsRaw($remoteThreadId, $data);
}

public function deleteThreadAsRaw(string $remoteThreadId): ThreadDeleteResponse
{
return $this->rawService->deleteThreadAsRaw($remoteThreadId);
}
}
44 changes: 28 additions & 16 deletions src/ChatBotServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace HalilCosdu\ChatBot;

use HalilCosdu\ChatBot\Services\ChatBotService;
use HalilCosdu\ChatBot\Services\OpenAI\RawService;
use InvalidArgumentException;
use OpenAI as OpenAIFactory;
use Spatie\LaravelPackageTools\Package;
Expand Down Expand Up @@ -30,25 +31,36 @@ public function configurePackage(Package $package): void

public function packageRegistered(): void
{
$this->app->singleton(ChatBotService::class, function ($app) {
$apiKey = config('chatbot.api_key');
$organization = config('chatbot.organization');
$timeout = config('chatbot.request_timeout', 30);

if (! is_string($apiKey) || ($organization !== null && ! is_string($organization))) {
throw new InvalidArgumentException(
'The OpenAI API Key is missing. Please publish the [chatbot.php] configuration file and set the [api_key].'
);
}

return new ChatBotService(
OpenAIFactory::factory()
$this->registerServices();
}

private function registerServices(): void
{
$services = [
ChatBotService::class,
RawService::class,
];
foreach ($services as $serviceClass) {
$this->app->singleton($serviceClass, function () use ($serviceClass) {
$apiKey = config('chatbot.api_key');
$organization = config('chatbot.organization');
$timeout = config('chatbot.request_timeout', 30);

if (! is_string($apiKey) || ($organization !== null && ! is_string($organization))) {
throw new InvalidArgumentException(
'The OpenAI API Key is missing. Please publish the [chatbot.php] configuration file and set the [api_key].'
);
}

$openAI = OpenAIFactory::factory()
->withApiKey($apiKey)
->withOrganization($organization)
->withHttpHeader('OpenAI-Beta', 'assistants=v1')
->withHttpClient(new \GuzzleHttp\Client(['timeout' => $timeout]))
->make()
);
});
->make();

return new $serviceClass($openAI);
});
}
}
}
7 changes: 7 additions & 0 deletions src/Facades/ChatBot.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@
* @method static \HalilCosdu\ChatBot\ChatBot thread(int $id, mixed $ownerId = null)
* @method static \HalilCosdu\ChatBot\ChatBot updateThread(string $message, int $id, mixed $ownerId = null)
* @method static \HalilCosdu\ChatBot\ChatBot deleteThread(int $id, mixed $ownerId = null)
* @method static \HalilCosdu\ChatBot\ChatBot createThreadAsRaw(string $subject)
* @method static \HalilCosdu\ChatBot\ChatBot listThreadMessagesAsRaw(string $remoteThreadId)
* @method static \HalilCosdu\ChatBot\ChatBot updateThreadAsRaw(string $remoteThreadId, array $data)
* @method static \HalilCosdu\ChatBot\ChatBot deleteThreadAsRaw(string $remoteThreadId)
* @method static \HalilCosdu\ChatBot\ChatBot threadAsRaw(string $threadId)
* @method static \HalilCosdu\ChatBot\ChatBot messageAsRaw(string $threadId,string $messageId)
* @method static \HalilCosdu\ChatBot\ChatBot modifyMessageAsRaw(string $threadId, string $messageId, array $parameters)
*/
class ChatBot extends Facade
{
Expand Down
13 changes: 3 additions & 10 deletions src/Services/ChatBotService.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@
namespace HalilCosdu\ChatBot\Services;

use HalilCosdu\ChatBot\Models\Thread;
use HalilCosdu\ChatBot\Traits\WaitsForThreadRunCompletion;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Sleep;
use Illuminate\Support\Str;
use OpenAI\Client;

class ChatBotService
{
use WaitsForThreadRunCompletion;

public function __construct(public Client $client)
{
//
Expand Down Expand Up @@ -115,13 +117,4 @@ public function delete(int $id, mixed $ownerId = null): void

$thread->delete();
}

public function waitForThreadRunCompletion($remoteThreadId, $runId): void
{
do {
Sleep::sleep(config('chatbot.sleep_seconds', .1));

$run = $this->client->threads()->runs()->retrieve($remoteThreadId, $runId);
} while ($run->status !== 'completed');
}
}
78 changes: 78 additions & 0 deletions src/Services/OpenAI/RawService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

namespace HalilCosdu\ChatBot\Services\OpenAI;

use HalilCosdu\ChatBot\Traits\WaitsForThreadRunCompletion;
use OpenAI\Client;
use OpenAI\Responses\Threads\Messages\ThreadMessageListResponse;
use OpenAI\Responses\Threads\Messages\ThreadMessageResponse;
use OpenAI\Responses\Threads\ThreadDeleteResponse;
use OpenAI\Responses\Threads\ThreadResponse;

class RawService
{
use WaitsForThreadRunCompletion;

public function __construct(public Client $client)
{
//
}

public function createThreadAsRaw(string $subject): ThreadResponse
{
$remoteThread = $this->client->threads()->create([
'messages' => [
[
'role' => 'user',
'content' => $subject,
],
],
]);

$run = $this->client->threads()->runs()->create($remoteThread->id, [
'assistant_id' => config('chatbot.assistant_id'),
]);

$this->waitForThreadRunCompletion($remoteThread->id, $run->id);

return $this->client->threads()->retrieve($remoteThread->id);
}

public function threadAsRaw(string $threadId): ThreadResponse
{
return $this->client->threads()->retrieve($threadId);
}

public function listThreadMessagesAsRaw(string $remoteThreadId): ThreadMessageListResponse
{
return $this->client->threads()->messages()->list($remoteThreadId);
}

public function messageAsRaw($threadId, $messageId): ThreadMessageResponse
{
return $this->client->threads()->messages()->retrieve($threadId, $messageId);
}

public function modifyMessageAsRaw(string $threadId, string $messageId, array $parameters): ThreadMessageResponse
{
return $this->client->threads()->messages()->modify($threadId, $messageId, $parameters);
}

public function updateThreadAsRaw(string $remoteThreadId, array $data): ThreadResponse
{
$this->client->threads()->messages()->create($remoteThreadId, $data);

$run = $this->client->threads()->runs()->create($remoteThreadId, [
'assistant_id' => config('chatbot.assistant_id'),
]);

$this->waitForThreadRunCompletion($remoteThreadId, $run->id);

return $this->client->threads()->retrieve($remoteThreadId);
}

public function deleteThreadAsRaw(string $remoteThreadId): ThreadDeleteResponse
{
return $this->client->threads()->delete($remoteThreadId);
}
}
17 changes: 17 additions & 0 deletions src/Traits/WaitsForThreadRunCompletion.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace HalilCosdu\ChatBot\Traits;

use Illuminate\Support\Sleep;

trait WaitsForThreadRunCompletion
{
public function waitForThreadRunCompletion($remoteThreadId, $runId): void
{
do {
Sleep::sleep(config('chatbot.sleep_seconds', .1));

$run = $this->client->threads()->runs()->retrieve($remoteThreadId, $runId);
} while ($run->status !== 'completed');
}
}
5 changes: 4 additions & 1 deletion tests/ChatBotTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

use HalilCosdu\ChatBot\ChatBot;
use HalilCosdu\ChatBot\Services\ChatBotService;
use HalilCosdu\ChatBot\Services\OpenAI\RawService;

beforeEach(function () {
$chatBotService = Mockery::mock(ChatBotService::class);
$chatBot = new ChatBot($chatBotService);
$rawService = Mockery::mock(RawService::class);
$chatBot = new ChatBot($chatBotService, $rawService);

$this->chatBotService = $chatBotService;
$this->rawService = $rawService;
$this->chatBot = $chatBot;
});

Expand Down

0 comments on commit 0eb9e17

Please sign in to comment.