Skip to content

Commit

Permalink
Merge pull request #2 from LlmLaraHub/claude
Browse files Browse the repository at this point in the history
Claude Driver
  • Loading branch information
alnutile authored Mar 30, 2024
2 parents 5095f83 + 8d287e8 commit 72a2ba7
Show file tree
Hide file tree
Showing 27 changed files with 470 additions and 63 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,12 @@ And just thinking how to make some of those flows work in a Laravel environment

Per the Laravel docs https://laravel.com/docs/11.x/reverb



## Local Dev

```bash
php artisan horizon:watch
php artisan reverb:start --debug
npm run dev
```
6 changes: 3 additions & 3 deletions app/Domains/Messages/SearchOrSummarizeChatRepo.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public function search(Chat $chat, string $input): string

/** @var EmbeddingsResponseDto $embedding */
$embedding = LlmDriverFacade::driver(
$chat->chatable->getDriver()
$chat->chatable->getEmbeddingDriver()
)->embedData($input);

$results = DocumentChunk::query()
Expand All @@ -40,12 +40,12 @@ public function search(Chat $chat, string $input): string
$content = [];

foreach ($results as $result) {
$content[] = reduce_text_size($result->content);
$content[] = remove_ascii(reduce_text_size($result->content)); //reduce_text_size seem to mess up Claude?
}

$content = implode(' ', $content);

$content = 'This is data from the search results when entering the users prompt please use this for context and only this: '.$content;
$content = 'This is data from the search results when entering the users prompt please use this for context and only this and return as markdown so I can render it: '.$content;

$chat->addInput(
message: $content,
Expand Down
1 change: 1 addition & 0 deletions app/Http/Controllers/CollectionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public function store()
'name' => 'required',
'description' => 'required',
'driver' => 'required',
'embedding_driver' => 'required',
]);

$validated['team_id'] = auth()->user()->current_team_id;
Expand Down
2 changes: 1 addition & 1 deletion app/Jobs/VectorlizeDataJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public function handle(): void
$content = $this->documentChunk->content;

/** @var EmbeddingsResponseDto $results */
$results = LlmDriverFacade::driver($this->documentChunk->getDriver())
$results = LlmDriverFacade::driver($this->documentChunk->getEmbeddingDriver())
->embedData($content);

$this->documentChunk->update([
Expand Down
132 changes: 107 additions & 25 deletions app/LlmDriver/ClaudeClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,58 +5,140 @@
use App\LlmDriver\Requests\MessageInDto;
use App\LlmDriver\Responses\CompletionResponse;
use App\LlmDriver\Responses\EmbeddingsResponseDto;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class ClaudeClient
{
protected string $baseUrl = 'https://api.anthropic.com/v1';

protected string $version = '2023-06-01';

protected string $driver = 'claude';

public function embedData(string $data): EmbeddingsResponseDto
{
if (! app()->environment('testing')) {
sleep(2);
}
Log::info('LlmDriver::MockClient::embedData');

$data = get_fixture('embedding_response.json');

return EmbeddingsResponseDto::from([
'embedding' => data_get($data, 'data.0.embedding'),
'token_count' => 1000,
]);
throw new \Exception('Not implemented');
}

/**
* @param MessageInDto[] $messages
*/
public function chat(array $messages): CompletionResponse
{
if (! app()->environment('testing')) {
sleep(2);
$model = $this->getConfig('claude')['models']['completion_model'];
$maxTokens = $this->getConfig('claude')['max_tokens'];

Log::info('LlmDriver::Claude::completion');

/**
* I need to iterate over each item
* then if there are two rows with role assistant I need to insert
* in betwee a user row with some copy to make it work like "And the user search results had"
* using the Laravel Collection library
*/
$messages = collect($messages)->map(function ($item) {
if ($item->role === 'system') {
$item->role = 'assistant';
}

return $item->toArray();
})->reverse()->values();

$messages = $messages->flatMap(function ($item, $index) use ($messages) {
if ($index > 0 && $item['role'] === 'assistant' && optional($messages->get($index + 1))['role'] === 'assistant') {
return [
$item,
['role' => 'user', 'content' => 'Continuation of search results'],
];
}

return [$item];
})->toArray();

put_fixture('claude_messages_debug.json', $messages);

$results = $this->getClient()->post('/messages', [
'model' => $model,
'system' => 'Return a markdown response.',
'max_tokens' => $maxTokens,
'messages' => $messages,
]);

if (! $results->ok()) {
$error = $results->json()['error']['type'];
$message = $results->json()['error']['message'];
Log::error('Claude API Error ', [
'type' => $error,
'message' => $message,
]);
throw new \Exception('Claude API Error '.$message);
}

Log::info('LlmDriver::MockClient::completion');
$data = null;

$data = <<<'EOD'
Voluptate irure cillum dolor anim officia reprehenderit dolor. Eiusmod veniam nostrud consectetur incididunt proident id. Anim adipisicing pariatur amet duis Lorem sunt veniam veniam est. Deserunt ea aliquip cillum pariatur consectetur. Dolor in reprehenderit adipisicing consectetur cupidatat ad cupidatat reprehenderit. Nostrud mollit voluptate aliqua anim pariatur excepteur eiusmod velit quis exercitation tempor quis excepteur.
EOD;
foreach ($results->json()['content'] as $content) {
$data = $content['text'];
}

return new CompletionResponse($data);
return CompletionResponse::from([
'content' => $data,
]);
}

public function completion(string $prompt): CompletionResponse
{
if (! app()->environment('testing')) {
sleep(2);
$model = $this->getConfig('claude')['models']['completion_model'];
$maxTokens = $this->getConfig('claude')['max_tokens'];

Log::info('LlmDriver::Claude::completion');

$results = $this->getClient()->post('/messages', [
'model' => $model,
'max_tokens' => $maxTokens,
'messages' => [
[
'role' => 'user',
'content' => $prompt,
],
],
]);

if (! $results->ok()) {
$error = $results->json()['error']['type'];
Log::error('Claude API Error '.$error);
throw new \Exception('Claude API Error '.$error);
}

Log::info('LlmDriver::MockClient::completion');
$data = null;

foreach ($results->json()['content'] as $content) {
$data = $content['text'];
}

$data = <<<'EOD'
Voluptate irure cillum dolor anim officia reprehenderit dolor. Eiusmod veniam nostrud consectetur incididunt proident id. Anim adipisicing pariatur amet duis Lorem sunt veniam veniam est. Deserunt ea aliquip cillum pariatur consectetur. Dolor in reprehenderit adipisicing consectetur cupidatat ad cupidatat reprehenderit. Nostrud mollit voluptate aliqua anim pariatur excepteur eiusmod velit quis exercitation tempor quis excepteur.
EOD;
return CompletionResponse::from([
'content' => $data,
]);
}

protected function getError(Response $response)
{
return $response->json()['error']['type'];
}

protected function getClient()
{
$api_token = $this->getConfig('claude')['api_key'];
if (! $api_token) {
throw new \Exception('Claude API Token not found');
}

return new CompletionResponse($data);
return Http::withHeaders([
'x-api-key' => $api_token,
'anthropic-version' => $this->version,
'content-type' => 'application/json',
])->baseUrl($this->baseUrl);
}

protected function getConfig(string $driver): array
Expand Down
13 changes: 13 additions & 0 deletions app/LlmDriver/DriversEnum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace App\LlmDriver;

enum DriversEnum: string
{
case Mock = 'mock';
case OpenAi = 'openai';
case OpenAiAzure = 'openai_azure';
case Ollama = 'ollama';
case Gemini = 'gemini';
case Claude = 'claude';
}
10 changes: 10 additions & 0 deletions app/LlmDriver/HasDrivers.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace App\LlmDriver;

interface HasDrivers
{
public function getDriver(): string;

public function getEmbeddingDriver(): string;
}
2 changes: 2 additions & 0 deletions app/LlmDriver/LlmDriverClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ protected function createDriver($name)
switch ($name) {
case 'openai':
return new OpenAiClient();
case 'claude':
return new ClaudeClient();
case 'mock':
return new MockClient();
default:
Expand Down
17 changes: 14 additions & 3 deletions app/Models/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace App\Models;

use App\LlmDriver\DriversEnum;
use App\LlmDriver\HasDrivers;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
Expand All @@ -14,19 +16,23 @@
* @property int $id
* @property string $name
* @property string|null $description
* @property DriversEnum $driver
* @property DriversEnum $embedding_driver
* @property bool $active
* @property int $team_id
* @property \Illuminate\Support\Carbon $created_at
* @property \Illuminate\Support\Carbon $updated_at
*/
class Collection extends Model
class Collection extends Model implements HasDrivers
{
use HasFactory;

protected $guarded = [];

protected $cast = [
protected $casts = [
'active' => 'boolean',
'driver' => DriversEnum::class,
'embedding_driver' => DriversEnum::class,
];

public function team(): BelongsTo
Expand All @@ -36,7 +42,12 @@ public function team(): BelongsTo

public function getDriver(): string
{
return $this->driver;
return $this->driver->value;
}

public function getEmbeddingDriver(): string
{
return $this->embedding_driver->value;
}

public function documents(): HasMany
Expand Down
10 changes: 8 additions & 2 deletions app/Models/Document.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use App\Domains\Documents\StatusEnum;
use App\Domains\Documents\TypesEnum;
use App\LlmDriver\HasDrivers;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
Expand All @@ -17,7 +18,7 @@
* @property string|null $summary
* @property string|null $file_path
*/
class Document extends Model
class Document extends Model implements HasDrivers
{
use HasFactory;

Expand Down Expand Up @@ -58,6 +59,11 @@ public function mkdirPathToFile(): ?string

public function getDriver(): string
{
return $this->collection->driver;
return $this->collection->driver->value;
}

public function getEmbeddingDriver(): string
{
return $this->collection->embedding_driver->value;
}
}
10 changes: 8 additions & 2 deletions app/Models/DocumentChunk.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
namespace App\Models;

use App\Domains\Documents\StatusEnum;
use App\LlmDriver\HasDrivers;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Pgvector\Laravel\Vector;

/**
* @property Document $document
*/
class DocumentChunk extends Model
class DocumentChunk extends Model implements HasDrivers
{
use HasFactory;

Expand Down Expand Up @@ -41,8 +42,13 @@ protected static function booted()
});
}

public function getEmbeddingDriver(): string
{
return $this->document->collection->embedding_driver->value;
}

public function getDriver(): string
{
return $this->document->collection->driver;
return $this->document->collection->driver->value;
}
}
2 changes: 1 addition & 1 deletion app/helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function put_fixture($file_name, $content = [], $json = true)
if (! function_exists('remove_ascii')) {
function remove_ascii($string): string
{
return preg_replace('/[^\x00-\x7F]+/', '', $string);
return str_replace("\u2019", ' ', preg_replace('/[^\x00-\x7F]+/', '', $string));
}
}

Expand Down
10 changes: 9 additions & 1 deletion config/llmdriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,16 @@
'completion_model' => env('OPENAI_COMPLETION_MODEL', 'gpt-4-turbo-preview'),
'chat_model' => env('OPENAICHAT_MODEL', 'gpt-4-turbo-preview'),
],
'azure' => [
'mock' => [

],
'claude' => [
'api_key' => env('CLAUDE_API_KEY'),
'max_tokens' => env('CLAUDE_MAX_TOKENS', 4000),
'models' => [
//@see https://www.anthropic.com/news/claude-3-family
'completion_model' => env('CLAUDE_COMPLETION_MODEL', 'claude-3-opus-20240229'),
],
],
'ollama' => [

Expand Down
Loading

0 comments on commit 72a2ba7

Please sign in to comment.