-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat (examples): add streamObject example with streamableValue (#1787)
Co-authored-by: Max Leiter <max.leiter@vercel.com>
- Loading branch information
Showing
4 changed files
with
114 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
'use server'; | ||
|
||
import { openai } from '@ai-sdk/openai'; | ||
import { streamObject } from 'ai'; | ||
import { createStreamableValue } from 'ai/rsc'; | ||
import { PartialNotification, notificationSchema } from './schema'; | ||
|
||
export async function generateNotifications(context: string) { | ||
const notificationsStream = createStreamableValue<PartialNotification>(); | ||
|
||
streamObject({ | ||
model: openai('gpt-4-turbo'), | ||
prompt: `Generate 3 notifications for a messages app in this context: ${context}`, | ||
schema: notificationSchema, | ||
}) | ||
.then(async ({ partialObjectStream }) => { | ||
for await (const partialObject of partialObjectStream) { | ||
notificationsStream.update(partialObject); | ||
} | ||
}) | ||
.finally(() => { | ||
notificationsStream.done(); | ||
}); | ||
|
||
return notificationsStream.value; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
'use client'; | ||
|
||
import { StreamableValue, useStreamableValue } from 'ai/rsc'; | ||
import { useState } from 'react'; | ||
import { generateNotifications } from './actions'; | ||
import { PartialNotification } from './schema'; | ||
|
||
// Force the page to be dynamic and allow streaming responses up to 30 seconds | ||
export const dynamic = 'force-dynamic'; | ||
export const maxDuration = 30; | ||
|
||
// page component with a button to generate notifications | ||
export default function Page() { | ||
const [notificationStream, setNotificationStream] = | ||
useState<StreamableValue<PartialNotification> | null>(null); | ||
|
||
return ( | ||
<div className="flex flex-col items-center min-h-screen p-4 m-4"> | ||
<button | ||
className="px-4 py-2 mt-4 text-white bg-blue-500 rounded-md" | ||
onClick={async () => { | ||
setNotificationStream( | ||
await generateNotifications('Messages during finals week.'), | ||
); | ||
}} | ||
> | ||
Generate notifications | ||
</button> | ||
|
||
{notificationStream && ( | ||
<NotificationsView notificationStream={notificationStream} /> | ||
)} | ||
</div> | ||
); | ||
} | ||
|
||
// separate component to display notifications that received the streamable value: | ||
function NotificationsView({ | ||
notificationStream, | ||
}: { | ||
notificationStream: StreamableValue<PartialNotification>; | ||
}) { | ||
const [data, pending, error] = useStreamableValue(notificationStream); | ||
|
||
return ( | ||
<div className="flex flex-col gap-4 mt-4"> | ||
{data?.notifications?.map((notification, index) => ( | ||
<div | ||
className="flex items-start gap-4 p-4 bg-gray-100 rounded-md dark:bg-gray-800" | ||
key={index} | ||
> | ||
<div className="flex-1 space-y-1"> | ||
<div className="flex items-center justify-between"> | ||
<p className="font-medium">{notification?.name}</p> | ||
<p className="text-sm text-gray-500 dark:text-gray-400"> | ||
{notification?.minutesAgo} | ||
{notification?.minutesAgo != null ? ' minutes ago' : ''} | ||
</p> | ||
</div> | ||
<p className="text-gray-700 dark:text-gray-300"> | ||
{notification?.message} | ||
</p> | ||
</div> | ||
</div> | ||
))} | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { DeepPartial } from 'ai'; | ||
import { z } from 'zod'; | ||
|
||
// define a schema for the notifications | ||
export const notificationSchema = z.object({ | ||
notifications: z.array( | ||
z.object({ | ||
name: z.string().describe('Name of a fictional person.'), | ||
message: z.string().describe('Message. Do not use emojis or links.'), | ||
minutesAgo: z.number(), | ||
}), | ||
), | ||
}); | ||
|
||
// define a type for the partial notifications during generation | ||
export type PartialNotification = DeepPartial< | ||
z.infer<typeof notificationSchema> | ||
>; |