├── .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 ├── app │ ├── chatbots │ │ ├── [chatbotId] │ │ │ ├── client-page.js │ │ │ ├── loading.js │ │ │ └── page.js │ │ ├── client-page.js │ │ ├── loading.js │ │ └── page.js │ ├── client-page.js │ ├── container.js │ ├── datasources │ │ ├── client-page.js │ │ ├── loading.js │ │ └── page.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 │ ├── message.js │ ├── output.js │ └── prompt-templates.js ├── code-block.js ├── datasources │ └── csv.js ├── file-picker.js ├── page-header.js └── user-menu.js ├── env.example ├── jsconfig.json ├── lib ├── api-docs.js ├── api.js ├── datasources.js ├── markdown.js ├── metal.js ├── prisma.js ├── s3.js ├── sidebar.js ├── theme.js ├── upload-file.js └── upload-url.js ├── next.config.js ├── package-lock.json ├── package.json ├── pages └── api │ ├── auth │ └── [...nextauth].js │ ├── chatbots │ ├── [chatbotId] │ │ ├── index.js │ │ └── messages │ │ │ └── index.js │ └── index.js │ ├── datasources │ ├── [datasourceId] │ │ └── index.js │ ├── index.js │ └── ingest.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 │ ├── 20230428114658_ │ │ └── migration.sql │ └── migration_lock.toml └── schema.prisma └── public ├── chatbot.png ├── next.svg ├── thirteen.svg ├── user.png └── vercel.svg /.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 | ## 🚨🚨 This repository is unmaintained 🚨🚨 4 | Note that this repository is unmaintained. We've started working on another approach which gives more granular access to LLM-powered Agents. Please check out out https://github.com/homanp/superagent. We appreciate all the feedback and contributions 🙏🙏🙏 5 | 6 | # 🧬 LangChain UI 7 | The no-code open source chat-ai toolkit built on top of [LangChain](https://github.com/hwchase17/langchain). 8 | 9 |

10 | GitHub Contributors 11 | GitHub Last Commit 12 | 13 | GitHub Issues 14 | GitHub Pull Requests 15 | Github License 16 |

17 | 18 | ## About the project 19 | 20 | LangChain UI enables anyone to create and host chatbots using a no-code type of inteface. 21 | 22 | Features: 23 | 24 | 👉 Create custom chatGPT like Chatbot. 25 | 26 | 👉 Give context to the chatbot using external datasources, chatGPT plugins and prompts. 27 | 28 | 👉 Dedicated API endpoint for each Chatbot. 29 | 30 | 👉 Bring your own DB 31 | 32 | 👉 Bring your own Auth provider (defaults to Github) 33 | 34 | 👉 Usage quoutas 35 | 36 | 👉 Embed Chatbots to any site or application 37 | 38 | 👉 Chatbot themes 39 | 40 | ... and more 41 | 42 | ## Roadmap 43 | 44 | - [x] Bring your own db 45 | - [x] Bring your own Auth provider 46 | - [x] Chatbots 47 | - [x] Prompt templates 48 | - [ ] API endpoints to chatbot 49 | - [ ] External datasources 50 | - [ ] chatGPT plugins 51 | - [ ] Chatbots themes 52 | - [ ] Chatbot embedding 53 | 54 | ## Stack 55 | 56 | - [Next.js](https://nextjs.org/?ref=langchain-ui) 57 | - [Chakra UI](https://chakra-ui.com/?ref=langchain-ui) 58 | - [Prisma](https://prisma.io/?ref=langchain-ui) 59 | - [NextAuth](https://next-auth.js.org/?ref=langchain-ui) 60 | 61 | LangChain UI utilizes NextJS 13 `appDir`. Read more about it [here](https://nextjs.org/blog/next-13#new-app-directory-beta) 62 | 63 | ## Getting started 64 | 65 | ### Langchain UI API 66 | 67 | We have migrated all agent functionality from LangChain Typescript to LangChain Python. Thus you will need to run the [Langchain UI API](https://github.com/homanp/langchain-ui-api) in order to interact with the chatbot. In the future when the TS package is on par with the Python package we will migrate to only using Javascript. 68 | 69 | ### Installation 70 | 71 | 1. Setup the [Langchain UI API](https://github.com/homanp/langchain-ui-api) 72 | 73 | 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. 74 | 75 | ```sh 76 | git clone https://github.com/homanp/langchain-ui.git 77 | ``` 78 | 79 | 1. Go to the project folder 80 | 81 | ```sh 82 | cd langchain-ui 83 | ``` 84 | 85 | 1. Install packages with npm 86 | 87 | ```sh 88 | npm install 89 | ``` 90 | 91 | 1. Set up your .env file 92 | 93 | - Duplicate `.env.example` to `.env` 94 | 95 | 1. Run the project 96 | 97 | ```sh 98 | npm run dev 99 | ``` 100 | 101 | 1. Run the linter 102 | 103 | ```sh 104 | npm run lint 105 | ``` 106 | 107 | 1. Build the project 108 | 109 | ```sh 110 | npm run build 111 | ``` 112 | 113 | ## Contributions 114 | 115 | 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. 116 | 117 | You can read more on how to contribute [here](https://github.com/homanp/langchain-ui/blob/main/.github/CONTRIBUTING.md). 118 | -------------------------------------------------------------------------------- /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 | HStack, 8 | SimpleGrid, 9 | Spinner, 10 | Stack, 11 | StackDivider, 12 | Tag, 13 | Text, 14 | } from "@chakra-ui/react"; 15 | import { useAsync } from "react-use"; 16 | import { getChatbotById } from "@/lib/api"; 17 | import Chat from "@/components/chat"; 18 | import CodeBlock from "@/components/code-block"; 19 | 20 | import { API_DOCS } from "@/lib/api-docs"; 21 | 22 | export default function ChatbotClientPage({ chatbotId }) { 23 | const [chatbot, setChatbot] = useState(); 24 | const { loading: isLoading } = useAsync(async () => { 25 | const { data } = await getChatbotById(chatbotId); 26 | 27 | setChatbot(data); 28 | }, [chatbotId, getChatbotById]); 29 | 30 | return ( 31 | 32 | {isLoading && ( 33 |
34 | 35 |
36 | )} 37 | {!isLoading && ( 38 | 39 | 40 | 41 | 42 | 43 | } spacing={0}> 44 | 45 | {chatbot.name} 46 | 47 | 48 | 49 | 50 | Datasources 51 | 52 | {chatbot.datasource ? ( 53 | 54 | 55 | {chatbot.datasource.name}{" "} 56 | 57 | {chatbot.datasource.type} 58 | 59 | 60 | 61 | ) : ( 62 | No datasource selected... 63 | )} 64 | 65 | 66 | 67 | API 68 | 69 | 70 | Interact with your chatbot using the following API call 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | )} 79 |
80 | ); 81 | } 82 | 83 | ChatbotClientPage.propTypes = { 84 | chatbotId: PropTypes.string, 85 | }; 86 | -------------------------------------------------------------------------------- /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 | getDatasources, 34 | getPrompTemplates, 35 | removeChatbotById, 36 | } from "@/lib/api"; 37 | 38 | export default function ChatbotsClientPage() { 39 | const [showForm, setShowForm] = useState(); 40 | const [chatbots, setChatbots] = useState([]); 41 | const [promptTemplates, setPromptTemplates] = useState([]); 42 | const [datasources, setDatasources] = useState([]); 43 | const buttonColorScheme = useColorModeValue("blackAlpha", "whiteAlpha"); 44 | const buttonBackgroundColor = useColorModeValue("black", "white"); 45 | const borderBottomColor = useColorModeValue("gray.50", "#333"); 46 | const router = useRouter(); 47 | const menu = useSidebar(); 48 | 49 | const { 50 | formState: { errors, isSubmitting }, 51 | handleSubmit, 52 | register, 53 | } = useForm(); 54 | 55 | const { loading: isLoading } = useAsync(async () => { 56 | const [ 57 | { data: chatbots }, 58 | { data: promptTemplates }, 59 | { data: datasources }, 60 | ] = await Promise.all([ 61 | getChatbots(), 62 | getPrompTemplates(), 63 | getDatasources(), 64 | ]); 65 | 66 | setChatbots(chatbots); 67 | setPromptTemplates(promptTemplates); 68 | setDatasources(datasources); 69 | 70 | return; 71 | }, [getChatbots, getPrompTemplates, setChatbots]); 72 | 73 | const handleRemoveChatbot = useCallback(async (chatbotId) => { 74 | await removeChatbotById(chatbotId); 75 | 76 | setChatbots((prev) => prev.filter(({ id }) => id !== chatbotId)); 77 | }, []); 78 | 79 | const onSubmit = useCallback( 80 | async (values) => { 81 | const { name, promptTemplateId, datasourceId } = values; 82 | const { data: chatbot } = await createChatbot({ 83 | name, 84 | promptTemplateId: parseInt(promptTemplateId), 85 | datasourceId: parseInt(datasourceId), 86 | }); 87 | 88 | router.push(`/app/chatbots/${chatbot.id}`); 89 | }, 90 | [router] 91 | ); 92 | 93 | return ( 94 | 95 | id === "chatbots").icon} 97 | title="Chatbots" 98 | > 99 | 100 | 111 | 112 | 113 | {isLoading && ( 114 |
115 | 116 |
117 | )} 118 | {!isLoading && !showForm && ( 119 | 120 | 121 | 122 | {chatbots.map(({ id, name }) => ( 123 | 124 | 131 | 139 | 140 | ))} 141 | 142 |
129 | {name} 130 | 132 | } 135 | variant="ghost" 136 | onClick={() => handleRemoveChatbot(id)} 137 | /> 138 |
143 |
144 | )} 145 | {showForm && ( 146 |
147 | 148 | 149 | 150 | id === "chatbots").icon} 153 | /> 154 | New chatbot 155 | 156 | Create a new chatbot 157 | 158 | 159 | 160 | 161 | 166 | 167 | 168 | 179 | 180 | 181 | 192 | 193 | 194 | 195 | 198 | 207 | 208 | 209 | 210 |
211 | )} 212 |
213 | ); 214 | } 215 | -------------------------------------------------------------------------------- /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/datasources/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 | FormErrorMessage, 10 | HStack, 11 | Icon, 12 | IconButton, 13 | Input, 14 | Spinner, 15 | Stack, 16 | Table, 17 | TableContainer, 18 | Tbody, 19 | Text, 20 | Tr, 21 | Td, 22 | useColorModeValue, 23 | Select, 24 | Tag, 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 | createDatasource, 33 | getDatasources, 34 | removeDatasourceById, 35 | } from "@/lib/api"; 36 | import { DATASOURCE_TYPES } from "@/lib/datasources"; 37 | import { uploadFile } from "@/lib/upload-file.js"; 38 | import { getUploadUrl } from "@/lib/upload-url.js"; 39 | 40 | export default function DatasourcesClientPage() { 41 | const buttonColorScheme = useColorModeValue("blackAlpha", "whiteAlpha"); 42 | const buttonBackgroundColor = useColorModeValue("black", "white"); 43 | const borderBottomColor = useColorModeValue("gray.50", "#333"); 44 | const menu = useSidebar(); 45 | const [datasources, setDatasources] = useState([]); 46 | 47 | const { loading: isLoading } = useAsync(async () => { 48 | const { data } = await getDatasources(); 49 | setDatasources(data); 50 | 51 | return data; 52 | }, [getDatasources, setDatasources]); 53 | const [showForm, setShowForm] = useState( 54 | !isLoading && datasources.length === 0 55 | ); 56 | 57 | const { 58 | formState: { isSubmitting, errors }, 59 | handleSubmit, 60 | register, 61 | reset, 62 | watch, 63 | } = useForm({ values: { type: "csv" } }); 64 | 65 | const files = watch("file"); 66 | const type = watch("type"); 67 | const validate = useCallback((value) => value.length > 0, []); 68 | 69 | const onSubmit = useCallback( 70 | async ({ name, type }) => { 71 | const fileType = files[0].type; 72 | const uploadUrl = await getUploadUrl({ type: fileType }); 73 | const s3Url = `${uploadUrl.url}/${uploadUrl.fields.key}`; 74 | 75 | await uploadFile(files[0], uploadUrl); 76 | 77 | const { data: datasource } = await createDatasource({ 78 | url: s3Url, 79 | name: name, 80 | type: type, 81 | }); 82 | 83 | setDatasources((prev) => [datasource, ...prev]); 84 | setShowForm(); 85 | reset(); 86 | }, 87 | [files, reset, setDatasources] 88 | ); 89 | 90 | const handleRemoveDatasource = useCallback(async (datasourceId) => { 91 | await removeDatasourceById(datasourceId); 92 | 93 | setDatasources((prev) => prev.filter(({ id }) => id !== datasourceId)); 94 | }, []); 95 | 96 | return ( 97 | 98 | id === "datasources").icon} 100 | title="Datasources" 101 | > 102 | 103 | 112 | 113 | 114 | {isLoading && ( 115 |
116 | 117 |
118 | )} 119 | {!isLoading && !showForm && ( 120 | 121 | 122 | 123 | {datasources.map(({ id, name, type }) => ( 124 | 125 | 137 | 145 | 146 | ))} 147 | 148 |
130 | 131 | {name}{" "} 132 | 133 | {type} 134 | 135 | 136 | 138 | } 141 | variant="ghost" 142 | onClick={() => handleRemoveDatasource(id)} 143 | /> 144 |
149 |
150 | )} 151 | {showForm && ( 152 |
153 | 154 | 155 | 156 | id === "datasources").icon} 159 | /> 160 | Datasources 161 | 162 | Create a datasource that you can use in your chat app. 163 | 164 | 165 | 166 | 167 | 172 | {errors?.file && ( 173 | Please choose a name 174 | )} 175 | 176 | 177 | 184 | {errors?.file && ( 185 | 186 | Please select a datasource 187 | 188 | )} 189 | 190 | 191 | id === type).component 194 | } 195 | files={files} 196 | register={register} 197 | validate={validate} 198 | /> 199 | {errors?.file && ( 200 | Please select a file 201 | )} 202 | 203 | 204 | 205 | 208 | 217 | 218 | 219 | 220 |
221 | )} 222 |
223 | ); 224 | } 225 | -------------------------------------------------------------------------------- /app/app/datasources/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/datasources/page.js: -------------------------------------------------------------------------------- 1 | import DatasourcesClientPage from "./client-page"; 2 | 3 | export const metadata = { 4 | title: "Datasources", 5 | description: "Manage your datasources", 6 | }; 7 | 8 | export default function PromptTemplatesPage() { 9 | return ; 10 | } 11 | -------------------------------------------------------------------------------- /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 | 106 | 107 | 108 | {isLoading && ( 109 |
110 | 111 |
112 | )} 113 | {!isLoading && !showForm && ( 114 | 115 | 116 | 117 | {promptTemplates.map(({ id, name }) => ( 118 | 119 | 126 | 134 | 135 | ))} 136 | 137 |
124 | {name} 125 | 127 | } 130 | variant="ghost" 131 | onClick={() => handleRemovePromptTemplate(id)} 132 | /> 133 |
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 |