Skip to content

Commit f1587fd

Browse files
committed
Implement basic playground using @axflow/models
1 parent b3122ec commit f1587fd

4 files changed

Lines changed: 127 additions & 0 deletions

File tree

app/api/openai/chat/route.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { NextRequest } from 'next/server';
2+
import { OpenAIChat } from '@axflow/models/openai/chat';
3+
import { NdJsonStream } from '@axflow/models/utils';
4+
5+
export const runtime = 'edge';
6+
7+
const apiKey = process.env.OPENAI_API_KEY!;
8+
9+
/**
10+
* Streaming OpenAI chat on the edge using @axflow/models.
11+
*
12+
* POST /api/openai/chat
13+
*/
14+
export async function POST(request: NextRequest) {
15+
const { message, history } = await request.json();
16+
17+
const model = 'gpt-4';
18+
const messages = history
19+
.map((msg: any) => ({ role: msg.role, content: msg.content }))
20+
.concat({ role: message.role, content: message.content });
21+
22+
const stream = await OpenAIChat.stream({ model, messages }, { apiKey });
23+
24+
return NdJsonStream.response(stream, {
25+
map: (chunk) => chunk.choices[0].delta.content || '',
26+
});
27+
}

app/playground/page.tsx

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
'use client';
2+
3+
import { CounterClockwiseClockIcon } from '@radix-ui/react-icons';
4+
5+
import { Button } from '@/components/ui/button';
6+
import { Textarea } from '@/components/ui/textarea';
7+
8+
import { useChat } from '@axflow/models/react';
9+
import type { MessageType } from '@axflow/models/shared';
10+
11+
const API_URL = '/api/openai/chat';
12+
13+
export default function Playground() {
14+
const { input, onChange, onSubmit, messages } = useChat({ url: API_URL });
15+
16+
return (
17+
<div className="pt-[52px]">
18+
<div className="flex justify-center gap-8">
19+
<Form input={input} onChange={onChange} onSubmit={onSubmit} />
20+
<Messages messages={messages} />
21+
</div>
22+
</div>
23+
);
24+
}
25+
26+
type FormPropsType = {
27+
input: string;
28+
onSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
29+
onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
30+
};
31+
32+
function Form(props: FormPropsType) {
33+
return (
34+
<section>
35+
<form onSubmit={props.onSubmit}>
36+
<div className="h-[600px] w-[500px]">
37+
<Textarea
38+
className="h-full"
39+
placeholder="Enter message here"
40+
value={props.input}
41+
onChange={props.onChange}
42+
></Textarea>
43+
</div>
44+
<div className="flex items-center space-x-2 pt-4">
45+
<Button type="submit">Submit</Button>
46+
<Button variant="secondary">
47+
<span className="sr-only">Show history</span>
48+
<CounterClockwiseClockIcon className="h-4 w-4" />
49+
</Button>
50+
</div>
51+
</form>
52+
</section>
53+
);
54+
}
55+
56+
function Messages(props: { messages: MessageType[] }) {
57+
return (
58+
<section>
59+
<div className="h-[600px] w-[500px] bg-muted bg-zinc-900 text-sm px-3 py-2 rounded space-y-4">
60+
{props.messages.map((msg) => (
61+
<p key={msg.id}>
62+
{msg.data && (
63+
<span className="block mt-2 text-xs">Has {msg.data.length} data items</span>
64+
)}
65+
{msg.content}
66+
</p>
67+
))}
68+
</div>
69+
</section>
70+
);
71+
}

package-lock.json

Lines changed: 28 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"lint": "next lint"
1010
},
1111
"dependencies": {
12+
"@axflow/models": "^0.0.1-beta.0",
1213
"@radix-ui/react-alert-dialog": "^1.0.4",
1314
"@radix-ui/react-icons": "^1.3.0",
1415
"@radix-ui/react-label": "^2.0.2",

0 commit comments

Comments
 (0)