$this->chatable::class, 'chatable_id' => $this->chatable->id, 'user_id' => auth()->id(), ], ['title' => 'Chat with investments'] ); $this->agent_conversation_id = $chatWith->id; $this->messages = $chatWith->messages() ->orderBy('id', 'desc') ->limit(20) ->get(['role', 'content', 'created_at']) ->map(fn ($m) => ['role' => $m->role, 'content' => $m->content, 'created_at' => $m->created_at]) ->reverse() ->values() ->toArray(); } public function startCompletion(?string $suggestedPrompt = null): void { if ($this->streaming) { return; } // prevent spam if ($this->isRateLimited()) { array_push($this->messages, [ 'role' => 'assistant', 'content' => __('Hang on! You\'re doing that too much.'), 'created_at' => now(), ]); $this->js('scrollChatWindow(250)'); return; } if ($suggestedPrompt) { $this->prompt = $suggestedPrompt; $this->suggested_prompts = []; } if (empty(trim($this->prompt ?? ''))) { $this->resetPrompt(); array_push($this->messages, ['role' => 'assistant', 'content' => __('Feel free to ask me a question!'), 'created_at' => now()]); $this->js('scrollChatWindow(250)'); return; } array_push($this->messages, ['role' => 'user', 'content' => $this->prompt, 'created_at' => now()]); $this->js('scrollChatWindow(250)'); $this->resetPrompt(); $this->streaming = true; $this->js('$wire.generateCompletion()'); } public function generateCompletion(): void { $userPrompt = end($this->messages)['content'] ?? ''; try { $agent = $this->makeAgent()->continue($this->agent_conversation_id, auth()->user()); $stream = $agent->stream($userPrompt); } catch (Exception $e) { array_push($this->messages, ['role' => 'assistant', 'content' => $e->getMessage(), 'created_at' => now()]); $this->resetPrompt(); return; } $this->stream(to: 'answer', content: '', replace: true); foreach ($stream as $event) { if ($event instanceof TextDelta) { $this->stream(to: 'answer', content: $event->delta, replace: false); $this->answer .= $event->delta; } $this->js('scrollChatWindow()'); } array_push($this->messages, ['role' => 'assistant', 'content' => $this->answer, 'created_at' => now()]); $this->resetPrompt(); $this->js('$wire.generateSuggestedPrompts()'); } #[Async] public function generateSuggestedPrompts(): void { try { $response = ChatWithSuggestedPromptsAgent::make(messages: array_slice($this->messages, -3))->prompt(''); $this->suggested_prompts = $response->toArray()['suggested_prompts'] ?? []; } catch (Exception $e) { $this->suggested_prompts = []; $this->error($e->getMessage()); } } public function resetPrompt(): void { $this->answer = null; $this->prompt = null; $this->streaming = false; } public function isRateLimited(): bool { $rateLimitKey = auth()->id().'/'.$this->chatable->id; if (RateLimiter::tooManyAttempts($rateLimitKey, 20)) { return true; } RateLimiter::hit($rateLimitKey, 60); return false; } private function makeAgent(): Agent { return match (true) { $this->chatable instanceof Portfolio => new ChatWithPortfolioAgent($this->chatable), $this->chatable instanceof Holding => new ChatWithHoldingAgent($this->chatable), }; } }; ?>
AI {{ __('Hi, how can I help?') }}
{{ __('You') }} {{ $message['content'] }}
@elseAI {{ $answer }}