React 组件部分
import React, { useState } from "react";
function ChatComponent() {
const [messages, setMessages] = useState([{ role: "user", content: "Tell me about JavaScript." },
]);
const [streamingText, setStreamingText] = useState(""); // 保存流式响应的内容
const [isLoading, setIsLoading] = useState(false);// 处理发送消息
const sendMessage = async () => {const apiKey = "your-api-key"; // 替换成你的 OpenAI API Key const url = "https://api.openai.com/v1/chat/completions"; const headers = { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}`, }; const body = JSON.stringify({ model: "gpt-3.5-turbo", messages: [ { role: "system", content: "You are a helpful assistant." }, ...messages, ], stream: true, // 启用流式输出 }); setIsLoading(true); setStreamingText(""); // 清空之前的流式内容 const response = await fetch(url, { method: "POST", headers: headers, body: body, }); if (!response.body) return; const reader = response.body.getReader(); const decoder = new TextDecoder("utf-8"); let done = false; // 逐块读取流 while (!done) { const { value, done: readerDone } = await reader.read(); done = readerDone; const chunk = decoder.decode(value, { stream: true }); // 解析并提取流式内容 const lines = chunk.split("\n").filter((line) => line.trim() !== ""); for (const line of lines) { const parsedLine = line.replace(/^data: /, ""); // 去掉开头的 "data: " if (parsedLine === "[DONE]") { return; // 流结束 } try { const parsed = JSON.parse(parsedLine); const content = parsed.choices[0].delta?.content || ""; setStreamingText((prev) => prev + content); // 更新 UI 中的流式文本 } catch (err) { console.error("Could not parse stream chunk", err); } } } setIsLoading(false);
};
return (
<div> <h2>ChatGPT Stream Output</h2> <div className="messages"> {messages.map((msg, index) => ( <div key={index}> <strong>{msg.role === "user" ? "You" : "Assistant"}: </strong> {msg.content} </div> ))} {isLoading && ( <div> <strong>Assistant: </strong> {streamingText} </div> )} </div> <button onClick={sendMessage} disabled={isLoading}> Send Message </button> </div>
);
}export default ChatComponent;
- 样式 (CSS)
可以添加一些简单的样式来美化聊天窗口:
.messages {
border: 1px solid #ddd;
padding: 10px;
max-width: 600px;
height: 400px;
overflow-y: auto;
margin-bottom: 20px;
background-color: #f9f9f9;
}
button {
padding: 10px 20px;
font-size: 16px;
}
关键点解析:
fetch 和 ReadableStream:
fetch 返回的流通过 response.body.getReader() 读取数据块。
使用 TextDecoder 将二进制流解码为文本。
逐步更新状态:
每次读取到新的数据块时,通过 setStreamingText 将内容逐步追加到当前的流式输出中。
这样可以确保用户能逐步看到 ChatGPT 的回复,而不是一次性全部显示。
控制按钮状态:
使用 isLoading 来控制按钮是否可点击,防止重复请求。
通过这种方式,你可以在 React 应用中实现 ChatGPT 流式输出的效果,并逐步显示内容。
本文由 admin 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Sep 5, 2024 at 09:59 pm