diff --git a/.dockerignore b/.dockerignore index 2bcdfd92b..e5b067a78 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +1,2 @@ models/ +plugins/ diff --git a/.gitignore b/.gitignore index d040022b1..2b16ce8b9 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,9 @@ sdist/ var/ wheels/ -models/* +models/ +plugins/ + pip-wheel-metadata/ share/python-wheels/ *.egg-info/ diff --git a/Dockerfile-webserver b/Dockerfile similarity index 83% rename from Dockerfile-webserver rename to Dockerfile index bd6aa73dd..3b6d7ef92 100644 --- a/Dockerfile-webserver +++ b/Dockerfile @@ -1,23 +1,23 @@ FROM nvidia/cuda:11.8.0-devel-ubuntu22.04 +WORKDIR /app + RUN apt-get update && apt-get install -y \ git \ python3 \ pip - -WORKDIR /app - -COPY . /app - - # upgrade pip RUN pip3 install --upgrade pip +COPY ./requirements.txt /app/requirements.txt + RUN pip install --no-cache-dir -r requirements.txt RUN python3 -m spacy download zh_core_web_sm -EXPOSE 7860 -CMD ["python3", "pilot/server/webserver.py"] +COPY . /app + +EXPOSE 7860 +EXPOSE 8000 \ No newline at end of file diff --git a/Dockerfile-llmserver b/Dockerfile-llmserver deleted file mode 100644 index c36567381..000000000 --- a/Dockerfile-llmserver +++ /dev/null @@ -1,21 +0,0 @@ -FROM nvidia/cuda:11.8.0-devel-ubuntu22.04 - -RUN apt-get update && apt-get install -y \ - git \ - python3 \ - pip - - -WORKDIR /app - -COPY . /app - - -# upgrade pip -RUN pip3 install --upgrade pip - -RUN pip install --no-cache-dir -r requirements.txt - -EXPOSE 8000 - -CMD ["python3", "pilot/server/llmserver.py"] diff --git a/README.md b/README.md index 41084d2c9..7191a3f96 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@

-[**简体中文**](README.zh.md) |[**Discord**](https://discord.gg/hmGPnMSb) |[**Documents**](https://db-gpt.readthedocs.io/en/latest/)|[**Wechat**](https://github.com/csunny/DB-GPT/blob/main/README.zh.md#%E8%81%94%E7%B3%BB%E6%88%91%E4%BB%AC) +[**简体中文**](README.zh.md) |[**Discord**](https://discord.gg/4BNdxm5d) |[**Documents**](https://db-gpt.readthedocs.io/en/latest/)|[**Wechat**](https://github.com/csunny/DB-GPT/blob/main/README.zh.md#%E8%81%94%E7%B3%BB%E6%88%91%E4%BB%AC) @@ -21,10 +21,12 @@ As large models are released and iterated upon, they are becoming increasingly i DB-GPT is an experimental open-source project that uses localized GPT large models to interact with your data and environment. With this solution, you can be assured that there is no risk of data leakage, and your data is 100% private and secure. ## News +- [2023/06/30]🔥DB-GPT product. [documents](https://db-gpt.readthedocs.io/en/latest/modules/llms.html) +- [2023/06/25]🔥support chatglm2-6b model. [documents](https://db-gpt.readthedocs.io/en/latest/modules/llms.html) - [2023/06/14] support gpt4all model, which can run at M1/M2, or cpu machine. [documents](https://db-gpt.readthedocs.io/en/latest/modules/llms.html) - [2023/06/01]🔥 On the basis of the Vicuna-13B basic model, task chain calls are implemented through plugins. For example, the implementation of creating a database with a single sentence.[demo](./assets/auto_plugin.gif) - [2023/06/01]🔥 QLoRA guanaco(7b, 13b, 33b) support. -- [2023/05/28]🔥 Learning from crawling data from the Internet [demo](./assets/chaturl_en.gif) +- [2023/05/28] Learning from crawling data from the Internet [demo](./assets/chaturl_en.gif) - [2023/05/21] Generate SQL and execute it automatically. [demo](./assets/auto_sql_en.gif) - [2023/05/15] Chat with documents. [demo](./assets/new_knownledge_en.gif) - [2023/05/06] SQL generation and diagnosis. [demo](./assets/demo_en.gif) @@ -47,9 +49,6 @@ https://github.com/csunny/DB-GPT/assets/17919400/654b5a49-5ea4-4c02-b5b2-72d089d

-

- -

## Features @@ -59,8 +58,9 @@ Currently, we have released multiple key features, which are listed below to dem - SQL generation - SQL diagnosis - Private domain Q&A and data processing + - Knowledge Management(We currently support many document formats: txt, pdf, md, html, doc, ppt, and url.) - Database knowledge Q&A - - Data processing + - knowledge Embedding - Plugins - Support custom plugin execution tasks and natively support the Auto-GPT plugin, such as: - Automatic execution of SQL and retrieval of query results @@ -68,13 +68,15 @@ Currently, we have released multiple key features, which are listed below to dem - Unified vector storage/indexing of knowledge base - Support for unstructured data such as PDF, TXT, Markdown, CSV, DOC, PPT, and WebURL -- Milti LLMs Support +- Multi LLMs Support - Supports multiple large language models, currently supporting Vicuna (7b, 13b), ChatGLM-6b (int4, int8), guanaco(7b,13b,33b), Gorilla(7b,13b) - TODO: codegen2, codet5p ## Introduction -DB-GPT creates a vast model operating system using [FastChat](https://github.com/lm-sys/FastChat) and offers a large language model powered by [Vicuna](https://huggingface.co/Tribbiani/vicuna-7b). In addition, we provide private domain knowledge base question-answering capability through LangChain. Furthermore, we also provide support for additional plugins, and our design natively supports the Auto-GPT plugin. +DB-GPT creates a vast model operating system using [FastChat](https://github.com/lm-sys/FastChat) and offers a large language model powered by [Vicuna](https://huggingface.co/Tribbiani/vicuna-7b). In addition, we provide private domain knowledge base question-answering capability. Furthermore, we also provide support for additional plugins, and our design natively supports the Auto-GPT plugin.Our vision is to make it easier and more convenient to build applications around databases and llm. + + Is the architecture of the entire DB-GPT shown in the following figure: @@ -101,24 +103,6 @@ The core capabilities mainly consist of the following parts: - [Multi LLMs Usage](https://db-gpt.readthedocs.io/en/latest/modules/llms.html) - [Create your own knowledge repository](https://db-gpt.readthedocs.io/en/latest/modules/knowledge.html) -We currently support many document formats: txt, pdf, md, html, doc, ppt, and url. -before execution: - -``` -python -m spacy download zh_core_web_sm - -``` -2.set .env configuration set your vector store type, eg:VECTOR_STORE_TYPE=Chroma, now we support Chroma and Milvus(version > 2.1) - -3.Run the knowledge repository script in the tools directory. - -```bash -& python tools/knowledge_init.py - ---vector_name : your vector store name default_value:default ---append: append mode, True:append, False: not append default_value:False -``` - If nltk-related errors occur during the use of the knowledge base, you need to install the nltk toolkit. For more details, please refer to: [nltk documents](https://www.nltk.org/data.html) Run the Python interpreter and type the commands: @@ -149,7 +133,7 @@ This project is standing on the shoulders of giants and is not going to work wit The MIT License (MIT) ## Contact Information -We are working on building a community, if you have any ideas about building the community, feel free to contact us. [Discord](https://discord.gg/hmGPnMSb) +We are working on building a community, if you have any ideas about building the community, feel free to contact us. [Discord](https://discord.gg/4BNdxm5d) [![Star History Chart](https://api.star-history.com/svg?repos=csunny/DB-GPT)](https://star-history.com/#csunny/DB-GPT) diff --git a/README.zh.md b/README.zh.md index 544fca460..9e3505def 100644 --- a/README.zh.md +++ b/README.zh.md @@ -15,7 +15,7 @@ ## DB-GPT 是什么? -随着大模型的发布迭代,大模型变得越来越智能,在使用大模型的过程当中,遇到极大的数据安全与隐私挑战。在利用大模型能力的过程中我们的私密数据跟环境需要掌握自己的手里,完全可控,避免任何的数据隐私泄露以及安全风险。基于此,我们发起了DB-GPT项目,为所有以数据库为基础的场景,构建一套完整的私有大模型解决方案。 此方案因为支持本地部署,所以不仅仅可以应用于独立私有环境,而且还可以根据业务模块独立部署隔离,让大模型的能力绝对私有、安全、可控。 +随着大模型的发布迭代,大模型变得越来越智能,在使用大模型的过程当中,遇到极大的数据安全与隐私挑战。在利用大模型能力的过程中我们的私密数据跟环境需要掌握自己的手里,完全可控,避免任何的数据隐私泄露以及安全风险。基于此,我们发起了DB-GPT项目,为所有以数据库为基础的场景,构建一套完整的私有大模型解决方案。 此方案因为支持本地部署,所以不仅仅可以应用于独立私有环境,而且还可以根据业务模块独立部署隔离,让大模型的能力绝对私有、安全、可控。我们的愿景是让围绕数据库构建大模型应用更简单,更方便。 DB-GPT 是一个开源的以数据库为基础的GPT实验项目,使用本地化的GPT大模型与您的数据和环境进行交互,无数据泄露风险,100% 私密 @@ -23,6 +23,8 @@ DB-GPT 是一个开源的以数据库为基础的GPT实验项目,使用本地 ## 最新发布 +- [2023/06/30]🔥 DB-GPT产品。 [使用文档](https://db-gpt.readthedocs.io/projects/db-gpt-docs-zh-cn/zh_CN/latest/modules/llms.html) +- [2023/06/25]🔥 支持ChatGLM2-6B模型。 [使用文档](https://db-gpt.readthedocs.io/projects/db-gpt-docs-zh-cn/zh_CN/latest/modules/llms.html) - [2023/06/14]🔥 支持gpt4all模型,可以在M1/M2 或者CPU机器上运行。 [使用文档](https://db-gpt.readthedocs.io/projects/db-gpt-docs-zh-cn/zh_CN/latest/modules/llms.html) - [2023/06/01]🔥 在Vicuna-13B基础模型的基础上,通过插件实现任务链调用。例如单句创建数据库的实现. - [2023/06/01]🔥 QLoRA guanaco(原驼)支持, 支持4090运行33B @@ -38,6 +40,7 @@ DB-GPT 是一个开源的以数据库为基础的GPT实验项目,使用本地 - SQL生成 - SQL诊断 - 私域问答与数据处理 + - 知识库管理(目前支持 txt, pdf, md, html, doc, ppt, and url) - 数据库知识问答 - 数据处理 - 插件模型 @@ -107,37 +110,6 @@ DB-GPT基于 [FastChat](https://github.com/lm-sys/FastChat) 构建大模型运 ### 打造属于你的知识库 - [参考手册](https://db-gpt.readthedocs.io/projects/db-gpt-docs-zh-cn/zh_CN/latest/modules/knowledge.html) -1.将个人知识文件或者文件夹放入pilot/datasets目录中 - -当前支持的文档格式: txt, pdf, md, html, doc, ppt, and url. - -在操作之前先执行 - -``` -python -m spacy download zh_core_web_sm - -``` - -2.在.env文件指定你的向量数据库类型,VECTOR_STORE_TYPE(默认Chroma),目前支持Chroma,Milvus(需要设置MILVUS_URL和MILVUS_PORT) - -**注意Milvus版本需要>2.1** - -3.在tools目录执行知识入库脚本, 如果是选择默认知识库,不需要指定 --vector_name, 默认default - -``` -python tools/knowledge_init.py -``` - -如果选择新增知识库,在界面上新增知识库输入你的知识库名, - -``` -python tools/knowledge_init.py --vector_name = yourname - ---vector_name: vector_name default_value:default -``` -就可以根据你的知识库进行问答 - -注意,这里默认向量模型是text2vec-large-chinese(模型比较大,如果个人电脑配置不够建议采用text2vec-base-chinese),因此确保需要将模型download下来放到models目录中。 如果在使用知识库时遇到与nltk相关的错误,您需要安装nltk工具包。更多详情,请参见:[nltk文档](https://www.nltk.org/data.html) Run the Python interpreter and type the commands: @@ -146,7 +118,7 @@ Run the Python interpreter and type the commands: >>> nltk.download() ``` -我们提供了Gradio的用户界面,可以通过我们的用户界面使用DB-GPT, 同时关于我们项目相关的一些代码跟原理介绍,我们也准备了以下几篇参考文章。 +我们提供了全新的的用户界面,可以通过我们的用户界面使用DB-GPT, 同时关于我们项目相关的一些代码跟原理介绍,我们也准备了以下几篇参考文章。 1. [大模型实战系列(1) —— 强强联合Langchain-Vicuna应用实战](https://zhuanlan.zhihu.com/p/628750042) 2. [大模型实战系列(2) —— DB-GPT 阿里云部署指南](https://zhuanlan.zhihu.com/p/629467580) 3. [大模型实战系列(3) —— DB-GPT插件模型原理与使用](https://zhuanlan.zhihu.com/p/629623125) diff --git a/assets/DB-GPT.png b/assets/DB-GPT.png index 1c9bee139..b136a1e57 100644 Binary files a/assets/DB-GPT.png and b/assets/DB-GPT.png differ diff --git a/datacenter/app/agents/page.tsx b/datacenter/app/agents/page.tsx index 814e03efe..3dcd8462e 100644 --- a/datacenter/app/agents/page.tsx +++ b/datacenter/app/agents/page.tsx @@ -16,7 +16,7 @@ const Item = styled(Sheet)(({ theme }) => ({ const Agents = () => { const { handleChatSubmit, history } = useAgentChat({ - queryAgentURL: `http://30.183.153.109:5000/v1/chat/completions`, + queryAgentURL: `/v1/chat/completions`, }); const data = [ diff --git a/datacenter/app/agents/[agentId]/page.tsx b/datacenter/app/chat/page.tsx similarity index 100% rename from datacenter/app/agents/[agentId]/page.tsx rename to datacenter/app/chat/page.tsx diff --git a/datacenter/app/datastores/constants.tsx b/datacenter/app/datastores/constants.tsx deleted file mode 100644 index 427f053b4..000000000 --- a/datacenter/app/datastores/constants.tsx +++ /dev/null @@ -1 +0,0 @@ -export const fetchBaseURL = 'http://30.183.153.109:5000'; diff --git a/datacenter/app/datastores/documents/chunklist/page.tsx b/datacenter/app/datastores/documents/chunklist/page.tsx index 0a3db6383..2664ed1bd 100644 --- a/datacenter/app/datastores/documents/chunklist/page.tsx +++ b/datacenter/app/datastores/documents/chunklist/page.tsx @@ -1,13 +1,20 @@ 'use client' -import { useSearchParams } from 'next/navigation' +import { useSearchParams, useRouter } from 'next/navigation' import React, { useState, useEffect } from 'react' -import { useColorScheme, Table, Stack } from '@/lib/mui' +import { + useColorScheme, + Table, + Stack, + Typography, + Breadcrumbs, + Link +} from '@/lib/mui' import { Popover, Pagination } from 'antd' -import { fetchBaseURL } from '@/app/datastores/constants' const page_size = 20 const ChunkList = () => { + const router = useRouter() const { mode } = useColorScheme() const spaceName = useSearchParams().get('spacename') const documentId = useSearchParams().get('documentid') @@ -17,7 +24,7 @@ const ChunkList = () => { useEffect(() => { async function fetchChunks() { const res = await fetch( - `${fetchBaseURL}/knowledge/${spaceName}/chunk/list`, + `${process.env.API_BASE_URL}/knowledge/${spaceName}/chunk/list`, { method: 'POST', headers: { @@ -41,99 +48,137 @@ const ChunkList = () => { }, []) return (
- {chunkList.length ? ( - <> - + + { + router.push('/datastores') }} + key="Knowledge Space" + underline="hover" + color="neutral" + fontSize="inherit" > - - - - - - - - - {chunkList.map((row: any) => ( - - - - - - ))} - -
NameContentMeta Data
{row.doc_name} - { - - {row.content.length > 10 - ? `${row.content.slice(0, 10)}...` - : row.content} - - } - - { - - {row.meta_info.length > 10 - ? `${row.meta_info.slice(0, 10)}...` - : row.meta_info} - - } -
- + { + router.push(`/datastores/documents?name=${spaceName}`) }} + key="Knowledge Space" + underline="hover" + color="neutral" + fontSize="inherit" > - { - const res = await fetch( - `${fetchBaseURL}/knowledge/${spaceName}/chunk/list`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - document_id: documentId, - page, - page_size - }) - } - ) - const data = await res.json() - if (data.success) { - setChunkList(data.data.data) - setTotal(data.data.total) - setCurrent(data.data.page) + Documents + + Chunks + + +
+ {chunkList.length ? ( + <> + - - - ) : ( - <> - )} + > + + + + + + + + + {chunkList.map((row: any) => ( + + + + + + ))} + +
NameContentMeta Data
{row.doc_name} + { + + {row.content.length > 10 + ? `${row.content.slice(0, 10)}...` + : row.content} + + } + + { + + {row.meta_info.length > 10 + ? `${row.meta_info.slice(0, 10)}...` + : row.meta_info} + + } +
+ + { + const res = await fetch( + `${process.env.API_BASE_URL}/knowledge/${spaceName}/chunk/list`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + document_id: documentId, + page, + page_size + }) + } + ) + const data = await res.json() + if (data.success) { + setChunkList(data.data.data) + setTotal(data.data.total) + setCurrent(data.data.page) + } + }} + hideOnSinglePage + /> + + + ) : ( + <> + )} +
) } diff --git a/datacenter/app/datastores/documents/page.tsx b/datacenter/app/datastores/documents/page.tsx index 8e14b5d2c..134fe5f4f 100644 --- a/datacenter/app/datastores/documents/page.tsx +++ b/datacenter/app/datastores/documents/page.tsx @@ -13,13 +13,18 @@ import { Input, Textarea, Chip, + Switch, + Typography, + Breadcrumbs, + Link, styled } from '@/lib/mui' import moment from 'moment' import { InboxOutlined } from '@ant-design/icons' +import CheckCircleOutlinedIcon from '@mui/icons-material/CheckCircleOutlined'; +import CachedIcon from '@mui/icons-material/Cached'; import type { UploadProps } from 'antd' -import { Upload, Pagination, message } from 'antd' -import { fetchBaseURL } from '@/app/datastores/constants' +import { Upload, Pagination, Popover, message } from 'antd' const { Dragger } = Upload const Item = styled(Sheet)(({ theme }) => ({ @@ -72,6 +77,7 @@ const Documents = () => { const [originFileObj, setOriginFileObj] = useState(null) const [total, setTotal] = useState(0) const [current, setCurrent] = useState(0) + const [synchChecked, setSynchChecked] = useState(true) const props: UploadProps = { name: 'file', multiple: false, @@ -89,7 +95,7 @@ const Documents = () => { useEffect(() => { async function fetchDocuments() { const res = await fetch( - `${fetchBaseURL}/knowledge/${spaceName}/document/list`, + `${process.env.API_BASE_URL}/knowledge/${spaceName}/document/list`, { method: 'POST', headers: { @@ -112,24 +118,38 @@ const Documents = () => { }, []) return (
- + + { + router.push('/datastores') + }} + key="Knowledge Space" + underline="hover" + color="neutral" + fontSize="inherit" + > + Knowledge Space + + Documents + - + {documents.length ? ( <> { + @@ -156,11 +177,7 @@ const Documents = () => { @@ -168,8 +185,8 @@ const Documents = () => { +
Size Last Synch StatusResult Operation
{row.doc_name} - + {row.doc_type} {moment(row.last_sync).format('YYYY-MM-DD HH:MM:SS')} { {row.status} + {(function () { + if (row.status === 'TODO' || row.status === 'RUNNING') { + return '' + } else if (row.status === 'FINISHED') { + return ( + + + SUCCESS + + + ) + } else { + return ( + + + FAILED + + + ) + } + })()} + { <> } @@ -247,7 +298,7 @@ const Documents = () => { total={total} onChange={async (page) => { const res = await fetch( - `${fetchBaseURL}/knowledge/${spaceName}/document/list`, + `${process.env.API_BASE_URL}/knowledge/${spaceName}/document/list`, { method: 'POST', headers: { @@ -297,9 +348,13 @@ const Documents = () => { {stepsOfAddingDocument.map((item: any, index: number) => ( - {item} + {index < activeStep ? : `${index + 1}.`} + {`${item}`} ))} @@ -387,151 +442,224 @@ const Documents = () => { /> )} + + setSynchChecked(event.target.checked) + } + /> + } + > + Synch: + - + + + )} diff --git a/datacenter/app/datastores/page.tsx b/datacenter/app/datastores/page.tsx index e66c39a1f..05033bca5 100644 --- a/datacenter/app/datastores/page.tsx +++ b/datacenter/app/datastores/page.tsx @@ -3,8 +3,9 @@ import { useRouter } from 'next/navigation' import React, { useState, useEffect } from 'react' import { InboxOutlined } from '@ant-design/icons' +import CheckCircleOutlinedIcon from '@mui/icons-material/CheckCircleOutlined'; import type { UploadProps } from 'antd' -import { message, Upload } from 'antd' +import { message, Upload, Popover } from 'antd' import { useColorScheme, Modal, @@ -16,9 +17,10 @@ import { Input, Textarea, Chip, + Switch, + Typography, styled } from '@/lib/mui' -import { fetchBaseURL } from '@/app/datastores/constants' const { Dragger } = Upload @@ -34,7 +36,7 @@ const Item = styled(Sheet)(({ theme }) => ({ })) const stepsOfAddingSpace = [ - 'Knowledge Space Configuration', + 'Knowledge Space Config', 'Choose a Datasource type', 'Setup the Datasource' ] @@ -71,6 +73,7 @@ const Index = () => { const [textSource, setTextSource] = useState('') const [text, setText] = useState('') const [originFileObj, setOriginFileObj] = useState(null) + const [synchChecked, setSynchChecked] = useState(true) const props: UploadProps = { name: 'file', multiple: false, @@ -87,7 +90,7 @@ const Index = () => { } useEffect(() => { async function fetchData() { - const res = await fetch(`${fetchBaseURL}/knowledge/space/list`, { + const res = await fetch(`${process.env.API_BASE_URL}/knowledge/space/list`, { method: 'POST', headers: { 'Content-Type': 'application/json' @@ -128,8 +131,8 @@ const Index = () => {
{knowledgeSpaceList.length ? ( { }, '& tbody tr: hover a': { textDecoration: 'underline' + }, + '& tbody tr a': { + color: 'rgb(13, 96, 217)' } }} > @@ -146,6 +152,7 @@ const Index = () => { + @@ -165,23 +172,22 @@ const Index = () => { } + ))} @@ -214,9 +220,13 @@ const Index = () => { {stepsOfAddingSpace.map((item: any, index: number) => ( - {item} + {index < activeStep ? : `${index + 1}.`} + {`${item}`} ))} @@ -237,24 +247,27 @@ const Index = () => { message.error('please input the name') return } - const res = await fetch(`${fetchBaseURL}/knowledge/space/add`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - name: knowledgeSpaceName, - vector_type: 'Chroma', - owner: 'keting', - desc: 'test1' - }) - }) + const res = await fetch( + `${process.env.API_BASE_URL}/knowledge/space/add`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + name: knowledgeSpaceName, + vector_type: 'Chroma', + owner: 'keting', + desc: 'test1' + }) + } + ) const data = await res.json() if (data.success) { message.success('success') setActiveStep(1) const res = await fetch( - `${fetchBaseURL}/knowledge/space/list`, + `${process.env.API_BASE_URL}/knowledge/space/list`, { method: 'POST', headers: { @@ -358,94 +371,164 @@ const Index = () => { /> )} + + setSynchChecked(event.target.checked) + } + /> + } + > + Synch: + - + + + )} diff --git a/datacenter/app/globals.css b/datacenter/app/globals.css index 153cf633c..93095ccd9 100644 --- a/datacenter/app/globals.css +++ b/datacenter/app/globals.css @@ -12,28 +12,6 @@ body { background-color: var(--joy-palette-background-body); } -table { - border-collapse: collapse; - width: 100%; -} - -th, td { - border: 1px solid #ddd; - text-align: left; - padding: 8px; -} - -th { - background-color: #f2f2f2; -} - -tr:nth-child(even) { - background-color: #f2f2f2; -} -tr:hover { - background-color: #ddd; -} - body .ant-btn-primary { background-color: #1677ff; } diff --git a/datacenter/app/page.tsx b/datacenter/app/page.tsx index 61384178f..e1d3bbea5 100644 --- a/datacenter/app/page.tsx +++ b/datacenter/app/page.tsx @@ -1,7 +1,7 @@ "use client"; import { useRequest } from 'ahooks'; import { useState } from 'react'; -import { Button, Input, useColorScheme } from '@/lib/mui'; +import { Button, Input, Box, buttonClasses } from '@/lib/mui'; import IconButton from '@mui/joy/IconButton'; import SendRoundedIcon from '@mui/icons-material/SendRounded'; import { zodResolver } from '@hookform/resolvers/zod'; @@ -13,7 +13,6 @@ import { useRouter } from 'next/navigation'; export default function Home() { const Schema = z.object({ query: z.string().min(1) }); const router = useRouter(); - const { mode } = useColorScheme(); const [isLoading, setIsLoading] = useState(false); const methods = useForm>({ resolver: zodResolver(Schema), @@ -29,7 +28,7 @@ export default function Home() { chat_mode: 'chat_normal' }); if (res?.success && res?.data?.conv_uid) { - router.push(`/agents/${res?.data?.conv_uid}?initMessage=${query}`); + router.push(`/chat?id=${res?.data?.conv_uid}&initMessage=${query}`); } } catch (err) { } finally { @@ -38,73 +37,78 @@ export default function Home() { }; return ( - <> -
-
- - - - -
-
-
-
-
-

Scenes

-
+ <> +
+
+
+

Scenes

+ {scenesList?.data?.map(scene => ( ))} -
+
-
-
-
-
{ - methods.handleSubmit(submit)(e); - }} - > - - - - } - {...methods.register('query')} - /> - +
+
{ + methods.handleSubmit(submit)(e); + }} + > + + + + } + {...methods.register('query')} + /> + +
+ ) diff --git a/datacenter/components/agentPage.tsx b/datacenter/components/agentPage.tsx index 9caffbeaa..ac2541e58 100644 --- a/datacenter/components/agentPage.tsx +++ b/datacenter/components/agentPage.tsx @@ -2,14 +2,12 @@ import { useRequest } from 'ahooks'; import { sendGetRequest, sendPostRequest } from '@/utils/request'; import useAgentChat from '@/hooks/useAgentChat'; -import ChatBoxComp from '@/components/chatBox'; +import ChatBoxComp from '@/components/chatBoxTemp'; import { useDialogueContext } from '@/app/context/dialogue'; const AgentPage = (props: { - params: { - agentId?: string; - }, searchParams: { + id?: string; scene?: string; initMessage?: string; } @@ -17,26 +15,28 @@ const AgentPage = (props: { const { refreshDialogList } = useDialogueContext(); const { data: historyList } = useRequest(async () => await sendGetRequest('/v1/chat/dialogue/messages/history', { - con_uid: props.params?.agentId + con_uid: props.searchParams?.id }), { - ready: !!props.params?.agentId + ready: !!props.searchParams?.id, + refreshDeps: [props.searchParams?.id] }); const { data: paramsList } = useRequest(async () => await sendPostRequest(`/v1/chat/mode/params/list?chat_mode=${props.searchParams?.scene}`), { - ready: !!props.searchParams?.scene + ready: !!props.searchParams?.scene, + refreshDeps: [props.searchParams?.scene] }); const { history, handleChatSubmit } = useAgentChat({ - queryAgentURL: `http://30.183.153.109:5000/v1/chat/completions`, + queryAgentURL: `/v1/chat/completions`, queryBody: { - conv_uid: props.params?.agentId, + conv_uid: props.searchParams?.id, chat_mode: props.searchParams?.scene || 'chat_normal', }, initHistory: historyList?.data }); return ( -
+ <> { @@ -46,7 +46,7 @@ const AgentPage = (props: { onSubmit={handleChatSubmit} paramsList={paramsList?.data} /> -
+ ) } diff --git a/datacenter/components/chatBox.tsx b/datacenter/components/chatBox.tsx index 682ec9e09..ab642a2e0 100644 --- a/datacenter/components/chatBox.tsx +++ b/datacenter/components/chatBox.tsx @@ -96,168 +96,171 @@ const ChatBoxComp = ({ }, [paramsList]); return ( - +
- {firstMsg && ( - - {firstMsg?.context} - - )} - - {messages.filter(item => ['view', 'human'].includes(item.role)).map((each, index) => ( - + + {firstMsg && ( ({ - px: 2, - 'ol, ul': { - my: 0, - pl: 2, - }, - ol: { - listStyle: 'numeric', - }, - ul: { - listStyle: 'disc', - mb: 2, - }, - li: { - my: 1, - }, - a: { - textDecoration: 'underline', - }, - })} + color={'primary'} + className="message-agent" + sx={{ + mr: 'auto', + ml: 'none', + whiteSpace: 'pre-wrap', + }} > - - {each.context?.replaceAll('\\n', '\n')} - + {firstMsg?.context} - - ))} - - {isLoading && ( - - )} - - {!readOnly && ( -
{ - e.stopPropagation(); - methods.handleSubmit(submit)(e); - }} - > - {(Object.keys(paramsList || {}).length > 0) && ( -
- - - - -
)} - - - - } - {...methods.register('query')} - /> - - )} -
+ {messages.filter(item => ['view', 'human'].includes(item.role)).map((each, index) => ( + + ({ + px: 2, + 'ol, ul': { + my: 0, + pl: 2, + }, + ol: { + listStyle: 'numeric', + }, + ul: { + listStyle: 'disc', + mb: 2, + }, + li: { + my: 1, + }, + a: { + textDecoration: 'underline', + }, + })} + > + + {each.context?.replaceAll('\\n', '\n')} + + + + ))} + + {isLoading && ( + + )} + + {!readOnly && ( +
{ + e.stopPropagation(); + methods.handleSubmit(submit)(e); + }} + > + {(Object.keys(paramsList || {}).length > 0) && ( +
+ + + + +
+ )} + + + + + } + {...methods.register('query')} + /> + + )} + +
+ ); } diff --git a/datacenter/components/chatBoxTemp.tsx b/datacenter/components/chatBoxTemp.tsx new file mode 100644 index 000000000..56f4762a7 --- /dev/null +++ b/datacenter/components/chatBoxTemp.tsx @@ -0,0 +1,252 @@ +import { zodResolver } from '@hookform/resolvers/zod'; +import SendRoundedIcon from '@mui/icons-material/SendRounded'; +import { Card, CircularProgress, IconButton, Input, Stack, Select, Option, Tooltip, Box, useColorScheme } from '@/lib/mui'; +import React, { useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import { Message } from '@/types'; +import FaceRetouchingNaturalOutlinedIcon from '@mui/icons-material/FaceRetouchingNaturalOutlined'; +import SmartToyOutlinedIcon from '@mui/icons-material/SmartToyOutlined'; +import Markdown from 'markdown-to-jsx'; +import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; +import { okaidia } from 'react-syntax-highlighter/dist/esm/styles/prism'; + +type Props = { + messages: Message[]; + onSubmit: (message: string, otherQueryBody?: any) => Promise; + initialMessage?: string; + readOnly?: boolean; + paramsList?: { [key: string]: string }; + clearIntialMessage?: () => void; +}; + +const Schema = z.object({ query: z.string().min(1) }); + +const ChatBoxComp = ({ + messages, + onSubmit, + initialMessage, + readOnly, + paramsList, + clearIntialMessage +}: Props) => { + const { mode } = useColorScheme(); + const scrollableRef = React.useRef(null); + const [isLoading, setIsLoading] = useState(false); + const [currentParam, setCurrentParam] = useState(); + + const methods = useForm>({ + resolver: zodResolver(Schema), + defaultValues: {}, + }); + + const submit = async ({ query }: z.infer) => { + try { + setIsLoading(true); + methods.reset(); + await onSubmit(query, { + select_param: paramsList?.[currentParam] + }); + } catch (err) { + } finally { + setIsLoading(false); + } + }; + + const handleInitMessage = async () => { + try { + const searchParams = new URLSearchParams(window.location.search); + searchParams.delete('initMessage'); + window.history.replaceState(null, null, `?${searchParams.toString()}`); + await submit({ query: (initialMessage as string) }); + } catch (err) { + console.log(err); + } finally { + clearIntialMessage?.(); + } + } + + const options = { + overrides: { + code: ({ children }) => ( + + {children} + + ), + }, + }; + + React.useEffect(() => { + if (!scrollableRef.current) { + return; + } + + scrollableRef.current.scrollTo(0, scrollableRef.current.scrollHeight); + }, [messages?.length]); + + React.useEffect(() => { + if (initialMessage && messages.length <= 0) { + handleInitMessage(); + } + }, [initialMessage]); + + React.useEffect(() => { + if (paramsList && Object.keys(paramsList || {})?.length > 0) { + setCurrentParam(Object.keys(paramsList || {})?.[0]); + } + }, [paramsList]); + + return ( +
+ + + {messages.filter(item => ['view', 'human'].includes(item.role))?.map((each, index) => { + return ( + + ({ + background: each.role === 'view' ? 'var(--joy-palette-primary-softBg, var(--joy-palette-primary-100, #DDF1FF))': 'unset', + border: 'unset', + borderRadius: 'unset', + padding: '24px 0 26px 0', + lineHeight: '24px', + })} + > + +
+ {each.role === 'view' ? ( + + ) : ( + + )} +
+
+ + {each.context?.replaceAll('\\n', '\n')} + +
+
+
+
+ ) + })} + {isLoading && ( + + )} +
+ {!readOnly && ( + +
{ + e.stopPropagation(); + methods.handleSubmit(submit)(e); + }} + > + {(Object.keys(paramsList || {}).length > 0) && ( +
+ + +
+ )} + + + + + } + {...methods.register('query')} + /> + +
+ )} +
+
+ ); +} + +export default ChatBoxComp; diff --git a/datacenter/components/leftSider.tsx b/datacenter/components/leftSider.tsx index 04e7fe5c4..0dc412907 100644 --- a/datacenter/components/leftSider.tsx +++ b/datacenter/components/leftSider.tsx @@ -1,20 +1,21 @@ "use client"; import React, { useEffect, useMemo } from 'react'; -import { usePathname, useRouter } from 'next/navigation'; +import { usePathname, useRouter, useSearchParams } from 'next/navigation'; import Link from 'next/link'; -import { Popconfirm } from 'antd'; +import { Modal } from 'antd'; import { Box, List, ListItem, ListItemButton, ListItemDecorator, ListItemContent, Typography, Button, useColorScheme, IconButton } from '@/lib/mui'; import Article from '@mui/icons-material/Article'; import DarkModeIcon from '@mui/icons-material/DarkMode'; import WbSunnyIcon from '@mui/icons-material/WbSunny'; import MenuIcon from '@mui/icons-material/Menu'; import AddIcon from '@mui/icons-material/Add'; -import { useDialogueContext } from '@/app/context/dialogue'; +import SmsOutlinedIcon from '@mui/icons-material/SmsOutlined';import { useDialogueContext } from '@/app/context/dialogue'; import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined'; import { sendPostRequest } from '@/utils/request'; const LeftSider = () => { const pathname = usePathname(); + const searchParams = useSearchParams(); const router = useRouter(); const { dialogueList, queryDialogueList, refreshDialogList } = useDialogueContext(); const { mode, setMode } = useColorScheme(); @@ -44,7 +45,7 @@ const LeftSider = () => { return ( <> -
Name Vector OwnerDescription
- + {row.vector_type} - + {row.owner} + + {row.desc.length > 10 + ? `${row.desc.slice(0, 10)}...` + : row.desc} + +