Skip to content

Commit 6a12751

Browse files
authored
Merge pull request #4 from nedhmn/feature/web-chatbot-ui
Feature/web chatbot UI
2 parents a77cc30 + e03135b commit 6a12751

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1713
-354
lines changed

.github/workflows/lint.yml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,9 @@ jobs:
4545
- name: Lint
4646
run: pnpm lint
4747

48-
# Need to build before "check-types" for export types to be available
49-
50-
- name: Build
51-
run: pnpm build
52-
5348
- name: Check types
54-
run: pnpm check-types
49+
run: pnpm build
50+
env:
51+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
52+
PINECONE_API_KEY: ${{ secrets.PINECONE_API_KEY }}
53+
PINECONE_INDEX_NAME: ${{ secrets.PINECONE_INDEX_NAME }}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
# YGO Ruling AI Chatbot
1+
# Yu-Gi-Oh! Ruling AI Chatbot

apps/web/README.md

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1 @@
1-
## Getting Started
2-
3-
First, run the development server:
4-
5-
```bash
6-
yarn dev
7-
```
8-
9-
Open [http://localhost:3001](http://localhost:3001) with your browser to see the result.
10-
11-
You can start editing the page by modifying `src/app/page.tsx`. The page auto-updates as you edit the file.
12-
13-
To create [API routes](https://nextjs.org/docs/app/building-your-application/routing/router-handlers) add an `api/` directory to the `app/` directory with a `route.ts` file. For individual endpoints, create a subfolder in the `api` directory, like `api/hello/route.ts` would map to [http://localhost:3001/api/hello](http://localhost:3001/api/hello).
14-
15-
## Learn More
16-
17-
To learn more about Next.js, take a look at the following resources:
18-
19-
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
20-
- [Learn Next.js](https://nextjs.org/learn/foundations/about-nextjs) - an interactive Next.js tutorial.
21-
22-
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
23-
24-
## Deploy on Vercel
25-
26-
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_source=github.com&utm_medium=referral&utm_campaign=turborepo-readme) from the creators of Next.js.
27-
28-
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
1+
# Yu-Gi-Oh! Ruling Chatbot

apps/web/app/(home)/page.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
"use client";
2+
3+
import Chat from "@/components/chat";
4+
5+
export default function Page() {
6+
return (
7+
<div>
8+
<Chat />
9+
</div>
10+
);
11+
}

apps/web/app/api/chat/route.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import getOpenAIClient from "@repo/embeddings/openai";
2+
import { streamText } from "ai";
3+
4+
export const maxDuration = 60;
5+
6+
export async function POST(req: Request) {
7+
try {
8+
const { messages } = await req.json();
9+
const openai = getOpenAIClient();
10+
11+
const result = streamText({
12+
model: openai.responses("gpt-4o-mini"),
13+
messages,
14+
});
15+
16+
return result.toDataStreamResponse();
17+
} catch (error) {
18+
console.error("Error in chat API:", error);
19+
return new Response(
20+
JSON.stringify({ error: "Failed to process chat request" }),
21+
{
22+
status: 500,
23+
headers: { "Content-Type": "application/json" },
24+
},
25+
);
26+
}
27+
}

apps/web/app/env.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { createEnv } from "@t3-oss/env-nextjs";
2+
import { z } from "zod";
3+
4+
export const env = createEnv({
5+
/*
6+
* Serverside Environment variables, not available on the client.
7+
* Will throw if you access these variables on the client.
8+
*/
9+
server: {
10+
OPENAI_API_KEY: z.string(),
11+
PINECONE_API_KEY: z.string(),
12+
PINECONE_INDEX_NAME: z.string(),
13+
},
14+
/*
15+
* Environment variables available on the client (and server).
16+
*
17+
* 💡 You'll get type errors if these are not prefixed with NEXT_PUBLIC_.
18+
*/
19+
client: {},
20+
/*
21+
* Due to how Next.js bundles environment variables on Edge and Client,
22+
* we need to manually destructure them to make sure all are included in bundle.
23+
*
24+
* 💡 You'll get type errors if not all variables from `server` & `client` are included here.
25+
*/
26+
runtimeEnv: {
27+
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
28+
PINECONE_API_KEY: process.env.PINECONE_API_KEY,
29+
PINECONE_INDEX_NAME: process.env.PINECONE_INDEX_NAME,
30+
},
31+
});

apps/web/app/globals.css

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,25 @@
22
@import "@repo/tailwind-config";
33
@import "@repo/ui/styles.css";
44

5-
:root {
6-
--foreground-rgb: 0, 0, 0;
7-
--background-start-rgb: 214, 219, 220;
8-
--background-end-rgb: 255, 255, 255;
5+
/* Custom scrollbar styles */
6+
::-webkit-scrollbar {
7+
width: 8px;
98
}
109

11-
@media (prefers-color-scheme: dark) {
12-
:root {
13-
--foreground-rgb: 255, 255, 255;
14-
--background-start-rgb: 0, 0, 0;
15-
--background-end-rgb: 0, 0, 0;
16-
}
10+
::-webkit-scrollbar-track {
11+
background: transparent;
1712
}
1813

19-
body {
20-
color: rgb(var(--foreground-rgb));
21-
background: linear-gradient(
22-
to bottom,
23-
transparent,
24-
rgb(var(--background-end-rgb))
25-
)
26-
rgb(var(--background-start-rgb));
14+
::-webkit-scrollbar-thumb {
15+
background: #888;
16+
border-radius: 4px;
17+
}
18+
19+
::-webkit-scrollbar-thumb:hover {
20+
background: #555;
21+
}
22+
23+
/* System markdown styles */
24+
.system-message-styles p + p {
25+
@apply mt-3;
2726
}

apps/web/app/layout.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import "./globals.css";
22
import type { Metadata } from "next";
3-
import { Geist } from "next/font/google";
3+
import { Inter } from "next/font/google";
4+
import { Provider } from "@repo/ui";
5+
import Navbar from "@/components/navbar";
46

5-
const geist = Geist({ subsets: ["latin"] });
7+
const inter = Inter({ subsets: ["latin"] });
68

79
export const metadata: Metadata = {
810
title: "Create Turborepo",
@@ -15,8 +17,13 @@ export default function RootLayout({
1517
children: React.ReactNode;
1618
}) {
1719
return (
18-
<html lang="en">
19-
<body className={geist.className}>{children}</body>
20+
<html lang="en" suppressHydrationWarning>
21+
<body className={inter.className}>
22+
<Provider>
23+
<Navbar />
24+
{children}
25+
</Provider>
26+
</body>
2027
</html>
2128
);
2229
}

apps/web/app/page.tsx

Lines changed: 0 additions & 116 deletions
This file was deleted.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
"use client";
2+
3+
import { useSendMessage } from "@/hooks/use-send-message";
4+
import { UseChatHelpers } from "@ai-sdk/react";
5+
import { Textarea } from "@repo/ui/components/ui/textarea";
6+
import { KeyboardEvent } from "react";
7+
8+
type ChatInputAreaProps = {
9+
chatHelpers: UseChatHelpers;
10+
input: string;
11+
setInput: (value: string) => void;
12+
};
13+
14+
const ChatInputArea = ({
15+
chatHelpers,
16+
input,
17+
setInput,
18+
}: ChatInputAreaProps) => {
19+
const { status } = chatHelpers;
20+
const isGeneratingResponse = ["streaming", "submitted"].includes(status);
21+
22+
const { handleSendMessage } = useSendMessage({
23+
chatHelpers,
24+
isGeneratingResponse,
25+
input,
26+
setInput,
27+
});
28+
29+
const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {
30+
if (event.key === "Enter" && !event.shiftKey) {
31+
event.preventDefault();
32+
handleSendMessage();
33+
}
34+
};
35+
36+
return (
37+
<Textarea
38+
value={input}
39+
placeholder="How can I help with Yu-Gi-Oh! rulings?"
40+
className="pr-12 py-3 min-h-[60px] max-h-[120px] focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:outline-none border-0 resize-none"
41+
disabled={isGeneratingResponse}
42+
autoFocus
43+
onChange={(event) => {
44+
setInput(event.currentTarget.value);
45+
}}
46+
onKeyDown={handleKeyDown}
47+
/>
48+
);
49+
};
50+
51+
export default ChatInputArea;

0 commit comments

Comments
 (0)