Skip to content

Commit

Permalink
feat: add code and text block types (vercel#609)
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremyphilemon authored Dec 16, 2024
1 parent 3df0fd4 commit 9778631
Show file tree
Hide file tree
Showing 27 changed files with 1,736 additions and 272 deletions.
169 changes: 120 additions & 49 deletions app/(chat)/api/chat/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
type Message,
StreamData,
convertToCoreMessages,
generateObject,
streamObject,
streamText,
} from 'ai';
Expand All @@ -10,7 +11,11 @@ import { z } from 'zod';
import { auth } from '@/app/(auth)/auth';
import { customModel } from '@/lib/ai';
import { models } from '@/lib/ai/models';
import { systemPrompt } from '@/lib/ai/prompts';
import {
codePrompt,
systemPrompt,
updateDocumentPrompt,
} from '@/lib/ai/prompts';
import {
deleteChatById,
getChatById,
Expand Down Expand Up @@ -119,11 +124,12 @@ export async function POST(request: Request) {
},
},
createDocument: {
description: 'Create a document for a writing activity',
description: 'Create a document for a writing activity.',
parameters: z.object({
title: z.string(),
kind: z.enum(['text', 'code']),
}),
execute: async ({ title }) => {
execute: async ({ title, kind }) => {
const id = generateUUID();
let draftText = '';

Expand All @@ -137,38 +143,75 @@ export async function POST(request: Request) {
content: title,
});

streamingData.append({
type: 'kind',
content: kind,
});

streamingData.append({
type: 'clear',
content: '',
});

const { fullStream } = streamText({
model: customModel(model.apiIdentifier),
system:
'Write about the given topic. Markdown is supported. Use headings wherever appropriate.',
prompt: title,
});
if (kind === 'text') {
const { fullStream } = streamText({
model: customModel(model.apiIdentifier),
system:
'Write about the given topic. Markdown is supported. Use headings wherever appropriate.',
prompt: title,
});

for await (const delta of fullStream) {
const { type } = delta;
for await (const delta of fullStream) {
const { type } = delta;

if (type === 'text-delta') {
const { textDelta } = delta;
if (type === 'text-delta') {
const { textDelta } = delta;

draftText += textDelta;
streamingData.append({
type: 'text-delta',
content: textDelta,
});
draftText += textDelta;
streamingData.append({
type: 'text-delta',
content: textDelta,
});
}
}
}

streamingData.append({ type: 'finish', content: '' });
streamingData.append({ type: 'finish', content: '' });
} else if (kind === 'code') {
const { fullStream } = streamObject({
model: customModel(model.apiIdentifier),
system: codePrompt,
prompt: title,
schema: z.object({
code: z.string(),
}),
});

for await (const delta of fullStream) {
const { type } = delta;

if (type === 'object') {
const { object } = delta;
const { code } = object;

if (code) {
streamingData.append({
type: 'code-delta',
content: code ?? '',
});

draftText = code;
}
}
}

streamingData.append({ type: 'finish', content: '' });
}

if (session.user?.id) {
await saveDocument({
id,
title,
kind,
content: draftText,
userId: session.user.id,
});
Expand All @@ -177,6 +220,7 @@ export async function POST(request: Request) {
return {
id,
title,
kind,
content: 'A document was created and is now visible to the user.',
};
},
Expand Down Expand Up @@ -206,55 +250,81 @@ export async function POST(request: Request) {
content: document.title,
});

const { fullStream } = streamText({
model: customModel(model.apiIdentifier),
system:
'You are a helpful writing assistant. Based on the description, please update the piece of writing.',
experimental_providerMetadata: {
openai: {
prediction: {
type: 'content',
content: currentContent,
if (document.kind === 'text') {
const { fullStream } = streamText({
model: customModel(model.apiIdentifier),
system: updateDocumentPrompt(currentContent),
prompt: description,
experimental_providerMetadata: {
openai: {
prediction: {
type: 'content',
content: currentContent,
},
},
},
},
messages: [
{
role: 'user',
content: description,
},
{ role: 'user', content: currentContent },
],
});
});

for await (const delta of fullStream) {
const { type } = delta;
for await (const delta of fullStream) {
const { type } = delta;

if (type === 'text-delta') {
const { textDelta } = delta;
if (type === 'text-delta') {
const { textDelta } = delta;

draftText += textDelta;
streamingData.append({
type: 'text-delta',
content: textDelta,
});
draftText += textDelta;
streamingData.append({
type: 'text-delta',
content: textDelta,
});
}
}
}

streamingData.append({ type: 'finish', content: '' });
streamingData.append({ type: 'finish', content: '' });
} else if (document.kind === 'code') {
const { fullStream } = streamObject({
model: customModel(model.apiIdentifier),
system: updateDocumentPrompt(currentContent),
prompt: description,
schema: z.object({
code: z.string(),
}),
});

for await (const delta of fullStream) {
const { type } = delta;

if (type === 'object') {
const { object } = delta;
const { code } = object;

if (code) {
streamingData.append({
type: 'code-delta',
content: code ?? '',
});

draftText = code;
}
}
}

streamingData.append({ type: 'finish', content: '' });
}

if (session.user?.id) {
await saveDocument({
id,
title: document.title,
content: draftText,
kind: document.kind,
userId: session.user.id,
});
}

return {
id,
title: document.title,
kind: document.kind,
content: 'The document has been updated successfully.',
};
},
Expand Down Expand Up @@ -328,6 +398,7 @@ export async function POST(request: Request) {
return {
id: documentId,
title: document.title,
kind: document.kind,
message: 'Suggestions have been added to the document',
};
},
Expand Down
9 changes: 7 additions & 2 deletions app/(chat)/api/document/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { auth } from '@/app/(auth)/auth';
import { BlockKind } from '@/components/block';
import {
deleteDocumentsByIdAfterTimestamp,
getDocumentsById,
Expand Down Expand Up @@ -48,14 +49,18 @@ export async function POST(request: Request) {
return new Response('Unauthorized', { status: 401 });
}

const { content, title }: { content: string; title: string } =
await request.json();
const {
content,
title,
kind,
}: { content: string; title: string; kind: BlockKind } = await request.json();

if (session.user?.id) {
const document = await saveDocument({
id,
content,
title,
kind,
userId: session.user.id,
});

Expand Down
15 changes: 11 additions & 4 deletions app/(chat)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { AppSidebar } from '@/components/app-sidebar';
import { SidebarInset, SidebarProvider } from '@/components/ui/sidebar';

import { auth } from '../(auth)/auth';
import Script from 'next/script';

export const experimental_ppr = true;

Expand All @@ -16,9 +17,15 @@ export default async function Layout({
const isCollapsed = cookieStore.get('sidebar:state')?.value !== 'true';

return (
<SidebarProvider defaultOpen={!isCollapsed}>
<AppSidebar user={session?.user} />
<SidebarInset>{children}</SidebarInset>
</SidebarProvider>
<>
<Script
src="https://cdn.jsdelivr.net/pyodide/v0.23.4/full/pyodide.js"
strategy="beforeInteractive"
/>
<SidebarProvider defaultOpen={!isCollapsed}>
<AppSidebar user={session?.user} />
<SidebarInset>{children}</SidebarInset>
</SidebarProvider>
</>
);
}
Loading

0 comments on commit 9778631

Please sign in to comment.