Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<a href="https://chat.vercel.ai/">
<img alt="Next.js 14 and App Router-ready OpenChat." src="app/(chat)/opengraph-image.png">
<h1 align="center">OpenChat</h1>
<img alt="Next.js 14 and App Router-ready Chatbot." src="app/(chat)/opengraph-image.png">
<h1 align="center">Chatbot</h1>
</a>

<p align="center">
OpenChat (formerly AI Chatbot) is a free, open-source template built with Next.js and the AI SDK that helps you quickly build powerful chatbot applications.
Chatbot (formerly AI Chatbot) is a free, open-source template built with Next.js and the AI SDK that helps you quickly build powerful chatbot applications.
</p>

<p align="center">
<a href="https://openchat.dev"><strong>Read Docs</strong></a> ·
<a href="https://chatbot.dev"><strong>Read Docs</strong></a> ·
<a href="#features"><strong>Features</strong></a> ·
<a href="#model-providers"><strong>Model Providers</strong></a> ·
<a href="#deploy-your-own"><strong>Deploy Your Own</strong></a> ·
Expand Down Expand Up @@ -48,13 +48,13 @@ With the [AI SDK](https://ai-sdk.dev/docs/introduction), you can also switch to

## Deploy Your Own

You can deploy your own version of OpenChat to Vercel with one click:
You can deploy your own version of Chatbot to Vercel with one click:

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/templates/next.js/openchat)
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/templates/next.js/chatbot)

## Running locally

You will need to use the environment variables [defined in `.env.example`](.env.example) to run OpenChat. 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.
You will need to use the environment variables [defined in `.env.example`](.env.example) to run 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.

> 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.
Expand Down
22 changes: 11 additions & 11 deletions app/(chat)/api/chat/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
updateMessage,
} from "@/lib/db/queries";
import type { DBMessage } from "@/lib/db/schema";
import { OpenChatError } from "@/lib/errors";
import { ChatbotError } from "@/lib/errors";
import type { ChatMessage } from "@/lib/types";
import { convertToUIMessages, generateUUID } from "@/lib/utils";
import { generateTitleFromUserMessage } from "../../actions";
Expand All @@ -55,7 +55,7 @@ export async function POST(request: Request) {
const json = await request.json();
requestBody = postRequestBodySchema.parse(json);
} catch (_) {
return new OpenChatError("bad_request:api").toResponse();
return new ChatbotError("bad_request:api").toResponse();
}

try {
Expand All @@ -65,7 +65,7 @@ export async function POST(request: Request) {
const session = await auth();

if (!session?.user) {
return new OpenChatError("unauthorized:chat").toResponse();
return new ChatbotError("unauthorized:chat").toResponse();
}

const userType: UserType = session.user.type;
Expand All @@ -76,7 +76,7 @@ export async function POST(request: Request) {
});

if (messageCount > entitlementsByUserType[userType].maxMessagesPerDay) {
return new OpenChatError("rate_limit:chat").toResponse();
return new ChatbotError("rate_limit:chat").toResponse();
}

const isToolApprovalFlow = Boolean(messages);
Expand All @@ -87,7 +87,7 @@ export async function POST(request: Request) {

if (chat) {
if (chat.userId !== session.user.id) {
return new OpenChatError("forbidden:chat").toResponse();
return new ChatbotError("forbidden:chat").toResponse();
}
if (!isToolApprovalFlow) {
messagesFromDb = await getMessagesByChatId({ id });
Expand Down Expand Up @@ -244,7 +244,7 @@ export async function POST(request: Request) {
} catch (error) {
const vercelId = request.headers.get("x-vercel-id");

if (error instanceof OpenChatError) {
if (error instanceof ChatbotError) {
return error.toResponse();
}

Expand All @@ -254,11 +254,11 @@ export async function POST(request: Request) {
"AI Gateway requires a valid credit card on file to service requests"
)
) {
return new OpenChatError("bad_request:activate_gateway").toResponse();
return new ChatbotError("bad_request:activate_gateway").toResponse();
}

console.error("Unhandled error in chat API:", error, { vercelId });
return new OpenChatError("offline:chat").toResponse();
return new ChatbotError("offline:chat").toResponse();
}
}

Expand All @@ -267,19 +267,19 @@ export async function DELETE(request: Request) {
const id = searchParams.get("id");

if (!id) {
return new OpenChatError("bad_request:api").toResponse();
return new ChatbotError("bad_request:api").toResponse();
}

const session = await auth();

if (!session?.user) {
return new OpenChatError("unauthorized:chat").toResponse();
return new ChatbotError("unauthorized:chat").toResponse();
}

const chat = await getChatById({ id });

if (chat?.userId !== session.user.id) {
return new OpenChatError("forbidden:chat").toResponse();
return new ChatbotError("forbidden:chat").toResponse();
}

const deletedChat = await deleteChatById({ id });
Expand Down
24 changes: 12 additions & 12 deletions app/(chat)/api/document/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import {
getDocumentsById,
saveDocument,
} from "@/lib/db/queries";
import { OpenChatError } from "@/lib/errors";
import { ChatbotError } from "@/lib/errors";

export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const id = searchParams.get("id");

if (!id) {
return new OpenChatError(
return new ChatbotError(
"bad_request:api",
"Parameter id is missing"
).toResponse();
Expand All @@ -21,19 +21,19 @@ export async function GET(request: Request) {
const session = await auth();

if (!session?.user) {
return new OpenChatError("unauthorized:document").toResponse();
return new ChatbotError("unauthorized:document").toResponse();
}

const documents = await getDocumentsById({ id });

const [document] = documents;

if (!document) {
return new OpenChatError("not_found:document").toResponse();
return new ChatbotError("not_found:document").toResponse();
}

if (document.userId !== session.user.id) {
return new OpenChatError("forbidden:document").toResponse();
return new ChatbotError("forbidden:document").toResponse();
}

return Response.json(documents, { status: 200 });
Expand All @@ -44,7 +44,7 @@ export async function POST(request: Request) {
const id = searchParams.get("id");

if (!id) {
return new OpenChatError(
return new ChatbotError(
"bad_request:api",
"Parameter id is required."
).toResponse();
Expand All @@ -53,7 +53,7 @@ export async function POST(request: Request) {
const session = await auth();

if (!session?.user) {
return new OpenChatError("not_found:document").toResponse();
return new ChatbotError("not_found:document").toResponse();
}

const {
Expand All @@ -69,7 +69,7 @@ export async function POST(request: Request) {
const [doc] = documents;

if (doc.userId !== session.user.id) {
return new OpenChatError("forbidden:document").toResponse();
return new ChatbotError("forbidden:document").toResponse();
}
}

Expand All @@ -90,14 +90,14 @@ export async function DELETE(request: Request) {
const timestamp = searchParams.get("timestamp");

if (!id) {
return new OpenChatError(
return new ChatbotError(
"bad_request:api",
"Parameter id is required."
).toResponse();
}

if (!timestamp) {
return new OpenChatError(
return new ChatbotError(
"bad_request:api",
"Parameter timestamp is required."
).toResponse();
Expand All @@ -106,15 +106,15 @@ export async function DELETE(request: Request) {
const session = await auth();

if (!session?.user) {
return new OpenChatError("unauthorized:document").toResponse();
return new ChatbotError("unauthorized:document").toResponse();
}

const documents = await getDocumentsById({ id });

const [document] = documents;

if (document.userId !== session.user.id) {
return new OpenChatError("forbidden:document").toResponse();
return new ChatbotError("forbidden:document").toResponse();
}

const documentsDeleted = await deleteDocumentsByIdAfterTimestamp({
Expand Down
8 changes: 4 additions & 4 deletions app/(chat)/api/history/route.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { NextRequest } from "next/server";
import { auth } from "@/app/(auth)/auth";
import { deleteAllChatsByUserId, getChatsByUserId } from "@/lib/db/queries";
import { OpenChatError } from "@/lib/errors";
import { ChatbotError } from "@/lib/errors";

export async function GET(request: NextRequest) {
const { searchParams } = request.nextUrl;
Expand All @@ -11,7 +11,7 @@ export async function GET(request: NextRequest) {
const endingBefore = searchParams.get("ending_before");

if (startingAfter && endingBefore) {
return new OpenChatError(
return new ChatbotError(
"bad_request:api",
"Only one of starting_after or ending_before can be provided."
).toResponse();
Expand All @@ -20,7 +20,7 @@ export async function GET(request: NextRequest) {
const session = await auth();

if (!session?.user) {
return new OpenChatError("unauthorized:chat").toResponse();
return new ChatbotError("unauthorized:chat").toResponse();
}

const chats = await getChatsByUserId({
Expand All @@ -37,7 +37,7 @@ export async function DELETE() {
const session = await auth();

if (!session?.user) {
return new OpenChatError("unauthorized:chat").toResponse();
return new ChatbotError("unauthorized:chat").toResponse();
}

const result = await deleteAllChatsByUserId({ userId: session.user.id });
Expand Down
8 changes: 4 additions & 4 deletions app/(chat)/api/suggestions/route.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { auth } from "@/app/(auth)/auth";
import { getSuggestionsByDocumentId } from "@/lib/db/queries";
import { OpenChatError } from "@/lib/errors";
import { ChatbotError } from "@/lib/errors";

export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const documentId = searchParams.get("documentId");

if (!documentId) {
return new OpenChatError(
return new ChatbotError(
"bad_request:api",
"Parameter documentId is required."
).toResponse();
Expand All @@ -16,7 +16,7 @@ export async function GET(request: Request) {
const session = await auth();

if (!session?.user) {
return new OpenChatError("unauthorized:suggestions").toResponse();
return new ChatbotError("unauthorized:suggestions").toResponse();
}

const suggestions = await getSuggestionsByDocumentId({
Expand All @@ -30,7 +30,7 @@ export async function GET(request: Request) {
}

if (suggestion.userId !== session.user.id) {
return new OpenChatError("forbidden:api").toResponse();
return new ChatbotError("forbidden:api").toResponse();
}

return Response.json(suggestions, { status: 200 });
Expand Down
18 changes: 9 additions & 9 deletions app/(chat)/api/vote/route.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { auth } from "@/app/(auth)/auth";
import { getChatById, getVotesByChatId, voteMessage } from "@/lib/db/queries";
import { OpenChatError } from "@/lib/errors";
import { ChatbotError } from "@/lib/errors";

export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const chatId = searchParams.get("chatId");

if (!chatId) {
return new OpenChatError(
return new ChatbotError(
"bad_request:api",
"Parameter chatId is required."
).toResponse();
Expand All @@ -16,17 +16,17 @@ export async function GET(request: Request) {
const session = await auth();

if (!session?.user) {
return new OpenChatError("unauthorized:vote").toResponse();
return new ChatbotError("unauthorized:vote").toResponse();
}

const chat = await getChatById({ id: chatId });

if (!chat) {
return new OpenChatError("not_found:chat").toResponse();
return new ChatbotError("not_found:chat").toResponse();
}

if (chat.userId !== session.user.id) {
return new OpenChatError("forbidden:vote").toResponse();
return new ChatbotError("forbidden:vote").toResponse();
}

const votes = await getVotesByChatId({ id: chatId });
Expand All @@ -43,7 +43,7 @@ export async function PATCH(request: Request) {
await request.json();

if (!chatId || !messageId || !type) {
return new OpenChatError(
return new ChatbotError(
"bad_request:api",
"Parameters chatId, messageId, and type are required."
).toResponse();
Expand All @@ -52,17 +52,17 @@ export async function PATCH(request: Request) {
const session = await auth();

if (!session?.user) {
return new OpenChatError("unauthorized:vote").toResponse();
return new ChatbotError("unauthorized:vote").toResponse();
}

const chat = await getChatById({ id: chatId });

if (!chat) {
return new OpenChatError("not_found:vote").toResponse();
return new ChatbotError("not_found:vote").toResponse();
}

if (chat.userId !== session.user.id) {
return new OpenChatError("forbidden:vote").toResponse();
return new ChatbotError("forbidden:vote").toResponse();
}

await voteMessage({
Expand Down
Binary file modified app/(chat)/opengraph-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 7 additions & 4 deletions components/app-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,12 @@ export function AppSidebar({ user }: { user: User | undefined }) {
const [showDeleteAllDialog, setShowDeleteAllDialog] = useState(false);

const handleDeleteAll = () => {
const deletePromise = fetch(`${process.env.NEXT_PUBLIC_BASE_PATH ?? ""}/api/history`, {
method: "DELETE",
});
const deletePromise = fetch(
`${process.env.NEXT_PUBLIC_BASE_PATH ?? ""}/api/history`,
{
method: "DELETE",
}
);

toast.promise(deletePromise, {
loading: "Deleting all chats...",
Expand Down Expand Up @@ -72,7 +75,7 @@ export function AppSidebar({ user }: { user: User | undefined }) {
}}
>
<span className="cursor-pointer rounded-md px-2 font-semibold text-lg hover:bg-muted">
OpenChat
Chatbot
</span>
</Link>
<div className="flex flex-row gap-1">
Expand Down
Loading