Skip to content

Commit

Permalink
Yeah! the Solutions are working
Browse files Browse the repository at this point in the history
  • Loading branch information
alnutile committed Jul 12, 2024
1 parent 6305045 commit 63542d4
Show file tree
Hide file tree
Showing 29 changed files with 808 additions and 32 deletions.
1 change: 1 addition & 0 deletions Modules/LlmDriver/app/ClaudeClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ public function completionPool(array $prompts, int $temperature = 0): array
])->baseUrl($this->baseUrl)
->timeout(240)
->post('/messages', $payload);

}

});
Expand Down
143 changes: 125 additions & 18 deletions Modules/LlmDriver/app/Functions/ReportingTool.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,26 @@

namespace LlmLaraHub\LlmDriver\Functions;

use App\Domains\Chat\MetaDataDto;
use App\Domains\Messages\RoleEnum;
use App\Domains\Prompts\FindSolutionsPrompt;
use App\Domains\Prompts\ReportBuildingFindRequirementsPrompt;
use App\Domains\Prompts\ReportingSummaryPrompt;
use App\Domains\Reporting\EntryTypeEnum;
use App\Domains\Reporting\ReportTypeEnum;
use App\Domains\Reporting\StatusEnum;
use App\Models\Document;
use App\Models\DocumentChunk;
use App\Models\Entry;
use App\Models\Message;
use App\Models\Report;
use App\Models\Section;
use Illuminate\Support\Facades\Log;
use Laravel\Pennant\Feature;
use LlmLaraHub\LlmDriver\DistanceQuery\DistanceQueryFacade;
use LlmLaraHub\LlmDriver\LlmDriverFacade;
use LlmLaraHub\LlmDriver\Responses\CompletionResponse;
use LlmLaraHub\LlmDriver\Responses\EmbeddingsResponseDto;
use LlmLaraHub\LlmDriver\Responses\FunctionResponse;
use LlmLaraHub\LlmDriver\ToolsHelper;

Expand All @@ -35,28 +44,15 @@ public function handle(
{
Log::info('[LaraChain] ReportingTool Function called');

//make or update a reports table for this message - chat
//gather all the documents
//and for each document
//GOT TO TRIGGER THE PROMPT TO BE RELATIVE
// like a summary of the goal or something
//build up a list of sections that are requests (since this is a flexible tool that will be part of a prompt
//then save each one with a reference to the document, chunk to the sections table
//then for each section review each related collections solutions to make numerous
// or use vector search
//entries to address the sections requirements
//saving to the entries the related collection, document, document_chunk, full text (siblings)
//then build a response for each section to the response field of the section.
//finally build up a summary of all the responses for the report
//this will lead to a ui to comment on "sections" and "responses"

$report = Report::firstOrCreate([
'chat_id' => $message->getChat()->id,
'message_id' => $message->id,
'reference_collection_id' => $message->getReferenceCollection()?->id,
'user_id' => $message->getChat()->user_id,
], [
'type' => ReportTypeEnum::RFP,
'status_sections_generation' => StatusEnum::Pending,
'status_entries_generation' => StatusEnum::Pending,
]);

$documents = $message->getChatable()->documents;
Expand All @@ -65,8 +61,6 @@ public function handle(

$this->results = [];

$sectionContent = [];

Log::info('[LaraChain] - Reporting Tool', [
'documents_count' => count($documents),
]);
Expand Down Expand Up @@ -107,10 +101,14 @@ public function handle(
}
}

notify_ui($message->getChat(), 'Wow that was a lot of document! Now to finalize the output');
notify_ui($message->getChat(), 'Building Summary');

$response = $this->summarizeReport($report);

$report->update([
'status_sections_generation' => StatusEnum::Complete,
]);

$assistantMessage = $message->getChat()->addInput(
message: $response->content,
role: RoleEnum::Assistant,
Expand All @@ -126,6 +124,19 @@ public function handle(
$report->message_id = $assistantMessage->id;
$report->save();

notify_ui_complete($message->getChat());

notify_ui($message->getChat(), 'Building Solutions list');
notify_ui_report($report, 'Building Solutions list');

$this->makeEntriesFromSections($report);

$report->update([
'status_entries_generation' => StatusEnum::Complete,
]);

notify_ui_complete($message->getChat());
notify_ui_report_complete($report);
//as a final output
//get deadlines
//get contacts
Expand All @@ -139,6 +150,87 @@ public function handle(
]);
}

protected function makeEntriesFromSections(Report $report): void
{
$referenceCollection = $report->reference_collection;

if (! $referenceCollection) {
return;
}

foreach ($report->refresh()->sections->chunk(3) as $sectionChunk) {
$prompts = []; //reset every 3 sections
$sections = []; //reset every 3 sections

/** @var Section $section */
foreach ($sectionChunk as $section) {

$input = $section->content;

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

$embeddingSize = get_embedding_size($report->getEmbeddingDriver());

/** @phpstan-ignore-next-line */
$documentChunkResults = DistanceQueryFacade::cosineDistance(
$embeddingSize,
/** @phpstan-ignore-next-line */
$referenceCollection->id, //holy luck batman this is nice!
$embedding->embedding,
MetaDataDto::from([])//@NOTE could use this later if needed
);

$content = [];
/** @var DocumentChunk $result */
foreach ($documentChunkResults as $result) {
$contentString = remove_ascii($result->content);
$content[] = $contentString; //reduce_text_size seem to mess up Claude?
}

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

$prompt = FindSolutionsPrompt::prompt(
$section->content,
$context,
$report->getChatable()->description
);

$prompts[] = $prompt;
$sections[] = $section;
}

$results = LlmDriverFacade::driver($report->getDriver())
->completionPool($prompts);

foreach ($results as $resultIndex => $result) {
$section = data_get($sections, $resultIndex, null);

if (! $section) {
continue;
}

$content = $result->content;
$title = str($content)->limit(125)->toString();

Entry::updateOrCreate([
'section_id' => $section->id,
'document_id' => $section->document_id,
],
[
'title' => $title,
'content' => $content,
'type' => EntryTypeEnum::Solution,
]);

notify_ui_report($report, 'Added Solution');
}
}

}

protected function poolPrompt(array $prompts, Report $report, Document $document): void
{
$results = LlmDriverFacade::driver($report->getDriver())
Expand Down Expand Up @@ -173,6 +265,16 @@ protected function makeSectionFromContent(
Report $report): void
{
try {

notify_ui($report->getChat(), 'Building Requirements list');
notify_ui_report($report, 'Building Requirements list');

/**
* @TODO
* use the force tool feature to then
* make a tool that it has to return the values
* as
*/
$content = str($content)
->remove('```json')
->remove('```')
Expand All @@ -189,6 +291,7 @@ protected function makeSectionFromContent(
'subject' => $title,
'content' => $contentBody,
]);
notify_ui_report($report, 'Added Requirement');
}
} catch (\Exception $e) {
Section::updateOrCreate([
Expand All @@ -199,12 +302,16 @@ protected function makeSectionFromContent(
'subject' => '[ERROR FORMATTING PLEASE FIX]',
'content' => $content,
]);
notify_ui_report($report, 'Added Requirement');
Log::error('Error parsing JSON', [
'error' => $e->getMessage(),
'content' => $content,
'line' => $e->getLine(),
]);
}

notify_ui($report->getChat(), 'Done Building Requirements list');
notify_ui_report($report, 'Done Building Requirements list');
}

/**
Expand Down
37 changes: 37 additions & 0 deletions app/Domains/Prompts/FindSolutionsPrompt.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace App\Domains\Prompts;

use Illuminate\Support\Facades\Log;

class FindSolutionsPrompt
{
public static function prompt(string $requirement, string $possibleSolutions, string $collectionDescription): string
{
Log::info('[LaraChain] - FindSolutionsPrompt');

return <<<PROMPT
### ROLE ###
Role solutions finder. You will be handed a requirement then the possible strategy or strategies to solve it.
### TASK ###
Using the REQUIREMENT text you will see if the given Strategy is a good fit.
If it is reply with a paragraph or two of text that is a solution to the requirement.
Start each paragraph with a section title.
If it is not just return a blank response. Some requirements are
just contact info and due dates for those just highlight that info.
### FORMAT ###
Output is just Markdown And "" if no solution is found.
### REQUIREMENT ###
$requirement
$collectionDescription
### SOLUTION ###
$possibleSolutions
PROMPT;
}
}
10 changes: 10 additions & 0 deletions app/Domains/Reporting/EntryTypeEnum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace App\Domains\Reporting;

enum EntryTypeEnum: string
{
case Solution = 'solution';
case Reference = 'reference';

}
12 changes: 12 additions & 0 deletions app/Domains/Reporting/StatusEnum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace App\Domains\Reporting;

enum StatusEnum: string
{
case Pending = 'pending';
case Complete = 'complete';
case Cancelled = 'cancelled';
case CompleteWithErrors = 'complete_with_errors';
case Running = 'running';
}
5 changes: 4 additions & 1 deletion app/Events/ChatUiUpdateEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ class ChatUiUpdateEvent implements ShouldBroadcast
/**
* Create a new event instance.
*/
public function __construct(public Collection|HasDrivers $collection, public Chat $chat, public string $updateMessage)
public function __construct(
public Collection|HasDrivers $collection,
public Chat $chat,
public string $updateMessage)
{
//
}
Expand Down
55 changes: 55 additions & 0 deletions app/Events/ReportingEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

namespace App\Events;

use App\Models\Report;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class ReportingEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;

/**
* Create a new event instance.
*/
public function __construct(
public Report $report,
public string $updateMessage
) {
//
}

/**
* Get the channels the event should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new PrivateChannel(
'collection.chat.reports.'.$this->report->id),
];
}

public function broadcastAs(): string
{
return 'update';
}

public function broadcastWith(): array
{
return [
'id' => $this->report->id,
/** @phpstan-ignore-next-line */
'status_sections_generation' => $this->report->status_sections_generation?->value,
/** @phpstan-ignore-next-line */
'status_entries_generation' => $this->report->status_entries_generation?->value,
'updateMessage' => $this->updateMessage,
];
}
}
16 changes: 16 additions & 0 deletions app/Http/Controllers/ReportController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace App\Http\Controllers;

use App\Http\Resources\ReportResource;
use App\Models\Report;

class ReportController extends Controller
{
public function show(Report $report)
{
return response()->json([
'report' => new ReportResource($report),
]);
}
}
Loading

0 comments on commit 63542d4

Please sign in to comment.