Skip to content

Commit 9c4dbc8

Browse files
refactor: improve block modularity on server (vercel#758)
1 parent 711da0b commit 9c4dbc8

File tree

14 files changed

+419
-259
lines changed

14 files changed

+419
-259
lines changed

app/(chat)/api/chat/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export async function POST(request: Request) {
120120
sendReasoning: true,
121121
});
122122
},
123-
onError: (error) => {
123+
onError: () => {
124124
return 'Oops, an error occured!';
125125
},
126126
});
File renamed without changes.

blocks/code/server.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { z } from 'zod';
2+
import { streamObject } from 'ai';
3+
import { myProvider } from '@/lib/ai/models';
4+
import { codePrompt, updateDocumentPrompt } from '@/lib/ai/prompts';
5+
import { createDocumentHandler } from '@/lib/blocks/server';
6+
7+
export const codeDocumentHandler = createDocumentHandler<'code'>({
8+
kind: 'code',
9+
onCreateDocument: async ({ title, dataStream }) => {
10+
let draftContent = '';
11+
12+
const { fullStream } = streamObject({
13+
model: myProvider.languageModel('block-model'),
14+
system: codePrompt,
15+
prompt: title,
16+
schema: z.object({
17+
code: z.string(),
18+
}),
19+
});
20+
21+
for await (const delta of fullStream) {
22+
const { type } = delta;
23+
24+
if (type === 'object') {
25+
const { object } = delta;
26+
const { code } = object;
27+
28+
if (code) {
29+
dataStream.writeData({
30+
type: 'code-delta',
31+
content: code ?? '',
32+
});
33+
34+
draftContent = code;
35+
}
36+
}
37+
}
38+
39+
return draftContent;
40+
},
41+
onUpdateDocument: async ({ document, description, dataStream }) => {
42+
let draftContent = '';
43+
44+
const { fullStream } = streamObject({
45+
model: myProvider.languageModel('block-model'),
46+
system: updateDocumentPrompt(document.content, 'code'),
47+
prompt: description,
48+
schema: z.object({
49+
code: z.string(),
50+
}),
51+
});
52+
53+
for await (const delta of fullStream) {
54+
const { type } = delta;
55+
56+
if (type === 'object') {
57+
const { object } = delta;
58+
const { code } = object;
59+
60+
if (code) {
61+
dataStream.writeData({
62+
type: 'code-delta',
63+
content: code ?? '',
64+
});
65+
66+
draftContent = code;
67+
}
68+
}
69+
}
70+
71+
return draftContent;
72+
},
73+
});
File renamed without changes.

blocks/image/server.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { myProvider } from '@/lib/ai/models';
2+
import { createDocumentHandler } from '@/lib/blocks/server';
3+
import { saveDocument } from '@/lib/db/queries';
4+
import { experimental_generateImage } from 'ai';
5+
6+
export const imageDocumentHandler = createDocumentHandler<'image'>({
7+
kind: 'image',
8+
onCreateDocument: async ({ id, title, dataStream, session }) => {
9+
let draftContent = '';
10+
11+
const { image } = await experimental_generateImage({
12+
model: myProvider.imageModel('small-model'),
13+
prompt: title,
14+
n: 1,
15+
});
16+
17+
draftContent = image.base64;
18+
19+
dataStream.writeData({
20+
type: 'image-delta',
21+
content: image.base64,
22+
});
23+
24+
if (session?.user?.id) {
25+
await saveDocument({
26+
id,
27+
title,
28+
kind: 'image',
29+
content: draftContent,
30+
userId: session.user.id,
31+
});
32+
}
33+
34+
return draftContent;
35+
},
36+
onUpdateDocument: async ({ description, dataStream }) => {
37+
let draftContent = '';
38+
39+
const { image } = await experimental_generateImage({
40+
model: myProvider.imageModel('image-model'),
41+
prompt: description,
42+
n: 1,
43+
});
44+
45+
draftContent = image.base64;
46+
47+
dataStream.writeData({
48+
type: 'image-delta',
49+
content: image.base64,
50+
});
51+
52+
return draftContent;
53+
},
54+
});
File renamed without changes.

blocks/sheet/server.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { myProvider } from '@/lib/ai/models';
2+
import { sheetPrompt, updateDocumentPrompt } from '@/lib/ai/prompts';
3+
import { createDocumentHandler } from '@/lib/blocks/server';
4+
import { streamObject } from 'ai';
5+
import { z } from 'zod';
6+
7+
export const sheetDocumentHandler = createDocumentHandler<'sheet'>({
8+
kind: 'sheet',
9+
onCreateDocument: async ({ title, dataStream }) => {
10+
let draftContent = '';
11+
12+
const { fullStream } = streamObject({
13+
model: myProvider.languageModel('block-model'),
14+
system: sheetPrompt,
15+
prompt: title,
16+
schema: z.object({
17+
csv: z.string().describe('CSV data'),
18+
}),
19+
});
20+
21+
for await (const delta of fullStream) {
22+
const { type } = delta;
23+
24+
if (type === 'object') {
25+
const { object } = delta;
26+
const { csv } = object;
27+
28+
if (csv) {
29+
dataStream.writeData({
30+
type: 'sheet-delta',
31+
content: csv,
32+
});
33+
34+
draftContent = csv;
35+
}
36+
}
37+
}
38+
39+
dataStream.writeData({
40+
type: 'sheet-delta',
41+
content: draftContent,
42+
});
43+
44+
return draftContent;
45+
},
46+
onUpdateDocument: async ({ document, description, dataStream }) => {
47+
let draftContent = '';
48+
49+
const { fullStream } = streamObject({
50+
model: myProvider.languageModel('block-model'),
51+
system: updateDocumentPrompt(document.content, 'sheet'),
52+
prompt: description,
53+
schema: z.object({
54+
csv: z.string(),
55+
}),
56+
});
57+
58+
for await (const delta of fullStream) {
59+
const { type } = delta;
60+
61+
if (type === 'object') {
62+
const { object } = delta;
63+
const { csv } = object;
64+
65+
if (csv) {
66+
dataStream.writeData({
67+
type: 'sheet-delta',
68+
content: csv,
69+
});
70+
71+
draftContent = csv;
72+
}
73+
}
74+
}
75+
76+
return draftContent;
77+
},
78+
});

blocks/text.tsx renamed to blocks/text/client.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
} from '@/components/icons';
1313
import { Suggestion } from '@/lib/db/schema';
1414
import { toast } from 'sonner';
15-
import { getSuggestions } from './actions';
15+
import { getSuggestions } from '../actions';
1616

1717
interface TextBlockMetadata {
1818
suggestions: Array<Suggestion>;

blocks/text/server.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { smoothStream, streamText } from 'ai';
2+
import { myProvider } from '@/lib/ai/models';
3+
import { createDocumentHandler } from '@/lib/blocks/server';
4+
import { updateDocumentPrompt } from '@/lib/ai/prompts';
5+
6+
export const textDocumentHandler = createDocumentHandler<'text'>({
7+
kind: 'text',
8+
onCreateDocument: async ({ title, dataStream }) => {
9+
let draftContent = '';
10+
11+
const { fullStream } = streamText({
12+
model: myProvider.languageModel('block-model'),
13+
system:
14+
'Write about the given topic. Markdown is supported. Use headings wherever appropriate.',
15+
experimental_transform: smoothStream({ chunking: 'word' }),
16+
prompt: title,
17+
});
18+
19+
for await (const delta of fullStream) {
20+
const { type } = delta;
21+
22+
if (type === 'text-delta') {
23+
const { textDelta } = delta;
24+
25+
draftContent += textDelta;
26+
27+
dataStream.writeData({
28+
type: 'text-delta',
29+
content: textDelta,
30+
});
31+
}
32+
}
33+
34+
return draftContent;
35+
},
36+
onUpdateDocument: async ({ document, description, dataStream }) => {
37+
let draftContent = '';
38+
39+
const { fullStream } = streamText({
40+
model: myProvider.languageModel('block-model'),
41+
system: updateDocumentPrompt(document.content, 'text'),
42+
experimental_transform: smoothStream({ chunking: 'word' }),
43+
prompt: description,
44+
experimental_providerMetadata: {
45+
openai: {
46+
prediction: {
47+
type: 'content',
48+
content: document.content,
49+
},
50+
},
51+
},
52+
});
53+
54+
for await (const delta of fullStream) {
55+
const { type } = delta;
56+
57+
if (type === 'text-delta') {
58+
const { textDelta } = delta;
59+
60+
draftContent += textDelta;
61+
dataStream.writeData({
62+
type: 'text-delta',
63+
content: textDelta,
64+
});
65+
}
66+
}
67+
68+
return draftContent;
69+
},
70+
});

components/block-actions.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export const BlockActions = memo(PureBlockActions, (prevProps, nextProps) => {
9191
if (prevProps.currentVersionIndex !== nextProps.currentVersionIndex)
9292
return false;
9393
if (prevProps.isCurrentVersion !== nextProps.isCurrentVersion) return false;
94+
if (prevProps.block.content !== nextProps.block.content) return false;
9495

9596
return true;
9697
});

0 commit comments

Comments
 (0)