Skip to content

Commit ee58eed

Browse files
committed
feat: more uniform output
1 parent f22c637 commit ee58eed

File tree

4 files changed

+813
-750
lines changed

4 files changed

+813
-750
lines changed

app/api/chat/route.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,16 @@ import { tools } from "@/app/api/chat/tools";
55
import { NextResponse } from "next/server";
66
import { ERROR_PREFIX, MODE_TRANSLATE } from "@/lib/constants";
77

8+
const STREAM_INTERVAL = 60;
9+
const MAX_SIZE = 6;
10+
811
export async function POST(req: Request) {
912
const { messages, config } = await req.json();
1013

1114
try {
15+
const controller = new AbortController();
1216
const { fullStream } = streamText({
17+
abortSignal: controller.signal,
1318
temperature: config.temperature,
1419
model: getOpenAI(config.apiKey).chat(config.model),
1520
system: getSystem(config.systemPrompt),
@@ -21,12 +26,33 @@ export async function POST(req: Request) {
2126
),
2227
});
2328

29+
let intervalId: any;
2430
const stream = new ReadableStream({
2531
async start(controller) {
32+
let buffer = "";
33+
let done = false;
34+
intervalId = setInterval(() => {
35+
if (buffer.length === 0) {
36+
if (done) {
37+
clearInterval(intervalId);
38+
controller.close();
39+
}
40+
return;
41+
}
42+
if (buffer.length <= MAX_SIZE) {
43+
controller.enqueue(buffer);
44+
buffer = "";
45+
} else {
46+
const chunk = buffer.slice(0, MAX_SIZE);
47+
buffer = buffer.slice(MAX_SIZE);
48+
controller.enqueue(chunk);
49+
}
50+
}, STREAM_INTERVAL);
51+
2652
for await (const part of fullStream) {
2753
switch (part.type) {
2854
case "text-delta": {
29-
controller.enqueue(part.textDelta);
55+
buffer += part.textDelta;
3056
break;
3157
}
3258
case "error": {
@@ -38,7 +64,11 @@ export async function POST(req: Request) {
3864
}
3965
}
4066
}
41-
controller.close();
67+
done = true;
68+
},
69+
cancel() {
70+
clearInterval(intervalId);
71+
controller.abort();
4272
},
4373
});
4474

components/chat.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ function Chat() {
3434
reload,
3535
stop,
3636
} = useChat({
37-
experimental_throttle: 80,
3837
streamProtocol: "text",
3938
onError(err) {
4039
toast.error(err.message);

package.json

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,45 +9,45 @@
99
"lint": "next lint"
1010
},
1111
"dependencies": {
12-
"@ai-sdk/openai": "^1.0.7",
13-
"@radix-ui/react-dialog": "^1.1.2",
14-
"@radix-ui/react-dropdown-menu": "^2.1.2",
15-
"@radix-ui/react-label": "^2.1.0",
16-
"@radix-ui/react-scroll-area": "^1.2.1",
17-
"@radix-ui/react-select": "^2.1.2",
18-
"@radix-ui/react-separator": "^1.1.0",
19-
"@radix-ui/react-slider": "^1.2.1",
20-
"@radix-ui/react-slot": "^1.1.0",
21-
"@radix-ui/react-switch": "^1.1.1",
22-
"@radix-ui/react-tooltip": "^1.1.4",
23-
"ai": "^4.0.13",
12+
"@ai-sdk/openai": "^1.0.8",
13+
"@radix-ui/react-dialog": "^1.1.3",
14+
"@radix-ui/react-dropdown-menu": "^2.1.3",
15+
"@radix-ui/react-label": "^2.1.1",
16+
"@radix-ui/react-scroll-area": "^1.2.2",
17+
"@radix-ui/react-select": "^2.1.3",
18+
"@radix-ui/react-separator": "^1.1.1",
19+
"@radix-ui/react-slider": "^1.2.2",
20+
"@radix-ui/react-slot": "^1.1.1",
21+
"@radix-ui/react-switch": "^1.1.2",
22+
"@radix-ui/react-tooltip": "^1.1.5",
23+
"ai": "^4.0.18",
2424
"class-variance-authority": "^0.7.1",
2525
"clsx": "^2.1.1",
2626
"lucide-react": "^0.468.0",
2727
"mitt": "^3.0.1",
28-
"next": "^15.0.4",
28+
"next": "^15.1.0",
2929
"next-themes": "^0.4.4",
3030
"react": "^18.3.1",
3131
"react-dom": "^18.3.1",
32-
"react-markdown": "8.0.7",
32+
"react-markdown": "^8.0.7",
3333
"react-syntax-highlighter": "^15.6.1",
3434
"react-textarea-autosize": "^8.5.6",
35-
"remark-breaks": "3.0.3",
36-
"remark-gfm": "3.0.1",
35+
"remark-breaks": "^3.0.3",
36+
"remark-gfm": "^3.0.1",
3737
"sonner": "^1.7.1",
3838
"tailwind-merge": "^2.5.5",
39-
"zod": "^3.23.8",
39+
"zod": "^3.24.1",
4040
"zustand": "^5.0.2"
4141
},
4242
"devDependencies": {
4343
"@tailwindcss/typography": "^0.5.15",
44-
"@types/node": "^22.10.1",
45-
"@types/react": "^18.3.14",
46-
"@types/react-dom": "^18.3.2",
44+
"@types/node": "^22.10.2",
45+
"@types/react": "^18.3.16",
46+
"@types/react-dom": "^18.3.5",
4747
"@types/react-syntax-highlighter": "^15.5.13",
4848
"autoprefixer": "^10.4.20",
49-
"eslint": "9.16.0",
50-
"eslint-config-next": "^15.0.4",
49+
"eslint": "^9.17.0",
50+
"eslint-config-next": "^15.1.0",
5151
"eslint-config-prettier": "^9.1.0",
5252
"postcss": "^8.4.49",
5353
"prettier": "^3.4.2",

0 commit comments

Comments
 (0)