Skip to content

Commit 8ab7db2

Browse files
Merge branch 'main' into jrmy/chat-config
2 parents 222c65b + 235b0ed commit 8ab7db2

19 files changed

Lines changed: 2085 additions & 1904 deletions

.env.example

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
# Get your OpenAI API Key here for chat models: https://platform.openai.com/account/api-keys
2-
OPENAI_API_KEY=****
3-
4-
# Get your Fireworks AI API Key here for reasoning models: https://fireworks.ai/account/api-keys
5-
FIREWORKS_API_KEY=****
6-
71
# Generate a random secret: https://generate-secret.vercel.app/32 or `openssl rand -base64 32`
82
AUTH_SECRET=****
93

104
# The following keys below are automatically created and
115
# added to your environment when you deploy on vercel
126

7+
# Get your xAI API Key here for chat and image models: https://console.x.ai/
8+
XAI_API_KEY=****
9+
10+
# Get your Groq API Key here for reasoning models: https://console.groq.com/keys
11+
GROQ_API_KEY=****
12+
1313
# Instructions to create a Vercel Blob Store here: https://vercel.com/docs/storage/vercel-blob
1414
BLOB_READ_WRITE_TOKEN=****
1515

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ yarn-error.log*
3434

3535
.env
3636
.vercel
37-
.vscode
3837
.env*.local
3938

4039
# Playwright

.vscode/extensions.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"recommendations": ["biomejs.biome"]
3+
}

.vscode/settings.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"editor.formatOnSave": true,
3+
"[javascript]": {
4+
"editor.defaultFormatter": "biomejs.biome"
5+
},
6+
"[typescript]": {
7+
"editor.defaultFormatter": "biomejs.biome"
8+
},
9+
"[typescriptreact]": {
10+
"editor.defaultFormatter": "biomejs.biome"
11+
},
12+
"typescript.tsdk": "node_modules/typescript/lib",
13+
"eslint.workingDirectories": [
14+
{ "pattern": "app/*" },
15+
{ "pattern": "packages/*" }
16+
]
17+
}

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
- [AI SDK](https://sdk.vercel.ai/docs)
2424
- Unified API for generating text, structured objects, and tool calls with LLMs
2525
- Hooks for building dynamic chat and generative user interfaces
26-
- Supports OpenAI (default), Anthropic, Cohere, and other model providers
26+
- Supports xAI (default), OpenAI, Fireworks, and other model providers
2727
- [shadcn/ui](https://ui.shadcn.com)
2828
- Styling with [Tailwind CSS](https://tailwindcss.com)
2929
- Component primitives from [Radix UI](https://radix-ui.com) for accessibility and flexibility
@@ -35,19 +35,19 @@
3535

3636
## Model Providers
3737

38-
This template ships with OpenAI `gpt-4o` as the default. However, with the [AI SDK](https://sdk.vercel.ai/docs), you can switch LLM providers to [OpenAI](https://openai.com), [Anthropic](https://anthropic.com), [Cohere](https://cohere.com/), and [many more](https://sdk.vercel.ai/providers/ai-sdk-providers) with just a few lines of code.
38+
This template ships with [xAI](https://x.ai) `grok-2-1212` as the default chat model. However, with the [AI SDK](https://sdk.vercel.ai/docs), you can switch LLM providers to [OpenAI](https://openai.com), [Anthropic](https://anthropic.com), [Cohere](https://cohere.com/), and [many more](https://sdk.vercel.ai/providers/ai-sdk-providers) with just a few lines of code.
3939

4040
## Deploy Your Own
4141

4242
You can deploy your own version of the Next.js AI Chatbot to Vercel with one click:
4343

44-
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fai-chatbot&env=AUTH_SECRET,OPENAI_API_KEY&envDescription=Learn%20more%20about%20how%20to%20get%20the%20API%20Keys%20for%20the%20application&envLink=https%3A%2F%2Fgithub.com%2Fvercel%2Fai-chatbot%2Fblob%2Fmain%2F.env.example&demo-title=AI%20Chatbot&demo-description=An%20Open-Source%20AI%20Chatbot%20Template%20Built%20With%20Next.js%20and%20the%20AI%20SDK%20by%20Vercel.&demo-url=https%3A%2F%2Fchat.vercel.ai&stores=[{%22type%22:%22postgres%22},{%22type%22:%22blob%22}])
44+
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fai-chatbot&env=AUTH_SECRET&envDescription=Generate%20a%20random%20secret%20to%20use%20for%20authentication&envLink=https%3A%2F%2Fgenerate-secret.vercel.app%2F32&project-name=my-awesome-chatbot&repository-name=my-awesome-chatbot&demo-title=AI%20Chatbot&demo-description=An%20Open-Source%20AI%20Chatbot%20Template%20Built%20With%20Next.js%20and%20the%20AI%20SDK%20by%20Vercel&demo-url=https%3A%2F%2Fchat.vercel.ai&products=%5B%7B%22type%22%3A%22integration%22%2C%22protocol%22%3A%22ai%22%2C%22productSlug%22%3A%22grok%22%2C%22integrationSlug%22%3A%22xai%22%7D%2C%7B%22type%22%3A%22integration%22%2C%22protocol%22%3A%22ai%22%2C%22productSlug%22%3A%22api-key%22%2C%22integrationSlug%22%3A%22groq%22%7D%2C%7B%22type%22%3A%22integration%22%2C%22protocol%22%3A%22storage%22%2C%22productSlug%22%3A%22neon%22%2C%22integrationSlug%22%3A%22neon%22%7D%2C%7B%22type%22%3A%22blob%22%7D%5D)
4545

4646
## Running locally
4747

4848
You will need to use the environment variables [defined in `.env.example`](.env.example) to run Next.js AI Chatbot. It's recommended you use [Vercel Environment Variables](https://vercel.com/docs/projects/environment-variables) for this, but a `.env` file is all that is necessary.
4949

50-
> Note: You should not commit your `.env` file or it will expose secrets that will allow others to control access to your various OpenAI and authentication provider accounts.
50+
> Note: You should not commit your `.env` file or it will expose secrets that will allow others to control access to your various AI and authentication provider accounts.
5151
5252
1. Install Vercel CLI: `npm i -g vercel`
5353
2. Link local instance with Vercel and GitHub accounts (creates `.vercel` directory): `vercel link`

app/(chat)/api/chat/route.ts

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,28 @@ import {
44
createDataStreamResponse,
55
smoothStream,
66
streamText,
7-
} from 'ai';
8-
import { auth } from '@/app/(auth)/auth';
9-
import { systemPrompt } from '@/lib/ai/prompts';
7+
} from "ai";
8+
import { auth } from "@/app/(auth)/auth";
9+
import { systemPrompt } from "@/lib/ai/prompts";
1010
import {
1111
deleteChatById,
1212
getChatById,
1313
saveChat,
1414
saveMessages,
15-
} from '@/lib/db/queries';
15+
} from "@/lib/db/queries";
1616
import {
1717
generateUUID,
1818
getMostRecentUserMessage,
1919
getTrailingMessageId,
20-
} from '@/lib/utils';
21-
import { generateTitleFromUserMessage } from '../../actions';
22-
import { createDocument } from '@/lib/ai/tools/create-document';
23-
import { updateDocument } from '@/lib/ai/tools/update-document';
24-
import { requestSuggestions } from '@/lib/ai/tools/request-suggestions';
25-
import { getWeather } from '@/lib/ai/tools/get-weather';
26-
import { isProductionEnvironment } from '@/lib/constants';
27-
import { myProvider } from '@/lib/ai/providers';
28-
import { chatConfig } from '@/lib/chat-config';
20+
} from "@/lib/utils";
21+
import { generateTitleFromUserMessage } from "../../actions";
22+
import { createDocument } from "@/lib/ai/tools/create-document";
23+
import { updateDocument } from "@/lib/ai/tools/update-document";
24+
import { requestSuggestions } from "@/lib/ai/tools/request-suggestions";
25+
import { getWeather } from "@/lib/ai/tools/get-weather";
26+
import { isProductionEnvironment } from "@/lib/constants";
27+
import { myProvider } from "@/lib/ai/providers";
28+
import { chatConfig } from "@/lib/chat-config";
2929

3030
export const maxDuration = 60;
3131

@@ -44,7 +44,7 @@ export async function POST(request: Request) {
4444
const session = await auth();
4545

4646
if (!chatConfig.guestUsage.isEnabled && !session?.user?.id) {
47-
return new Response('Unauthorized', { status: 401 });
47+
return new Response("Unauthorized", { status: 401 });
4848
}
4949

5050
const userId = session?.user?.id;
@@ -53,7 +53,7 @@ export async function POST(request: Request) {
5353
const userMessage = getMostRecentUserMessage(messages);
5454

5555
if (!userMessage) {
56-
return new Response('No user message found', { status: 400 });
56+
return new Response("No user message found", { status: 400 });
5757
}
5858

5959
const chat = await getChatById({ id });
@@ -66,7 +66,7 @@ export async function POST(request: Request) {
6666
if (isAuthenticated) await saveChat({ id, userId, title });
6767
} else {
6868
if (chat.userId !== userId) {
69-
return new Response('Unauthorized', { status: 401 });
69+
return new Response("Unauthorized", { status: 401 });
7070
}
7171
}
7272

@@ -76,7 +76,7 @@ export async function POST(request: Request) {
7676
{
7777
chatId: id,
7878
id: userMessage.id,
79-
role: 'user',
79+
role: "user",
8080
parts: userMessage.parts,
8181
attachments: userMessage.experimental_attachments ?? [],
8282
createdAt: new Date(),
@@ -92,15 +92,15 @@ export async function POST(request: Request) {
9292
messages,
9393
maxSteps: 5,
9494
experimental_activeTools:
95-
selectedChatModel === 'chat-model-reasoning'
95+
selectedChatModel === "chat-model-reasoning"
9696
? []
9797
: [
98-
'getWeather',
99-
'createDocument',
100-
'updateDocument',
101-
'requestSuggestions',
98+
"getWeather",
99+
"createDocument",
100+
"updateDocument",
101+
"requestSuggestions",
102102
],
103-
experimental_transform: smoothStream({ chunking: 'word' }),
103+
experimental_transform: smoothStream({ chunking: "word" }),
104104
experimental_generateMessageId: generateUUID,
105105
tools: {
106106
getWeather,
@@ -116,12 +116,12 @@ export async function POST(request: Request) {
116116
try {
117117
const assistantId = getTrailingMessageId({
118118
messages: response.messages.filter(
119-
(message) => message.role === 'assistant',
119+
(message) => message.role === "assistant",
120120
),
121121
});
122122

123123
if (!assistantId) {
124-
throw new Error('No assistant message found!');
124+
throw new Error("No assistant message found!");
125125
}
126126

127127
const [, assistantMessage] = appendResponseMessages({
@@ -142,14 +142,14 @@ export async function POST(request: Request) {
142142
},
143143
],
144144
});
145-
} catch (error) {
146-
console.error('Failed to save chat');
145+
} catch (_) {
146+
console.error("Failed to save chat");
147147
}
148148
}
149149
},
150150
experimental_telemetry: {
151151
isEnabled: isProductionEnvironment,
152-
functionId: 'stream-text',
152+
functionId: "stream-text",
153153
},
154154
});
155155

@@ -160,42 +160,42 @@ export async function POST(request: Request) {
160160
});
161161
},
162162
onError: () => {
163-
return 'Oops, an error occured!';
163+
return "Oops, an error occured!";
164164
},
165165
});
166166
} catch (error) {
167-
return new Response('An error occurred while processing your request!', {
167+
return new Response("An error occurred while processing your request!", {
168168
status: 404,
169169
});
170170
}
171171
}
172172

173173
export async function DELETE(request: Request) {
174174
const { searchParams } = new URL(request.url);
175-
const id = searchParams.get('id');
175+
const id = searchParams.get("id");
176176

177177
if (!id) {
178-
return new Response('Not Found', { status: 404 });
178+
return new Response("Not Found", { status: 404 });
179179
}
180180

181181
const session = await auth();
182182

183183
if (!session || !session.user) {
184-
return new Response('Unauthorized', { status: 401 });
184+
return new Response("Unauthorized", { status: 401 });
185185
}
186186

187187
try {
188188
const chat = await getChatById({ id });
189189

190190
if (chat.userId !== session.user.id) {
191-
return new Response('Unauthorized', { status: 401 });
191+
return new Response("Unauthorized", { status: 401 });
192192
}
193193

194194
await deleteChatById({ id });
195195

196-
return new Response('Chat deleted', { status: 200 });
196+
return new Response("Chat deleted", { status: 200 });
197197
} catch (error) {
198-
return new Response('An error occurred while processing your request!', {
198+
return new Response("An error occurred while processing your request!", {
199199
status: 500,
200200
});
201201
}

components/chat-header.tsx

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
'use client';
1+
"use client";
22

3-
import Link from 'next/link';
4-
import { useRouter } from 'next/navigation';
5-
import { useWindowSize } from 'usehooks-ts';
3+
import Link from "next/link";
4+
import { useRouter } from "next/navigation";
5+
import { useWindowSize } from "usehooks-ts";
66

7-
import { ModelSelector } from '@/components/model-selector';
8-
import { SidebarToggle } from '@/components/sidebar-toggle';
9-
import { Button } from '@/components/ui/button';
10-
import { PlusIcon, VercelIcon } from './icons';
11-
import { useSidebar } from './ui/sidebar';
12-
import { memo } from 'react';
13-
import { Tooltip, TooltipContent, TooltipTrigger } from './ui/tooltip';
14-
import { VisibilityType, VisibilitySelector } from './visibility-selector';
15-
import { UserIcon } from 'lucide-react';
7+
import { ModelSelector } from "@/components/model-selector";
8+
import { SidebarToggle } from "@/components/sidebar-toggle";
9+
import { Button } from "@/components/ui/button";
10+
import { PlusIcon, VercelIcon } from "./icons";
11+
import { useSidebar } from "./ui/sidebar";
12+
import { memo } from "react";
13+
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip";
14+
import { VisibilityType, VisibilitySelector } from "./visibility-selector";
15+
import { UserIcon } from "lucide-react";
1616

1717
function PureChatHeader({
1818
chatId,
@@ -46,7 +46,7 @@ function PureChatHeader({
4646
variant="outline"
4747
className="order-2 md:order-1 md:px-2 px-2 md:h-fit ml-auto md:ml-0"
4848
onClick={() => {
49-
router.push('/');
49+
router.push("/");
5050
router.refresh();
5151
}}
5252
>
@@ -79,7 +79,7 @@ function PureChatHeader({
7979
asChild
8080
>
8181
<Link
82-
href="https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fai-chatbot&env=AUTH_SECRET,OPENAI_API_KEY&envDescription=Learn%20more%20about%20how%20to%20get%20the%20API%20Keys%20for%20the%20application&envLink=https%3A%2F%2Fgithub.com%2Fvercel%2Fai-chatbot%2Fblob%2Fmain%2F.env.example&demo-title=AI%20Chatbot&demo-description=An%20Open-Source%20AI%20Chatbot%20Template%20Built%20With%20Next.js%20and%20the%20AI%20SDK%20by%20Vercel.&demo-url=https%3A%2F%2Fchat.vercel.ai&stores=%5B%7B%22type%22:%22postgres%22%7D,%7B%22type%22:%22blob%22%7D%5D"
82+
href={`https://vercel.com/new/clone?repository-url=https://github.com/vercel/ai-chatbot&env=AUTH_SECRET&envDescription=Learn more about how to get the API Keys for the application&envLink=https://github.com/vercel/ai-chatbot/blob/main/.env.example&demo-title=AI Chatbot&demo-description=An Open-Source AI Chatbot Template Built With Next.js and the AI SDK by Vercel.&demo-url=https://chat.vercel.ai&products=[{"type":"integration","protocol":"ai","productSlug":"grok","integrationSlug":"xai"},{"type":"integration","protocol":"ai","productSlug":"api-key","integrationSlug":"groq"},{"type":"integration","protocol":"storage","productSlug":"neon","integrationSlug":"neon"},{"type":"blob"}]`}
8383
target="_noblank"
8484
>
8585
<VercelIcon size={16} />

components/icons.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,7 @@ export const PlusIcon = ({ size = 16 }: { size?: number }) => (
757757
<path
758758
fillRule="evenodd"
759759
clipRule="evenodd"
760-
d="M8.75 1.75V1H7.25V1.75V6.75H2.25H1.5V8.25H2.25H7.25V13.25V14H8.75V13.25V8.25H13.75H14.5V6.75H13.75H8.75V1.75Z"
760+
d="M 8.75,1 H7.25 V7.25 H1.5 V8.75 H7.25 V15 H8.75 V8.75 H14.5 V7.25 H8.75 V1.75 Z"
761761
fill="currentColor"
762762
/>
763763
</svg>

0 commit comments

Comments
 (0)