Директива wire:stream⚓︎
Livewire позволяет передавать поток контента на веб-страницу до завершения запроса через API wire:stream. Это чрезвычайно полезная функция для таких вещей, как чат-боты с ИИ, которые передают ответы по мере их генерации.
Не совместимо с Laravel Octane
В настоящее время Livewire не поддерживает использование wire:stream с Laravel Octane.
Чтобы продемонстрировать наиболее базовую функциональность wire:stream, ниже приведён простой компонент CountDown, который при нажатии кнопки отображает обратный отсчёт для пользователя от «3» до «0»:
<?php
use Livewire\Component;
class CountDown extends Component
{
public $start = 3;
public function begin()
{
while ($this->start >= 0) {
// Передаём текущее значение отсчёта в браузер...
$this->stream(
to: 'count',
content: $this->start,
replace: true,
);
// Пауза в 1 секунду между числами...
sleep(1);
// Уменьшаем счётчик...
$this->start = $this->start - 1;
};
}
public function render()
{
return <<<'HTML'
<div>
<button wire:click="begin">Начать отсчёт</button>
<h1>Отсчёт: <span wire:stream="count">{{ $start }}</span></h1>
</div>
HTML;
}
}
Вот что происходит с точки зрения пользователя, когда он нажимает «Начать отсчёт»:
- На странице отображается «Отсчёт: 3»
- Пользователь нажимает кнопку «Начать отсчёт»
- Проходит одна секунда, и отображается «Отсчёт: 2»
- Этот процесс продолжается до тех пор, пока не будет показано «Отсчёт: 0»
Всё вышеперечисленное происходит во время одного сетевого запроса к серверу.
Вот что происходит с точки зрения системы при нажатии кнопки:
- Запрос отправляется в Livewire для вызова метода
begin() - Вызывается метод
begin()и запускается циклwhile - Вызывается
$this->stream()и немедленно начинается «потоковый ответ» в браузер - Браузер получает потоковый ответ с инструкциями найти элемент в компоненте с
wire:stream="count"и заменить его содержимое полученной полезной нагрузкой («3» в случае первого переданного числа) - Метод
sleep(1)заставляет сервер ожидать одну секунду - Цикл
whileповторяется, и процесс передачи нового числа каждую секунду продолжается до тех пор, пока условиеwhileне станет ложным - Когда метод
begin()завершает выполнение и все значения отсчёта переданы в браузер, Livewire завершает свой жизненный цикл запроса, рендерит компонент и отправляет финальный ответ в браузер
Потоковая передача ответов чат-бота⚓︎
Обычным вариантом использования для wire:stream является потоковая передача ответов чат-бота, полученных от API, поддерживающего потоковые ответы (например, ChatGPT от OpenAI).
Ниже приведён пример использования wire:stream для создания интерфейса, подобного ChatGPT:
<?php
use Livewire\Component;
class ChatBot extends Component
{
public $prompt = '';
public $question = '';
public $answer = '';
function submitPrompt()
{
$this->question = $this->prompt;
$this->prompt = '';
$this->js('$wire.ask()');
}
function ask()
{
$this->answer = OpenAI::ask($this->question, function ($partial) {
$this->stream(to: 'answer', content: $partial);
});
}
public function render()
{
return <<<'HTML'
<div>
<section>
<div>Чат-бот</div>
@if ($question)
<article>
<hgroup>
<h3>Пользователь</h3>
<p>{{ $question }}</p>
</hgroup>
<hgroup>
<h3>Чат-бот</h3>
<p wire:stream="answer">{{ $answer }}</p>
</hgroup>
</article>
@endif
</section>
<form wire:submit="submitPrompt">
<input wire:model="prompt" type="text" placeholder="Отправить сообщение" autofocus>
</form>
</div>
HTML;
}
}
Вот что происходит в приведённом выше примере:
- Пользователь вводит текст в поле «Отправить сообщение», чтобы задать вопрос чат-боту.
- Пользователь нажимает клавишу [Enter].
- Сетевой запрос отправляется на сервер, устанавливает сообщение в свойство
$questionи очищает свойство$prompt. - Ответ отправляется обратно в браузер, и поле ввода очищается. Поскольку был вызван
$this->js('...'), запускается новый запрос к серверу, вызывающий методask(). - Метод
ask()обращается к API чат-бота и получает частичные потоковые ответы через параметр$partialв обратном вызове. - Каждая часть
$partialпередаётся в браузер в элементwire:stream="answer"на странице, постепенно показывая ответ пользователю. - Когда полный ответ получен, запрос Livewire завершается, и пользователь получает полный ответ.
Замена или добавление⚓︎
При передаче контента в элемент с помощью $this->stream() вы можете указать Livewire либо заменить содержимое целевого элемента переданным содержимым, либо добавить его к существующему содержимому.
Замена или добавление могут быть желательны в зависимости от сценария. Например, при потоковой передаче ответа от чат-бота обычно требуется добавление (поэтому оно и является значением по умолчанию). Однако при отображении чего-то вроде обратного отсчёта замена более уместна.
Вы можете настроить любой из вариантов, передав параметр replace: в $this->stream с логическим значением:
<?php
// Добавить содержимое...
$this->stream(to: 'target', content: '...');
// Заменить содержимое...
$this->stream(to: 'target', content: '...', replace: true);
Добавление/замену также можно указать на уровне целевого элемента, добавив или удалив модификатор .replace:
<?php
// Добавить содержимое...
<div wire:stream="Target">
// Заменить содержимое...
<div wire:stream.replace="target">
Справочник⚓︎
Модификаторы⚓︎
| Модификатор | Описание |
|---|---|
.replace |
Заменяет содержимое элемента вместо добавления |