Initial commit: EGBE chatbot template

Stripped from vercel/chatbot (Apache 2.0):
- Dropped @vercel/* packages and AI Gateway
- Removed artifacts feature (code/text/sheet/image side panel)
- Switched AI provider to @ai-sdk/openai-compatible -> EGBE LiteLLM
- Replaced Vercel Blob upload with data URLs
- Dropped Redis resumable streams and rate limiter (in-memory now)
- Added Dockerfile (Next.js standalone) + entrypoint that runs migrations
- Wired DATABASE_URL, EGBE_AI_API_URL/KEY, NEXT_PUBLIC_BASE_URL for app-deploy.sh
This commit is contained in:
dmitry.galkin 2026-05-25 14:54:04 +04:00
commit 3e21c2334c
129 changed files with 21913 additions and 0 deletions

78
app/(chat)/actions.ts Normal file
View file

@ -0,0 +1,78 @@
"use server";
import { generateText, type UIMessage } from "ai";
import { cookies } from "next/headers";
import { auth } from "@/app/(auth)/auth";
import type { VisibilityType } from "@/components/chat/visibility-selector";
import { titlePrompt } from "@/lib/ai/prompts";
import { getTitleModel } from "@/lib/ai/providers";
import {
deleteMessagesByChatIdAfterTimestamp,
getChatById,
getMessageById,
updateChatVisibilityById,
} from "@/lib/db/queries";
import { getTextFromMessage } from "@/lib/utils";
export async function saveChatModelAsCookie(model: string) {
const cookieStore = await cookies();
cookieStore.set("chat-model", model);
}
export async function generateTitleFromUserMessage({
message,
}: {
message: UIMessage;
}) {
const { text } = await generateText({
model: getTitleModel(),
system: titlePrompt,
prompt: getTextFromMessage(message),
});
return text
.replace(/^[#*"\s]+/, "")
.replace(/["]+$/, "")
.trim();
}
export async function deleteTrailingMessages({ id }: { id: string }) {
const session = await auth();
if (!session?.user?.id) {
throw new Error("Unauthorized");
}
const [message] = await getMessageById({ id });
if (!message) {
throw new Error("Message not found");
}
const chat = await getChatById({ id: message.chatId });
if (!chat || chat.userId !== session.user.id) {
throw new Error("Unauthorized");
}
await deleteMessagesByChatIdAfterTimestamp({
chatId: message.chatId,
timestamp: message.createdAt,
});
}
export async function updateChatVisibility({
chatId,
visibility,
}: {
chatId: string;
visibility: VisibilityType;
}) {
const session = await auth();
if (!session?.user?.id) {
throw new Error("Unauthorized");
}
const chat = await getChatById({ id: chatId });
if (!chat || chat.userId !== session.user.id) {
throw new Error("Unauthorized");
}
await updateChatVisibilityById({ chatId, visibility });
}