如何基于Firebase Cloud Functions实现ChatGPT响应实时流式返回?
实现ChatGPT流式响应返回至Firebase Cloud Functions客户端
要实现实时流式返回ChatGPT的响应,你需要修改Cloud Functions代码以处理OpenAI的流式输出,并通过分块传输将内容逐步发送给客户端。以下是具体方案:
核心修改点
- 设置流式响应头:启用分块编码,告诉客户端准备接收连续的数据流
- 处理OpenAI流式输出:遍历SDK返回的异步迭代器(或监听数据流事件),将每个内容片段即时发送
- 客户端适配:通过Fetch API的ReadableStream或Server-Sent Events(SSE)接收并渲染流式内容
修改后的Cloud Functions代码(基于OpenAI SDK v4)
const functions = require("firebase-functions"); const { OpenAI } = require("openai"); const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY // 从环境变量读取API密钥 }); exports.chat = functions.https.onRequest(async (req, res) => { const { message } = req.body; // 配置流式响应头 res.setHeader("Content-Type", "text/event-stream"); res.setHeader("Cache-Control", "no-cache"); res.setHeader("Connection", "keep-alive"); res.setHeader("Access-Control-Allow-Origin", "*"); // 根据实际需求调整跨域规则 try { // 调用OpenAI流式聊天接口 const stream = await openai.chat.completions.create({ model: "gpt-3.5-turbo", stream: true, messages: [ { role: "system", content: "You are a helpful assistant." }, { role: "user", content: message } ] }); // 遍历流式响应的每个片段 for await (const chunk of stream) { const content = chunk.choices[0]?.delta?.content || ""; if (content) { // 以SSE格式发送内容(方便客户端解析) res.write(`data: ${JSON.stringify({ content })}\n\n`); } } // 结束响应 res.end(); } catch (error) { // 发送错误信息 res.write(`data: ${JSON.stringify({ error: error.message })}\n\n`); res.end(); } });
旧版OpenAI SDK(v3)兼容代码
如果你仍在使用v3版本SDK,可改用事件监听方式处理流式输出:
const functions = require("firebase-functions"); const openai = require("openai"); openai.apiKey = process.env.OPENAI_API_KEY; exports.chat = functions.https.onRequest((req, res) => { const { message } = req.body; // 配置响应头 res.setHeader("Content-Type", "text/event-stream"); res.setHeader("Cache-Control", "no-cache"); res.setHeader("Connection", "keep-alive"); res.setHeader("Access-Control-Allow-Origin", "*"); // 调用流式接口 openai.ChatCompletion.create({ model: "gpt-3.5-turbo", stream: true, messages: [ { role: "system", content: "You are a helpful assistant." }, { role: "user", content: message } ] }) .on("data", (chunk) => { const lines = chunk.toString().split("\n").filter(line => line.trim() !== ""); for (const line of lines) { const data = line.replace(/^data: /, ""); if (data === "[DONE]") { res.end(); return; } try { const json = JSON.parse(data); const content = json.choices[0]?.delta?.content || ""; if (content) { res.write(`data: ${JSON.stringify({ content })}\n\n`); } } catch (err) { console.error("解析流式数据失败:", err); } } }) .on("error", (error) => { res.write(`data: ${JSON.stringify({ error: error.message })}\n\n`); res.end(); }) .on("end", () => { res.end(); }); });
客户端接收示例(Fetch API)
async function sendChatMessage(userMessage) { const response = await fetch("/chat", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message: userMessage }) }); const reader = response.body.getReader(); const decoder = new TextDecoder(); const outputElement = document.getElementById("chat-output"); while (true) { const { done, value } = await reader.read(); if (done) break; const text = decoder.decode(value); // 拆分并解析SSE格式的消息 const messages = text.split("\n\n").filter(msg => msg.startsWith("data: ")); for (const msg of messages) { const data = JSON.parse(msg.replace("data: ", "")); if (data.content) { // 将内容追加到聊天界面 outputElement.textContent += data.content; } else if (data.error) { outputElement.textContent += `\n错误: ${data.error}`; } } } }
注意事项
- 函数超时设置:Firebase HTTP函数默认超时60秒,流式响应可能需要更长时间,可在Firebase控制台将函数超时调整至最大值90秒
- 跨域配置:根据客户端域名调整
Access-Control-Allow-Origin头,避免跨域错误 - 错误处理:需处理OpenAI API调用失败、网络中断等异常情况,确保客户端能收到错误提示
内容的提问来源于stack exchange,提问作者Miguel Dey
相关产品推荐
相关产品推荐

