Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
![image](https://github.com/fixie-ai/ai-jsx/assets/829827/ee36980d-555f-400d-9f91-0e0d747c4006) With this approach, we compile MDX on the client. Pros: * It's easy to get the components (e.g. `Card`) in scope – no need to pass them up and down to the server. * Easy for the client to otherwise customize the Markdown rendering as they would like. * Maintains support for the text streaming model, allowing us to stay closer to the Vercel `useChat` paved path. * Enables other AI.JSX components to render UI simply by emitting MDX. (Of course, we need to ensure those emitted components are in scope at compile time.) * I suspect that the MDX compiler/runtime may be published in a way that causes trouble for CJS importers. By keeping the MDX usage to "user-land", or at least on the client, if there is a problem here, we minimize the impact. Potential objections * Performance of doing `O(count of stream chunks)` compiles – I don't think this will be noticeable, particularly in context of LLM response times. Future work * Devising a scheme for the user to interact with the components – e.g. if the user clicks a button or fills out a form, how do we communicate that to the AI? * AI does a decent but not amazing job of adhering to the spec – for instance, all my few-shot examples say `Badge` needs a `color` prop (e.g. `<Badge color="yellow">In progress</Badge>`), but the model does not always do that. There may be more prompt engineering work we can do here. * The demo itself in the nextjs project isn't super compelling. I would rather focus that demo energy on HS. * Sometimes the model still emits \`\`\`mdx blocks wrapping large parts of its response. * Sometimes the model uses `<details>` and `<summary>` in a way that causes the compiler to produce `<details><p><summary>,` which is invalid. I think this approach will work reasonable well for RSC / Architecture 4, with some modification. Once we align on this approach, I'll add docs.
- Loading branch information
1 parent
670ea52
commit 58062b9
Showing
14 changed files
with
1,936 additions
and
88 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
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
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
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,7 @@ | ||
export default function Failure() { | ||
return ( | ||
<div className="flex items-center justify-center w-screen h-screen"> | ||
<p>500</p> | ||
</div> | ||
); | ||
} |
67 changes: 67 additions & 0 deletions
67
packages/nextjs-demo/src/app/building-blocks/api/route.tsx
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,67 @@ | ||
/** @jsxImportSource ai-jsx/react */ | ||
import { NextRequest } from 'next/server'; | ||
import { UserMessage, ChatCompletion } from 'ai-jsx/core/completion'; | ||
import * as BuildingBlocks from '@/components/BuildingBlocks'; | ||
const { Card, ButtonGroup, Badge, Toggle } = BuildingBlocks; | ||
import { MdxSystemMessage } from 'ai-jsx/react/jit-ui/mdx'; | ||
import { toTextStream } from 'ai-jsx/stream'; | ||
import { Message, StreamingTextResponse } from 'ai'; | ||
import _ from 'lodash'; | ||
import { OpenAI } from 'ai-jsx/lib/openai'; | ||
|
||
function BuildingBlocksAI({ query }: { query: string }) { | ||
const usageExamples = ( | ||
<> | ||
Use a Card to display collected information to the user. The children can be markdown. Only use the card if you | ||
have a logically-grouped set of information to show the user, in the context of a larger response. Generally, your | ||
entire response should not be a card. A card takes optional header and footer props. Example 1 of how you might | ||
use this component: Here's the best candidate I found: | ||
<Card header="Sam Smith"> | ||
**Skills**: React, TypeScript, Node.js **Location**: Seattle, WA **Years of experience**: 5 **Availability**: | ||
Full-time | ||
</Card> | ||
Example 2 of how you might use this component: | ||
<Card header="Your Ferry Booking" footer="Reservation held for 20 minutes"> | ||
**Leaves** at 4:15p and **arrives** at 6:20p. | ||
</Card> | ||
Example 3 of how you might use this component (using with surrounding markdown): Sure, I'd be happy to help you | ||
find a car wash. Here are some options: | ||
<Card header="AutoWorld">$50 for a quick car wash.</Card> | ||
<Card header="Big Joel Big Trucks">$155 for a detailing</Card> | ||
<Card header="Small Joel Small Trucks">$10 for some guy to spray your car with a hose.</Card> | ||
Example 4 of how you might use this component, after writing out a report on economics: ... and that concludes the | ||
report on economics. | ||
<Card header="Primary Points"> | ||
* Price is determined by supply and demand * Setting price floors or ceilings cause deadweight loss. * | ||
Interfering with the natural price can also cause shortages. | ||
</Card> | ||
Use a button group when the user needs to make a choice. A ButtonGroup requires a labels prop. Example 1 of how | ||
you might use this component: | ||
<ButtonGroup labels={['Yes', 'No']} /> | ||
Example 2 of how you might use this component (using with surrounding markdown): The system is configured. How | ||
would you like to proceed? | ||
<ButtonGroup labels={['Deploy to prod', 'Deploy to staging', 'Cancel']} /> | ||
Use a badge to indicate status: | ||
<Badge color="yellow">In progress</Badge> | ||
<Badge color="green">Complete</Badge> | ||
Use a toggle to let users enable/disable an option: | ||
<Toggle title="Use rocket fuel" subtitle="($7 surcharge)" /> | ||
</> | ||
); | ||
|
||
return ( | ||
<OpenAI chatModel="gpt-4"> | ||
<ChatCompletion> | ||
<MdxSystemMessage usageExamples={usageExamples} /> | ||
<UserMessage>{query}</UserMessage> | ||
</ChatCompletion> | ||
</OpenAI> | ||
); | ||
} | ||
|
||
export async function POST(request: NextRequest) { | ||
const { messages } = await request.json(); | ||
const lastMessage = _.last(messages) as Message; | ||
|
||
return new StreamingTextResponse(toTextStream(<BuildingBlocksAI query={lastMessage.content} />)); | ||
} |
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,7 @@ | ||
export default function Loading() { | ||
return ( | ||
<div className="flex items-center justify-center w-screen h-screen"> | ||
<p>Loading...</p> | ||
</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,17 @@ | ||
import InputPrompt from '@/components/InputPrompt'; | ||
import ResultContainer from '@/components/ResultContainer'; | ||
import BuildingBlocks from '@/components/BuildingBlocksGenerator'; | ||
|
||
export default function BuildingBlocksPage({ searchParams }: { searchParams: any }) { | ||
const defaultValue = | ||
'Summarize this JSON blob for me, using a Card: {"reservation":{"reservationId":"1234567890","passengerName":"John Doe","flightNumber":"ABC123","origin":"Los Angeles","destination":"New York","departureDate":"2022-01-01","departureTime":"09:00","arrivalDate":"2022-01-01","arrivalTime":"15:00"}}. Also use a Badge. And give me some other github-flavored markdown, using a table, <details>, and strikethrough.'; | ||
const query = searchParams.q ?? defaultValue; | ||
return ( | ||
<div> | ||
<ResultContainer title="Building Blocks" description="In this demo, the AI can use building block UI components"> | ||
<InputPrompt label="Ask me anything..." defaultValue={query} /> | ||
</ResultContainer> | ||
<BuildingBlocks topic={query} /> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.
58062b9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
ai-jsx-docs – ./packages/docs
ai-jsx-docs-fixie-ai.vercel.app
ai-jsx-docs-git-main-fixie-ai.vercel.app
docs.ai-jsx.com
ai-jsx-docs.vercel.app
58062b9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
ai-jsx-tutorial-nextjs – ./packages/tutorial-nextjs
ai-jsx-tutorial-nextjs.vercel.app
ai-jsx-tutorial-nextjs-fixie-ai.vercel.app
ai-jsx-tutorial-nextjs-git-main-fixie-ai.vercel.app
58062b9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
ai-jsx-nextjs-demo – ./packages/nextjs-demo
ai-jsx-nextjs-demo.vercel.app
ai-jsx-nextjs-demo-git-main-fixie-ai.vercel.app
ai-jsx-nextjs-demo-fixie-ai.vercel.app