
[英]How to see if openAI (node js) createModeration response "flagged" is true
[英]How to return streams from node js with openai
我正在尝试设置一个从 openai 流式传输结果的节点/反应设置。 我找到了一个执行此操作的示例项目,但它使用的是 next.js。我成功地进行了调用并且结果按预期返回,但是,问题是如何将 stream 返回给客户端。 这是在 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;
当尝试在节点中进行此操作时,我遇到的第一个问题是“ReadableStream”未定义。 我使用 polyfill 解决了它
从 'web-streams-polyfill/ponyfill/es2018' 导入 { ReadableStream };
当我登录
const text = json.choices[0].delta.content;
它表明来自 API 的多个响应已正确返回。
我没有使用新的 Response 返回数据,而是使用:
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 项目时,这里是来自这些日志的示例 output。
在我的节点版本中,这里是这些日志的截图
如果您正在处理从 Node.js 到客户端的流数据,您可以为此目的使用服务器发送事件 (SSE)。
这是快递的例子:
const express = require('express');
const app = express();
app.get('/stream', async (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
for await (const data of getOpenAIData()) {
res.write(`data: ${JSON.stringify(data)}\n\n`);
}
});
app.listen(3000);
在此代码中, getOpenAIData()
是一个假设的异步生成器 function,它从 OpenAI API 获取和生成数据。
在客户端 (React.js),您可以使用 EventSource API 来使用服务器发送的事件:
import React, { useEffect, useState } from 'react';
function MyComponent() {
const [data, setData] = useState([]);
useEffect(() => {
const eventSource = new EventSource('http://localhost:3000/stream');
eventSource.onmessage = (event) => {
const newData = JSON.parse(event.data);
setData((prevData) => [...prevData, newData]);
};
return () => {
eventSource.close();
};
}, []);
return (
<div>
{data.map((item, index) => (
<p key={index}>{item}</p>
))}
</div>
);
}
export default MyComponent;
从您的代码中,我看到您正在从 API 返回 JSON 响应。不确定您为什么要尝试在客户端将其解析为文本。
请尝试以下
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 {
try{
const data = await response.json();
console.log(data)
} catch (err) {
console.log({err});
}
}
如果这不起作用,请分享您正在谈论的示例应用程序和您的代码的链接,以便我们可以为您提供更多帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.