From a6503fb498dc2638f5eab1d70a6c8f288324ef89 Mon Sep 17 00:00:00 2001 From: Mckay Wrigley Date: Mon, 13 Mar 2023 19:21:14 -0600 Subject: [PATCH] chatbot-ui starter --- .eslintrc.json | 3 + .gitignore | 36 + README.md | 71 - components/Chat/Chat.tsx | 36 + components/Chat/ChatInput.tsx | 65 + components/Chat/ChatLoader.tsx | 17 + components/Chat/ChatMessage.tsx | 19 + components/Layout/Footer.tsx | 5 + components/Layout/Navbar.tsx | 16 + license | 21 + next.config.js | 6 + package-lock.json | 6702 +++++++++++++++++++++++++++++++ package.json | 30 + pages/_app.tsx | 13 + pages/_document.tsx | 13 + pages/api/chat.ts | 36 + pages/index.tsx | 127 + postcss.config.js | 6 + public/favicon.ico | Bin 0 -> 15406 bytes public/screenshot.png | Bin 0 -> 485927 bytes styles/globals.css | 3 + tailwind.config.js | 8 + tsconfig.json | 23 + types/index.ts | 10 + utils/index.ts | 64 + 25 files changed, 7259 insertions(+), 71 deletions(-) create mode 100644 .eslintrc.json create mode 100644 .gitignore create mode 100644 components/Chat/Chat.tsx create mode 100644 components/Chat/ChatInput.tsx create mode 100644 components/Chat/ChatLoader.tsx create mode 100644 components/Chat/ChatMessage.tsx create mode 100644 components/Layout/Footer.tsx create mode 100644 components/Layout/Navbar.tsx create mode 100644 license create mode 100644 next.config.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 pages/_app.tsx create mode 100644 pages/_document.tsx create mode 100644 pages/api/chat.ts create mode 100644 pages/index.tsx create mode 100644 postcss.config.js create mode 100644 public/favicon.ico create mode 100644 public/screenshot.png create mode 100644 styles/globals.css create mode 100644 tailwind.config.js create mode 100644 tsconfig.json create mode 100644 types/index.ts create mode 100644 utils/index.ts diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..bffb357 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c87c9b3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/README.md b/README.md index 9c7d378..8109f21 100644 --- a/README.md +++ b/README.md @@ -1,72 +1 @@ # Chatbot UI - -A simple chatbot starter kit for OpenAI's chat model using Next.js, TypeScript, and Tailwind CSS. - -See a [demo](https://twitter.com/mckaywrigley/status/1634549098954248193?s=46&t=AowqkodyK6B4JccSOxSPew). - -![Chatbot UI](./public/screenshot.png) - -## Features - -Chatbot UI provides a simple, fully-functional chat interface that you can use to start building your own chatbot apps powered by OpenAI. - -It has everything you need to hit the ground running. - -Modify the chat interface in `components/Chat`. - -Tweak the system prompt in `utils/index.ts`. - -Tweak the assistant prompt in `pages/index.tsx`. - -## Deploy - -**Vercel** - -Host your own live version of Chatbot UI with Vercel. - -[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fmckaywrigley%2Fchatbot-ui&env=OPENAI_API_KEY&envDescription=OpenAI%20API%20Key%20needed%20for%20chat.&envLink=https%3A%2F%2Fopenai.com%2Fproduct&project-name=chatbot-ui&repository-name=chatbot-ui) - -**Replit** - -Fork Chatbot UI on Replit [here](https://replit.com/@MckayWrigley/chatbot-ui). - -## Running Locally - -**1. Clone Repo** - -```bash -git clone https://github.com/mckaywrigley/chatbot-ui.git -``` - -**2. Install Dependencies** - -```bash -npm i -``` - -**3. Provide OpenAI API Key** - -Create a .env.local file in the root of the repo with your OpenAI API Key: - -```bash -OPENAI_API_KEY= -``` - -**4. Run App** - -```bash -npm run dev -``` - -**5. Start Building** - -You should be able to start chatting with the bot. - -Now, go build the app into whatever kind of chatbot you want! - -## Contact - -If you have any questions, feel free to reach out to me on [Twitter](https://twitter.com/mckaywrigley). - -I'd also love to see what you build with this starter kit - share your projects with me! -# chatbot-ui-pro diff --git a/components/Chat/Chat.tsx b/components/Chat/Chat.tsx new file mode 100644 index 0000000..d7a3c94 --- /dev/null +++ b/components/Chat/Chat.tsx @@ -0,0 +1,36 @@ +import { Message } from "@/types"; +import { FC } from "react"; +import { ChatInput } from "./ChatInput"; +import { ChatLoader } from "./ChatLoader"; +import { ChatMessage } from "./ChatMessage"; + +interface Props { + messages: Message[]; + loading: boolean; + onSend: (message: Message) => void; +} + +export const Chat: FC = ({ messages, loading, onSend }) => { + return ( +
+ {messages.map((message, index) => ( +
+ +
+ ))} + + {loading && ( +
+ +
+ )} + +
+ +
+
+ ); +}; diff --git a/components/Chat/ChatInput.tsx b/components/Chat/ChatInput.tsx new file mode 100644 index 0000000..75bc7a3 --- /dev/null +++ b/components/Chat/ChatInput.tsx @@ -0,0 +1,65 @@ +import { Message } from "@/types"; +import { IconArrowUp } from "@tabler/icons-react"; +import { FC, KeyboardEvent, useEffect, useRef, useState } from "react"; + +interface Props { + onSend: (message: Message) => void; +} + +export const ChatInput: FC = ({ onSend }) => { + const [content, setContent] = useState(); + + const textareaRef = useRef(null); + + const handleChange = (e: React.ChangeEvent) => { + const value = e.target.value; + if (value.length > 4000) { + alert("Message limit is 4000 characters"); + return; + } + + setContent(value); + }; + + const handleSend = () => { + if (!content) { + alert("Please enter a message"); + return; + } + onSend({ role: "user", content }); + setContent(""); + }; + + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault(); + handleSend(); + } + }; + + useEffect(() => { + if (textareaRef && textareaRef.current) { + textareaRef.current.style.height = "inherit"; + textareaRef.current.style.height = `${textareaRef.current?.scrollHeight}px`; + } + }, [content]); + + return ( +
+