├── .env.example
├── .eslintrc.json
├── .github
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── pull_request_template.md
└── workflows
│ └── ci.yml
├── .gitignore
├── LICENSE
├── README.md
├── app
├── api
│ └── v1
│ │ └── chatbots
│ │ └── [chatbotId]
│ │ └── route.js
├── app
│ ├── chatbots
│ │ ├── [chatbotId]
│ │ │ ├── client-page.js
│ │ │ ├── loading.js
│ │ │ └── page.js
│ │ ├── client-page.js
│ │ ├── loading.js
│ │ └── page.js
│ ├── client-page.js
│ ├── container.js
│ ├── layout.js
│ ├── loading.js
│ ├── page.js
│ ├── prompt-templates
│ │ ├── client-page.js
│ │ ├── loading.js
│ │ └── page.js
│ └── sidebar.js
├── favicon.ico
├── landing-page.js
├── layout.js
├── loading.js
├── page.js
├── providers.js
└── user
│ └── login
│ ├── login.js
│ └── page.js
├── components
├── chat
│ ├── index.js
│ ├── input.js
│ ├── output.js
│ └── prompt-templates.js
├── code-block.js
├── page-header.js
└── user-menu.js
├── jsconfig.json
├── lib
├── api-docs.js
├── api.js
├── chain.js
├── prisma.js
├── prompt-template.js
├── sidebar.js
└── theme.js
├── next.config.js
├── package-lock.json
├── package.json
├── pages
└── api
│ ├── auth
│ └── [...nextauth].js
│ ├── chatbots
│ ├── [chatbotId]
│ │ ├── index.js
│ │ └── messages
│ │ │ └── index.js
│ └── index.js
│ └── prompt-templates
│ ├── [promptId]
│ └── index.js
│ └── index.js
├── prisma
├── migrations
│ ├── 20230327164641_user_defaults
│ │ └── migration.sql
│ ├── 20230327201911_prompt_templates
│ │ └── migration.sql
│ ├── 20230329205257_chatbots
│ │ └── migration.sql
│ ├── 20230406080854_chatbot_message
│ │ └── migration.sql
│ ├── 20230409152256_chatbot_prompt_template
│ │ └── migration.sql
│ └── migration_lock.toml
└── schema.prisma
└── public
├── chatbot.png
├── next.svg
├── thirteen.svg
├── user.png
└── vercel.svg
/.env.example:
--------------------------------------------------------------------------------
1 | DATABASE_URL=""
2 | NEXTAUTH_SECRET=""
3 | NEXTAUTH_URL=""
4 | NEXT_PUBLIC_GITHUB_ID=""
5 | NEXT_PUBLIC_GITHUB_SECRET=""
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to LangChain UI
2 |
3 | Thanks for being interested in contributing to LangChain UI ❤️.
4 | We are extremely open to any and all contributions you might be intersted in making.
5 | To contribute to this project, please follow a ["fork and pull request"](https://docs.github.com/en/get-started/quickstart/contributing-to-projects) workflow.
6 | Please do not try to push directly to this repo unless you are maintainer.
7 |
8 | ## Guidelines
9 |
10 | ### Issues
11 |
12 | The [issues](https://github.com/homanp/langchain-ui/issues) contains all current bugs, improvements, and feature requests.
13 | Please use the correspondnig label when creating an issue.
14 |
15 | The current set of labels are:
16 |
17 | - `api` for LangChain related API integrations
18 | - `infrastructure` for general issues regarding the infra of LangChain UI
19 | - `user interface` for UI/UX related issues.
20 |
21 | ### Getting Help
22 |
23 | Contact a maintainer of LangChain UI with any questions or help you might need.
24 |
25 | ### Release process
26 |
27 | LangChain UI tries to follow the same ad hoc realease proccess as [Langchain](https://github.com/hwchase17/langchain).
28 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🐞 Bug Report
3 | about: Create a report to help us improve
4 | title: ""
5 | labels: bug
6 | assignees: ""
7 | ---
8 |
9 | **Describe the bug**
10 | A clear and concise description of what the bug is.
11 |
12 | **To Reproduce**
13 | Steps to reproduce the behavior:
14 |
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🚀 Feature request
3 | about: Suggest an idea for improving Langchain UI
4 | title:
5 | labels: enhancement
6 | assignees:
7 | ---
8 |
9 | ### Is your proposal related to a problem?
10 |
11 |
15 |
16 | (Write your answer here.)
17 |
18 | ### Describe the solution you'd like
19 |
20 |
23 |
24 | (Describe your proposed solution here.)
25 |
26 | ### Describe alternatives you've considered
27 |
28 |
31 |
32 | (Write your answer here.)
33 |
34 | ### Additional context
35 |
36 |
40 |
41 | (Write your answer here.)
42 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ## Summary
2 |
3 |
4 |
5 | Fixes
6 |
7 | Depends on
8 |
9 | ## Test plan
10 |
11 |
12 |
13 | -
14 |
15 | ## Screenshots
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | - push
4 | - pull_request
5 | jobs:
6 | test:
7 | name: Node.js ${{ matrix.node-version }}
8 | runs-on: ubuntu-latest
9 | strategy:
10 | fail-fast: false
11 | matrix:
12 | node-version:
13 | - 18
14 | - 16
15 | steps:
16 | - uses: actions/checkout@v3
17 | - uses: actions/setup-node@v3
18 | with:
19 | node-version: ${{ matrix.node-version }}
20 | - run: npm install
21 | - run: npm test
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 | .pnpm-debug.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 | .env
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) Ismail Pelaseyed
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # 🧬 LangChain UI
4 |
5 | The no-code open source chat-ai toolkit built on top of [LangChain](https://github.com/hwchase17/langchain).
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | ## About the project
17 |
18 | LangChain UI enables anyone to create and host chatbots using a no-code type of inteface.
19 |
20 | Features:
21 |
22 | 👉 Create custom chatGPT like Chatbot.
23 |
24 | 👉 Give context to the chatbot using external datasources, chatGPT plugins and prompts.
25 |
26 | 👉 Dedicated API endpoint for each Chatbot.
27 |
28 | 👉 Bring your own DB
29 |
30 | 👉 Bring your own Auth provider (defaults to Github)
31 |
32 | 👉 Usage quoutas
33 |
34 | 👉 Embed Chatbots to any site or application
35 |
36 | 👉 Chatbot themes
37 |
38 | ... and more
39 |
40 | ## Roadmap
41 |
42 | - [x] Bring your own db
43 | - [x] Bring your own Auth provider
44 | - [x] Chatbots
45 | - [x] Prompt templates
46 | - [ ] API endpoints to chatbot
47 | - [ ] External datasources
48 | - [ ] chatGPT plugins
49 | - [ ] Chatbots themes
50 | - [ ] Chatbot embedding
51 |
52 | ## Stack
53 |
54 | - [Next.js](https://nextjs.org/?ref=langchain-ui)
55 | - [Chakra UI](https://chakra-ui.com/?ref=langchain-ui)
56 | - [Prisma](https://prisma.io/?ref=langchain-ui)
57 | - [NextAuth](https://next-auth.js.org/?ref=langchain-ui)
58 |
59 | LangChain UI utilizes NextJS 13 `appDir`. Read more about it [here](https://nextjs.org/blog/next-13#new-app-directory-beta)
60 |
61 | ## Getting started
62 |
63 | 1. Clone the repo into a public GitHub repository (or fork https://github.com/homanp/langchain-ui/fork). If you plan to distribute the code, keep the source code public.
64 |
65 | ```sh
66 | git clone https://github.com/homanp/langchain-ui.git
67 | ```
68 |
69 | 1. Go to the project folder
70 |
71 | ```sh
72 | cd langchain-ui
73 | ```
74 |
75 | 1. Install packages with npm
76 |
77 | ```sh
78 | npm install
79 | ```
80 |
81 | 1. Set up your .env file
82 |
83 | - Duplicate `.env.example` to `.env`
84 |
85 | 1. Run the project
86 |
87 | ```sh
88 | npm run dev
89 | ```
90 |
91 | 1. Run the linter
92 |
93 | ```sh
94 | npm run lint
95 | ```
96 |
97 | 1. Build the project
98 |
99 | ```sh
100 | npm run build
101 | ```
102 |
103 | ## Contributions
104 |
105 | Our mission is to make it easy for anyone to create and run LLM apps in the cloud. We are super happy for any contributions you would like to make. Create new features, fix bugs or improve on infra.
106 |
107 | You can read more on how to contribute [here](https://github.com/homanp/langchain-ui/blob/main/.github/CONTRIBUTING.md).
108 |
--------------------------------------------------------------------------------
/app/api/v1/chatbots/[chatbotId]/route.js:
--------------------------------------------------------------------------------
1 | import { NextResponse } from "next/server";
2 | import { ChatOpenAI } from "langchain/chat_models/openai";
3 | import { ConversationChain } from "langchain/chains";
4 | import {
5 | ChatPromptTemplate,
6 | HumanMessagePromptTemplate,
7 | SystemMessagePromptTemplate,
8 | } from "langchain/prompts";
9 | import { MessagesPlaceholder } from "langchain/prompts";
10 | import { BufferMemory, ChatMessageHistory } from "langchain/memory";
11 | import { HumanChatMessage, AIChatMessage } from "langchain/schema";
12 | import { DEFAULT_PROMPT_TEMPLATE } from "@/lib/prompt-template";
13 | import { prismaClient } from "@/lib/prisma";
14 |
15 | export const runtime = "nodejs";
16 |
17 | export const dynamic = "force-dynamic";
18 |
19 | export async function POST(request, { params }) {
20 | const { chatbotId } = params;
21 | const { message } = await request.json();
22 |
23 | let responseStream = new TransformStream();
24 | const writer = responseStream.writable.getWriter();
25 | const encoder = new TextEncoder();
26 |
27 | const [{ promptTemplateId }, messages] = await Promise.all([
28 | prismaClient.chatbot.findUnique({
29 | where: { id: parseInt(chatbotId) },
30 | }),
31 | prismaClient.chatbotMessage.findMany({
32 | where: { chatbotId: parseInt(chatbotId) },
33 | orderBy: {
34 | createdAt: "desc",
35 | },
36 | take: 5,
37 | }),
38 | ]);
39 |
40 | const promptTemplate = promptTemplateId
41 | ? await prismaClient.promptTemplate.findUnique({
42 | where: { id: promptTemplateId },
43 | })
44 | : undefined;
45 |
46 | const history = messages.map(({ agent, message }) =>
47 | agent === "ai" ? new AIChatMessage(message) : new HumanChatMessage(message)
48 | );
49 |
50 | const memory = new BufferMemory({
51 | memoryKey: "history",
52 | chatHistory: new ChatMessageHistory(history),
53 | returnMessages: true,
54 | });
55 |
56 | const llm = new ChatOpenAI({
57 | temperature: 0,
58 | streaming: true,
59 | });
60 |
61 | const prompt = ChatPromptTemplate.fromPromptMessages([
62 | SystemMessagePromptTemplate.fromTemplate(
63 | promptTemplate?.prompt || DEFAULT_PROMPT_TEMPLATE
64 | ),
65 | new MessagesPlaceholder("history"),
66 | HumanMessagePromptTemplate.fromTemplate("{message}"),
67 | ]);
68 |
69 | const chain = new ConversationChain({
70 | memory,
71 | prompt,
72 | llm,
73 | });
74 |
75 | return NextResponse.json({
76 | success: true,
77 | data: await chain.call({ message }),
78 | });
79 | }
80 |
--------------------------------------------------------------------------------
/app/app/chatbots/[chatbotId]/client-page.js:
--------------------------------------------------------------------------------
1 | "use client";
2 | import React, { useState } from "react";
3 | import PropTypes from "prop-types";
4 | import {
5 | Center,
6 | GridItem,
7 | SimpleGrid,
8 | Spinner,
9 | Stack,
10 | StackDivider,
11 | Text,
12 | } from "@chakra-ui/react";
13 | import { useAsync } from "react-use";
14 | import { getChatbotById } from "@/lib/api";
15 | import Chat from "@/components/chat";
16 | import CodeBlock from "@/components/code-block";
17 |
18 | import { API_DOCS } from "@/lib/api-docs";
19 |
20 | export default function ChatbotClientPage({ chatbotId }) {
21 | const [chatbot, setChatbot] = useState();
22 | const { loading: isLoading } = useAsync(async () => {
23 | const { data } = await getChatbotById(chatbotId);
24 |
25 | setChatbot(data);
26 | }, [chatbotId, getChatbotById]);
27 |
28 | return (
29 |
30 | {isLoading && (
31 |
32 |
33 |
34 | )}
35 | {!isLoading && (
36 |
37 |
38 |
39 |
40 |
41 | } spacing={0}>
42 |
43 | {chatbot.name}
44 |
45 |
46 |
47 |
48 | Datasources
49 |
50 | Coming soon...
51 |
52 |
53 |
54 | Plugins
55 |
56 | Coming soon...
57 |
58 |
59 |
60 | API
61 |
62 |
63 | Interact with your chatbot using the following API call
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | )}
72 |
73 | );
74 | }
75 |
76 | ChatbotClientPage.propTypes = {
77 | chatbotId: PropTypes.string,
78 | };
79 |
--------------------------------------------------------------------------------
/app/app/chatbots/[chatbotId]/loading.js:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { Center, Spinner } from "@chakra-ui/react";
3 |
4 | export default function Loading() {
5 | return (
6 |
7 |
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/app/app/chatbots/[chatbotId]/page.js:
--------------------------------------------------------------------------------
1 | import ChatbotClientPage from "./client-page";
2 |
3 | export const metadata = {
4 | title: "Chatbot",
5 | description: "Manage your chatbot",
6 | };
7 |
8 | export default async function ChatbotsPage({ params }) {
9 | const { chatbotId } = params;
10 |
11 | return ;
12 | }
13 |
--------------------------------------------------------------------------------
/app/app/chatbots/client-page.js:
--------------------------------------------------------------------------------
1 | "use client";
2 | import React, { useCallback, useState } from "react";
3 | import { useRouter } from "next/navigation";
4 | import Link from "next/link";
5 | import {
6 | Button,
7 | Center,
8 | Container,
9 | FormControl,
10 | HStack,
11 | Icon,
12 | IconButton,
13 | Input,
14 | Select,
15 | Spinner,
16 | Stack,
17 | Table,
18 | TableContainer,
19 | Tbody,
20 | Text,
21 | Tr,
22 | Td,
23 | useColorModeValue,
24 | } from "@chakra-ui/react";
25 | import { TbPlus, TbTrashX } from "react-icons/tb";
26 | import { useAsync } from "react-use";
27 | import { useForm } from "react-hook-form";
28 | import PageHeader from "@/components/page-header";
29 | import { useSidebar } from "@/lib/sidebar";
30 | import {
31 | createChatbot,
32 | getChatbots,
33 | getPrompTemplates,
34 | removeChatbotById,
35 | } from "@/lib/api";
36 |
37 | export default function ChatbotsClientPage() {
38 | const [showForm, setShowForm] = useState();
39 | const [chatbots, setChatbots] = useState([]);
40 | const [promptTemplates, setPromptTemplates] = useState([]);
41 | const buttonColorScheme = useColorModeValue("blackAlpha", "whiteAlpha");
42 | const buttonBackgroundColor = useColorModeValue("black", "white");
43 | const borderBottomColor = useColorModeValue("gray.50", "#333");
44 | const router = useRouter();
45 | const menu = useSidebar();
46 |
47 | const {
48 | formState: { errors, isSubmitting },
49 | handleSubmit,
50 | register,
51 | } = useForm();
52 |
53 | const { loading: isLoading } = useAsync(async () => {
54 | const [{ data: chatbots }, { data: promptTemplates }] = await Promise.all([
55 | getChatbots(),
56 | getPrompTemplates(),
57 | ]);
58 |
59 | setChatbots(chatbots);
60 | setPromptTemplates(promptTemplates);
61 |
62 | return;
63 | }, [getChatbots, getPrompTemplates, setChatbots]);
64 |
65 | const handleRemoveChatbot = useCallback(async (chatbotId) => {
66 | await removeChatbotById(chatbotId);
67 |
68 | setChatbots((prev) => prev.filter(({ id }) => id !== chatbotId));
69 | }, []);
70 |
71 | const onSubmit = useCallback(
72 | async (values) => {
73 | const { name, promptTemplateId } = values;
74 | const { data: chatbot } = await createChatbot({
75 | name,
76 | promptTemplateId: parseInt(promptTemplateId),
77 | });
78 |
79 | router.push(`/app/chatbots/${chatbot.id}`);
80 | },
81 | [router]
82 | );
83 |
84 | return (
85 |
86 | id === "chatbots").icon}
88 | title="Chatbots"
89 | >
90 |
91 | }
93 | colorScheme={buttonColorScheme}
94 | backgroundColor={buttonBackgroundColor}
95 | size="sm"
96 | onClick={() => setShowForm(true)}
97 | isLoading={isSubmitting}
98 | loadingText="Creating..."
99 | >
100 | New chatbot
101 |
102 |
103 |
104 | {isLoading && (
105 |
106 |
107 |
108 | )}
109 | {!isLoading && !showForm && (
110 |
111 |
112 |
113 | {chatbots.map(({ id, name }) => (
114 |
115 |
120 | {name}
121 | |
122 |
123 | }
126 | variant="ghost"
127 | onClick={() => handleRemoveChatbot(id)}
128 | />
129 | |
130 |
131 | ))}
132 |
133 |
134 |
135 | )}
136 | {showForm && (
137 |
138 |
139 |
140 |
141 | id === "chatbots").icon}
144 | />
145 | New chatbot
146 |
147 | Create a new chatbot
148 |
149 |
150 |
151 |
152 |
157 |
158 |
159 |
170 |
171 |
172 |
173 |
176 |
185 |
186 |
187 |
188 |
189 | )}
190 |
191 | );
192 | }
193 |
--------------------------------------------------------------------------------
/app/app/chatbots/loading.js:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { Center, Spinner } from "@chakra-ui/react";
3 |
4 | export default function Loading() {
5 | return (
6 |
7 |
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/app/app/chatbots/page.js:
--------------------------------------------------------------------------------
1 | import ChatbotsClientPage from "./client-page";
2 |
3 | export const metadata = {
4 | title: "Chatbots",
5 | description: "Manage your chatbots",
6 | };
7 |
8 | export default function ChatbotsPage() {
9 | return ;
10 | }
11 |
--------------------------------------------------------------------------------
/app/app/client-page.js:
--------------------------------------------------------------------------------
1 | "use client";
2 | import {
3 | Card,
4 | CardBody,
5 | CardHeader,
6 | SimpleGrid,
7 | Stack,
8 | Text,
9 | } from "@chakra-ui/react";
10 | import PageHeader from "@/components/page-header";
11 | import { useSidebar } from "@/lib/sidebar";
12 |
13 | export default function AppClientPage() {
14 | const menu = useSidebar();
15 |
16 | return (
17 |
18 | id === "home").icon}
20 | title="Home"
21 | />
22 |
23 |
24 | Connected datasources
25 |
26 | -
27 |
28 |
29 |
30 | Active chatbots
31 |
32 | -
33 |
34 |
35 |
36 | Used tokens
37 |
38 | -
39 |
40 |
41 |
42 | Estimated costs
43 |
44 | -
45 |
46 |
47 |
48 |
49 | );
50 | }
51 |
--------------------------------------------------------------------------------
/app/app/container.js:
--------------------------------------------------------------------------------
1 | "use client";
2 | import React from "react";
3 | import { Flex } from "@chakra-ui/react";
4 | import Sidebar from "./sidebar";
5 |
6 | export default function AppContainer({ children }) {
7 | return (
8 |
9 |
10 | {children}
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/app/app/layout.js:
--------------------------------------------------------------------------------
1 | import { getServerSession } from "next-auth/next";
2 | import { redirect } from "next/navigation";
3 | import { authOptions } from "pages/api/auth/[...nextauth]";
4 | import AppContainer from "./container";
5 |
6 | export const metadata = {
7 | title: "Home",
8 | description: "LangChain UI app home page",
9 | };
10 |
11 | export default async function AppLayout({ children }) {
12 | const session = await getServerSession(authOptions);
13 |
14 | if (!session) {
15 | redirect("/");
16 | }
17 |
18 | return {children};
19 | }
20 |
--------------------------------------------------------------------------------
/app/app/loading.js:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { Center, Spinner } from "@chakra-ui/react";
3 |
4 | export default function Loading() {
5 | return (
6 |
7 |
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/app/app/page.js:
--------------------------------------------------------------------------------
1 | import { Inter } from "next/font/google";
2 | import AppClientPage from "./client-page";
3 |
4 | const inter = Inter({ subsets: ["latin"] });
5 |
6 | export default function Home() {
7 | return ;
8 | }
9 |
--------------------------------------------------------------------------------
/app/app/prompt-templates/client-page.js:
--------------------------------------------------------------------------------
1 | "use client";
2 | import React, { useCallback, useState } from "react";
3 | import {
4 | Box,
5 | Button,
6 | Center,
7 | Container,
8 | FormControl,
9 | FormHelperText,
10 | HStack,
11 | Icon,
12 | IconButton,
13 | Input,
14 | Spinner,
15 | Stack,
16 | Table,
17 | TableContainer,
18 | Tag,
19 | Tbody,
20 | Textarea,
21 | Text,
22 | Tr,
23 | Td,
24 | useColorModeValue,
25 | } from "@chakra-ui/react";
26 | import { TbPlus, TbTrashX } from "react-icons/tb";
27 | import { useAsync } from "react-use";
28 | import { useForm } from "react-hook-form";
29 | import PageHeader from "@/components/page-header";
30 | import { useSidebar } from "@/lib/sidebar";
31 | import {
32 | createPromptTemplate,
33 | getPrompTemplates,
34 | getPromptVariables,
35 | removePromptTemplateById,
36 | } from "@/lib/api";
37 |
38 | export default function PromptTemplatesClientPage() {
39 | const buttonColorScheme = useColorModeValue("blackAlpha", "whiteAlpha");
40 | const buttonBackgroundColor = useColorModeValue("black", "white");
41 | const borderBottomColor = useColorModeValue("gray.50", "#333");
42 | const menu = useSidebar();
43 | const [promptTemplates, setPromptTemplates] = useState([]);
44 |
45 | const { loading: isLoading } = useAsync(async () => {
46 | const { data } = await getPrompTemplates();
47 | setPromptTemplates(data);
48 |
49 | return data;
50 | }, [getPrompTemplates, setPromptTemplates]);
51 | const [showForm, setShowForm] = useState(
52 | !isLoading && promptTemplates.length === 0
53 | );
54 |
55 | const {
56 | formState: { isSubmitting, errors },
57 | handleSubmit,
58 | register,
59 | reset,
60 | watch,
61 | } = useForm();
62 |
63 | const prompt = watch("prompt");
64 |
65 | const onSubmit = useCallback(
66 | async ({ name, prompt }) => {
67 | const payload = {
68 | name,
69 | prompt,
70 | inputs: getPromptVariables(prompt),
71 | };
72 |
73 | const { data: promptTemplate } = await createPromptTemplate(payload);
74 |
75 | setPromptTemplates((prev) => [promptTemplate, ...prev]);
76 | setShowForm();
77 | reset();
78 | },
79 | [reset, setPromptTemplates]
80 | );
81 |
82 | const handleRemovePromptTemplate = useCallback(async (promptTemplateId) => {
83 | await removePromptTemplateById(promptTemplateId);
84 |
85 | setPromptTemplates((prev) =>
86 | prev.filter(({ id }) => id !== promptTemplateId)
87 | );
88 | }, []);
89 |
90 | return (
91 |
92 | id === "prompt_templates").icon}
94 | title="Prompt templates"
95 | >
96 |
97 | }
99 | colorScheme={buttonColorScheme}
100 | backgroundColor={buttonBackgroundColor}
101 | size="sm"
102 | onClick={() => setShowForm(true)}
103 | >
104 | New template
105 |
106 |
107 |
108 | {isLoading && (
109 |
110 |
111 |
112 | )}
113 | {!isLoading && !showForm && (
114 |
115 |
116 |
117 | {promptTemplates.map(({ id, name }) => (
118 |
119 |
124 | {name}
125 | |
126 |
127 | }
130 | variant="ghost"
131 | onClick={() => handleRemovePromptTemplate(id)}
132 | />
133 | |
134 |
135 | ))}
136 |
137 |
138 |
139 | )}
140 | {showForm && (
141 |
142 |
143 |
144 |
145 | id === "prompt_templates").icon}
148 | />
149 | New prompt template
150 |
151 | Create a prompt template to use in your chat apps
152 |
153 |
154 |
155 |
156 |
161 |
162 |
163 |
169 |
175 |
176 |
183 |
192 |
193 |
194 |
195 | Type {`{{myVariable}}`} to insert
196 | variables into your template.
197 |
198 |
199 |
200 |
201 | Inputs:
202 |
203 | {getPromptVariables(prompt).map((variable) => (
204 |
205 | {variable}
206 |
207 | ))}
208 |
209 |
210 |
211 |
212 |
213 | )}
214 |
215 | );
216 | }
217 |
--------------------------------------------------------------------------------
/app/app/prompt-templates/loading.js:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { Center, Spinner } from "@chakra-ui/react";
3 |
4 | export default function Loading() {
5 | return (
6 |
7 |
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/app/app/prompt-templates/page.js:
--------------------------------------------------------------------------------
1 | import PromptTemplatesClientPage from "./client-page";
2 |
3 | export const metadata = {
4 | title: "Prompt templates",
5 | description: "Manage your prompt templates",
6 | };
7 |
8 | export default function PromptTemplatesPage() {
9 | return ;
10 | }
11 |
--------------------------------------------------------------------------------
/app/app/sidebar.js:
--------------------------------------------------------------------------------
1 | "use client";
2 | import React from "react";
3 | import PropTypes from "prop-types";
4 | import { useRouter } from "next/navigation";
5 | import { Box, Button, Icon, Stack, useColorMode } from "@chakra-ui/react";
6 | import { useSidebar } from "@/lib/sidebar";
7 | import UserMenu from "@/components/user-menu";
8 |
9 | function SidebarItem({ id, href, label, icon, ...properties }) {
10 | const router = useRouter();
11 |
12 | return (
13 | }
20 | onClick={() => router.push(href)}
21 | {...properties}
22 | >
23 | {label}
24 |
25 | );
26 | }
27 |
28 | SidebarItem.propTypes = {
29 | id: PropTypes.string,
30 | href: PropTypes.string,
31 | label: PropTypes.string,
32 | icon: PropTypes.func,
33 | };
34 |
35 | export default function Sidebar() {
36 | const menu = useSidebar();
37 | const { colorMode } = useColorMode();
38 | const isLight = colorMode === "light";
39 | const backgroundColor = isLight ? "gray.50" : "gray.900";
40 |
41 | return (
42 |
50 |
51 |
52 |
53 | {menu
54 | .filter(({ placement }) => placement === "top")
55 | .map(({ id, label, href, icon, iconDark, ...properties }) => (
56 |
64 | ))}
65 |
66 |
67 |
68 | {menu
69 | .filter(({ placement }) => placement === "bottom")
70 | .map(
71 | ({ id, label, labelDark, href, icon, iconDark, ...properties }) => (
72 |
80 | )
81 | )}
82 |
83 |
84 | );
85 | }
86 |
--------------------------------------------------------------------------------
/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JayZeeDesign/langchain-ui/5cd7a75d5c5bded9134bddaff9029fc1a0b01d3c/app/favicon.ico
--------------------------------------------------------------------------------
/app/landing-page.js:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { Inter } from "next/font/google";
3 | import {
4 | Button,
5 | Container,
6 | Flex,
7 | Heading,
8 | HStack,
9 | Icon,
10 | Link,
11 | Stack,
12 | Text,
13 | useColorModeValue,
14 | } from "@chakra-ui/react";
15 | import { TbBrandGithub, TbLink } from "react-icons/tb";
16 | import { signIn } from "next-auth/react";
17 |
18 | const inter = Inter({ subsets: ["latin"] });
19 |
20 | export default function LandingPage() {
21 | const backgroundColor = useColorModeValue("#131416", "#131416");
22 | const buttonColorScheme = useColorModeValue("blackAlpha", "whiteAlpha");
23 | const buttonBackgroundColor = useColorModeValue("black", "white");
24 | const fontColor = useColorModeValue("white", "white");
25 |
26 | return (
27 |
32 |
33 |
34 |
35 | LangChain
36 |
41 | UI
42 |
43 |
44 |
45 |
49 | Github
50 |
51 |
55 | Contribute
56 |
57 |
61 | Docs
62 |
63 |
64 |
65 |
71 |
77 | The open source{" "}
78 |
82 | chat-ai toolkit
83 |
84 |
85 |
86 | }
88 | colorScheme={buttonColorScheme}
89 | backgroundColor={buttonBackgroundColor}
90 | size="sm"
91 | onClick={() => signIn("github", { callbackUrl: "/app" })}
92 | >
93 | Sign in with Github
94 |
95 |
96 |
97 |
103 | Contribute on Github
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 | );
114 | }
115 |
--------------------------------------------------------------------------------
/app/layout.js:
--------------------------------------------------------------------------------
1 | import { Inter } from "next/font/google";
2 | import { Analytics } from "@vercel/analytics/react";
3 | import Providers from "./providers";
4 |
5 | const inter = Inter({ subsets: ["latin"] });
6 |
7 | export const metadata = {
8 | title: "LangChain UI",
9 | description: "The opensource Chat AI toolkit",
10 | };
11 |
12 | export default function RootLayout({ children }) {
13 | return (
14 |
15 |
16 | {children}
17 |
18 |
19 |
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/app/loading.js:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { Center, Spinner } from "@chakra-ui/react";
3 |
4 | export default function Loading() {
5 | return (
6 |
7 |
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/app/page.js:
--------------------------------------------------------------------------------
1 | import LandingPage from "./landing-page";
2 |
3 | export default function Home() {
4 | return ;
5 | }
6 |
--------------------------------------------------------------------------------
/app/providers.js:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { CacheProvider } from "@chakra-ui/next-js";
3 | import { ChakraProvider } from "@chakra-ui/react";
4 | import { SessionProvider } from "next-auth/react";
5 | import theme from "@/lib/theme";
6 |
7 | export default function Providers({ children }) {
8 | return (
9 |
10 |
11 | {children}
12 |
13 |
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/app/user/login/login.js:
--------------------------------------------------------------------------------
1 | "use client";
2 | import React from "react";
3 | import {
4 | Button,
5 | Center,
6 | Container,
7 | Flex,
8 | Icon,
9 | Stack,
10 | Text,
11 | } from "@chakra-ui/react";
12 | import { signIn } from "next-auth/react";
13 | import { TbBrandGithub } from "react-icons/tb";
14 |
15 | export default function Login() {
16 | return (
17 |
18 |
19 |
20 |
21 |
22 | LangChain UI
23 |
24 |
25 | }
29 | onClick={() => signIn("github", { callbackUrl: "/app" })}
30 | >
31 | Login with Github
32 |
33 |
34 |
35 |
36 |
37 |
38 | );
39 | }
40 |
--------------------------------------------------------------------------------
/app/user/login/page.js:
--------------------------------------------------------------------------------
1 | import Login from "./login";
2 |
3 | export const metadata = {
4 | title: "Login - LangChain UI",
5 | description: "Login to your account",
6 | };
7 |
8 | export default function LoginPage() {
9 | return ;
10 | }
11 |
--------------------------------------------------------------------------------
/components/chat/index.js:
--------------------------------------------------------------------------------
1 | import React, { useCallback, useState } from "react";
2 | import PropTypes from "prop-types";
3 | import { Stack } from "@chakra-ui/react";
4 | import { fetchEventSource } from "@microsoft/fetch-event-source";
5 | import ChatInput from "./input";
6 | import ChatOuput from "./output";
7 | import { createChatbotMessage, sendChatMessage } from "@/lib/api";
8 |
9 | export default function Chat({ id, ...properties }) {
10 | const [messages, setMessages] = useState([]);
11 | const [isSendingMessage, setIsSendingMessage] = useState();
12 |
13 | const onSubmit = useCallback(
14 | async (values) => {
15 | setIsSendingMessage(true);
16 | setMessages((previousMessages) => [
17 | ...previousMessages,
18 | { data: { response: values } },
19 | ]);
20 |
21 | await createChatbotMessage(id, {
22 | message: values,
23 | agent: "user",
24 | });
25 |
26 | const response = await sendChatMessage({
27 | id,
28 | message: values,
29 | });
30 |
31 | createChatbotMessage(id, {
32 | message: response.data.response,
33 | agent: "ai",
34 | });
35 |
36 | setMessages((previousMessages) => [...previousMessages, response]);
37 |
38 | setIsSendingMessage();
39 | },
40 | [id]
41 | );
42 |
43 | return (
44 |
51 |
57 |
65 |
66 | );
67 | }
68 |
69 | Chat.propTypes = {
70 | id: PropTypes.string,
71 | };
72 |
--------------------------------------------------------------------------------
/components/chat/input.js:
--------------------------------------------------------------------------------
1 | import React, { useCallback, useEffect, useRef, useState } from "react";
2 | import PropTypes from "prop-types";
3 | import {
4 | Box,
5 | Container,
6 | HStack,
7 | Icon,
8 | IconButton,
9 | Stack,
10 | Textarea,
11 | useColorModeValue,
12 | } from "@chakra-ui/react";
13 | import { TbSend } from "react-icons/tb";
14 | import autosize from "autosize";
15 | import { BeatLoader } from "react-spinners";
16 |
17 | export default function ChatInput({ isLoading, onSubmit, ...properties }) {
18 | const backgroundColor = useColorModeValue("gray.100", "gray.600");
19 | const backgroundGradient = useColorModeValue(
20 | "linear(to-t, white, transparent)",
21 | "linear(to-t, gray.800, transparent)"
22 | );
23 | const loaderColor = useColorModeValue("gray.100", "white");
24 | const iconColor = useColorModeValue("gray.500", "white");
25 | const [message, setMessage] = useState();
26 | const textareaReference = useRef();
27 |
28 | const handleKeyDown = useCallback(
29 | (event) => {
30 | if (event.keyCode === 13 && !event.shiftKey) {
31 | event.preventDefault();
32 |
33 | onSubmit(message);
34 | setMessage("");
35 |
36 | autosize.destroy(textareaReference?.current);
37 | }
38 | },
39 | [message, onSubmit]
40 | );
41 |
42 | useEffect(() => {
43 | const ref = textareaReference?.current;
44 |
45 | autosize(ref);
46 |
47 | return () => {
48 | autosize.destroy(ref);
49 | };
50 | }, []);
51 |
52 | return (
53 |
54 |
55 |
62 |
95 |
96 |
97 | );
98 | }
99 |
100 | ChatInput.propTypes = {
101 | isLoading: PropTypes.bool,
102 | onSubmit: PropTypes.func,
103 | };
104 |
--------------------------------------------------------------------------------
/components/chat/output.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef } from "react";
2 | import {
3 | Avatar,
4 | Box,
5 | HStack,
6 | Icon,
7 | IconButton,
8 | Stack,
9 | useColorModeValue,
10 | } from "@chakra-ui/react";
11 | import ReactMarkdown from "react-markdown";
12 | import remarkGfm from "remark-gfm";
13 | import PropTypes from "prop-types";
14 | import { BeatLoader } from "react-spinners";
15 | import SyntaxHighlighter from "react-syntax-highlighter";
16 | import { dracula } from "react-syntax-highlighter/dist/esm/styles/prism";
17 | import { TbCopy } from "react-icons/tb";
18 |
19 | export default function ChatOuput({ messages, isLoading, ...properties }) {
20 | const loaderColor = useColorModeValue("gray.100", "white");
21 | const unevenBackgroundColor = useColorModeValue("gray.100", "gray.600");
22 | const lastMessageReference = useRef();
23 |
24 | useEffect(() => {
25 | if (lastMessageReference?.current) {
26 | lastMessageReference?.current.scrollIntoView();
27 | }
28 | }, [messages]);
29 |
30 | return (
31 |
32 |
33 | {messages.map(({ agent, data: { response } }, index) => (
34 |
42 |
48 |
49 |
50 | {
53 | const codeChunk = pre.node.children[0].children[0].value;
54 |
55 | const handleCopyCode = () => {
56 | navigator.clipboard.writeText(codeChunk);
57 | };
58 |
59 | return (
60 |
61 | }
67 | onClick={() => handleCopyCode()}
68 | />
69 |
70 | {pre.children[0].props.children[0]}
71 |
72 |
73 | );
74 | },
75 | }}
76 | remarkPlugins={[remarkGfm]}
77 | >
78 | {response}
79 |
80 |
81 |
82 |
83 | ))}
84 | {isLoading && (
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | )}
94 |
95 |
96 | );
97 | }
98 |
99 | ChatOuput.propTypes = {
100 | messages: PropTypes.array,
101 | isLoading: PropTypes.bool,
102 | };
103 |
--------------------------------------------------------------------------------
/components/chat/prompt-templates.js:
--------------------------------------------------------------------------------
1 | import React, { useCallback } from "react";
2 | import PropTypes from "prop-types";
3 | import { useRouter } from "next/navigation";
4 | import {
5 | Button,
6 | Center,
7 | HStack,
8 | Popover,
9 | PopoverTrigger,
10 | PopoverContent,
11 | PopoverHeader,
12 | PopoverBody,
13 | PopoverCloseButton,
14 | Spinner,
15 | Stack,
16 | Text,
17 | useColorModeValue,
18 | Icon,
19 | useDisclosure,
20 | } from "@chakra-ui/react";
21 | import { useAsync, useAsyncFn } from "react-use";
22 | import { getPrompTemplates, updateChatbotById } from "@/lib/api";
23 | import { TbChevronDown } from "react-icons/tb";
24 |
25 | export default function AssignPromptTemplate({ chatbot, onChange }) {
26 | const popoverBackgroundColor = useColorModeValue("white", "#2F3239");
27 | const { isOpen, onToggle, onClose } = useDisclosure();
28 | const { loading: isLoading, value: promptTemplates = [] } =
29 | useAsync(async () => {
30 | const { data } = await getPrompTemplates();
31 |
32 | return data;
33 | }, []);
34 |
35 | const [{ loading: isSelectingPromptTemplate }, handleSelect] = useAsyncFn(
36 | async (promptTemplateId) => {
37 | onToggle();
38 | const { id, chatbotData } = chatbot;
39 | const { data } = await updateChatbotById(id, {
40 | ...chatbotData,
41 | promptTemplateId: promptTemplateId || null,
42 | });
43 |
44 | onChange(data);
45 | },
46 | [onChange, onToggle, updateChatbotById]
47 | );
48 |
49 | return (
50 |
51 |
52 | Prompt templates
53 |
54 |
55 |
56 | }
62 | >
63 | {promptTemplates.find(({ id }) => id === chatbot.promptTemplateId)
64 | ?.name || "Select template"}
65 |
66 |
67 |
72 |
73 |
74 | Prompt templates
75 |
76 |
82 |
83 | {isLoading && (
84 |
85 |
86 |
87 | )}
88 |
97 | {!isLoading &&
98 | promptTemplates.map(({ id, name }) => (
99 |
109 | ))}
110 |
111 |
112 |
113 |
114 |
115 | );
116 | }
117 |
118 | AssignPromptTemplate.propTypes = {
119 | chatbot: PropTypes.object,
120 | onChange: PropTypes.func,
121 | };
122 |
--------------------------------------------------------------------------------
/components/code-block.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import PropTypes from "prop-types";
3 | import { Box, Button, HStack, Stack, StackDivider } from "@chakra-ui/react";
4 | import CodeMirror from "@uiw/react-codemirror";
5 | import { markdown, markdownLanguage } from "@codemirror/lang-markdown";
6 | import { languages } from "@codemirror/language-data";
7 | import { xcodeDark } from "@uiw/codemirror-theme-xcode";
8 |
9 | export default function CodeBlock({ items }) {
10 | const [item, setItem] = useState(items[0].id);
11 |
12 | return (
13 | }
18 | spacing={0}
19 | >
20 |
21 | {items.map(({ id, label }) => (
22 |
31 | ))}
32 |
33 |
34 | id === item).code}
41 | />
42 |
43 |
44 | );
45 | }
46 |
--------------------------------------------------------------------------------
/components/page-header.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import { HStack, Icon, Stack, Text } from "@chakra-ui/react";
4 |
5 | export default function PageHeader({ title, children, icon, ...properties }) {
6 | return (
7 |
8 |
9 |
10 |
11 | {title}
12 |
13 |
14 | {children}
15 |
16 | );
17 | }
18 |
19 | PageHeader.propTypes = {
20 | title: PropTypes.string,
21 | icon: PropTypes.func,
22 | children: PropTypes.node,
23 | };
24 |
--------------------------------------------------------------------------------
/components/user-menu.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Avatar, Divider, HStack, Stack, Text } from "@chakra-ui/react";
3 | import { useSession } from "next-auth/react";
4 |
5 | export default function UserMenu({ ...properties }) {
6 | const { data: session, status } = useSession();
7 |
8 | return (
9 |
10 |
11 |
12 |
13 |
14 | {session?.user.name}
15 |
16 |
17 | {session?.user.email}
18 |
19 |
20 |
21 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "paths": {
4 | "@/*": ["./*"]
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/lib/api-docs.js:
--------------------------------------------------------------------------------
1 | const cURL = `\`\`\`bash
2 | # cURL request to chatbot API endpoint.
3 | curl -X POST https://langchain-ui.vercel.app/api/v1/chatbot/{{id}}
4 | -H "Content-Type: application/json"
5 | -H "Authorization: Bearer {token}"
6 | -d '{"message": "Hello!"}'
7 | \`\`\``;
8 |
9 | const javascript = `\`\`\`jsx
10 | # Javascript request to chatbot API endpoint.
11 | const requestOptions = {
12 | method: 'POST',
13 | headers: {
14 | 'Content-Type': 'application/json'
15 | 'Authorization': 'Bearer {token}'
16 | },
17 | body: JSON.stringify({ message: 'Hello!' })
18 | };
19 |
20 | const response = await fetch(
21 | 'https://langchain-ui.vercel.app/api/v1/chatbot/{{id}}',
22 | requestOptions
23 | );
24 | const data = await response.json();
25 | \`\`\``;
26 |
27 | const python = `\`\`\`python
28 | # Python request to chatbot API endpoint using the requests library.
29 | import requests
30 |
31 | url = 'https://langchain-ui.vercel.app/api/v1/chatbot/{{id}}'
32 | headers = {'Authorization': 'Bearer {token}'}
33 | payload = {'messsage': 'Hello!'}
34 |
35 | response = requests.post(url, data = payload, headers = headers)
36 |
37 | print(response.text)
38 | \`\`\``;
39 |
40 | const php = `\`\`\`php
41 | # PHP request to chatbot API endpoint.
42 | "Hello!"
46 | );
47 |
48 | $headers = array(
49 | "Content-Type: application/json",
50 | "Authorization: Bearer {TOKEN}"
51 | );
52 |
53 | $ch = curl_init();
54 | curl_setopt($ch, CURLOPT_URL, $url);
55 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
56 | curl_setopt($ch, CURLOPT_POST, true);
57 | curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
58 | curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
59 |
60 | $response = curl_exec($ch);
61 | curl_close($ch);
62 |
63 | echo $response;
64 | ?>
65 | \`\`\``;
66 |
67 | export const API_DOCS = [
68 | {
69 | id: "curl",
70 | label: "cURL",
71 | code: cURL,
72 | },
73 | {
74 | id: "javascript",
75 | label: "Javascript",
76 | code: javascript,
77 | },
78 | {
79 | id: "python",
80 | label: "Python",
81 | code: python,
82 | },
83 | {
84 | id: "php",
85 | label: "PHP",
86 | code: php,
87 | },
88 | ];
89 |
--------------------------------------------------------------------------------
/lib/api.js:
--------------------------------------------------------------------------------
1 | import ky from "ky";
2 |
3 | export const createChatbot = (data) =>
4 | ky.post("/api/chatbots", { json: data }).json();
5 |
6 | export const createChatbotMessage = async (id, data) =>
7 | ky
8 | .post(`/api/chatbots/${id}/messages`, {
9 | json: { ...data },
10 | timeout: 60000,
11 | })
12 | .json();
13 |
14 | export const createPromptTemplate = (data) =>
15 | ky.post("/api/prompt-templates", { json: data }).json();
16 |
17 | export const getChatbotById = async (id) =>
18 | ky.get(`/api/chatbots/${id}`).json();
19 |
20 | export const getChatbots = async () => ky.get("/api/chatbots").json();
21 |
22 | export const getPromptVariables = (string) => {
23 | let variables = [];
24 | let regex = /{{(.*?)}}/g;
25 | let match;
26 |
27 | while ((match = regex.exec(string))) {
28 | variables.push(match[1].trim());
29 | }
30 |
31 | return variables;
32 | };
33 |
34 | export const getPrompTemplates = async () =>
35 | ky.get("/api/prompt-templates").json();
36 |
37 | export const removePromptTemplateById = async (id) =>
38 | ky.delete(`/api/prompt-templates/${id}`).json();
39 | export const removeChatbotById = async (id) =>
40 | ky.delete(`/api/chatbots/${id}`).json();
41 |
42 | export const sendChatMessage = async ({ id, message, history }) =>
43 | ky
44 | .post(`/api/v1/chatbots/${id}`, {
45 | json: { message, history },
46 | timeout: 60000,
47 | })
48 | .json();
49 |
50 | export const updateChatbotById = async (id, data) =>
51 | ky
52 | .patch(`/api/chatbots/${id}`, {
53 | json: { ...data },
54 | })
55 | .json();
56 |
--------------------------------------------------------------------------------
/lib/chain.js:
--------------------------------------------------------------------------------
1 | import { ChatOpenAI } from "langchain/chat_models";
2 | import { ConversationChain } from "langchain/chains";
3 | import { CallbackManager } from "langchain/callbacks";
4 | import {
5 | ChatPromptTemplate,
6 | HumanMessagePromptTemplate,
7 | SystemMessagePromptTemplate,
8 | } from "langchain/prompts";
9 | import { DEFAULT_PROMPT_TEMPLATE } from "@/lib/prompt-template";
10 |
11 | export const makeChain = ({ onTokenStream = () => {} }) => {
12 | const llm = new ChatOpenAI({
13 | temperature: 0,
14 | streaming: true,
15 | callbackManager: CallbackManager.fromHandlers({
16 | handleLLMNewToken(token) {
17 | onTokenStream(token);
18 | },
19 | }),
20 | });
21 |
22 | const prompt = ChatPromptTemplate.fromPromptMessages([
23 | SystemMessagePromptTemplate.fromTemplate(DEFAULT_PROMPT_TEMPLATE),
24 | HumanMessagePromptTemplate.fromTemplate("{message}"),
25 | ]);
26 |
27 | return new ConversationChain({
28 | prompt,
29 | llm,
30 | });
31 | };
32 |
--------------------------------------------------------------------------------
/lib/prisma.js:
--------------------------------------------------------------------------------
1 | import { PrismaClient } from "@prisma/client";
2 |
3 | export const prismaClient = new PrismaClient();
4 |
--------------------------------------------------------------------------------
/lib/prompt-template.js:
--------------------------------------------------------------------------------
1 | export const DEFAULT_PROMPT_TEMPLATE = `
2 | Assistant is a large language model trained by OpenAI.
3 |
4 | Assistant is designed to be able to assist with a wide range of tasks, from answering simple questions to providing in-depth explanations and discussions on a wide range of topics. As a language model, Assistant is able to generate human-like text based on the input it receives, allowing it to engage in natural-sounding conversations and provide responses that are coherent and relevant to the topic at hand.
5 |
6 | Assistant is constantly learning and improving, and its capabilities are constantly evolving. It is able to process and understand large amounts of text, and can use this knowledge to provide accurate and informative responses to a wide range of questions. Additionally, Assistant is able to generate its own text based on the input it receives, allowing it to engage in discussions and provide explanations and descriptions on a wide range of topics.
7 |
8 | Overall, Assistant is a powerful tool that can help with a wide range of tasks and provide valuable insights and information on a wide range of topics. Whether you need help with a specific question or just want to have a conversation about a particular topic, Assistant is here to assist.
9 |
10 | {history}
11 |
12 | Human: {message}
13 | Assitant:
14 | `;
15 |
--------------------------------------------------------------------------------
/lib/sidebar.js:
--------------------------------------------------------------------------------
1 | import { signOut } from "next-auth/react";
2 | import { useColorMode } from "@chakra-ui/react";
3 | import {
4 | TbDatabase,
5 | TbLogout,
6 | TbMessage,
7 | TbPrompt,
8 | TbSettings,
9 | TbMoon,
10 | TbSun,
11 | TbHome,
12 | } from "react-icons/tb";
13 |
14 | const PLACEMENT = {
15 | top: "top",
16 | bottom: "bottom",
17 | };
18 |
19 | export const useSidebar = () => {
20 | const { toggleColorMode } = useColorMode();
21 |
22 | return [
23 | {
24 | id: "home",
25 | label: "Home",
26 | href: "/app",
27 | icon: TbHome,
28 | placement: PLACEMENT.top,
29 | },
30 | {
31 | id: "datasources",
32 | label: "Datasources",
33 | href: "/app/datasources",
34 | icon: TbDatabase,
35 | placement: PLACEMENT.top,
36 | },
37 | {
38 | id: "prompt_templates",
39 | label: "Prompt templates",
40 | href: "/app/prompt-templates",
41 | icon: TbPrompt,
42 | placement: PLACEMENT.top,
43 | },
44 | {
45 | id: "chatbots",
46 | label: "Chatbots",
47 | href: "/app/chatbots",
48 | icon: TbMessage,
49 | placement: PLACEMENT.top,
50 | },
51 | {
52 | id: "dark_mode",
53 | label: "Dark",
54 | labelDark: "Light",
55 | onClick: () => toggleColorMode(),
56 | icon: TbMoon,
57 | iconDark: TbSun,
58 | placement: PLACEMENT.bottom,
59 | },
60 | {
61 | id: "settings",
62 | label: "Settings",
63 | href: "/app/settings",
64 | icon: TbSettings,
65 | placement: PLACEMENT.bottom,
66 | },
67 | {
68 | id: "singout",
69 | label: "Sign out",
70 | onClick: () => signOut(),
71 | icon: TbLogout,
72 | placement: PLACEMENT.bottom,
73 | },
74 | ];
75 | };
76 |
--------------------------------------------------------------------------------
/lib/theme.js:
--------------------------------------------------------------------------------
1 | import { mode } from "@chakra-ui/theme-tools";
2 | import { extendTheme } from "@chakra-ui/react";
3 |
4 | const theme = extendTheme({
5 | config: {
6 | initialColorMode: "dark",
7 | },
8 | fonts: {
9 | heading: "Inter, sans-serif",
10 | body: "Inter, sans-serif",
11 | },
12 | });
13 |
14 | export default theme;
15 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | experimental: {
4 | appDir: true,
5 | },
6 | }
7 |
8 | module.exports = nextConfig
9 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "langchain-ui",
3 | "version": "0.0.1",
4 | "engines": {
5 | "node": ">=18"
6 | },
7 | "private": true,
8 | "scripts": {
9 | "dev": "next dev",
10 | "build": "next build",
11 | "start": "next start",
12 | "lint": "next lint",
13 | "test": "next lint"
14 | },
15 | "dependencies": {
16 | "@chakra-ui/next-js": "^2.0.1",
17 | "@chakra-ui/react": "^2.5.2",
18 | "@chakra-ui/theme-tools": "^2.0.17",
19 | "@codemirror/lang-json": "^6.0.1",
20 | "@codemirror/lang-markdown": "^6.1.0",
21 | "@codemirror/language-data": "^6.2.0",
22 | "@dqbd/tiktoken": "^1.0.2",
23 | "@emotion/react": "^11.10.6",
24 | "@emotion/styled": "^11.10.6",
25 | "@microsoft/fetch-event-source": "^2.0.1",
26 | "@next-auth/prisma-adapter": "^1.0.5",
27 | "@prisma/client": "^4.11.0",
28 | "@uiw/codemirror-theme-xcode": "^4.19.11",
29 | "@uiw/react-codemirror": "^4.19.11",
30 | "@vercel/analytics": "^0.1.11",
31 | "autosize": "^6.0.1",
32 | "eslint": "8.36.0",
33 | "eslint-config-next": "13.2.4",
34 | "framer-motion": "^10.8.5",
35 | "install": "^0.13.0",
36 | "ky": "^0.33.3",
37 | "langchain": "^0.0.52",
38 | "next": "^13.3.0",
39 | "next-auth": "^4.20.1",
40 | "npm": "^9.6.3",
41 | "react": "18.2.0",
42 | "react-dom": "18.2.0",
43 | "react-hook-form": "^7.43.7",
44 | "react-icons": "^4.8.0",
45 | "react-markdown": "^8.0.6",
46 | "react-spinners": "^0.13.8",
47 | "react-syntax-highlighter": "^15.5.0",
48 | "react-use": "^17.4.0",
49 | "remark-gfm": "^3.0.1",
50 | "typeorm": "^0.3.12"
51 | },
52 | "devDependencies": {
53 | "prisma": "^4.11.0"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/pages/api/auth/[...nextauth].js:
--------------------------------------------------------------------------------
1 | import NextAuth from "next-auth";
2 | import GithubProvider from "next-auth/providers/github";
3 | import { PrismaAdapter } from "@next-auth/prisma-adapter";
4 | import { prismaClient } from "@/lib/prisma";
5 |
6 | export const authOptions = {
7 | adapter: PrismaAdapter(prismaClient),
8 | providers: [
9 | GithubProvider({
10 | clientId: process.env.NEXT_PUBLIC_GITHUB_ID,
11 | clientSecret: process.env.NEXT_PUBLIC_GITHUB_SECRET,
12 | }),
13 | ],
14 | pages: {
15 | signIn: "/",
16 | signOut: "/user/logout",
17 | },
18 | };
19 |
20 | export default NextAuth(authOptions);
21 |
--------------------------------------------------------------------------------
/pages/api/chatbots/[chatbotId]/index.js:
--------------------------------------------------------------------------------
1 | import { getServerSession } from "next-auth/next";
2 | import { authOptions } from "../../auth/[...nextauth]";
3 | import { prismaClient } from "@/lib/prisma";
4 |
5 | const chatbotHandler = async (request, response) => {
6 | const session = await getServerSession(request, response, authOptions);
7 | const { chatbotId } = request.query;
8 |
9 | if (!session) {
10 | return response
11 | .status(403)
12 | .json({ success: false, error: "Not authenticated" });
13 | }
14 |
15 | if (request.method === "DELETE") {
16 | const data = await prismaClient.chatbot.delete({
17 | where: {
18 | id: parseInt(chatbotId),
19 | },
20 | });
21 |
22 | return response.status(200).json({
23 | success: true,
24 | data,
25 | });
26 | }
27 |
28 | if (request.method === "GET") {
29 | const data = await prismaClient.chatbot.findUnique({
30 | where: {
31 | id: parseInt(chatbotId),
32 | },
33 | });
34 |
35 | return response.status(200).json({
36 | success: true,
37 | data,
38 | });
39 | }
40 |
41 | if (request.method === "PATCH") {
42 | const data = await prismaClient.chatbot.update({
43 | where: {
44 | id: parseInt(chatbotId),
45 | },
46 | data: { ...request.body },
47 | });
48 |
49 | return response.status(200).json({
50 | success: true,
51 | data,
52 | });
53 | }
54 | };
55 |
56 | export default chatbotHandler;
57 |
--------------------------------------------------------------------------------
/pages/api/chatbots/[chatbotId]/messages/index.js:
--------------------------------------------------------------------------------
1 | import { prismaClient } from "@/lib/prisma";
2 |
3 | export const chatbotMessagesHandler = async (request, response) => {
4 | const { chatbotId } = request.query;
5 |
6 | if (request.method === "POST") {
7 | const message = await prismaClient.chatbotMessage.create({
8 | data: {
9 | chatbotId: parseInt(chatbotId),
10 | ...request.body,
11 | },
12 | });
13 |
14 | return response.status(200).json({ sucess: true, data: message });
15 | }
16 | };
17 |
18 | export default chatbotMessagesHandler;
19 |
--------------------------------------------------------------------------------
/pages/api/chatbots/index.js:
--------------------------------------------------------------------------------
1 | import { getServerSession } from "next-auth/next";
2 | import { authOptions } from "../auth/[...nextauth]";
3 | import { prismaClient } from "@/lib/prisma";
4 |
5 | const chatbotsHandler = async (request, response) => {
6 | const session = await getServerSession(request, response, authOptions);
7 | const user = await prismaClient.user.findUnique({
8 | where: { email: session.user.email },
9 | });
10 |
11 | if (request.method === "GET") {
12 | const data = await prismaClient.chatbot.findMany({
13 | where: {
14 | userId: {
15 | equals: user.id,
16 | },
17 | },
18 | orderBy: {
19 | createdAt: "desc",
20 | },
21 | });
22 |
23 | return response.status(200).json({
24 | success: true,
25 | data,
26 | });
27 | }
28 |
29 | if (request.method === "POST") {
30 | const chatbot = await prismaClient.chatbot.create({
31 | data: {
32 | userId: user.id,
33 | ...request.body,
34 | },
35 | });
36 |
37 | return response.status(200).json({ sucess: true, data: chatbot });
38 | }
39 | };
40 |
41 | export default chatbotsHandler;
42 |
--------------------------------------------------------------------------------
/pages/api/prompt-templates/[promptId]/index.js:
--------------------------------------------------------------------------------
1 | import { getServerSession } from "next-auth/next";
2 | import { authOptions } from "../../auth/[...nextauth]";
3 | import { prismaClient } from "@/lib/prisma";
4 |
5 | const promptTemplateHandler = async (request, response) => {
6 | const session = await getServerSession(request, response, authOptions);
7 | const { promptId } = request.query;
8 |
9 | if (!session) {
10 | return response
11 | .status(403)
12 | .json({ success: false, error: "Not authenticated" });
13 | }
14 |
15 | if (request.method === "DELETE") {
16 | const data = await prismaClient.promptTemplate.delete({
17 | where: {
18 | id: parseInt(promptId),
19 | },
20 | });
21 |
22 | return response.status(200).json({
23 | success: true,
24 | data,
25 | });
26 | }
27 |
28 | if (request.method === "PATCH") {
29 | const data = await prismaClient.promptTemplate.update({
30 | where: {
31 | id: parseInt(promptId),
32 | },
33 | data: { ...request.body },
34 | });
35 |
36 | return response.status(200).json({
37 | success: true,
38 | data,
39 | });
40 | }
41 | };
42 |
43 | export default promptTemplateHandler;
44 |
--------------------------------------------------------------------------------
/pages/api/prompt-templates/index.js:
--------------------------------------------------------------------------------
1 | import { getServerSession } from "next-auth/next";
2 | import { authOptions } from "../auth/[...nextauth]";
3 | import { prismaClient } from "@/lib/prisma";
4 |
5 | const promptTemplatesHandler = async (request, response) => {
6 | const session = await getServerSession(request, response, authOptions);
7 | const user = await prismaClient.user.findUnique({
8 | where: { email: session.user.email },
9 | });
10 |
11 | if (request.method === "GET") {
12 | const data = await prismaClient.promptTemplate.findMany({
13 | where: {
14 | userId: {
15 | equals: user.id,
16 | },
17 | },
18 | orderBy: {
19 | createdAt: "desc",
20 | },
21 | });
22 |
23 | return response.status(200).json({
24 | success: true,
25 | data,
26 | });
27 | }
28 |
29 | if (request.method === "POST") {
30 | const promptTemplate = await prismaClient.promptTemplate.create({
31 | data: {
32 | userId: user.id,
33 | ...request.body,
34 | },
35 | });
36 |
37 | return response.status(200).json({ sucess: true, data: promptTemplate });
38 | }
39 | };
40 |
41 | export default promptTemplatesHandler;
42 |
--------------------------------------------------------------------------------
/prisma/migrations/20230327164641_user_defaults/migration.sql:
--------------------------------------------------------------------------------
1 | -- CreateTable
2 | CREATE TABLE "Account" (
3 | "id" TEXT NOT NULL,
4 | "userId" TEXT NOT NULL,
5 | "type" TEXT NOT NULL,
6 | "provider" TEXT NOT NULL,
7 | "providerAccountId" TEXT NOT NULL,
8 | "refresh_token" TEXT,
9 | "access_token" TEXT,
10 | "expires_at" INTEGER,
11 | "token_type" TEXT,
12 | "scope" TEXT,
13 | "id_token" TEXT,
14 | "session_state" TEXT,
15 |
16 | CONSTRAINT "Account_pkey" PRIMARY KEY ("id")
17 | );
18 |
19 | -- CreateTable
20 | CREATE TABLE "Session" (
21 | "id" TEXT NOT NULL,
22 | "sessionToken" TEXT NOT NULL,
23 | "userId" TEXT NOT NULL,
24 | "expires" TIMESTAMP(3) NOT NULL,
25 |
26 | CONSTRAINT "Session_pkey" PRIMARY KEY ("id")
27 | );
28 |
29 | -- CreateTable
30 | CREATE TABLE "User" (
31 | "id" TEXT NOT NULL,
32 | "name" TEXT,
33 | "email" TEXT,
34 | "emailVerified" TIMESTAMP(3),
35 | "image" TEXT,
36 |
37 | CONSTRAINT "User_pkey" PRIMARY KEY ("id")
38 | );
39 |
40 | -- CreateTable
41 | CREATE TABLE "VerificationToken" (
42 | "identifier" TEXT NOT NULL,
43 | "token" TEXT NOT NULL,
44 | "expires" TIMESTAMP(3) NOT NULL
45 | );
46 |
47 | -- CreateIndex
48 | CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId");
49 |
50 | -- CreateIndex
51 | CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken");
52 |
53 | -- CreateIndex
54 | CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
55 |
56 | -- CreateIndex
57 | CREATE UNIQUE INDEX "VerificationToken_token_key" ON "VerificationToken"("token");
58 |
59 | -- CreateIndex
60 | CREATE UNIQUE INDEX "VerificationToken_identifier_token_key" ON "VerificationToken"("identifier", "token");
61 |
62 | -- AddForeignKey
63 | ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
64 |
65 | -- AddForeignKey
66 | ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
67 |
--------------------------------------------------------------------------------
/prisma/migrations/20230327201911_prompt_templates/migration.sql:
--------------------------------------------------------------------------------
1 | -- CreateTable
2 | CREATE TABLE "PromptTemplate" (
3 | "id" SERIAL NOT NULL,
4 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
5 | "updatedAt" TIMESTAMP(3) NOT NULL,
6 | "prompt" TEXT NOT NULL,
7 | "userId" TEXT NOT NULL,
8 | "inputs" JSONB NOT NULL,
9 | "name" TEXT NOT NULL,
10 |
11 | CONSTRAINT "PromptTemplate_pkey" PRIMARY KEY ("id")
12 | );
13 |
14 | -- AddForeignKey
15 | ALTER TABLE "PromptTemplate" ADD CONSTRAINT "PromptTemplate_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
16 |
--------------------------------------------------------------------------------
/prisma/migrations/20230329205257_chatbots/migration.sql:
--------------------------------------------------------------------------------
1 | -- CreateTable
2 | CREATE TABLE "Chatbot" (
3 | "id" SERIAL NOT NULL,
4 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
5 | "updatedAt" TIMESTAMP(3) NOT NULL,
6 | "userId" TEXT NOT NULL,
7 | "promtTemplateId" INTEGER,
8 | "name" TEXT NOT NULL,
9 |
10 | CONSTRAINT "Chatbot_pkey" PRIMARY KEY ("id")
11 | );
12 |
13 | -- AddForeignKey
14 | ALTER TABLE "Chatbot" ADD CONSTRAINT "Chatbot_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
15 |
16 | -- AddForeignKey
17 | ALTER TABLE "Chatbot" ADD CONSTRAINT "Chatbot_promtTemplateId_fkey" FOREIGN KEY ("promtTemplateId") REFERENCES "PromptTemplate"("id") ON DELETE CASCADE ON UPDATE CASCADE;
18 |
--------------------------------------------------------------------------------
/prisma/migrations/20230406080854_chatbot_message/migration.sql:
--------------------------------------------------------------------------------
1 | -- CreateTable
2 | CREATE TABLE "ChatbotMessage" (
3 | "id" SERIAL NOT NULL,
4 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
5 | "updatedAt" TIMESTAMP(3) NOT NULL,
6 | "chatbotId" INTEGER,
7 | "message" VARCHAR NOT NULL,
8 | "agent" TEXT NOT NULL,
9 |
10 | CONSTRAINT "ChatbotMessage_pkey" PRIMARY KEY ("id")
11 | );
12 |
13 | -- AddForeignKey
14 | ALTER TABLE "ChatbotMessage" ADD CONSTRAINT "ChatbotMessage_chatbotId_fkey" FOREIGN KEY ("chatbotId") REFERENCES "Chatbot"("id") ON DELETE CASCADE ON UPDATE CASCADE;
15 |
--------------------------------------------------------------------------------
/prisma/migrations/20230409152256_chatbot_prompt_template/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - You are about to drop the column `promtTemplateId` on the `Chatbot` table. All the data in the column will be lost.
5 |
6 | */
7 | -- DropForeignKey
8 | ALTER TABLE "Chatbot" DROP CONSTRAINT "Chatbot_promtTemplateId_fkey";
9 |
10 | -- AlterTable
11 | ALTER TABLE "Chatbot" DROP COLUMN "promtTemplateId",
12 | ADD COLUMN "promptTemplateId" INTEGER;
13 |
14 | -- AddForeignKey
15 | ALTER TABLE "Chatbot" ADD CONSTRAINT "Chatbot_promptTemplateId_fkey" FOREIGN KEY ("promptTemplateId") REFERENCES "PromptTemplate"("id") ON DELETE CASCADE ON UPDATE CASCADE;
16 |
--------------------------------------------------------------------------------
/prisma/migrations/migration_lock.toml:
--------------------------------------------------------------------------------
1 | # Please do not edit this file manually
2 | # It should be added in your version-control system (i.e. Git)
3 | provider = "postgresql"
--------------------------------------------------------------------------------
/prisma/schema.prisma:
--------------------------------------------------------------------------------
1 | // This is your Prisma schema file,
2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema
3 |
4 | generator client {
5 | provider = "prisma-client-js"
6 | }
7 |
8 | datasource db {
9 | provider = "postgresql"
10 | url = env("DATABASE_URL")
11 | }
12 |
13 | model User {
14 | id String @id @default(cuid())
15 | name String?
16 | email String? @unique
17 | emailVerified DateTime?
18 | image String?
19 | accounts Account[]
20 | sessions Session[]
21 | PromptTemplate PromptTemplate[]
22 | Chatbot Chatbot[]
23 | }
24 |
25 | model Account {
26 | id String @id @default(cuid())
27 | userId String
28 | type String
29 | provider String
30 | providerAccountId String
31 | refresh_token String? @db.Text
32 | access_token String? @db.Text
33 | expires_at Int?
34 | token_type String?
35 | scope String?
36 | id_token String? @db.Text
37 | session_state String?
38 |
39 | user User @relation(fields: [userId], references: [id], onDelete: Cascade)
40 |
41 | @@unique([provider, providerAccountId])
42 | }
43 |
44 | model Session {
45 | id String @id @default(cuid())
46 | sessionToken String @unique
47 | userId String
48 | expires DateTime
49 | user User @relation(fields: [userId], references: [id], onDelete: Cascade)
50 | }
51 |
52 | model VerificationToken {
53 | identifier String
54 | token String @unique
55 | expires DateTime
56 |
57 | @@unique([identifier, token])
58 | }
59 |
60 | model PromptTemplate {
61 | id Int @id @default(autoincrement())
62 | createdAt DateTime @default(now())
63 | updatedAt DateTime @updatedAt
64 | prompt String
65 | user User @relation(fields: [userId], references: [id], onDelete: Cascade)
66 | userId String
67 | inputs Json
68 | name String
69 | Chatbot Chatbot[]
70 | }
71 |
72 | model Chatbot {
73 | id Int @id @default(autoincrement())
74 | createdAt DateTime @default(now())
75 | updatedAt DateTime @updatedAt
76 | user User @relation(fields: [userId], references: [id], onDelete: Cascade)
77 | userId String
78 | promptTemplate PromptTemplate? @relation(fields: [promptTemplateId], references: [id], onDelete: Cascade)
79 | promptTemplateId Int?
80 | name String
81 | ChatbotMessage ChatbotMessage[]
82 | }
83 |
84 | model ChatbotMessage {
85 | id Int @id @default(autoincrement())
86 | createdAt DateTime @default(now())
87 | updatedAt DateTime @updatedAt
88 | chatbot Chatbot? @relation(fields: [chatbotId], references: [id], onDelete: Cascade)
89 | chatbotId Int?
90 | message String @db.VarChar()
91 | agent String
92 | }
93 |
--------------------------------------------------------------------------------
/public/chatbot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JayZeeDesign/langchain-ui/5cd7a75d5c5bded9134bddaff9029fc1a0b01d3c/public/chatbot.png
--------------------------------------------------------------------------------
/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/thirteen.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JayZeeDesign/langchain-ui/5cd7a75d5c5bded9134bddaff9029fc1a0b01d3c/public/user.png
--------------------------------------------------------------------------------
/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------