wire:stream
您是视觉学习者吗?
通过我们深入的屏幕录制掌握 Livewire
立即观看
Livewire 允许您通过 wire:stream
API 在请求完成之前将内容流式传输到网页。对于诸如 AI 聊天机器人(在生成响应时流式传输响应)之类的功能,这是一个非常有用的特性。
与 Laravel Octane 不兼容
Livewire 目前不支持将 wire:stream
与 Laravel Octane 一起使用。
为了演示 wire:stream
的最基本功能,下面是一个简单的 CountDown 组件,当按下按钮时,它会向用户显示从“3”到“0”的倒计时
use Livewire\Component; class CountDown extends Component{ public $start = 3; public function begin() { while ($this->start >= 0) { // Stream the current count to the browser... $this->stream( to: 'count', content: $this->start, replace: true, ); // Pause for 1 second between numbers... sleep(1); // Decrement the counter... $this->start = $this->start - 1; }; } public function render() { return <<<'HTML' <div> <button wire:click="begin">Start count-down</button> <h1>Count: <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(如 OpenAI 的 ChatGPT)接收的。
以下是使用 wire:stream
实现类似 ChatGPT 界面示例
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>ChatBot</div> @if ($question) <article> <hgroup> <h3>User</h3> <p>{{ $question }}</p> </hgroup> <hgroup> <h3>ChatBot</h3> <p wire:stream="answer">{{ $answer }}</p> </hgroup> </article> @endif </section> <form wire:submit="submitPrompt"> <input wire:model="prompt" type="text" placeholder="Send a message" autofocus> </form> </div> HTML; }}
以下是上述示例中发生的情况
- 用户在标记为“发送消息”的文本字段中输入内容,以向聊天机器人提问。
- 他们按下 [Enter] 键。
- 向服务器发送网络请求,将消息设置为
$question
属性,并清除$prompt
属性。 - 将响应发送回浏览器并清除输入。由于调用了
$this->js('...')
,因此会触发一个新的请求到调用ask()
方法的服务器。 ask()
方法调用 ChatBot API,并通过回调中的$partial
参数接收流式响应部分。- 每个
$partial
都流式传输到浏览器的页面上的wire:stream="answer"
元素中,向用户逐步显示答案。 - 当收到整个响应时,Livewire 请求完成,用户收到完整响应。
替换与追加
使用 $this->stream()
将内容流式传输到元素时,你可以告诉 Livewire 用流式传输的内容替换目标元素的内容或将其追加到现有内容中。
根据场景的不同,替换或追加都是可取的。例如,在从聊天机器人流式传输响应时,通常需要追加(因此是默认设置)。但是,在显示倒计时等内容时,替换更合适。
您可以通过将 replace:
参数传递给 $this->stream
(带有布尔值)进行配置
// Append contents...$this->stream(to: 'target', content: '...'); // Replace contents...$this->stream(to: 'target', content: '...', replace: true);
还可以通过追加或删除 .replace
修饰符在目标元素级别指定追加/替换
// Append contents...<div wire:stream="target"> // Replace contents...<div wire:stream.replace="target">