如何将来自Nextjs API的OpenAI流响应发送到客户端。

6

我尝试了openai-streamsnextjs-openai, 它们只适用于Node 18+,但是在Node 17及以下版本上失败。由于Digital Oceans应用平台目前不支持Node 18,所以我被限制在Node 17及以下版本。

我还尝试了this method,它在客户端方面效果良好,但会暴露API密钥。我想在NextJS API路由中实现它,但无法将流式响应传递给客户端。

使用下面的代码,我只能从API路由获取第一个响应块,并且无法获得流式响应以产生ChatGPT效果。请亲切地帮助。

// /api/prompt.js

import { Configuration, OpenAIApi } from "openai";
import { Readable } from "readable-stream";

const configuration = new Configuration({
  apiKey: process.env.NEXT_PUBLIC_OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);

export default async function handler(req, res) {
  const completion = await openai.createCompletion(
    {
      model: "text-davinci-003",
      prompt: "tell me a story",
      max_tokens: 500,
      stream: true,
    },
    { responseType: "stream" }
  );

  completion.data.on("data", async (data) => {
    const lines = data
      .toString()
      .split("\n")
      .filter((line) => line.trim() !== "");

    for (const line of lines) {
      const message = line.replace(/^data: /, "");
      if (message === "[DONE]") {
        return;
      }
      try {
        const parsed = JSON.parse(message);
        const string = parsed.choices[0].text;
        Readable.from(string).pipe(res);
      } catch (error) {
        console.error("Could not JSON parse stream message", message, error);
      }
    }
  });

// /components/Completion.js

export default function Completion() {
  const [text, setText] = useState();

  const generate = async () => {
    const response = await fetch("/api/prompt");
    console.log("response: ", response);
    const text = await response.text();
    console.log("text: ", text);
    setText((state) => state + text);
  };
  
  // ... rest
}

3个回答

2

您可以在 Node <18 上使用 openai-streams/node 入口点,它将返回一个 Node.js 的 Readable 而不是 WHATWG 的 ReadableStream。我很快会更新文档以使其更清晰。


Node:在Next.js API路由中使用流

如果您无法使用Edge运行时或希望以其他原因使用Node.js流,请使用openai-streams/node

import type { NextApiRequest, NextApiResponse } from "next";
import { OpenAI } from "openai-streams/node";

export default async function test(_: NextApiRequest, res: NextApiResponse) {
  const stream = await OpenAI("completions", {
    model: "text-davinci-003",
    prompt: "Write a happy sentence.\n\n",
    max_tokens: 25,
  });

  stream.pipe(res);
}

1

你可以使用 vercel AI sdkStreamingTextResponse

附上了一些来自他们文档的示例代码 example code

import { Configuration, OpenAIApi } from 'openai-edge'
import { OpenAIStream, StreamingTextResponse } from 'ai'

const config = new Configuration({
  apiKey: process.env.OPENAI_API_KEY
})
const openai = new OpenAIApi(config)

export const runtime = 'edge'

export async function POST(req) {
  const { messages } = await req.json()
  const response = await openai.createChatCompletion({
    model: 'gpt-4',
    stream: true,
    messages
  })
  const stream = OpenAIStream(response)
  return new StreamingTextResponse(stream)
}

注意事项:
  1. 这需要Edge Runtime
  2. openai-edge 需要 Node 18+。然而,预计很快将使用官方openai库中的流式支持来取代它。

回答需要支持信息 您的回答可以通过提供更多的支持信息来改进。请[编辑]以添加进一步的细节,例如引用或文档,以便他人可以确认您的回答是否正确。您可以在帮助中心找到关于如何撰写良好回答的更多信息。 - moken
回答需要支持信息 您的回答可以通过提供更多的支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认您的回答是否正确。您可以在帮助中心中找到关于如何撰写良好回答的更多信息。 - undefined
能否修改此流中的数据?例如,我希望返回一个带有内容(data.choices[0].message?.content)和自定义字段的对象。我的理解是,由于OpenAiStream格式化响应的原因,这是不可能的,您需要构建一个自定义流。 - undefined
能否修改此流中的数据?例如,我希望返回一个包含内容(data.choices[0].message?.content)和自定义字段的对象。我的理解是,由于OpenAiStream格式化响应的原因,这是不可能的,您需要构建一个自定义流程。 - DeveloperRyan

0
不要使用openai-edge或其他类似的工具,应该继续使用官方的软件包/模块。

1
目前您的回答表达不够清晰。请[编辑]以添加更多细节,帮助其他人理解您的回答如何解决所提出的问题。您可以在帮助中心找到更多有关撰写好回答的信息。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接