63 lines
1.5 KiB
TypeScript
63 lines
1.5 KiB
TypeScript
|
|
import {
|
||
|
|
createParser,
|
||
|
|
type ParsedEvent,
|
||
|
|
type ReconnectInterval,
|
||
|
|
} from "eventsource-parser";
|
||
|
|
import { Configuration, OpenAIApi } from "openai-edge";
|
||
|
|
|
||
|
|
const configuration = new Configuration({
|
||
|
|
apiKey: process.env.OPENAI_API_KEY,
|
||
|
|
});
|
||
|
|
|
||
|
|
export const openai = new OpenAIApi(configuration);
|
||
|
|
|
||
|
|
if (!process.env.OPENAI_API_KEY) {
|
||
|
|
throw new Error("Missing env var from OpenAI");
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function OpenAIStream(res: Response) {
|
||
|
|
const encoder = new TextEncoder();
|
||
|
|
const decoder = new TextDecoder();
|
||
|
|
|
||
|
|
let counter = 0;
|
||
|
|
|
||
|
|
const stream = new ReadableStream({
|
||
|
|
async start(controller) {
|
||
|
|
function onParse(event: ParsedEvent | ReconnectInterval) {
|
||
|
|
if (event.type === "event") {
|
||
|
|
const data = event.data;
|
||
|
|
if (data === "[DONE]") {
|
||
|
|
controller.close();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
try {
|
||
|
|
const json = JSON.parse(data) as {
|
||
|
|
choices: any;
|
||
|
|
};
|
||
|
|
const text =
|
||
|
|
json.choices[0]?.delta?.content ?? json.choices[0]?.text ?? "";
|
||
|
|
|
||
|
|
if (counter < 2 && (text.match(/\n/) || []).length) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
const queue = encoder.encode(JSON.stringify(text) + "\n");
|
||
|
|
controller.enqueue(queue);
|
||
|
|
counter++;
|
||
|
|
} 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;
|
||
|
|
}
|