bounty将在14小时后到期。回答此问题可获得+350声望奖励。texas697正在寻找一个答案从一个有信誉的来源。
我正在尝试设置一个node/react设置,它可以从openai流结果。我找到了一个这样做的示例项目,但它使用的是next.js。我成功地进行了调用,结果按预期返回,但是,问题是如何将流返回给客户端。下面是在next.js中工作的代码
import {
GetServerSidePropsContext,
} from 'next';
import { DEFAULT_SYSTEM_PROMPT, DEFAULT_TEMPERATURE } from '@/utils/app/const';
import { OpenAIError, OpenAIStream } from '@/utils/server';
import { ChatBody, Message } from '@/types/chat';
// @ts-expect-error
import wasm from '../../node_modules/@dqbd/tiktoken/lite/tiktoken_bg.wasm?module';
import tiktokenModel from '@dqbd/tiktoken/encoders/cl100k_base.json';
import { Tiktoken, init } from '@dqbd/tiktoken/lite/init';
const handler = async (
req: GetServerSidePropsContext['req'],
res: GetServerSidePropsContext['res'],
): Promise<Response> => {
try {
const { model, messages, key, prompt, temperature } = (await (
req as unknown as Request
).json()) as ChatBody;
-(
(await init((imports) => WebAssembly.instantiate(wasm, imports)))
);
console.log({ model, messages, key, prompt, temperature })
const encoding = new Tiktoken(
tiktokenModel.bpe_ranks,
tiktokenModel.special_tokens,
tiktokenModel.pat_str,
);
let promptToSend = prompt;
if (!promptToSend) {
promptToSend = DEFAULT_SYSTEM_PROMPT;
}
let temperatureToUse = temperature;
if (temperatureToUse == null) {
temperatureToUse = DEFAULT_TEMPERATURE;
}
const prompt_tokens = encoding.encode(promptToSend);
let tokenCount = prompt_tokens.length;
let messagesToSend: Message[] = [];
for (let i = messages.length - 1; i >= 0; i--) {
const message = messages[i];
const tokens = encoding.encode(message.content);
if (tokenCount + tokens.length + 1000 > model.tokenLimit) {
break;
}
tokenCount += tokens.length;
messagesToSend = [message, ...messagesToSend];
}
encoding.free();
const stream = await OpenAIStream(
model,
promptToSend,
temperatureToUse,
key,
messagesToSend,
);
return new Response(stream);
} catch (error) {
console.error(error);
if (error instanceof OpenAIError) {
return new Response('Error', { status: 500, statusText: error.message });
} else {
return new Response('Error', { status: 500 });
}
}
};
export default handler;
OpenAIStream.ts
const res = await fetch(url, {...});
const encoder = new TextEncoder();
const decoder = new TextDecoder();
const stream = new ReadableStream({
async start(controller) {
const onParse = (event: ParsedEvent | ReconnectInterval) => {
if (event.type === 'event') {
const data = event.data;
try {
const json = JSON.parse(data);
if (json.choices[0].finish_reason != null) {
controller.close();
return;
}
const text = json.choices[0].delta.content;
const queue = encoder.encode(text);
controller.enqueue(queue);
} catch (e) {
controller.error(e);
}
}
};
const parser = createParser(onParse);
for await (const chunk of res.body as any) {
parser.feed(decoder.decode(chunk));
}
},
});
return stream;
当尝试在node中执行此操作时,我遇到的第一个问题是“ReadableStream”未定义。我用polyfill解决了
import { ReadableStream } from 'web-streams-polyfill/ponyfill/es2018';
当我记录
const text = json.choices[0].delta.content;
它显示来自API的多个响应正在正确返回。
而不是使用返回数据使用新的响应我使用:
import { toJSON } from 'flatted';
export const fetchChatOpenAI = async (
req: AuthenticatedRequest,
res: Response
) => {
try {
const stream = await OpenAIStream(
model,
promptToSend,
temperatureToUse,
key,
messagesToSend
);
res.status(200).send(toJSON(stream));
} catch (error) {
if (error instanceof OpenAIError) {
console.error(error);
res.status(500).json({ statusText: error.message });
} else {
res.status(500).json({ statusText: 'ERROR' });
}
}
};
在客户端中,这里是如何处理响应的。
const controller = new AbortController();
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
signal: controller.signal,
body: JSON.stringify(chatBody),
});
if (!response.ok) {
console.log(response.statusText);
} else {
const data = response.body;
if (data) {
const reader = data.getReader();
const decoder = new TextDecoder();
let done = false;
let text = '';
while (!done) {
const { value, done: doneReading } = await reader.read();
console.log(value);
done = doneReading;
const chunkValue = decoder.decode(value);
console.log(chunkValue);
text += chunkValue;
}
}
}
当运行next.js项目时,这里是这些日志的示例输出。
在我的Node版本中,下面是这些日志的屏幕截图
2条答案
按热度按时间roqulrg31#
如果您正在处理从Node.js到客户端的流数据,则可以使用服务器发送事件(SSE)来实现此目的。
这是一个express的例子:
在这段代码中,
getOpenAIData()
是一个假设的异步生成器函数,它从OpenAI API获取并生成数据。在客户端(React.js),你可以使用EventSource API来消费服务器发送的事件:
3phpmpom2#
从您的代码中,我看到您正在从API返回JSON响应。不知道为什么你试图在客户端将其解析为文本。
请尝试以下操作
如果这不起作用,请分享您正在谈论的示例应用程序和您的代码的链接,以便我们可以为您提供更多帮助。