The issue with the current implementation is that the foreach loop in the generateDescription method is blocking the Livewire component from updating the front-end until the entire response is received from OpenAI. To update the front-end as the words are coming in, the foreach loop needs to be run in a separate thread. This can be achieved using PHP's pcntl_fork function.
Here's an updated version of the Livewire component and class:
Livewire component:
<div>
<button wire:click="generateDescription">Generate description</button>
<div x-data="{ reply: '' }" x-init="listenForDescriptionGeneratedEvent()">
<p class="description" x-text="reply"></p>
</div>
</div>
@push('scripts')
<script>
function listenForDescriptionGeneratedEvent() {
window.livewire.on('description-generated', ({ reply }) => {
document.querySelector('.description').textContent = reply;
});
}
</script>
@endpush
Livewire class:
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use OpenAI\Laravel\Facades\OpenAI;
class DescriptionGenerator extends Component
{
public function generateDescription()
{
$stream = OpenAI::chat()->createStreamed([
"model" => "gpt-3.5-turbo",
'messages' => [
['role' => 'user', 'content' => 'PHP is '],
],
]);
$pid = pcntl_fork();
if ($pid == -1) {
// Fork failed
$this->dispatchBrowserEvent('description-generated', ['reply' => 'Error: Fork failed']);
} elseif ($pid) {
// Parent process
pcntl_wait($status); // Wait for child process to finish
} else {
// Child process
foreach ($stream as $response) {
$reply = $response->choices[0]->delta->content;
$this->dispatchBrowserEvent('description-generated', ['reply' => $reply]);
}
exit(); // Exit child process
}
}
public function render()
{
return view('livewire.description-generator');
}
}
Explanation:
- The
generateDescriptionmethod now forks a child process to run theforeachloop in the background. - The
listenForDescriptionGeneratedEventmethod is called when the Livewire component is initialized. It listens for thedescription-generatedevent and updates the front-end with the new reply. - The
dispatchBrowserEventmethod is called inside the child process to send thedescription-generatedevent to the front-end with the new reply.