forked from CopilotKit/CopilotKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparse-chat-completion.ts
More file actions
84 lines (73 loc) · 2.12 KB
/
Copy pathparse-chat-completion.ts
File metadata and controls
84 lines (73 loc) · 2.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import { Role } from "../types/openai-assistant";
export interface ChatCompletionChunk {
choices: {
delta: {
role: Role;
content?: string | null;
function_call?: {
name?: string;
arguments?: string;
};
};
}[];
}
// TODO:
// it's possible that unicode characters could be split across chunks
// make sure to properly handle that
export function parseChatCompletion(
stream: ReadableStream<Uint8Array>,
): ReadableStream<ChatCompletionChunk> {
const reader = stream.getReader();
let buffer = new Uint8Array();
async function cleanup(controller?: ReadableStreamDefaultController<any>) {
if (controller) {
try {
controller.close();
} catch (_) {}
}
if (reader) {
try {
await reader.cancel();
} catch (_) {}
}
}
return new ReadableStream<ChatCompletionChunk>({
async pull(controller) {
while (true) {
try {
const { done, value } = await reader.read();
if (done) {
await cleanup(controller);
return;
}
const newBuffer = new Uint8Array(buffer.length + value.length);
newBuffer.set(buffer);
newBuffer.set(value, buffer.length);
buffer = newBuffer;
const valueString = new TextDecoder("utf-8").decode(buffer);
const lines = valueString.split("\n").filter((line) => line.trim() !== "");
// If the last line isn't complete, keep it in the buffer for next time
buffer = !valueString.endsWith("\n")
? new TextEncoder().encode(lines.pop() || "")
: new Uint8Array();
for (const line of lines) {
const cleanedLine = line.replace(/^data: /, "");
if (cleanedLine === "[DONE]") {
await cleanup(controller);
return;
}
const json = JSON.parse(cleanedLine);
controller.enqueue(json);
}
} catch (error) {
controller.error(error);
await cleanup(controller);
return;
}
}
},
cancel() {
reader.cancel();
},
});
}