feat:adds more robust suggested follow up prompts

ensures the ai agent has access to the current date
This commit is contained in:
hackerESQ
2024-11-01 23:18:22 -05:00
parent 9cd6a37b05
commit 73dd885741
@@ -60,17 +60,19 @@ new class extends Component {
$this->resetPrompt(); $this->resetPrompt();
$this->streaming = true; $this->streaming = true;
$this->js('$wire.generate()'); $this->js('$wire.generateCompletion()');
} }
public function generate(): void public function generateCompletion(): void
{ {
try { try {
$stream = OpenAI::chat()->createStreamed([ $stream = OpenAI::chat()->createStreamed([
'model' => config('openai.model'), 'model' => config('openai.model'),
'messages' => [ 'messages' => [
['role' => 'system', 'content' => $this->system_prompt], ['role' => 'system', 'content' => "Today's date is "
.now()->format('Y-m-d')
.".\n\n".$this->system_prompt],
...array_slice($this->messages, -10) ...array_slice($this->messages, -10)
], ],
]); ]);
@@ -96,6 +98,76 @@ new class extends Component {
$this->chatable->chats()->save(new AiChat(['role' => 'assistant', 'content' => $this->answer])); $this->chatable->chats()->save(new AiChat(['role' => 'assistant', 'content' => $this->answer]));
array_push($this->messages, ['role' => 'assistant', 'content' => $this->answer]); array_push($this->messages, ['role' => 'assistant', 'content' => $this->answer]);
$this->resetPrompt(); $this->resetPrompt();
$this->js('$wire.generateSuggestedPrompts()');
}
public function generateSuggestedPrompts(): void
{
try {
$suggested_prompts = OpenAI::chat()->create([
'model' => config('openai.model'),
'response_format' => [
'type' => 'json_schema',
'json_schema' => [
'name' => 'suggested_prompts_schema',
'strict' => true,
'schema' => [
"type" => "object",
"properties" => [
"suggested_prompts" => [
"type" => "array",
"items" => [
"type" => "object",
"properties" => [
"text" => [
"type" => "string",
"description" => "The prompt question (no more than 5 words)"
],
"value" => [
"type" => "string",
"description" => "The detailed version of the question"
]
],
"required" => ["text", "value"],
"additionalProperties" => false
]
]
],
"required" => ["suggested_prompts"],
"additionalProperties" => false
]
]
],
'messages' => [
['role' => 'system', 'content' => "
Your role is to assist investors in asking thoughtful questions to their investment advisors.
When you help investors ask good questions, you should ensure the questions are based on the
provided context. Be sure to keep the questions short!
The questions you recommend might be based on natural follow up from the given context, requests
to clarify undefined terms, common decision frameworks, possible risks or benefits, or commonly
understood investing concepts.
Your response should only include valid JSON.
"],
['role' => 'user', 'content' => "
Generate a list of ". rand(1,5) ." follow up questions a savvy investor might ask their advisor
based on the following conversation:
\n\n
".json_encode(array_slice($this->messages, -4))
],
],
]);
$this->suggested_prompts = json_decode($suggested_prompts->choices[0]->message->content, true)['suggested_prompts'];
} catch (\Exception $e) {
$this->suggested_prompts = [];
$this->error($e->getMessage());
return;
}
} }
public function resetPrompt(): void public function resetPrompt(): void
@@ -161,7 +233,7 @@ new class extends Component {
key="ai-chat" key="ai-chat"
class="fixed bg-base-100 shadow-2xl rounded-none md:rounded-lg class="fixed bg-base-100 shadow-2xl rounded-none md:rounded-lg
inset-0 h-screen w-full inset-0 h-screen w-full
md:inset-auto md:right-6 md:bottom-6 md:w-[30rem] md:h-[46rem]" md:inset-auto md:right-6 md:bottom-6 md:w-[32rem] md:h-[46rem]"
> >
<div <div
class="absolute inset-0 flex flex-col overflow-hidden p-4" class="absolute inset-0 flex flex-col overflow-hidden p-4"
@@ -266,9 +338,8 @@ new class extends Component {
@foreach($suggested_prompts as $prompt) @foreach($suggested_prompts as $prompt)
<x-button <x-button
class="btn-xs btn-primary btn-outline mr-1 mb-2" class="btn-xs btn-primary btn-outline mr-1 mb-2"
label="{{ $prompt['text'] }}" wire:click="startCompletion('{{ addslashes($prompt['value']) }}')"
wire:click="startCompletion('{{ $prompt['value'] }}')" >{{ $prompt['text'] }}</x-button>
/>
@endforeach @endforeach
</div> </div>
@@ -286,7 +357,7 @@ new class extends Component {
></x-textarea> ></x-textarea>
</div> </div>
<x-button <x-button
spinner="generate" spinner="generateCompletion"
wire:click="startCompletion" wire:click="startCompletion"
class="btn btn-ghost h-24" class="btn btn-ghost h-24"
icon="o-paper-airplane" icon="o-paper-airplane"
@@ -295,7 +366,7 @@ new class extends Component {
</div> </div>
<div class="w-full mt-2"> <div class="w-full mt-2">
<p class="text-xs text-secondary leading-tight">{{ __('Advice generated by AI may contain errors. Use at your own risk. Always consult a licensed investment advisor.') }} </p> <p class="text-xs text-secondary leading-tight">{{ __('Advice generateCompletiond by AI may contain errors. Use at your own risk. Always consult a licensed investment advisor.') }} </p>
</div> </div>
</form> </form>
</div> </div>