diff --git a/README.md b/README.md index ff7873e..a4b6721 100644 --- a/README.md +++ b/README.md @@ -103,9 +103,10 @@ This allows you to create a chatbot that remembers previos interactions. To start a new conversation: ```php -$sidekick = new SidekickConversation(new OpenAi()); +$sidekick = new SidekickConversation(); $conversation = $sidekick->begin( + driver: new OpenAi(), model: 'gtp-3.5-turbo', systemPrompt: 'You can instruct the chatbot using this parameter' ); @@ -138,7 +139,7 @@ An example of the formatted response can be found below: Once you have this response, to continue the conversation you can write the following in your controller making sure to pass the `conversation_id` in the request: ```PHP -$sidekick = new SidekickConversation(new OpenAi()); +$sidekick = new SidekickConversation(); $conversation = $sidekick->resume( conversationId: $conversation_id diff --git a/routes/web.php b/routes/web.php index d221c73..ba1505c 100644 --- a/routes/web.php +++ b/routes/web.php @@ -13,9 +13,10 @@ Route::post('/sidekick/playground/chat', function (Request $request) { $options = explode("|", $request->get('engine')); - $sidekick = new SidekickConversation(new $options[0]()); + $sidekick = new SidekickConversation(); $conversation = $sidekick->begin( + driver: new $options[0](), model: $options[1], systemPrompt: 'Your Sidekick, a robot to chat to users' ); diff --git a/src/Drivers/Claude.php b/src/Drivers/Claude.php index d61e979..4c3e1b2 100644 --- a/src/Drivers/Claude.php +++ b/src/Drivers/Claude.php @@ -32,12 +32,32 @@ class Claude implements Driver */ protected array $headers; + /** + * Message Roles + * + * Some AI tools have different naming for + * user and bot roles so added this so it + * can be specified. + * + * @array $messageRoles + */ public array $messageRoles = [ 'user' => 'user', 'assistant' => 'assistant' ]; + + /** + * List As Object + * + * This is to specify if the chat history + * should be sent as an Object or Array + * to the payload. + * + * @array $listAsObject + */ public bool $listAsObject = false; + public array $chatMaps = []; function __construct() diff --git a/src/Drivers/Cohere.php b/src/Drivers/Cohere.php index d215add..3d6955f 100644 --- a/src/Drivers/Cohere.php +++ b/src/Drivers/Cohere.php @@ -21,7 +21,7 @@ class Cohere implements Driver { /** - * OpenAi Api Base URL + * Api Base URL * @strind $baseUrl */ private string $baseUrl = "https://api.cohere.com/v1"; @@ -35,11 +35,30 @@ class Cohere implements Driver */ protected array $headers; + /** + * Message Roles + * + * Some AI tools have different naming for + * user and bot roles so added this so it + * can be specified. + * + * @array $messageRoles + */ public array $messageRoles = [ 'user' => 'USER', 'assistant' => 'CHATBOT' ]; + /** + * List As Object + * + * This is to specify if the chat history + * should be sent as an Object or Array + * to the payload. + * + * @array $listAsObject + */ + public bool $listAsObject = true; public array $chatMaps = [ diff --git a/src/Drivers/Mistral.php b/src/Drivers/Mistral.php index 14f3b28..3d1a306 100644 --- a/src/Drivers/Mistral.php +++ b/src/Drivers/Mistral.php @@ -20,7 +20,7 @@ class Mistral implements Driver { /** - * OpenAi Api Base URL + * Api Base URL * @strind $baseUrl */ private string $baseUrl = "https://api.mistral.ai/v1"; @@ -34,11 +34,29 @@ class Mistral implements Driver */ protected array $headers; + /** + * Message Roles + * + * Some AI tools have different naming for + * user and bot roles so added this so it + * can be specified. + * + * @array $messageRoles + */ public array $messageRoles = [ 'user' => 'user', 'assistant' => 'assistant' ]; + /** + * List As Object + * + * This is to specify if the chat history + * should be sent as an Object or Array + * to the payload. + * + * @array $listAsObject + */ public bool $listAsObject = false; public array $chatMaps = []; diff --git a/src/Drivers/OpenAi.php b/src/Drivers/OpenAi.php index 079635e..bf1d1fc 100644 --- a/src/Drivers/OpenAi.php +++ b/src/Drivers/OpenAi.php @@ -33,7 +33,7 @@ class OpenAi implements Driver { /** - * OpenAi Api Base URL + * Api Base URL * @strind $baseUrl */ private string $baseUrl = "https://api.openai.com/v1"; @@ -47,11 +47,29 @@ class OpenAi implements Driver */ protected array $headers; + /** + * Message Roles + * + * Some AI tools have different naming for + * user and bot roles so added this so it + * can be specified. + * + * @array $messageRoles + */ public array $messageRoles = [ 'user' => 'user', 'assistant' => 'assistant' ]; + /** + * List As Object + * + * This is to specify if the chat history + * should be sent as an Object or Array + * to the payload. + * + * @array $listAsObject + */ public bool $listAsObject = false; public array $chatMaps = []; @@ -62,8 +80,6 @@ function __construct() $this->headers = [ "Authorization" => "Bearer {$apiToken}", - "Content-Type" => "application/json", - "Accept" => "application/json", ]; } diff --git a/src/Features/Audio.php b/src/Features/Audio.php index 7f24e1d..ac6f52b 100644 --- a/src/Features/Audio.php +++ b/src/Features/Audio.php @@ -28,7 +28,7 @@ function __construct(protected string $url, protected array $headers) public function fromText( string $model, string $text, - String $voice = "alloy" + String $voice = "alloy" //default voice as OpenAi is the only supported driver ): string { return Http::withHeaders($this->headers) diff --git a/src/Features/Completion.php b/src/Features/Completion.php index a1ad0cf..eee1998 100644 --- a/src/Features/Completion.php +++ b/src/Features/Completion.php @@ -38,17 +38,18 @@ public function sendMessage( int $maxTokens = 1024 ): array { + // Takes request and maps it to the $this->requestRules $request = []; foreach ($this->requestRules as $key => $value) { if (is_array($value)) { - $temp = []; + $arrayMap = []; foreach ($value as $k => $val) { if ($eval = eval("return $val;")) { if(isset($eval['role'])) { - $temp[] = $eval; + $arrayMap[] = $eval; } else { - $temp = [ - ...$temp, + $arrayMap = [ + ...$arrayMap, ...$eval ]; } @@ -56,7 +57,7 @@ public function sendMessage( unset($value[$k]); } } - $request[$key] = [...$temp]; + $request[$key] = [...$arrayMap]; } else { $request[$key] = eval("return $value;"); } diff --git a/src/Helpers/StreamedResponse.php b/src/Helpers/StreamedResponse.php deleted file mode 100644 index af597c1..0000000 --- a/src/Helpers/StreamedResponse.php +++ /dev/null @@ -1,101 +0,0 @@ -headers = $headers; - - return $this; - } - - public function post(string $url, array $data): static - { - $this->url = $url; - $this->data = $data; - - return $this; - } - - public function streamedResponse(): string - { - $client = new Client(); - - $headers = [ - 'Content-Type' => 'application/json', - ...$this->headers - ]; - - $body = json_encode($this->data); - - try { - - $response = $client->request('POST', $this->url, [ - 'headers' => $headers, - 'body' => $body, - 'stream' => true - ]); - - header("Content-Type: text/event-stream"); - - $stream = $response->getBody(); - - $result = ""; - - while (!$stream->eof()) { - $line = $this->readLine($stream); - - if (!str_starts_with($line, 'data:')) { - continue; - } - - $data = trim(substr($line, strlen('data:'))); - - if ($data === '[DONE]') { - break; - } - - $response = json_decode($data, true); - - echo $response['choices'][0]['delta']['content'] ?? ""; - $result = $response['choices'][0]['delta']['content'] ?? ""; - - } - - ob_flush(); - ob_clean(); - - return $result; - - } catch (GuzzleException $e) { - // Handle any errors during the request - return "Error: " . $e->getMessage(); - } - } - - private function readLine($stream): string - { - $buffer = ''; - - while (! $stream->eof()) { - if ('' === ($byte = $stream->read(1))) { - return $buffer; - } - $buffer .= $byte; - if ($byte === "\n") { - break; - } - } - - return $buffer . "\n"; - } -} diff --git a/src/SidekickConversation.php b/src/SidekickConversation.php index 9f52179..8de0bac 100644 --- a/src/SidekickConversation.php +++ b/src/SidekickConversation.php @@ -11,14 +11,6 @@ class SidekickConversation protected Driver $sidekick; protected Conversation $conversation; - /** - * @param Driver $driver - */ - function __construct(Driver $driver) - { - $this->sidekick = Sidekick::create($driver); - } - /** * @param string $conversationId * @return $this @@ -26,21 +18,26 @@ function __construct(Driver $driver) public function resume(string $conversationId): static { $this->conversation = Conversation::findOrFail($conversationId); + $this->sidekick = Sidekick::create(new $this->conversation->class()); return $this; } /** + * @param Driver $driver * @param string $model * @param string $systemPrompt * @param int $maxTokens * @return $this */ public function begin( + Driver $driver, string $model, string $systemPrompt = '', int $maxTokens = 1024 ): static { + $this->sidekick = Sidekick::create($driver); + $this->conversation = new Conversation(); $this->conversation->model = $model; $this->conversation->class = get_class($this->sidekick); @@ -92,6 +89,12 @@ public function sendMessage(string $message) { return $this->sidekick->getErrorMessage($response); } + + /** + * @param array $messages + * @param array $mappings + * @return array + */ public function toCustomArray( array $messages, array $mappings = [],