Skip to content

Commit 341f49f

Browse files
init nextjs example
1 parent e76ab08 commit 341f49f

35 files changed

+6147
-1
lines changed

examples/nextjs-ai-chatbot

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.*
7+
.yarn/*
8+
yalc.lock
9+
!.yarn/patches
10+
!.yarn/plugins
11+
!.yarn/releases
12+
!.yarn/versions
13+
14+
# testing
15+
/coverage
16+
17+
# next.js
18+
/.next/
19+
/out/
20+
21+
# production
22+
/build
23+
24+
# misc
25+
.DS_Store
26+
*.pem
27+
28+
# debug
29+
npm-debug.log*
30+
yarn-debug.log*
31+
yarn-error.log*
32+
.pnpm-debug.log*
33+
34+
# env files (can opt-in for committing if needed)
35+
.env*
36+
37+
# vercel
38+
.vercel
39+
40+
# typescript
41+
*.tsbuildinfo
42+
next-env.d.ts
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
2+
3+
## Getting Started
4+
5+
### Environment Variables
6+
7+
Create a `.env.local` file in the root directory and add the following environment variables:
8+
9+
```bash
10+
# Required
11+
STREAM_API_KEY=your_stream_api_key
12+
STREAM_API_SECRET=your_stream_api_secret
13+
14+
# Optional for AI models
15+
OPENAI_API_KEY=your_openai_api_key
16+
XAI_API_KEY=your_xai_api_key
17+
GOOGLE_GENERATIVE_AI_API_KEY=your_google_api_key
18+
19+
# Optional for tools
20+
OPENWEATHER_API_KEY=your_openweather_api_key
21+
```
22+
23+
### Running the Development Server
24+
25+
First, run the development server:
26+
27+
```bash
28+
npm run dev
29+
# or
30+
yarn dev
31+
# or
32+
pnpm dev
33+
# or
34+
bun dev
35+
```
36+
37+
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
38+
39+
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
40+
41+
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
42+
43+
## Learn More
44+
45+
To learn more about Next.js, take a look at the following resources:
46+
47+
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
48+
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
49+
50+
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
51+
52+
## Deploy on Vercel
53+
54+
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
55+
56+
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"use client";
2+
3+
import Messages from "@/components/messages";
4+
5+
export default function ChatPage() {
6+
return <Messages />;
7+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { NextResponse } from "next/server";
2+
import { createStreamStorageClient } from "@stream-io/ai-sdk-storage";
3+
import { createConfigFromEnv } from "@stream-io/ai-sdk-storage/dist/utils";
4+
5+
const storage = createStreamStorageClient(createConfigFromEnv());
6+
7+
export async function GET(req: Request, { params }: any) {
8+
const { id } = await params;
9+
try {
10+
return NextResponse.json(
11+
await storage.streamStorage.getChannelMessages(id)
12+
);
13+
} catch (error) {
14+
return NextResponse.json([], { status: 404 });
15+
}
16+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { convertToModelMessages, streamText } from "ai";
2+
import { NextResponse } from "next/server";
3+
import { GetModel, MODELS } from "@/utils/models";
4+
import { createStreamStorageClient } from "@stream-io/ai-sdk-storage";
5+
import { createConfigFromEnv } from "@stream-io/ai-sdk-storage/dist/utils";
6+
import { tools } from "@/utils/tools";
7+
8+
const storage = createStreamStorageClient(createConfigFromEnv());
9+
10+
export async function POST(req: Request) {
11+
const { messages, id, user_id, model = MODELS[0].id } = await req.json();
12+
13+
const { processUserMessage, processAIResponse } =
14+
await storage.aiSDKStreamStorage.handleStreamText(
15+
id,
16+
messages,
17+
user_id,
18+
async (responseMessage) => {
19+
await storage.aiSDKStreamStorage.processAIResponse(id, responseMessage);
20+
}
21+
);
22+
23+
// Process the user message (handles attachments automatically)
24+
await processUserMessage();
25+
const result = streamText({
26+
model: GetModel(model),
27+
system: "You are a helpful assistant.",
28+
messages: convertToModelMessages(messages),
29+
tools,
30+
onAbort: (error) => {
31+
console.error(error, "error");
32+
},
33+
onError: (error) => {
34+
console.error(error, "error");
35+
},
36+
});
37+
38+
return result.toUIMessageStreamResponse({
39+
originalMessages: messages,
40+
onFinish: async ({ responseMessage }) => {
41+
await processAIResponse(responseMessage);
42+
},
43+
onError: (error) => {
44+
console.error(error, "error");
45+
return "Error: " + error;
46+
},
47+
});
48+
}
49+
50+
export async function GET(req: Request) {
51+
const { searchParams } = new URL(req.url);
52+
const user_id = searchParams.get("user_id");
53+
if (!user_id) {
54+
return NextResponse.json(
55+
{
56+
error: "User ID is required",
57+
},
58+
{ status: 400 }
59+
);
60+
}
61+
const channels = await storage.streamStorage.getChannels(user_id);
62+
return NextResponse.json(channels?.map((channel) => channel.data) || []);
63+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { NextRequest } from "next/server";
2+
import { experimental_transcribe as transcribe } from "ai";
3+
import { openai } from "@ai-sdk/openai";
4+
5+
export async function POST(req: NextRequest) {
6+
try {
7+
const form = await req.formData();
8+
const file = form.get("audio") as File | null;
9+
if (file && file.size < 20000) {
10+
return Response.json({ text: "" });
11+
}
12+
if (!file)
13+
return new Response(JSON.stringify({ error: "No audio" }), {
14+
status: 400,
15+
});
16+
17+
const result = await transcribe({
18+
model: openai.transcription("gpt-4o-transcribe"),
19+
audio: new Uint8Array(await file.arrayBuffer()),
20+
});
21+
22+
return Response.json({ text: result.text ?? "" });
23+
} catch (err) {
24+
console.error(err);
25+
return new Response(JSON.stringify({ error: "Transcription failed" }), {
26+
status: 500,
27+
});
28+
}
29+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import {
2+
createConfigFromEnv,
3+
createStreamStorageClient,
4+
} from "@stream-io/ai-sdk-storage/dist/utils";
5+
import { NextResponse } from "next/server";
6+
7+
const storage = createStreamStorageClient(createConfigFromEnv());
8+
9+
export async function POST() {
10+
const id = await storage.streamStorage.upsertUsers();
11+
12+
return NextResponse.json({ id });
13+
}
25.3 KB
Binary file not shown.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
@import "tailwindcss";
2+
@plugin "@tailwindcss/typography";
3+
@plugin "daisyui" {
4+
themes: dim;
5+
}
6+
7+
:root {
8+
--primary: blue;
9+
}
10+
11+
.overflow-y-auto {
12+
scrollbar-gutter: stable;
13+
}
14+
15+
pre {
16+
display: block !important;
17+
}
18+
19+
pre pre {
20+
border: none !important;
21+
background-color: transparent !important;
22+
box-shadow: none !important;
23+
}
24+
25+
.ai-thinking {
26+
background: linear-gradient(90deg, #00ffe0, #0072ff, #00ffe0);
27+
background-size: 200% auto;
28+
color: transparent;
29+
background-clip: text;
30+
-webkit-background-clip: text;
31+
animation: shimmer 2s linear infinite;
32+
}
33+
34+
@keyframes shimmer {
35+
to {
36+
background-position: 200% center;
37+
}
38+
}

0 commit comments

Comments
 (0)