diff --git a/app/Domains/Sources/BaseSource.php b/app/Domains/Sources/BaseSource.php index ad1d044a..98de2a8f 100644 --- a/app/Domains/Sources/BaseSource.php +++ b/app/Domains/Sources/BaseSource.php @@ -18,11 +18,12 @@ use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Log; use LlmLaraHub\LlmDriver\LlmDriverFacade; +use LlmLaraHub\LlmDriver\ToolsHelper; use LlmLaraHub\TagFunction\Jobs\TagDocumentJob; abstract class BaseSource { - use ChatHelperTrait; + use ChatHelperTrait, ToolsHelper; public string $batchTitle = 'Chunking Source'; diff --git a/app/Domains/Sources/EmailSource.php b/app/Domains/Sources/EmailSource.php index 1d5091ba..ee4406b7 100644 --- a/app/Domains/Sources/EmailSource.php +++ b/app/Domains/Sources/EmailSource.php @@ -53,72 +53,73 @@ public function handle(Source $source): void $this->meta_data = $this->mailDto->toArray(); - Log::info('[LaraChain] - Running Email Source'); - - //use the users source prompt to create this next step - //track the results in a chat_id thread - //and as a message? - //then using the source the results will do something with the content - // and then delete the email - // but we can leave it if it returns false? - // still too much coding there how do I let the tool do it. - $prompt = PromptMerge::merge( ['[CONTEXT]'], [$this->content], $source->getPrompt() ); + Log::info('[LaraChain] - Running Email Source', [ + 'prompt' => $prompt, + ]); + + $chat = $source->chat; - $chat->addInput( - message: $prompt, - role: RoleEnum::User, - show_in_thread: true, - meta_data: MetaDataDto::from([ - 'driver' => $source->getDriver(), - 'source' => $source->title, - ]), - ); + $results = LlmDriverFacade::driver( $source->getDriver() )->completion($prompt); - $chat->addInput( - message: $results->content, - role: RoleEnum::Assistant, - show_in_thread: true, - meta_data: MetaDataDto::from([ - 'driver' => $source->getDriver(), - 'source' => $source->title, - ]), - ); - - //@TODO how to look for false - // surface this "power" into the UI. - // tag or store the fact we checked this emails - - $document = Document::updateOrCreate([ - 'source_id' => $source->id, - 'type' => TypesEnum::Email, - 'subject' => $this->mailDto->subject, - 'collection_id' => $source->collection_id, - ], [ - 'summary' => $results->content, - 'meta_data' => $this->mailDto->toArray(), - 'original_content' => $this->mailDto->body, - 'status_summary' => StatusEnum::Pending, - 'status' => StatusEnum::Pending, - ]); - - Bus::batch([new ChunkDocumentJob($document)]) - ->name("Processing Email {$this->mailDto->subject}") - ->allowFailures() - ->dispatch(); + if($this->ifNotActionRequired($results->content)) { + Log::info('[LaraChain] - Email Source Skipping', [ + 'prompt' => $prompt, + ]); + } else { + + $userMessage = $chat->addInput( + message: $prompt, + role: RoleEnum::User, + show_in_thread: true, + meta_data: MetaDataDto::from([ + 'driver' => $source->getDriver(), + 'source' => $source->title, + ]), + ); + + $document = Document::updateOrCreate([ + 'source_id' => $source->id, + 'type' => TypesEnum::Email, + 'subject' => $this->mailDto->subject, + 'collection_id' => $source->collection_id, + ], [ + 'summary' => $results->content, + 'meta_data' => $this->mailDto->toArray(), + 'original_content' => $this->mailDto->body, + 'status_summary' => StatusEnum::Pending, + 'status' => StatusEnum::Pending, + ]); + + Bus::batch([new ChunkDocumentJob($document)]) + ->name("Processing Email {$this->mailDto->subject}") + ->allowFailures() + ->dispatch(); + + $assistantMessage = $chat->addInput( + message: $results->content, + role: RoleEnum::Assistant, + show_in_thread: true, + meta_data: MetaDataDto::from([ + 'driver' => $source->getDriver(), + 'source' => $source->title, + ]), + ); + + $this->savePromptHistory( + message: $assistantMessage, + prompt: $prompt); + } - //should we delete the email? - // right now it gets set to seen - // on the MailDto we have options } } diff --git a/app/Helpers/ChatHelperTrait.php b/app/Helpers/ChatHelperTrait.php index 1ac3c767..344e0b78 100644 --- a/app/Helpers/ChatHelperTrait.php +++ b/app/Helpers/ChatHelperTrait.php @@ -33,4 +33,19 @@ public function getUserId(Collection $collection): ?int return $collection->team?->user_id; } + + public function ifNotActionRequired(string $results): bool { + // @NOTE llms sometimes do not return the right + // string for example. + // false becomes false, "false" or "False" etc. + + $results = str($results) + ->trim() + ->lower() + ->remove('"') + ->remove("'") + ->toString(); + + return $results == "false"; + } } diff --git a/app/Jobs/ChunkDocumentJob.php b/app/Jobs/ChunkDocumentJob.php index 643d4528..336a512f 100644 --- a/app/Jobs/ChunkDocumentJob.php +++ b/app/Jobs/ChunkDocumentJob.php @@ -2,7 +2,9 @@ namespace App\Jobs; +use App\Helpers\TextChunker; use App\Models\Document; +use App\Models\DocumentChunk; use Illuminate\Bus\Batch; use Illuminate\Bus\Batchable; use Illuminate\Bus\Queueable; @@ -10,7 +12,16 @@ use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; +use Illuminate\Support\Facades\Bus; +use Illuminate\Support\Facades\Log; +use LlmLaraHub\LlmDriver\LlmDriverFacade; +use LlmLaraHub\TagFunction\Jobs\TagDocumentJob; +/** + * @NOTE + * Only really good for chunking content that can fit in the Original Content + * of a Document model. + */ class ChunkDocumentJob implements ShouldQueue { use Batchable; @@ -34,5 +45,62 @@ public function handle(): void return; } + + Log::info('[LaraChain] - Chunking Document', [ + 'document' => $this->document->id, + ]); + + $document = $this->document; + + $page_number = 0; + + $pageContent = $this->document->original_content; + + $size = config('llmdriver.chunking.default_size'); + + $chunked_chunks = TextChunker::handle($pageContent, $size); + + foreach ($chunked_chunks as $chunkSection => $chunkContent) { + $guid = md5($chunkContent); + + $DocumentChunk = DocumentChunk::updateOrCreate( + [ + 'document_id' => $document->id, + 'sort_order' => $page_number, + 'section_number' => $chunkSection, + ], + [ + 'guid' => $guid, + 'content' => to_utf8($chunkContent), + ] + ); + + $chunks[] = [ + new VectorlizeDataJob($DocumentChunk), + ]; + } + + $name = sprintf($document->type->name, $document->id); + + + + Bus::batch($chunks) + ->name($name) + ->allowFailures() + ->finally(function (Batch $batch) use ($document) { + + Bus::batch([ + [ + new SummarizeDocumentJob($document), + new TagDocumentJob($document), + new DocumentProcessingCompleteJob($document), + ] + ]) + ->name(sprintf("Final Document Steps Document %s id %d", $document->type->name, $document->id)) + ->allowFailures() + ->dispatch(); + }) + ->onQueue(LlmDriverFacade::driver($document->getDriver())->onQueue()) + ->dispatch(); } } diff --git a/resources/js/Pages/Sources/EmailSource/Components/Resources.vue b/resources/js/Pages/Sources/EmailSource/Components/Resources.vue index 3195660b..6c3555c3 100644 --- a/resources/js/Pages/Sources/EmailSource/Components/Resources.vue +++ b/resources/js/Pages/Sources/EmailSource/Components/Resources.vue @@ -9,7 +9,9 @@