@xsai/stream-text 0.0.28 → 0.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +17 -17
- package/dist/index.js +31 -27
- package/package.json +9 -9
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FinishReason, Usage, ChatOptions } from '@xsai/shared-chat';
|
|
2
2
|
|
|
3
|
+
interface ChunkResult {
|
|
4
|
+
choices: {
|
|
5
|
+
delta: {
|
|
6
|
+
content: string;
|
|
7
|
+
role: 'assistant';
|
|
8
|
+
};
|
|
9
|
+
finish_reason?: FinishReason;
|
|
10
|
+
index: number;
|
|
11
|
+
}[];
|
|
12
|
+
created: number;
|
|
13
|
+
id: string;
|
|
14
|
+
model: string;
|
|
15
|
+
object: 'chat.completion.chunk';
|
|
16
|
+
system_fingerprint: string;
|
|
17
|
+
usage?: Usage;
|
|
18
|
+
}
|
|
3
19
|
interface StreamTextOptions extends ChatOptions {
|
|
4
20
|
onChunk?: (chunk: ChunkResult) => Promise<void> | void;
|
|
5
21
|
/** if you want to disable stream, use `@xsai/generate-{text,object}` */
|
|
@@ -19,22 +35,6 @@ interface StreamTextResult {
|
|
|
19
35
|
textStream: ReadableStream<string>;
|
|
20
36
|
usage?: Usage;
|
|
21
37
|
}
|
|
22
|
-
interface ChunkResult {
|
|
23
|
-
choices: {
|
|
24
|
-
delta: {
|
|
25
|
-
content: string;
|
|
26
|
-
role: 'assistant';
|
|
27
|
-
};
|
|
28
|
-
finish_reason?: FinishReason;
|
|
29
|
-
index: number;
|
|
30
|
-
}[];
|
|
31
|
-
created: number;
|
|
32
|
-
id: string;
|
|
33
|
-
model: string;
|
|
34
|
-
object: 'chat.completion.chunk';
|
|
35
|
-
system_fingerprint: string;
|
|
36
|
-
usage?: Usage;
|
|
37
|
-
}
|
|
38
38
|
/**
|
|
39
39
|
* @experimental WIP, does not support function calling (tools).
|
|
40
40
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1,43 +1,47 @@
|
|
|
1
1
|
import { chat } from '@xsai/shared-chat';
|
|
2
2
|
|
|
3
|
-
const chunkHeaderPrefix = "data:
|
|
4
|
-
const
|
|
5
|
-
const streamText = async (options) => await chat({
|
|
3
|
+
const chunkHeaderPrefix = "data:";
|
|
4
|
+
const streamText = async (options) => chat({
|
|
6
5
|
...options,
|
|
7
6
|
stream: true
|
|
8
7
|
}).then(async (res) => {
|
|
9
8
|
const decoder = new TextDecoder();
|
|
10
9
|
let finishReason;
|
|
11
10
|
let usage;
|
|
11
|
+
const processLine = async (line, controller) => {
|
|
12
|
+
if (!line || !line.startsWith(chunkHeaderPrefix))
|
|
13
|
+
return;
|
|
14
|
+
const content = line.slice(chunkHeaderPrefix.length);
|
|
15
|
+
const data = content.startsWith(" ") ? content.slice(1) : content;
|
|
16
|
+
if (data === "[DONE]") {
|
|
17
|
+
controller.terminate();
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
if (data.startsWith("{") && data.includes('"error":')) {
|
|
21
|
+
controller.error(new Error(`Error from server: ${data}`));
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
const chunk = JSON.parse(data);
|
|
25
|
+
controller.enqueue(chunk);
|
|
26
|
+
if (options.onChunk)
|
|
27
|
+
await options.onChunk(chunk);
|
|
28
|
+
if (chunk.choices[0].finish_reason !== undefined) {
|
|
29
|
+
finishReason = chunk.choices[0].finish_reason;
|
|
30
|
+
}
|
|
31
|
+
if (chunk.usage !== undefined) {
|
|
32
|
+
usage = chunk.usage;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
12
35
|
let buffer = "";
|
|
13
36
|
const rawChunkStream = res.body.pipeThrough(new TransformStream({
|
|
14
37
|
transform: async (chunk, controller) => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
38
|
+
const text = decoder.decode(chunk, { stream: true });
|
|
39
|
+
buffer += text;
|
|
40
|
+
const lines = buffer.split("\n");
|
|
41
|
+
buffer = lines.pop() ?? "";
|
|
18
42
|
for (const line of lines) {
|
|
19
|
-
if (
|
|
20
|
-
continue;
|
|
21
|
-
}
|
|
22
|
-
if (line.startsWith(chunkErrorPrefix)) {
|
|
23
|
-
controller.error(new Error(`Error from server: ${line}`));
|
|
24
|
-
break;
|
|
25
|
-
}
|
|
26
|
-
const lineWithoutPrefix = line.slice(chunkHeaderPrefix.length);
|
|
27
|
-
if (lineWithoutPrefix === "[DONE]") {
|
|
28
|
-
controller.terminate();
|
|
43
|
+
if (await processLine(line, controller))
|
|
29
44
|
break;
|
|
30
|
-
}
|
|
31
|
-
const chunk2 = JSON.parse(lineWithoutPrefix);
|
|
32
|
-
controller.enqueue(chunk2);
|
|
33
|
-
if (options.onChunk)
|
|
34
|
-
await options.onChunk(chunk2);
|
|
35
|
-
if (chunk2.choices[0].finish_reason) {
|
|
36
|
-
finishReason = chunk2.choices[0].finish_reason;
|
|
37
|
-
}
|
|
38
|
-
if (chunk2.usage) {
|
|
39
|
-
usage = chunk2.usage;
|
|
40
|
-
}
|
|
41
45
|
}
|
|
42
46
|
}
|
|
43
47
|
}));
|
package/package.json
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xsai/stream-text",
|
|
3
|
-
"version": "0.0.28",
|
|
4
3
|
"type": "module",
|
|
4
|
+
"version": "0.0.30",
|
|
5
|
+
"description": "extra-small AI SDK for Browser, Node.js, Deno, Bun or Edge Runtime.",
|
|
5
6
|
"author": "Moeru AI",
|
|
6
7
|
"license": "MIT",
|
|
7
8
|
"homepage": "https://xsai.js.org",
|
|
8
|
-
"description": "extra-small AI SDK for Browser, Node.js, Deno, Bun or Edge Runtime.",
|
|
9
|
-
"keywords": [
|
|
10
|
-
"xsai",
|
|
11
|
-
"openai",
|
|
12
|
-
"ai"
|
|
13
|
-
],
|
|
14
9
|
"repository": {
|
|
15
10
|
"type": "git",
|
|
16
11
|
"url": "git+https://github.com/moeru-ai/xsai.git",
|
|
17
12
|
"directory": "packages/stream-text"
|
|
18
13
|
},
|
|
19
14
|
"bugs": "https://github.com/moeru-ai/xsai/issues",
|
|
15
|
+
"keywords": [
|
|
16
|
+
"xsai",
|
|
17
|
+
"openai",
|
|
18
|
+
"ai"
|
|
19
|
+
],
|
|
20
20
|
"sideEffects": false,
|
|
21
|
-
"main": "./dist/index.js",
|
|
22
|
-
"types": "./dist/index.d.ts",
|
|
23
21
|
"exports": {
|
|
24
22
|
".": {
|
|
25
23
|
"types": "./dist/index.d.ts",
|
|
26
24
|
"default": "./dist/index.js"
|
|
27
25
|
}
|
|
28
26
|
},
|
|
27
|
+
"main": "./dist/index.js",
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
29
|
"files": [
|
|
30
30
|
"dist"
|
|
31
31
|
],
|