如何在React Native(Expo)中实现ChatGPT Turbo API逐词流式输出?
在React Native(Expo)中实现ChatGPT Turbo API逐词流式输出
ChatGPT Turbo API完全支持逐词流式输出,只需在请求中开启流式参数并正确处理分块响应即可。以下是具体实现方案:
核心思路
开启API请求的stream: true参数后,OpenAI会将响应拆分为多个数据块逐步返回。我们需要在React Native中读取这些分块数据,提取增量文本并实时更新界面。
完整实现代码
import { useState } from 'react'; import { View, Text, TextInput, Button, ScrollView } from 'react-native'; const ChatScreen = () => { const [inputText, setInputText] = useState(''); const [responseText, setResponseText] = useState(''); const [isLoading, setIsLoading] = useState(false); const sendMessage = async () => { if (!inputText.trim() || isLoading) return; setIsLoading(true); setResponseText(''); try { const response = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.EXPO_PUBLIC_OPENAI_API_KEY}` }, body: JSON.stringify({ model: 'gpt-3.5-turbo', messages: [{ role: 'user', content: inputText }], stream: true }) }); if (!response.ok) { throw new Error(`API请求失败: ${response.status}`); } const reader = response.body.getReader(); const decoder = new TextDecoder('utf-8'); let done = false; while (!done) { const { value, done: streamDone } = await reader.read(); done = streamDone; if (value) { const chunk = decoder.decode(value, { stream: true }); 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 || ''; setResponseText(prev => prev + content); } catch (e) { console.error('解析响应块失败:', e); } } } } } } catch (error) { console.error('请求错误:', error); setResponseText(`请求失败: ${error.message}`); } finally { setIsLoading(false); } }; return ( <View style={{ flex: 1, padding: 16 }}> <ScrollView style={{ flex: 1, marginBottom: 16 }}> <Text style={{ fontSize: 16, lineHeight: 24 }}> {responseText} </Text> </ScrollView> <View style={{ flexDirection: 'row', gap: 8 }}> <TextInput style={{ flex: 1, borderWidth: 1, borderColor: '#ccc', padding: 8, borderRadius: 4 }} value={inputText} onChangeText={setInputText} placeholder="输入你的问题..." editable={!isLoading} /> <Button title={isLoading ? "加载中..." : "发送"} onPress={sendMessage} disabled={isLoading} /> </View> </View> ); }; export default ChatScreen;
关键注意事项
- API密钥安全:不要硬编码API密钥,使用Expo环境变量(前缀
EXPO_PUBLIC_)存储,生产环境建议通过自有后端代理请求,避免密钥暴露。 - 响应解析逻辑:API返回的每块内容以
data:开头,需过滤空行并裁剪前缀后解析JSON,[DONE]标记代表流结束,直接忽略即可。 - 状态更新方式:使用
setResponseText(prev => prev + content)确保每次更新基于最新状态,避免异步更新导致的文本丢失。
失败原因排查
之前用JavaScript实现失败,大概率是没正确处理流式响应的分块格式,或是未使用TextDecoder解码二进制流。另外要确认API密钥权限、账户余额是否正常,以及请求参数是否正确。
内容的提问来源于stack exchange,提问作者Saeed freelancer
相关产品推荐
相关产品推荐

