如何在GPT生成响应时即时显示用户输入的指令?
实现即时显示用户输入+流式AI回复的方案
核心思路
- 发送消息时立即将用户指令加入对话列表,AI回复先留空(或显示加载状态),让用户输入立刻显示在页面上
- 调用OpenAI API时启用流式响应(
stream: true),逐字接收AI生成的内容,实时更新对话中的AI回复,模拟ChatGPT的打字效果 - 使用React的函数式状态更新,确保每次对话修改都基于最新的列表数据,避免异步状态冲突
修改后的完整代码
import React, { useState } from 'react'; function TextInput({ label, ...props }) { return ( <div> <input type="text" {...props} value={props.instruction} onChange={props.handleInstructionChange} placeholder="输入你的问题..." /> <button onClick={props.startChat}>Send Message</button> <label htmlFor={props.id}>{label}</label> </div> ); } const Chat = () => { const [conversation, setConversation] = useState([]); const [instruction, setInstruction] = useState(''); const handleInstructionChange = (event) => { setInstruction(event.target.value); }; const startChat = async () => { if (!instruction.trim()) return; // 1. 立即添加用户消息到对话列表,AI回复先占位 const userMessage = { role: 'user', content: instruction }; setConversation(prev => [...prev, userMessage]); setInstruction(''); // 清空输入框 // 添加AI消息占位,后续实时更新内容 setConversation(prev => [...prev, { role: 'assistant', content: '' }]); const aiMessageIndex = conversation.length + 1; try { const response = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.REACT_APP_OPENAI_API_KEY}` }, body: JSON.stringify({ model: 'gpt-3.5-turbo', messages: [...conversation, userMessage].map(msg => ({ role: msg.role, content: msg.content })), stream: true // 开启流式响应 }) }); if (!response.ok) throw new Error('API请求失败'); const reader = response.body.getReader(); const decoder = new TextDecoder('utf-8'); // 2. 逐段读取流式数据,实时更新AI回复 while (true) { const { done, value } = await reader.read(); if (done) break; const chunk = decoder.decode(value); const lines = chunk.split('\n').filter(line => line.trim() !== ''); for (const line of lines) { if (line.startsWith('data: ')) { const data = line.slice(6); if (data === '[DONE]') continue; try { const json = JSON.parse(data); const content = json.choices[0].delta.content || ''; // 函数式更新,基于最新对话列表追加内容 setConversation(prev => { const newConversation = [...prev]; newConversation[aiMessageIndex].content += content; return newConversation; }); } catch (e) { console.error('解析流式数据失败:', e); } } } } } catch (error) { console.error('对话出错:', error); // 更新AI消息为错误提示 setConversation(prev => { const newConversation = [...prev]; newConversation[aiMessageIndex].content = '抱歉,生成回复时出错了,请重试。'; return newConversation; }); } }; return ( <div style={{ marginLeft: 20, maxWidth: 800 }}> {conversation.map((message, index) => ( <div key={index} style={{ marginBottom: 12, padding: 10, borderRadius: 8, backgroundColor: message.role === 'user' ? '#f0f4f8' : '#ffffff', border: '1px solid #e2e8f0' }}> <div style={{ fontWeight: 'bold', marginBottom: 4 }}> {message.role === 'user' ? '你' : 'AI'} </div> <div style={{ whiteSpace: 'pre-wrap' }}> {message.content || (message.role === 'assistant' ? '正在思考...' : '')} </div> </div> ))} <div style={{ marginTop: 20 }}> <TextInput label="输入问题" name="chat-input" autoComplete="off" startChat={startChat} handleInstructionChange={handleInstructionChange} instruction={instruction} /> </div> </div> ); }; export default Chat;
关键代码说明
- 即时显示用户输入:点击发送后立刻将用户消息插入对话列表,同时清空输入框,页面会瞬间渲染用户输入内容
- 流式响应处理:通过
stream: true开启OpenAI的流式输出,逐块读取服务器返回的数据,解析出每一段生成的文本并追加到AI回复中,实现打字机效果 - 函数式状态更新:所有对话列表的更新都使用
setConversation(prev => ...),确保每次修改都基于最新的状态,避免异步更新导致的内容覆盖 - 加载与错误提示:AI生成回复时显示"正在思考...",请求出错时更新为错误提示,提升用户体验
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

