wire:stream
Livewire le permite transmitir contenido a una página web antes de que se complete una solicitud a través de la API wire:stream. Se trata de una función muy útil para cosas como los chat-bots de inteligencia artificial, que transmiten las respuestas a medida que se generan.
Para demostrar la funcionalidad más básica de wire:stream, a continuación se muestra un simple componente CountDown que cuando se pulsa un botón muestra una cuenta atrás al usuario desde “3” hasta “0”:
use Livewire\Component;
class CountDown extends Component{ public $start = 3;
public function begin() { while ($this->start >= 0) { // Transmite el recuento actual al navegador... $this->stream( to: 'count', content: $this->start, replace: true, );
// Pausa de 1 segundo entre números... sleep(1);
// Disminuye el contador... $this->start = $this->start - 1; }; }
public function render() { return <<<'HTML' <div> <button wire:click="begin">Iniciar cuenta atrás</button>
<h1>Cuenta: <span wire:stream="count">{{ $start }}</span></h1> </div> HTML; }}Esto es lo que ocurre desde la perspectiva del usuario cuando pulsa “Iniciar cuenta atrás”:
- “Cuenta: 3” se muestra en la página
- Pulsan el botón “Iniciar cuenta atrás”
- Transcurre un segundo y se muestra “Cuenta: 2” se muestra
- Este proceso continúa hasta que se muestra “Count: 0” se muestra
- Todo lo anterior sucede mientras una única petición de red sale hacia el servidor.
Esto es lo que ocurre desde la perspectiva del sistema cuando se pulsa el botón:
- Se envía una petición a Livewire para llamar al método
begin() - Se llama al método
begin()y comienza el bucle while - Se llama a
$this->stream()e inmediatamente comienza una “respuesta en flujo” al navegador - El navegador recibe una respuesta en flujo con instrucciones para encontrar el elemento en el componente con
wire:stream="count", y reemplazar su contenido con el payload recibido (“3” en el caso del primer número transmitido) - El método
sleep(1)hace que el servidor cuelgue durante un segundo - El bucle
whilese repite y el proceso de transmisión de un nuevo número cada segundo continúa hasta que la condiciónwhilees falsa Cuandobegin()ha terminado de ejecutarse y todas las cuentas han sido transmitidas al navegador, Livewire finaliza su ciclo de vida, renderizando el componente y enviando la respuesta final al navegador.
Transmisión de respuestas de chat-bot
Un caso de uso común para wire:stream es la transmisión de respuestas de chat-bot a medida que se reciben de una API que soporta respuestas transmitidas (como ChatGPT de OpenAI).
A continuación se muestra un ejemplo de uso de wire:stream para lograr una interfaz similar a ChatGPT:
use Livewire\Component;
class ChatBot extends Component{ public $prompt = '';
public $pregunta = '';
public $respuseta = '';
function enviarPrompt() { $this->pregunta = $this->prompt;
$this->prompt = '';
$this->js('$wire.ask()'); }
function ask() { $this->respuseta = OpenAI::ask($this->pregunta, function ($partial) { $this->stream(to: 'respuseta', content: $partial); }); }
public function render() { return <<<'HTML' <div> <section> <div>ChatBot</div>
@if ($pregunta) <article> <hgroup> <h3>Usuario</h3> <p>{{ $pregunta }}</p> </hgroup>
<hgroup> <h3>ChatBot</h3> <p wire:stream="answer">{{ $respuesta }}</p> </hgroup> </article> @endif </section>
<form wire:submit="enviarPrompt"> <input wire:model="prompt" type="text" placeholder="Enviar Mensaje" autofocus> </form> </div> HTML; }}Esto es lo que ocurre en el ejemplo anterior:
- Un usuario escribe en un campo de texto llamado “Enviar un mensaje” para hacer una pregunta al chat-bot.
- Pulsa la tecla [Intro].
- Una petición de red es enviada al servidor, establece el mensaje en la propiedad
$pregunta, y borra la propiedad$prompt. - La respuesta se envía de vuelta al navegador y se borra la entrada. Debido a que
$this->js(“...”)fue llamado, se lanza una nueva petición al servidor llamando al métodoask(). - El método
ask()llama a la API de ChatBot y recibe respuestas parciales a través del parámetro$partialen el callback. - Cada
$partialse transmite al navegador en el elementowire:stream="answer"de la página, mostrando la respuesta progresivamente al usuario. - Cuando se recibe la respuesta completa, la solicitud Livewire finaliza y el usuario recibe la respuesta completa.
Reemplazar(replace) vs anexar(append)
Cuando transmita contenido a un elemento usando $this->stream(), puede decirle a Livewire que reemplace el contenido del elemento destino con el contenido transmitido o que lo anexe al contenido existente.
Reemplazar o añadir puede ser deseable dependiendo del escenario. Por ejemplo, cuando se transmite una respuesta de un chatbot, normalmente se desea anexar (y por lo tanto es el valor por defecto). Sin embargo, cuando se muestra algo como una cuenta atrás, reemplazar es más adecuado.
Puede configurar cualquiera de los dos pasando el parámetro replace: a $this->stream con un valor booleano:
// Añadir contenido...$this->stream(to: 'target', content: '...');
// Reemplaza el contenido...$this->stream(to: 'target', content: '...', replace: true);Append/replace también puede especificarse a nivel del elemento de destino añadiendo o eliminando el modificador .replace:
// Añadir contenido...<div wire:stream="target">
// Reemplaza el contenido...<div wire:stream.replace="target">