ai-utils.js
Version:
Build AI applications, chatbots, and agents with JavaScript and TypeScript.
113 lines (112 loc) • 4.7 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createOpenAIChatFullDeltaIterableQueue = void 0;
const secure_json_parse_1 = __importDefault(require("secure-json-parse"));
const zod_1 = require("zod");
const AsyncQueue_js_1 = require("../../../model-function/generate-text/AsyncQueue.cjs");
const parseEventSourceReadableStream_js_1 = require("../../../model-function/generate-text/parseEventSourceReadableStream.cjs");
const chatResponseStreamEventSchema = zod_1.z.object({
choices: zod_1.z.array(zod_1.z.object({
delta: zod_1.z.object({
role: zod_1.z.enum(["assistant", "user"]).optional(),
content: zod_1.z.string().nullable().optional(),
function_call: zod_1.z
.object({
name: zod_1.z.string().optional(),
arguments: zod_1.z.string().optional(),
})
.optional(),
}),
finish_reason: zod_1.z.enum(["stop", "length"]).nullable(),
index: zod_1.z.number(),
})),
created: zod_1.z.number(),
id: zod_1.z.string(),
model: zod_1.z.string(),
object: zod_1.z.string(),
});
async function createOpenAIChatFullDeltaIterableQueue(stream) {
const queue = new AsyncQueue_js_1.AsyncQueue();
const streamDelta = [];
// process the stream asynchonously (no 'await' on purpose):
(0, parseEventSourceReadableStream_js_1.parseEventSourceReadableStream)({
stream,
callback: (event) => {
if (event.type !== "event") {
return;
}
const data = event.data;
if (data === "[DONE]") {
queue.close();
return;
}
try {
const json = secure_json_parse_1.default.parse(data);
const parseResult = chatResponseStreamEventSchema.safeParse(json);
if (!parseResult.success) {
queue.push({
type: "error",
error: parseResult.error,
});
queue.close();
return;
}
const event = parseResult.data;
for (let i = 0; i < event.choices.length; i++) {
const eventChoice = event.choices[i];
const delta = eventChoice.delta;
if (streamDelta[i] == null) {
streamDelta[i] = {
role: undefined,
content: "",
isComplete: false,
delta,
};
}
const choice = streamDelta[i];
choice.delta = delta;
if (eventChoice.finish_reason != null) {
choice.isComplete = true;
}
if (delta.content != undefined) {
choice.content += delta.content;
}
if (delta.function_call != undefined) {
if (choice.function_call == undefined) {
choice.function_call = {
name: "",
arguments: "",
};
}
if (delta.function_call.name != undefined) {
choice.function_call.name += delta.function_call.name;
}
if (delta.function_call.arguments != undefined) {
choice.function_call.arguments += delta.function_call.arguments;
}
}
if (delta.role != undefined) {
choice.role = delta.role;
}
}
// Since we're mutating the choices array in an async scenario,
// we need to make a deep copy:
const streamDeltaDeepCopy = JSON.parse(JSON.stringify(streamDelta));
queue.push({
type: "delta",
fullDelta: streamDeltaDeepCopy,
});
}
catch (error) {
queue.push({ type: "error", error });
queue.close();
return;
}
},
});
return queue;
}
exports.createOpenAIChatFullDeltaIterableQueue = createOpenAIChatFullDeltaIterableQueue;