mirror of
https://github.com/csunny/DB-GPT.git
synced 2025-08-09 12:18:12 +00:00
Merge branch 'new-page-framework' into dev_ty_06_end
This commit is contained in:
commit
1acac4045f
@ -1,3 +1,8 @@
|
|||||||
{
|
{
|
||||||
"extends": "next/core-web-vitals"
|
"extends": "next/core-web-vitals",
|
||||||
|
"rules": {
|
||||||
|
"indent": ["warning", 2, {
|
||||||
|
"SwitchCase": 1
|
||||||
|
}]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
25
datacenter/app/agents/[agentId]/page.tsx
Normal file
25
datacenter/app/agents/[agentId]/page.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
"use client"
|
||||||
|
import { useRequest } from 'ahooks';
|
||||||
|
import { sendGetRequest } from '@/utils/request';
|
||||||
|
import useAgentChat from '@/hooks/useAgentChat';
|
||||||
|
import ChatBoxComp from '@/components/chatBox';
|
||||||
|
|
||||||
|
const AgentPage = (props) => {
|
||||||
|
const { data: historyList } = useRequest(async () => await sendGetRequest('/v1/chat/dialogue/messages/history', {
|
||||||
|
con_uid: props.params?.agentId
|
||||||
|
}), {
|
||||||
|
ready: !!props.params?.agentId
|
||||||
|
});
|
||||||
|
|
||||||
|
const { handleChatSubmit, history } = useAgentChat({
|
||||||
|
queryAgentURL: `/v1/chat/completions`,
|
||||||
|
queryBody: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='mx-auto flex h-full max-w-3xl flex-col gap-6 px-5 pt-6 sm:gap-8 xl:max-w-4xl'>
|
||||||
|
<ChatBoxComp messages={historyList?.data || []} onSubmit={handleChatSubmit}/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default AgentPage;
|
@ -203,7 +203,7 @@ const Agents = () => {
|
|||||||
</Stack>
|
</Stack>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid xs={4}>
|
<Grid xs={4}>
|
||||||
<ChatBoxComp messages={history} onSubmit={handleChatSubmit}/>
|
<ChatBoxComp messages={[]} onSubmit={handleChatSubmit}/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</div>
|
</div>
|
||||||
|
@ -32,7 +32,7 @@ const ChunkList = () => {
|
|||||||
}, [])
|
}, [])
|
||||||
return (
|
return (
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<Table sx={{ '& thead th:nth-child(1)': { width: '40%' } }}>
|
<Table color="neutral" stripe="odd" variant="outlined">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
|
@ -10,11 +10,25 @@ import {
|
|||||||
Box,
|
Box,
|
||||||
Stack,
|
Stack,
|
||||||
Input,
|
Input,
|
||||||
|
Chip,
|
||||||
styled
|
styled
|
||||||
} from '@/lib/mui'
|
} from '@/lib/mui'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import { message } from 'antd'
|
import { InboxOutlined } from '@ant-design/icons'
|
||||||
|
import type { UploadProps } from 'antd'
|
||||||
|
import { Upload, message } from 'antd'
|
||||||
|
|
||||||
|
const { Dragger } = Upload
|
||||||
|
const Item = styled(Sheet)(({ theme }) => ({
|
||||||
|
width: '50%',
|
||||||
|
backgroundColor:
|
||||||
|
theme.palette.mode === 'dark' ? theme.palette.background.level1 : '#fff',
|
||||||
|
...theme.typography.body2,
|
||||||
|
padding: theme.spacing(1),
|
||||||
|
textAlign: 'center',
|
||||||
|
borderRadius: 4,
|
||||||
|
color: theme.vars.palette.text.secondary
|
||||||
|
}))
|
||||||
const stepsOfAddingDocument = [
|
const stepsOfAddingDocument = [
|
||||||
'Choose a Datasource type',
|
'Choose a Datasource type',
|
||||||
'Setup the Datasource'
|
'Setup the Datasource'
|
||||||
@ -36,16 +50,6 @@ const documentTypeList = [
|
|||||||
subTitle: 'It can be: PDF, CSV, JSON, Text, PowerPoint, Word, Excel'
|
subTitle: 'It can be: PDF, CSV, JSON, Text, PowerPoint, Word, Excel'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
const Item = styled(Sheet)(({ theme }) => ({
|
|
||||||
width: '50%',
|
|
||||||
backgroundColor:
|
|
||||||
theme.palette.mode === 'dark' ? theme.palette.background.level1 : '#fff',
|
|
||||||
...theme.typography.body2,
|
|
||||||
padding: theme.spacing(1),
|
|
||||||
textAlign: 'center',
|
|
||||||
borderRadius: 4,
|
|
||||||
color: theme.vars.palette.text.secondary
|
|
||||||
}))
|
|
||||||
|
|
||||||
const Documents = () => {
|
const Documents = () => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@ -53,9 +57,25 @@ const Documents = () => {
|
|||||||
const [isAddDocumentModalShow, setIsAddDocumentModalShow] =
|
const [isAddDocumentModalShow, setIsAddDocumentModalShow] =
|
||||||
useState<boolean>(false)
|
useState<boolean>(false)
|
||||||
const [activeStep, setActiveStep] = useState<number>(0)
|
const [activeStep, setActiveStep] = useState<number>(0)
|
||||||
|
const [documentType, setDocumentType] = useState<string>('')
|
||||||
const [documents, setDocuments] = useState<any>([])
|
const [documents, setDocuments] = useState<any>([])
|
||||||
const [webPageUrl, setWebPageUrl] = useState<string>('')
|
const [webPageUrl, setWebPageUrl] = useState<string>('')
|
||||||
const [documentName, setDocumentName] = useState<string>('')
|
const [documentName, setDocumentName] = useState<any>('')
|
||||||
|
const [originFileObj, setOriginFileObj] = useState<any>(null)
|
||||||
|
const props: UploadProps = {
|
||||||
|
name: 'file',
|
||||||
|
multiple: false,
|
||||||
|
onChange(info) {
|
||||||
|
console.log(info)
|
||||||
|
if (info.fileList.length === 0) {
|
||||||
|
setOriginFileObj(null)
|
||||||
|
setDocumentName('')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setOriginFileObj(info.file.originFileObj)
|
||||||
|
setDocumentName(info.file.originFileObj?.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchDocuments() {
|
async function fetchDocuments() {
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
@ -90,7 +110,7 @@ const Documents = () => {
|
|||||||
+ Add Datasource
|
+ Add Datasource
|
||||||
</Button>
|
</Button>
|
||||||
</Sheet>
|
</Sheet>
|
||||||
<Table sx={{ '& thead th:nth-child(1)': { width: '40%' } }}>
|
<Table color="neutral" stripe="odd" variant="outlined">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
@ -108,12 +128,30 @@ const Documents = () => {
|
|||||||
<td>{row.doc_type}</td>
|
<td>{row.doc_type}</td>
|
||||||
<td>{row.chunk_size}</td>
|
<td>{row.chunk_size}</td>
|
||||||
<td>{moment(row.last_sync).format('YYYY-MM-DD HH:MM:SS')}</td>
|
<td>{moment(row.last_sync).format('YYYY-MM-DD HH:MM:SS')}</td>
|
||||||
<td>{row.status}</td>
|
<td>
|
||||||
|
<Chip
|
||||||
|
color={(function () {
|
||||||
|
switch (row.status) {
|
||||||
|
case 'TODO':
|
||||||
|
return 'neutral'
|
||||||
|
case 'RUNNING':
|
||||||
|
return 'primary'
|
||||||
|
case 'FINISHED':
|
||||||
|
return 'success'
|
||||||
|
case 'FAILED':
|
||||||
|
return 'danger'
|
||||||
|
}
|
||||||
|
})()}
|
||||||
|
>
|
||||||
|
{row.status}
|
||||||
|
</Chip>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{
|
{
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
size="sm"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
`http://localhost:8000/knowledge/${spaceName}/document/sync`,
|
`http://localhost:8000/knowledge/${spaceName}/document/sync`,
|
||||||
@ -139,6 +177,7 @@ const Documents = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
size="sm"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
router.push(
|
router.push(
|
||||||
`/datastores/documents/chunklist?spacename=${spaceName}&documentid=${row.id}`
|
`/datastores/documents/chunklist?spacename=${spaceName}&documentid=${row.id}`
|
||||||
@ -204,9 +243,8 @@ const Documents = () => {
|
|||||||
cursor: 'pointer'
|
cursor: 'pointer'
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (item.type === 'webPage') {
|
setDocumentType(item.type)
|
||||||
setActiveStep(1)
|
setActiveStep(1)
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Sheet sx={{ fontSize: '20px', fontWeight: 'bold' }}>
|
<Sheet sx={{ fontSize: '20px', fontWeight: 'bold' }}>
|
||||||
@ -227,10 +265,36 @@ const Documents = () => {
|
|||||||
sx={{ marginBottom: '20px' }}
|
sx={{ marginBottom: '20px' }}
|
||||||
/>
|
/>
|
||||||
Web Page URL:
|
Web Page URL:
|
||||||
<Input
|
{documentType === 'webPage' ? (
|
||||||
placeholder="Please input the Web Page URL"
|
<>
|
||||||
onChange={(e: any) => setWebPageUrl(e.target.value)}
|
Web Page URL:
|
||||||
/>
|
<Input
|
||||||
|
placeholder="Please input the Web Page URL"
|
||||||
|
onChange={(e: any) => setWebPageUrl(e.target.value)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : documentType === 'file' ? (
|
||||||
|
<>
|
||||||
|
<Dragger {...props}>
|
||||||
|
<p className="ant-upload-drag-icon">
|
||||||
|
<InboxOutlined />
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
style={{ color: 'rgb(22, 108, 255)', fontSize: '20px' }}
|
||||||
|
>
|
||||||
|
Select or Drop file
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
className="ant-upload-hint"
|
||||||
|
style={{ color: 'rgb(22, 108, 255)' }}
|
||||||
|
>
|
||||||
|
PDF, PowerPoint, Excel, Word, Text, Markdown,
|
||||||
|
</p>
|
||||||
|
</Dragger>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
<Button
|
<Button
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
@ -238,44 +302,83 @@ const Documents = () => {
|
|||||||
message.error('Please input the name')
|
message.error('Please input the name')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (webPageUrl === '') {
|
if (documentType === 'webPage') {
|
||||||
message.error('Please input the Web Page URL')
|
if (webPageUrl === '') {
|
||||||
return
|
message.error('Please input the Web Page URL')
|
||||||
}
|
return
|
||||||
const res = await fetch(
|
|
||||||
`http://localhost:8000/knowledge/${spaceName}/document/add`,
|
|
||||||
{
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
doc_name: documentName,
|
|
||||||
content: webPageUrl,
|
|
||||||
doc_type: 'URL'
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
)
|
|
||||||
const data = await res.json()
|
|
||||||
if (data.success) {
|
|
||||||
message.success('success')
|
|
||||||
setIsAddDocumentModalShow(false)
|
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
`http://localhost:8000/knowledge/${spaceName}/document/list`,
|
`http://localhost:8000/knowledge/${spaceName}/document/add`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({})
|
body: JSON.stringify({
|
||||||
|
doc_name: documentName,
|
||||||
|
content: webPageUrl,
|
||||||
|
doc_type: 'URL'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
setDocuments(data.data)
|
message.success('success')
|
||||||
|
setIsAddDocumentModalShow(false)
|
||||||
|
const res = await fetch(
|
||||||
|
`http://localhost:8000/knowledge/${spaceName}/document/list`,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const data = await res.json()
|
||||||
|
if (data.success) {
|
||||||
|
setDocuments(data.data)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.error(data.err_msg || 'failed')
|
||||||
|
}
|
||||||
|
} else if (documentType === 'file') {
|
||||||
|
if (!originFileObj) {
|
||||||
|
message.error('Please select a file')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('doc_name', documentName);
|
||||||
|
formData.append('doc_file', originFileObj);
|
||||||
|
formData.append('doc_type', 'DOCUMENT');
|
||||||
|
const res = await fetch(
|
||||||
|
`http://localhost:8000/knowledge/${spaceName}/document/upload`,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const data = await res.json()
|
||||||
|
if (data.success) {
|
||||||
|
message.success('success')
|
||||||
|
setIsAddDocumentModalShow(false)
|
||||||
|
const res = await fetch(
|
||||||
|
`http://localhost:8000/knowledge/${spaceName}/document/list`,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const data = await res.json()
|
||||||
|
if (data.success) {
|
||||||
|
setDocuments(data.data)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.error(data.err_msg || 'failed')
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
message.error(data.err_msg || 'failed')
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import { message } from 'antd'
|
import { InboxOutlined } from '@ant-design/icons'
|
||||||
|
import type { UploadProps } from 'antd'
|
||||||
|
import { message, Upload } from 'antd'
|
||||||
import {
|
import {
|
||||||
Modal,
|
Modal,
|
||||||
Button,
|
Button,
|
||||||
@ -14,6 +16,8 @@ import {
|
|||||||
styled
|
styled
|
||||||
} from '@/lib/mui'
|
} from '@/lib/mui'
|
||||||
|
|
||||||
|
const { Dragger } = Upload
|
||||||
|
|
||||||
const Item = styled(Sheet)(({ theme }) => ({
|
const Item = styled(Sheet)(({ theme }) => ({
|
||||||
width: '33%',
|
width: '33%',
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
@ -51,12 +55,28 @@ const documentTypeList = [
|
|||||||
const Index = () => {
|
const Index = () => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const [activeStep, setActiveStep] = useState<number>(0)
|
const [activeStep, setActiveStep] = useState<number>(0)
|
||||||
|
const [documentType, setDocumentType] = useState<string>('')
|
||||||
const [knowledgeSpaceList, setKnowledgeSpaceList] = useState<any>([])
|
const [knowledgeSpaceList, setKnowledgeSpaceList] = useState<any>([])
|
||||||
const [isAddKnowledgeSpaceModalShow, setIsAddKnowledgeSpaceModalShow] =
|
const [isAddKnowledgeSpaceModalShow, setIsAddKnowledgeSpaceModalShow] =
|
||||||
useState<boolean>(false)
|
useState<boolean>(false)
|
||||||
const [knowledgeSpaceName, setKnowledgeSpaceName] = useState<string>('')
|
const [knowledgeSpaceName, setKnowledgeSpaceName] = useState<string>('')
|
||||||
const [webPageUrl, setWebPageUrl] = useState<string>('')
|
const [webPageUrl, setWebPageUrl] = useState<string>('')
|
||||||
const [documentName, setDocumentName] = useState<string>('')
|
const [documentName, setDocumentName] = useState<any>('')
|
||||||
|
const [originFileObj, setOriginFileObj] = useState<any>(null)
|
||||||
|
const props: UploadProps = {
|
||||||
|
name: 'file',
|
||||||
|
multiple: false,
|
||||||
|
onChange(info) {
|
||||||
|
console.log(info)
|
||||||
|
if (info.fileList.length === 0) {
|
||||||
|
setOriginFileObj(null)
|
||||||
|
setDocumentName('')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setOriginFileObj(info.file.originFileObj)
|
||||||
|
setDocumentName(info.file.originFileObj?.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchData() {
|
async function fetchData() {
|
||||||
const res = await fetch('http://localhost:8000/knowledge/space/list', {
|
const res = await fetch('http://localhost:8000/knowledge/space/list', {
|
||||||
@ -75,14 +95,21 @@ const Index = () => {
|
|||||||
}, [])
|
}, [])
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Sheet sx={{
|
<Sheet
|
||||||
display: "flex",
|
sx={{
|
||||||
justifyContent: "space-between"
|
display: 'flex',
|
||||||
}} className="p-4">
|
justifyContent: 'space-between'
|
||||||
<Sheet sx={{
|
}}
|
||||||
fontSize: '30px',
|
className="p-4"
|
||||||
fontWeight: 'bold'
|
>
|
||||||
}}>Knowledge Spaces</Sheet>
|
<Sheet
|
||||||
|
sx={{
|
||||||
|
fontSize: '30px',
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Knowledge Spaces
|
||||||
|
</Sheet>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => setIsAddKnowledgeSpaceModalShow(true)}
|
onClick={() => setIsAddKnowledgeSpaceModalShow(true)}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@ -91,7 +118,7 @@ const Index = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Sheet>
|
</Sheet>
|
||||||
<div className="page-body p-4">
|
<div className="page-body p-4">
|
||||||
<Table sx={{ '& thead th:nth-child(1)': { width: '40%' } }}>
|
<Table color="neutral" stripe="odd" variant="outlined">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
@ -218,7 +245,7 @@ const Index = () => {
|
|||||||
sx={{
|
sx={{
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
height: '80px',
|
height: '80px',
|
||||||
padding: '12px',
|
padding: '12px',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
@ -228,12 +255,13 @@ const Index = () => {
|
|||||||
cursor: 'pointer'
|
cursor: 'pointer'
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (item.type === 'webPage') {
|
setDocumentType(item.type)
|
||||||
setActiveStep(2);
|
setActiveStep(2)
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Sheet sx={{ fontSize: '20px', fontWeight: 'bold' }}>{item.title}</Sheet>
|
<Sheet sx={{ fontSize: '20px', fontWeight: 'bold' }}>
|
||||||
|
{item.title}
|
||||||
|
</Sheet>
|
||||||
<Sheet>{item.subTitle}</Sheet>
|
<Sheet>{item.subTitle}</Sheet>
|
||||||
</Sheet>
|
</Sheet>
|
||||||
))}
|
))}
|
||||||
@ -246,44 +274,94 @@ const Index = () => {
|
|||||||
<Input
|
<Input
|
||||||
placeholder="Please input the name"
|
placeholder="Please input the name"
|
||||||
onChange={(e: any) => setDocumentName(e.target.value)}
|
onChange={(e: any) => setDocumentName(e.target.value)}
|
||||||
sx={{ marginBottom: '20px'}}
|
sx={{ marginBottom: '20px' }}
|
||||||
/>
|
|
||||||
Web Page URL:
|
|
||||||
<Input
|
|
||||||
placeholder="Please input the Web Page URL"
|
|
||||||
onChange={(e: any) => setWebPageUrl(e.target.value)}
|
|
||||||
/>
|
/>
|
||||||
|
{documentType === 'webPage' ? (
|
||||||
|
<>
|
||||||
|
Web Page URL:
|
||||||
|
<Input
|
||||||
|
placeholder="Please input the Web Page URL"
|
||||||
|
onChange={(e: any) => setWebPageUrl(e.target.value)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : documentType === 'file' ? (
|
||||||
|
<>
|
||||||
|
<Dragger {...props}>
|
||||||
|
<p className="ant-upload-drag-icon">
|
||||||
|
<InboxOutlined />
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
style={{ color: 'rgb(22, 108, 255)', fontSize: '20px' }}
|
||||||
|
>
|
||||||
|
Select or Drop file
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
className="ant-upload-hint"
|
||||||
|
style={{ color: 'rgb(22, 108, 255)' }}
|
||||||
|
>
|
||||||
|
PDF, PowerPoint, Excel, Word, Text, Markdown,
|
||||||
|
</p>
|
||||||
|
</Dragger>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
<Button
|
<Button
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
if (documentName === '') {
|
if (documentName === '') {
|
||||||
message.error('Please input the name');
|
message.error('Please input the name')
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
if (webPageUrl === '') {
|
if (documentType === 'webPage') {
|
||||||
message.error('Please input the Web Page URL');
|
if (webPageUrl === '') {
|
||||||
return;
|
message.error('Please input the Web Page URL')
|
||||||
}
|
return
|
||||||
const res = await fetch(
|
}
|
||||||
`http://localhost:8000/knowledge/${knowledgeSpaceName}/document/add`,
|
const res = await fetch(
|
||||||
{
|
`http://localhost:8000/knowledge/${knowledgeSpaceName}/document/add`,
|
||||||
method: 'POST',
|
{
|
||||||
headers: {
|
method: 'POST',
|
||||||
'Content-Type': 'application/json'
|
headers: {
|
||||||
},
|
'Content-Type': 'application/json'
|
||||||
body: JSON.stringify({
|
},
|
||||||
doc_name: documentName,
|
body: JSON.stringify({
|
||||||
content: webPageUrl,
|
doc_name: documentName,
|
||||||
doc_type: 'URL'
|
content: webPageUrl,
|
||||||
})
|
doc_type: 'URL'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const data = await res.json()
|
||||||
|
if (data.success) {
|
||||||
|
message.success('success')
|
||||||
|
setIsAddKnowledgeSpaceModalShow(false)
|
||||||
|
} else {
|
||||||
|
message.error(data.err_msg || 'failed')
|
||||||
|
}
|
||||||
|
} else if (documentType === 'file') {
|
||||||
|
if (!originFileObj) {
|
||||||
|
message.error('Please select a file')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('doc_name', documentName);
|
||||||
|
formData.append('doc_file', originFileObj);
|
||||||
|
formData.append('doc_type', 'DOCUMENT');
|
||||||
|
const res = await fetch(
|
||||||
|
`http://localhost:8000/knowledge/${knowledgeSpaceName}/document/upload`,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const data = await res.json()
|
||||||
|
if (data.success) {
|
||||||
|
message.success('success')
|
||||||
|
setIsAddKnowledgeSpaceModalShow(false)
|
||||||
|
} else {
|
||||||
|
message.error(data.err_msg || 'failed')
|
||||||
}
|
}
|
||||||
)
|
|
||||||
const data = await res.json()
|
|
||||||
if (data.success) {
|
|
||||||
message.success('success')
|
|
||||||
setIsAddKnowledgeSpaceModalShow(false)
|
|
||||||
} else {
|
|
||||||
message.error(data.err_msg || 'failed')
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -10,7 +10,7 @@ export const joyTheme = extendTheme({
|
|||||||
...colors.purple,
|
...colors.purple,
|
||||||
},
|
},
|
||||||
neutral: {
|
neutral: {
|
||||||
plainColor: '#25252D',
|
plainColor: '#4d4d4d',
|
||||||
plainHoverColor: '#131318',
|
plainHoverColor: '#131318',
|
||||||
plainHoverBg: '#EBEBEF',
|
plainHoverBg: '#EBEBEF',
|
||||||
plainActiveBg: '#D8D8DF',
|
plainActiveBg: '#D8D8DF',
|
||||||
@ -42,7 +42,7 @@ export const joyTheme = extendTheme({
|
|||||||
primary: '#EBEBEF'
|
primary: '#EBEBEF'
|
||||||
},
|
},
|
||||||
background: {
|
background: {
|
||||||
body: '#09090D',
|
body: '#0f172a',
|
||||||
surface: '#1e293b40'
|
surface: '#1e293b40'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -2,9 +2,6 @@
|
|||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
a {
|
|
||||||
color: #1677ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -10,20 +10,21 @@ export default function RootLayout({
|
|||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang="en" className="min-h-full font-sans">
|
<html lang="en" className="h-full font-sans">
|
||||||
<body className={`min-h-screen font-sans`}>
|
<body className={`h-full font-sans`}>
|
||||||
<ThemeProvider theme={joyTheme}>
|
<ThemeProvider theme={joyTheme}>
|
||||||
<CssVarsProvider theme={joyTheme} defaultMode="light">
|
<CssVarsProvider theme={joyTheme} defaultMode="light">
|
||||||
<TopProgressBar />
|
<TopProgressBar />
|
||||||
<div className='min-h-screen flex flex-col'>
|
<div className={`contents h-full`}>
|
||||||
<div className="flex flex-1 flex-row">
|
<div className="grid h-full w-screen grid-cols-1 grid-rows-[auto,1fr] overflow-hidden text-smd dark:text-gray-300 md:grid-cols-[280px,1fr] md:grid-rows-[1fr]">
|
||||||
<LeftSider />
|
<LeftSider />
|
||||||
<div className='flex-1 overflow-auto'>{children}</div>
|
<div className='relative min-h-0 min-w-0'>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</CssVarsProvider>
|
</CssVarsProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</body>
|
</body>
|
||||||
|
@ -1,267 +1,98 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
import { useState } from 'react';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import { Button, Input, useColorScheme } from '@/lib/mui';
|
||||||
import { Collapse } from 'antd';
|
import IconButton from '@mui/joy/IconButton';
|
||||||
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
|
import SendRoundedIcon from '@mui/icons-material/SendRounded';
|
||||||
import { Box, Slider, Input, Tabs, TabList, Typography, TabPanel, Tab, RadioGroup, Radio, tabClasses, useColorScheme, radioClasses } from '@/lib/mui';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { sendGetRequest } from '@/utils/request';
|
import { useForm } from 'react-hook-form';
|
||||||
import { useEffect, useState } from 'react';
|
import { z } from 'zod';
|
||||||
import ChatBoxComp from '@/components/chatBox';
|
import { sendPostRequest } from '@/utils/request';
|
||||||
import useAgentChat from '@/hooks/useAgentChat';
|
import { useRouter } from 'next/navigation';
|
||||||
|
import { useQueryDialog } from '@/hooks/useQueryDialogue';
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const [temperatureNum, setTemperatureNum] = useState(3);
|
const Schema = z.object({ query: z.string().min(1) });
|
||||||
const [tokenSize, setTokenSize] = useState(0);
|
const router = useRouter();
|
||||||
const { mode, setMode } = useColorScheme();
|
const { mode } = useColorScheme();
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const { handleChatSubmit, history } = useAgentChat({
|
const methods = useForm<z.infer<typeof Schema>>({
|
||||||
queryAgentURL: `/api/agents/query`,
|
resolver: zodResolver(Schema),
|
||||||
|
defaultValues: {},
|
||||||
});
|
});
|
||||||
|
const { refreshDialogList } = useQueryDialog();
|
||||||
|
const submit = async ({ query }: z.infer<typeof Schema>) => {
|
||||||
|
try {
|
||||||
|
setIsLoading(true);
|
||||||
|
methods.reset();
|
||||||
|
const res = await sendPostRequest('/v1/chat/dialogue/new', {
|
||||||
|
chat_mode: 'chat_normal'
|
||||||
|
});
|
||||||
|
if (res?.success && res?.data?.conv_uid) {
|
||||||
|
// router.push(`/agents/${res?.data?.conv_uid}?newMessage=${query}`);
|
||||||
|
// await refreshDialogList();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleGetD = () => {
|
|
||||||
sendGetRequest('/v1/chat/dialogue/list', {
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
handleGetD();
|
|
||||||
}, []);
|
|
||||||
return (
|
return (
|
||||||
<div className='p-6 w-full h-full text-sm flex flex-col gap-4'>
|
<>
|
||||||
<ReactMarkdown linkTarget={'_blank'}>
|
<div className={`${mode} absolute z-20 top-0 inset-x-0 flex justify-center overflow-hidden pointer-events-none`}>
|
||||||
[DB-GPT](https://github.com/csunny/DB-GPT) 是一个开源的以数据库为基础的GPT实验项目,使用本地化的GPT大模型与您的数据和环境进行交互,无数据泄露风险,100% 私密,100% 安全。
|
<div className='w-[108rem] flex-none flex justify-end'>
|
||||||
</ReactMarkdown>
|
<picture>
|
||||||
<Box
|
<source srcSet='/bg1.avif' type='image/avif'></source>
|
||||||
sx={{
|
<img srcSet='/bg2.png' alt="" className='w-[71.75rem] flex-none max-w-none '/>
|
||||||
'& .ant-collapse': {
|
</picture>
|
||||||
backgroundColor: 'var(--joy-palette-background-level1)',
|
</div>
|
||||||
color: 'var(--joy-palette-neutral-plainColor)'
|
</div>
|
||||||
},
|
<div className='mx-auto flex h-full max-w-3xl flex-col gap-6 px-5 pt-6 sm:gap-8 xl:max-w-4xl'>
|
||||||
'& .ant-collapse>.ant-collapse-item >.ant-collapse-header, & .ant-collapse .ant-collapse-content': {
|
<div className='lg:my-auto grid gap-8 lg:grid-cols-3'>
|
||||||
color: 'var(--joy-palette-neutral-plainColor)'
|
<div className='lg:col-span-3 lg:mt-12'>
|
||||||
},
|
<p className='mb-3'>Scenes</p>
|
||||||
'& .ant-collapse .ant-collapse-content>.ant-collapse-content-box': {
|
<div className='grid gap-2 lg:grid-cols-4 lg:gap-5'>
|
||||||
paddingTop: 0
|
<Button size="md" variant="soft">LLM native dialogue</Button>
|
||||||
}
|
<Button size="md" variant="soft">Default documents</Button>
|
||||||
}}
|
<Button size="md" variant="soft">New documents</Button>
|
||||||
>
|
<Button size="md" variant="soft">Chat with url</Button>
|
||||||
<Collapse
|
|
||||||
collapsible="header"
|
|
||||||
defaultActiveKey={['1']}
|
|
||||||
ghost
|
|
||||||
bordered
|
|
||||||
expandIcon={({ isActive }) => (
|
|
||||||
<div className={`text-2xl cursor-pointer ${isActive ? 'rotate-0' : 'rotate-90'}`}>
|
|
||||||
<ArrowDropDownIcon />
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
expandIconPosition="end"
|
</div>
|
||||||
items={[
|
<div className='h-60 flex-none'></div>
|
||||||
{
|
</div>
|
||||||
key: '1',
|
<div className='pointer-events-none absolute inset-x-0 bottom-0 z-0 mx-auto flex w-full max-w-3xl flex-col items-center justify-center px-3.5 py-4 max-md:border-t sm:px-5 md:py-8 xl:max-w-4xl [&>*]:pointer-events-auto'>
|
||||||
label: 'This panel can only be collapsed by clicking text',
|
<form
|
||||||
children: (
|
style={{
|
||||||
<>
|
maxWidth: '100%',
|
||||||
<Box
|
width: '100%',
|
||||||
className="p-4 border"
|
position: 'relative',
|
||||||
sx={{
|
display: 'flex',
|
||||||
borderColor: 'var(--joy-palette-background-level2)',
|
marginTop: 'auto',
|
||||||
}}
|
overflow: 'visible',
|
||||||
>
|
background: 'none',
|
||||||
<div className='flex flex-row justify-between items-center'>
|
justifyContent: 'center',
|
||||||
<span>Temperature</span>
|
marginLeft: 'auto',
|
||||||
<Input
|
marginRight: 'auto',
|
||||||
size='sm'
|
}}
|
||||||
type="number"
|
onSubmit={(e) => {
|
||||||
value={temperatureNum / 10}
|
methods.handleSubmit(submit)(e);
|
||||||
onChange={(e) => {
|
}}
|
||||||
setTemperatureNum(Number(e.target.value) * 10);
|
|
||||||
}}
|
|
||||||
slotProps={{
|
|
||||||
input: {
|
|
||||||
min: 0,
|
|
||||||
max: 1,
|
|
||||||
step: 0.1,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Slider
|
|
||||||
color="info"
|
|
||||||
value={temperatureNum}
|
|
||||||
max={10}
|
|
||||||
onChange={(e, value) => {
|
|
||||||
setTemperatureNum(value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Box
|
|
||||||
className="p-4 border border-t-0"
|
|
||||||
sx={{
|
|
||||||
borderColor: 'var(--joy-palette-background-level2)',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className='flex flex-row justify-between items-center'>
|
|
||||||
<span>Maximum output token size</span>
|
|
||||||
<Input
|
|
||||||
size="sm"
|
|
||||||
type="number"
|
|
||||||
value={tokenSize}
|
|
||||||
onChange={(e) => {
|
|
||||||
setTokenSize(Number(e.target.value));
|
|
||||||
}}
|
|
||||||
slotProps={{
|
|
||||||
input: {
|
|
||||||
min: 0,
|
|
||||||
max: 1024,
|
|
||||||
step: 64,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Slider
|
|
||||||
color="info"
|
|
||||||
value={tokenSize}
|
|
||||||
max={1024}
|
|
||||||
step={64}
|
|
||||||
onChange={(e, value) => {
|
|
||||||
setTokenSize(value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Tabs
|
|
||||||
className='w-full'
|
|
||||||
aria-label="Pricing plan"
|
|
||||||
defaultValue={0}
|
|
||||||
sx={(theme) => ({
|
|
||||||
'--Tabs-gap': '0px',
|
|
||||||
borderRadius: 'unset',
|
|
||||||
boxShadow: 'sm',
|
|
||||||
overflow: 'auto',
|
|
||||||
WebkitBoxShadow: 'none'
|
|
||||||
})}
|
|
||||||
>
|
>
|
||||||
<TabList
|
<Input
|
||||||
sx={{
|
sx={{ width: '100%' }}
|
||||||
'--ListItem-radius': '0px',
|
variant="outlined"
|
||||||
borderRadius: 0,
|
placeholder='Ask anything'
|
||||||
bgcolor: 'background.body',
|
endDecorator={
|
||||||
[`& .${tabClasses.root}`]: {
|
<IconButton type="submit" disabled={isLoading}>
|
||||||
fontWeight: 'lg',
|
<SendRoundedIcon />
|
||||||
flex: 'unset',
|
</IconButton>
|
||||||
position: 'relative',
|
}
|
||||||
[`&.${tabClasses.selected}`]: {
|
{...methods.register('query')}
|
||||||
border: '1px solid var(--joy-palette-background-level2)',
|
/>
|
||||||
borderTopLeftRadius: '8px',
|
</form>
|
||||||
borderTopRightRadius: '8px',
|
</div>
|
||||||
},
|
</>
|
||||||
[`&.${tabClasses.selected}:before`]: {
|
|
||||||
content: '""',
|
|
||||||
display: 'block',
|
|
||||||
position: 'absolute',
|
|
||||||
bottom: -4,
|
|
||||||
width: '100%',
|
|
||||||
height: 6,
|
|
||||||
bgcolor: mode == 'dark' ? '#000' : 'var(--joy-palette-background-surface)',
|
|
||||||
},
|
|
||||||
[`&.${tabClasses.focusVisible}`]: {
|
|
||||||
outlineOffset: '-3px',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Tab sx={{ py: 1.5 }}>Documents Chat</Tab>
|
|
||||||
<Tab>SQL Generation & Diagnostics</Tab>
|
|
||||||
<Tab>Plugin Mode</Tab>
|
|
||||||
</TabList>
|
|
||||||
<TabPanel
|
|
||||||
value={0}
|
|
||||||
sx={{
|
|
||||||
p: 3,
|
|
||||||
border: '1px solid var(--joy-palette-background-level2)',
|
|
||||||
borderBottomLeftRadius: '8px',
|
|
||||||
borderBottomRightRadius: '8px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<RadioGroup
|
|
||||||
orientation="horizontal"
|
|
||||||
defaultValue="LLM native dialogue"
|
|
||||||
name="radio-buttons-group"
|
|
||||||
className='gap-3 p-3'
|
|
||||||
sx={{
|
|
||||||
backgroundColor: 'var(--joy-palette-background-level1)',
|
|
||||||
'& .MuiRadio-radio': {
|
|
||||||
borderColor: '#707070'
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box className="px-2 py-1 border rounded" sx={{ borderColor: 'var(--joy-palette-background-level2)' }}>
|
|
||||||
<Radio value="LLM native dialogue" label="LLM native dialogue" variant="outlined"
|
|
||||||
sx={{
|
|
||||||
borderColor: 'var(--joy-palette-neutral-outlinedHoverColor)',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Box className="px-2 py-1 border rounded" sx={{ borderColor: 'var(--joy-palette-background-level2)' }}>
|
|
||||||
<Radio value="Default documents" label="Default documents" variant="outlined" />
|
|
||||||
</Box>
|
|
||||||
<Box className="px-2 py-1 border rounded" sx={{ borderColor: 'var(--joy-palette-background-level2)' }}>
|
|
||||||
<Radio value="New documents" label="New documents" variant="outlined" />
|
|
||||||
</Box>
|
|
||||||
<Box className="px-2 py-1 border rounded" sx={{ borderColor: 'var(--joy-palette-background-level2)' }}>
|
|
||||||
<Radio value="Chat with url" label="Chat with url" variant="outlined" />
|
|
||||||
</Box>
|
|
||||||
</RadioGroup>
|
|
||||||
</TabPanel>
|
|
||||||
<TabPanel value={1} sx={{ p: 3 }}>
|
|
||||||
<Typography level="inherit">
|
|
||||||
Best for professional developers building enterprise or data-rich
|
|
||||||
applications.
|
|
||||||
</Typography>
|
|
||||||
<Typography textColor="primary.400" fontSize="xl3" fontWeight="xl" my={1}>
|
|
||||||
$15{' '}
|
|
||||||
<Typography fontSize="sm" textColor="text.secondary" fontWeight="md">
|
|
||||||
/ dev / month
|
|
||||||
</Typography>
|
|
||||||
</Typography>
|
|
||||||
</TabPanel>
|
|
||||||
<TabPanel value={2} sx={{ p: 3 }}>
|
|
||||||
<Typography level="inherit">
|
|
||||||
The most advanced features for data-rich applications, as well as the
|
|
||||||
highest priority for support.
|
|
||||||
</Typography>
|
|
||||||
<Typography textColor="primary.400" fontSize="xl3" fontWeight="xl" my={1}>
|
|
||||||
<Typography
|
|
||||||
fontSize="xl"
|
|
||||||
borderRadius="sm"
|
|
||||||
px={0.5}
|
|
||||||
mr={0.5}
|
|
||||||
sx={(theme) => ({
|
|
||||||
...theme.variants.soft.danger,
|
|
||||||
color: 'danger.400',
|
|
||||||
verticalAlign: 'text-top',
|
|
||||||
textDecoration: 'line-through',
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
$49
|
|
||||||
</Typography>
|
|
||||||
$37*{' '}
|
|
||||||
<Typography fontSize="sm" textColor="text.secondary" fontWeight="md">
|
|
||||||
/ dev / month
|
|
||||||
</Typography>
|
|
||||||
</Typography>
|
|
||||||
</TabPanel>
|
|
||||||
</Tabs>
|
|
||||||
</Box>
|
|
||||||
<ChatBoxComp messages={history} onSubmit={handleChatSubmit}/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ type Props = {
|
|||||||
messages: Message[];
|
messages: Message[];
|
||||||
onSubmit: (message: string) => Promise<any>;
|
onSubmit: (message: string) => Promise<any>;
|
||||||
messageTemplates?: string[];
|
messageTemplates?: string[];
|
||||||
initialMessage?: string;
|
initialMessage?: Message;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ const ChatBoxComp = ({
|
|||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setFirstMsg(
|
setFirstMsg(
|
||||||
initialMessage ? { from: 'agent', message: initialMessage } : undefined
|
initialMessage ? initialMessage : undefined
|
||||||
);
|
);
|
||||||
}, 0);
|
}, 0);
|
||||||
}, [initialMessage]);
|
}, [initialMessage]);
|
||||||
@ -112,7 +112,7 @@ const ChatBoxComp = ({
|
|||||||
whiteSpace: 'pre-wrap',
|
whiteSpace: 'pre-wrap',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{firstMsg?.message}
|
{firstMsg?.context}
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -120,17 +120,17 @@ const ChatBoxComp = ({
|
|||||||
<Stack
|
<Stack
|
||||||
key={index}
|
key={index}
|
||||||
sx={{
|
sx={{
|
||||||
mr: each.from === 'agent' ? 'auto' : 'none',
|
mr: each.role === 'ai' ? 'auto' : 'none',
|
||||||
ml: each.from === 'human' ? 'auto' : 'none',
|
ml: each.role === 'human' ? 'auto' : 'none',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
size="sm"
|
size="sm"
|
||||||
variant={'outlined'}
|
variant={'outlined'}
|
||||||
className={
|
className={
|
||||||
each.from === 'agent' ? 'message-agent' : 'message-human'
|
each.role === 'ai' ? 'message-agent' : 'message-human'
|
||||||
}
|
}
|
||||||
color={each.from === 'agent' ? 'primary' : 'neutral'}
|
color={each.role === 'ai' ? 'primary' : 'neutral'}
|
||||||
sx={(theme) => ({
|
sx={(theme) => ({
|
||||||
px: 2,
|
px: 2,
|
||||||
'ol, ul': {
|
'ol, ul': {
|
||||||
@ -153,7 +153,7 @@ const ChatBoxComp = ({
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<ReactMarkdown remarkPlugins={[remarkGfm]} linkTarget={'_blank'}>
|
<ReactMarkdown remarkPlugins={[remarkGfm]} linkTarget={'_blank'}>
|
||||||
{each.message}
|
{each.context}
|
||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
</Card>
|
</Card>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
@ -3,42 +3,26 @@ import React, { useMemo, useState } from 'react';
|
|||||||
import { usePathname } from 'next/navigation';
|
import { usePathname } from 'next/navigation';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { Box, List, ListItem, ListItemButton, ListItemDecorator, ListItemContent, Typography, Button, useColorScheme } from '@/lib/mui';
|
import { Box, List, ListItem, ListItemButton, ListItemDecorator, ListItemContent, Typography, Button, useColorScheme, Alert } from '@/lib/mui';
|
||||||
import SmartToyRoundedIcon from '@mui/icons-material/SmartToyRounded'; // Icons import
|
import SmartToyRoundedIcon from '@mui/icons-material/SmartToyRounded'; // Icons import
|
||||||
import StorageRoundedIcon from '@mui/icons-material/StorageRounded';
|
import StorageRoundedIcon from '@mui/icons-material/StorageRounded';
|
||||||
import DarkModeIcon from '@mui/icons-material/DarkMode';
|
import DarkModeIcon from '@mui/icons-material/DarkMode';
|
||||||
import WbSunnyIcon from '@mui/icons-material/WbSunny';
|
import WbSunnyIcon from '@mui/icons-material/WbSunny';
|
||||||
|
import HomeIcon from '@mui/icons-material/Home';
|
||||||
const mockHistory = [{
|
import MenuIcon from '@mui/icons-material/Menu';
|
||||||
id: 1,
|
import AddIcon from '@mui/icons-material/Add';
|
||||||
summary: "chat1",
|
import { useQueryDialog } from '@/hooks/useQueryDialogue';
|
||||||
history: [{
|
|
||||||
from: 'human',
|
|
||||||
message: 'Hello'
|
|
||||||
}, {
|
|
||||||
from: 'agent',
|
|
||||||
message: 'Hello! How can I assist you today?'
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
id: 2,
|
|
||||||
summary: "天气",
|
|
||||||
history: [{
|
|
||||||
from: 'human',
|
|
||||||
message: '讲个笑话'
|
|
||||||
}, {
|
|
||||||
from: 'agent',
|
|
||||||
message: '当然!这是一个经典的笑话:xxx'
|
|
||||||
}]
|
|
||||||
}];
|
|
||||||
|
|
||||||
const LeftSider = () => {
|
const LeftSider = () => {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const { mode, setMode } = useColorScheme();
|
const { mode, setMode } = useColorScheme();
|
||||||
const [chatSelect, setChatSelect] = useState();
|
const [chatSelect, setChatSelect] = useState();
|
||||||
|
const { dialogueList } = useQueryDialog();
|
||||||
|
|
||||||
const menus = useMemo(() => {
|
const menus = useMemo(() => {
|
||||||
return [{
|
return [{
|
||||||
label: 'Home',
|
label: 'Home',
|
||||||
icon: <SmartToyRoundedIcon fontSize="small" />,
|
icon: <HomeIcon fontSize="small" />,
|
||||||
route: '/',
|
route: '/',
|
||||||
active: pathname === '/',
|
active: pathname === '/',
|
||||||
}, {
|
}, {
|
||||||
@ -63,153 +47,173 @@ const LeftSider = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<>
|
||||||
sx={{
|
<nav className='flex h-12 items-center justify-between border-b bg-gray-50 px-4 dark:border-gray-800 dark:bg-gray-800/70 md:hidden'>
|
||||||
display: 'flex',
|
<div>
|
||||||
flexDirection: 'column',
|
<MenuIcon />
|
||||||
borderRight: '1px solid',
|
|
||||||
borderColor: 'divider',
|
|
||||||
maxHeight: '100vh',
|
|
||||||
position: 'sticky',
|
|
||||||
left: '0px',
|
|
||||||
top: '0px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
p: 2,
|
|
||||||
gap: 2,
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
alignItems: 'center',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className='flex items-center justify-center gap-3'>
|
|
||||||
<Image
|
|
||||||
src="/databerry-logo-icon.png"
|
|
||||||
width="200"
|
|
||||||
height="200"
|
|
||||||
className='w-12'
|
|
||||||
alt="Databerry"
|
|
||||||
/>
|
|
||||||
<Typography component="h1" fontWeight="xl">
|
|
||||||
DB-GPT
|
|
||||||
</Typography>
|
|
||||||
</div>
|
</div>
|
||||||
</Box>
|
<span className='truncate px-4'>New Chat</span>
|
||||||
<Box
|
<a href='javascript: void(0)' className='-mr-3 flex h-9 w-9 shrink-0 items-center justify-center'>
|
||||||
sx={{
|
<AddIcon />
|
||||||
px: 2
|
</a>
|
||||||
}}
|
</nav>
|
||||||
>
|
<nav className="grid max-h-screen h-full max-md:hidden">
|
||||||
<Button variant="outlined" color="primary" className='w-full'>+ 新建对话</Button>
|
|
||||||
</Box>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
p: 2,
|
|
||||||
display: {
|
|
||||||
xs: 'none',
|
|
||||||
sm: 'initial',
|
|
||||||
},
|
|
||||||
maxHeight: '100%',
|
|
||||||
overflow: 'auto',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<List size="sm" sx={{ '--ListItem-radius': '8px' }}>
|
|
||||||
<ListItem nested>
|
|
||||||
<List
|
|
||||||
size="sm"
|
|
||||||
aria-labelledby="nav-list-browse"
|
|
||||||
sx={{
|
|
||||||
'& .JoyListItemButton-root': { p: '8px' },
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{mockHistory.map((each, index) => (
|
|
||||||
<ListItem key={index}>
|
|
||||||
<ListItemButton
|
|
||||||
selected={chatSelect === each.id}
|
|
||||||
variant={chatSelect === each.id ? 'soft' : 'plain'}
|
|
||||||
onClick={() => {
|
|
||||||
setChatSelect(each.id);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ListItemContent>{each.summary}</ListItemContent>
|
|
||||||
</ListItemButton>
|
|
||||||
</ListItem>
|
|
||||||
))}
|
|
||||||
</List>
|
|
||||||
</ListItem>
|
|
||||||
</List>
|
|
||||||
</Box>
|
|
||||||
<div className='flex flex-col justify-between flex-1'>
|
|
||||||
<div></div>
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
p: 2,
|
display: 'flex',
|
||||||
borderTop: '1px solid',
|
flexDirection: 'column',
|
||||||
|
borderRight: '1px solid',
|
||||||
borderColor: 'divider',
|
borderColor: 'divider',
|
||||||
display: {
|
maxHeight: '100vh',
|
||||||
xs: 'none',
|
|
||||||
sm: 'initial',
|
|
||||||
},
|
|
||||||
position: 'sticky',
|
position: 'sticky',
|
||||||
bottom: 0,
|
left: '0px',
|
||||||
zIndex: 100,
|
top: '0px',
|
||||||
background: 'var(--joy-palette-background-body)'
|
overflow: 'hidden',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<List size="sm" sx={{ '--ListItem-radius': '8px' }}>
|
<Box
|
||||||
<ListItem nested>
|
sx={{
|
||||||
<List
|
p: 2,
|
||||||
size="sm"
|
gap: 2,
|
||||||
aria-labelledby="nav-list-browse"
|
display: 'flex',
|
||||||
sx={{
|
flexDirection: 'row',
|
||||||
'& .JoyListItemButton-root': { p: '8px' },
|
justifyContent: 'space-between',
|
||||||
}}
|
alignItems: 'center',
|
||||||
>
|
}}
|
||||||
{menus.map((each) => (
|
>
|
||||||
<Link key={each.route} href={each.route}>
|
<div className='flex items-center gap-3'>
|
||||||
<ListItem>
|
<Image
|
||||||
|
src="/databerry-logo-icon.png"
|
||||||
|
width="100"
|
||||||
|
height="100"
|
||||||
|
className='w-12'
|
||||||
|
alt="Databerry"
|
||||||
|
/>
|
||||||
|
<Typography component="h1" fontWeight="xl">
|
||||||
|
DB-GPT
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
px: 2
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button variant="outlined" color="primary" className='w-full'>+ 新建对话</Button>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
p: 2,
|
||||||
|
display: {
|
||||||
|
xs: 'none',
|
||||||
|
sm: 'initial',
|
||||||
|
},
|
||||||
|
maxHeight: '100%',
|
||||||
|
overflow: 'auto',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<List size="sm" sx={{ '--ListItem-radius': '8px' }}>
|
||||||
|
<ListItem nested>
|
||||||
|
<List
|
||||||
|
size="sm"
|
||||||
|
aria-labelledby="nav-list-browse"
|
||||||
|
sx={{
|
||||||
|
'& .JoyListItemButton-root': { p: '8px' },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{dialogueList?.data?.map((each) => (
|
||||||
|
<ListItem key={each.conv_uid}>
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
color="neutral"
|
selected={chatSelect === each.conv_uid}
|
||||||
selected={each.active}
|
variant={chatSelect === each.conv_uid ? 'soft' : 'plain'}
|
||||||
variant={each.active ? 'soft' : 'plain'}
|
onClick={() => {
|
||||||
|
setChatSelect(each.conv_uid);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<ListItemDecorator
|
<ListItemContent>
|
||||||
sx={{
|
<Link href={`/agents/${each.conv_uid}`}>
|
||||||
color: each.active ? 'inherit' : 'neutral.500',
|
<Typography fontSize={14} noWrap={true}>
|
||||||
}}
|
{each?.user_name || each?.user_input || 'undefined'}
|
||||||
>
|
</Typography>
|
||||||
{each.icon}
|
</Link>
|
||||||
</ListItemDecorator>
|
|
||||||
<ListItemContent>{each.label}</ListItemContent>
|
</ListItemContent>
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</Link>
|
))}
|
||||||
))}
|
</List>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
</Box>
|
||||||
|
<div className='flex flex-col justify-between flex-1'>
|
||||||
|
<div></div>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
p: 2,
|
||||||
|
borderTop: '1px solid',
|
||||||
|
borderColor: 'divider',
|
||||||
|
display: {
|
||||||
|
xs: 'none',
|
||||||
|
sm: 'initial',
|
||||||
|
},
|
||||||
|
position: 'sticky',
|
||||||
|
bottom: 0,
|
||||||
|
zIndex: 100,
|
||||||
|
background: 'var(--joy-palette-background-body)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<List size="sm" sx={{ '--ListItem-radius': '8px' }}>
|
||||||
|
<ListItem nested>
|
||||||
|
<List
|
||||||
|
size="sm"
|
||||||
|
aria-labelledby="nav-list-browse"
|
||||||
|
sx={{
|
||||||
|
'& .JoyListItemButton-root': { p: '8px' },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{menus.map((each) => (
|
||||||
|
<Link key={each.route} href={each.route}>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemButton
|
||||||
|
color="neutral"
|
||||||
|
selected={each.active}
|
||||||
|
variant={each.active ? 'soft' : 'plain'}
|
||||||
|
onClick={() => { setChatSelect(undefined); }}
|
||||||
|
>
|
||||||
|
<ListItemDecorator
|
||||||
|
sx={{
|
||||||
|
color: each.active ? 'inherit' : 'neutral.500',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{each.icon}
|
||||||
|
</ListItemDecorator>
|
||||||
|
<ListItemContent>{each.label}</ListItemContent>
|
||||||
|
</ListItemButton>
|
||||||
|
</ListItem>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemButton
|
||||||
|
onClick={handleChangeTheme}
|
||||||
|
>
|
||||||
|
<ListItemDecorator>
|
||||||
|
{mode === 'dark' ? (
|
||||||
|
<DarkModeIcon fontSize="small"/>
|
||||||
|
) : (
|
||||||
|
<WbSunnyIcon fontSize="small"/>
|
||||||
|
)}
|
||||||
|
</ListItemDecorator>
|
||||||
|
<ListItemContent>Theme</ListItemContent>
|
||||||
|
</ListItemButton>
|
||||||
|
</ListItem>
|
||||||
</List>
|
</List>
|
||||||
</ListItem>
|
</Box>
|
||||||
<ListItem>
|
</div>
|
||||||
<ListItemButton
|
|
||||||
onClick={handleChangeTheme}
|
|
||||||
>
|
|
||||||
<ListItemDecorator>
|
|
||||||
{mode === 'dark' ? (
|
|
||||||
<DarkModeIcon fontSize="small"/>
|
|
||||||
) : (
|
|
||||||
<WbSunnyIcon fontSize="small"/>
|
|
||||||
)}
|
|
||||||
</ListItemDecorator>
|
|
||||||
<ListItemContent>Theme</ListItemContent>
|
|
||||||
</ListItemButton>
|
|
||||||
</ListItem>
|
|
||||||
</List>
|
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</nav>
|
||||||
|
</>
|
||||||
</Box>
|
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,22 +21,22 @@ import {
|
|||||||
}: Props) => {
|
}: Props) => {
|
||||||
const [state, setState] = useStateReducer({
|
const [state, setState] = useStateReducer({
|
||||||
history: [{
|
history: [{
|
||||||
from: 'human',
|
role: 'human',
|
||||||
message: 'hello',
|
context: 'hello',
|
||||||
}, {
|
}, {
|
||||||
from: 'agent',
|
role: 'agent',
|
||||||
message: 'Hello! How can I assist you today?',
|
context: 'Hello! How can I assist you today?',
|
||||||
}] as { from: 'human' | 'agent'; message: string; id?: string }[],
|
}] as { role: 'human' | 'agent'; context: string; id?: string }[],
|
||||||
});
|
});
|
||||||
|
|
||||||
const { visitorId } = useVisitorId();
|
const { visitorId } = useVisitorId();
|
||||||
|
|
||||||
const handleChatSubmit = async (message: string) => {
|
const handleChatSubmit = async (context: string) => {
|
||||||
if (!message) {
|
if (!context) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const history = [...state.history, { from: 'human', message }];
|
const history = [...state.history, { role: 'human', context }];
|
||||||
const nextIndex = history.length;
|
const nextIndex = history.length;
|
||||||
|
|
||||||
setState({
|
setState({
|
||||||
@ -61,7 +61,7 @@ import {
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
...queryBody,
|
...queryBody,
|
||||||
streaming: true,
|
streaming: true,
|
||||||
query: message,
|
query: context,
|
||||||
visitorId: visitorId,
|
visitorId: visitorId,
|
||||||
channel,
|
channel,
|
||||||
}),
|
}),
|
||||||
@ -112,8 +112,8 @@ import {
|
|||||||
history: [
|
history: [
|
||||||
...history,
|
...history,
|
||||||
{
|
{
|
||||||
from: 'agent',
|
role: 'agent',
|
||||||
message: event.data.replace('[ERROR]', ''),
|
context: event.data.replace('[ERROR]', ''),
|
||||||
} as any,
|
} as any,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@ -121,9 +121,9 @@ import {
|
|||||||
buffer += decodeURIComponent(event.data) as string;
|
buffer += decodeURIComponent(event.data) as string;
|
||||||
const h = [...history];
|
const h = [...history];
|
||||||
if (h?.[nextIndex]) {
|
if (h?.[nextIndex]) {
|
||||||
h[nextIndex].message = `${buffer}`;
|
h[nextIndex].context = `${buffer}`;
|
||||||
} else {
|
} else {
|
||||||
h.push({ from: 'agent', message: buffer });
|
h.push({ role: 'agent', context: buffer });
|
||||||
}
|
}
|
||||||
setState({
|
setState({
|
||||||
history: h as any,
|
history: h as any,
|
||||||
@ -136,7 +136,7 @@ import {
|
|||||||
setState({
|
setState({
|
||||||
history: [
|
history: [
|
||||||
...history,
|
...history,
|
||||||
{ from: 'agent', message: answer || '请求出错' as string },
|
{ role: 'agent', context: answer || '请求出错' as string },
|
||||||
] as any,
|
] as any,
|
||||||
});
|
});
|
||||||
// if (err instanceof ApiError) {
|
// if (err instanceof ApiError) {
|
||||||
|
20
datacenter/hooks/useQueryDialogue.ts
Normal file
20
datacenter/hooks/useQueryDialogue.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { useRequest } from 'ahooks';
|
||||||
|
import { sendGetRequest } from '@/utils/request';
|
||||||
|
|
||||||
|
export function useQueryDialog() {
|
||||||
|
const {
|
||||||
|
run: queryDialogueList,
|
||||||
|
data: dialogueList,
|
||||||
|
loading: loadingDialogList,
|
||||||
|
refresh: refreshDialogList,
|
||||||
|
} = useRequest(async () => await sendGetRequest('/v1/chat/dialogue/list'), {
|
||||||
|
manual: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
queryDialogueList,
|
||||||
|
dialogueList,
|
||||||
|
loadingDialogList,
|
||||||
|
refreshDialogList
|
||||||
|
};
|
||||||
|
}
|
112
datacenter/package-lock.json
generated
112
datacenter/package-lock.json
generated
@ -24,6 +24,7 @@
|
|||||||
"@types/node": "20.3.1",
|
"@types/node": "20.3.1",
|
||||||
"@types/react": "18.2.14",
|
"@types/react": "18.2.14",
|
||||||
"@types/react-dom": "18.2.6",
|
"@types/react-dom": "18.2.6",
|
||||||
|
"ahooks": "^3.7.8",
|
||||||
"antd": "^5.6.2",
|
"antd": "^5.6.2",
|
||||||
"autoprefixer": "10.4.14",
|
"autoprefixer": "10.4.14",
|
||||||
"axios": "^1.3.4",
|
"axios": "^1.3.4",
|
||||||
@ -31,6 +32,7 @@
|
|||||||
"cuid": "^3.0.0",
|
"cuid": "^3.0.0",
|
||||||
"eslint": "8.43.0",
|
"eslint": "8.43.0",
|
||||||
"eslint-config-next": "13.4.7",
|
"eslint-config-next": "13.4.7",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"next": "13.4.7",
|
"next": "13.4.7",
|
||||||
"next-auth": "^4.20.1",
|
"next-auth": "^4.20.1",
|
||||||
@ -48,6 +50,7 @@
|
|||||||
"zod": "^3.19.1"
|
"zod": "^3.19.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/lodash": "^4.14.195",
|
||||||
"@types/nprogress": "^0.2.0"
|
"@types/nprogress": "^0.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -2244,11 +2247,22 @@
|
|||||||
"@types/unist": "*"
|
"@types/unist": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/js-cookie": {
|
||||||
|
"version": "2.2.7",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@types/js-cookie/-/js-cookie-2.2.7.tgz",
|
||||||
|
"integrity": "sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA=="
|
||||||
|
},
|
||||||
"node_modules/@types/json5": {
|
"node_modules/@types/json5": {
|
||||||
"version": "0.0.29",
|
"version": "0.0.29",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/json5/-/json5-0.0.29.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/json5/-/json5-0.0.29.tgz",
|
||||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
|
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/lodash": {
|
||||||
|
"version": "4.14.195",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.195.tgz",
|
||||||
|
"integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/mdast": {
|
"node_modules/@types/mdast": {
|
||||||
"version": "3.0.11",
|
"version": "3.0.11",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/mdast/-/mdast-3.0.11.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/mdast/-/mdast-3.0.11.tgz",
|
||||||
@ -2443,6 +2457,34 @@
|
|||||||
"object-assign": "4.x"
|
"object-assign": "4.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ahooks": {
|
||||||
|
"version": "3.7.8",
|
||||||
|
"resolved": "https://registry.npmmirror.com/ahooks/-/ahooks-3.7.8.tgz",
|
||||||
|
"integrity": "sha512-e/NMlQWoCjaUtncNFIZk3FG1ImSkV/JhScQSkTqnftakRwdfZWSw6zzoWSG9OMYqPNs2MguDYBUFFC6THelWXA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.21.0",
|
||||||
|
"@types/js-cookie": "^2.x.x",
|
||||||
|
"ahooks-v3-count": "^1.0.0",
|
||||||
|
"dayjs": "^1.9.1",
|
||||||
|
"intersection-observer": "^0.12.0",
|
||||||
|
"js-cookie": "^2.x.x",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"resize-observer-polyfill": "^1.5.1",
|
||||||
|
"screenfull": "^5.0.0",
|
||||||
|
"tslib": "^2.4.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ahooks-v3-count": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/ahooks-v3-count/-/ahooks-v3-count-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-V7uUvAwnimu6eh/PED4mCDjE7tokeZQLKlxg9lCTMPhN+NjsSbtdacByVlR1oluXQzD3MOw55wylDmQo4+S9ZQ=="
|
||||||
|
},
|
||||||
"node_modules/ajv": {
|
"node_modules/ajv": {
|
||||||
"version": "6.12.6",
|
"version": "6.12.6",
|
||||||
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
|
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
|
||||||
@ -4566,6 +4608,11 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/intersection-observer": {
|
||||||
|
"version": "0.12.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.12.2.tgz",
|
||||||
|
"integrity": "sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg=="
|
||||||
|
},
|
||||||
"node_modules/is-arguments": {
|
"node_modules/is-arguments": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmmirror.com/is-arguments/-/is-arguments-1.1.1.tgz",
|
"resolved": "https://registry.npmmirror.com/is-arguments/-/is-arguments-1.1.1.tgz",
|
||||||
@ -4856,6 +4903,11 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/jose/-/jose-4.14.4.tgz",
|
"resolved": "https://registry.npmmirror.com/jose/-/jose-4.14.4.tgz",
|
||||||
"integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g=="
|
"integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g=="
|
||||||
},
|
},
|
||||||
|
"node_modules/js-cookie": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/js-cookie/-/js-cookie-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ=="
|
||||||
|
},
|
||||||
"node_modules/js-tokens": {
|
"node_modules/js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
@ -5018,7 +5070,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/lodash": {
|
"node_modules/lodash": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
},
|
},
|
||||||
"node_modules/lodash.debounce": {
|
"node_modules/lodash.debounce": {
|
||||||
@ -7308,6 +7360,14 @@
|
|||||||
"loose-envify": "^1.1.0"
|
"loose-envify": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/screenfull": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/screenfull/-/screenfull-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/scroll-into-view-if-needed": {
|
"node_modules/scroll-into-view-if-needed": {
|
||||||
"version": "3.0.10",
|
"version": "3.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.0.10.tgz",
|
||||||
@ -9888,11 +9948,22 @@
|
|||||||
"@types/unist": "*"
|
"@types/unist": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/js-cookie": {
|
||||||
|
"version": "2.2.7",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@types/js-cookie/-/js-cookie-2.2.7.tgz",
|
||||||
|
"integrity": "sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA=="
|
||||||
|
},
|
||||||
"@types/json5": {
|
"@types/json5": {
|
||||||
"version": "0.0.29",
|
"version": "0.0.29",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/json5/-/json5-0.0.29.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/json5/-/json5-0.0.29.tgz",
|
||||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
|
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
|
||||||
},
|
},
|
||||||
|
"@types/lodash": {
|
||||||
|
"version": "4.14.195",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.195.tgz",
|
||||||
|
"integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/mdast": {
|
"@types/mdast": {
|
||||||
"version": "3.0.11",
|
"version": "3.0.11",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/mdast/-/mdast-3.0.11.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/mdast/-/mdast-3.0.11.tgz",
|
||||||
@ -10049,6 +10120,28 @@
|
|||||||
"object-assign": "4.x"
|
"object-assign": "4.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ahooks": {
|
||||||
|
"version": "3.7.8",
|
||||||
|
"resolved": "https://registry.npmmirror.com/ahooks/-/ahooks-3.7.8.tgz",
|
||||||
|
"integrity": "sha512-e/NMlQWoCjaUtncNFIZk3FG1ImSkV/JhScQSkTqnftakRwdfZWSw6zzoWSG9OMYqPNs2MguDYBUFFC6THelWXA==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.21.0",
|
||||||
|
"@types/js-cookie": "^2.x.x",
|
||||||
|
"ahooks-v3-count": "^1.0.0",
|
||||||
|
"dayjs": "^1.9.1",
|
||||||
|
"intersection-observer": "^0.12.0",
|
||||||
|
"js-cookie": "^2.x.x",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"resize-observer-polyfill": "^1.5.1",
|
||||||
|
"screenfull": "^5.0.0",
|
||||||
|
"tslib": "^2.4.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ahooks-v3-count": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/ahooks-v3-count/-/ahooks-v3-count-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-V7uUvAwnimu6eh/PED4mCDjE7tokeZQLKlxg9lCTMPhN+NjsSbtdacByVlR1oluXQzD3MOw55wylDmQo4+S9ZQ=="
|
||||||
|
},
|
||||||
"ajv": {
|
"ajv": {
|
||||||
"version": "6.12.6",
|
"version": "6.12.6",
|
||||||
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
|
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
|
||||||
@ -11763,6 +11856,11 @@
|
|||||||
"side-channel": "^1.0.4"
|
"side-channel": "^1.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"intersection-observer": {
|
||||||
|
"version": "0.12.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.12.2.tgz",
|
||||||
|
"integrity": "sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg=="
|
||||||
|
},
|
||||||
"is-arguments": {
|
"is-arguments": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmmirror.com/is-arguments/-/is-arguments-1.1.1.tgz",
|
"resolved": "https://registry.npmmirror.com/is-arguments/-/is-arguments-1.1.1.tgz",
|
||||||
@ -11980,6 +12078,11 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/jose/-/jose-4.14.4.tgz",
|
"resolved": "https://registry.npmmirror.com/jose/-/jose-4.14.4.tgz",
|
||||||
"integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g=="
|
"integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g=="
|
||||||
},
|
},
|
||||||
|
"js-cookie": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/js-cookie/-/js-cookie-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ=="
|
||||||
|
},
|
||||||
"js-tokens": {
|
"js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
@ -12106,7 +12209,7 @@
|
|||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
},
|
},
|
||||||
"lodash.debounce": {
|
"lodash.debounce": {
|
||||||
@ -13904,6 +14007,11 @@
|
|||||||
"loose-envify": "^1.1.0"
|
"loose-envify": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"screenfull": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/screenfull/-/screenfull-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA=="
|
||||||
|
},
|
||||||
"scroll-into-view-if-needed": {
|
"scroll-into-view-if-needed": {
|
||||||
"version": "3.0.10",
|
"version": "3.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.0.10.tgz",
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
"@types/node": "20.3.1",
|
"@types/node": "20.3.1",
|
||||||
"@types/react": "18.2.14",
|
"@types/react": "18.2.14",
|
||||||
"@types/react-dom": "18.2.6",
|
"@types/react-dom": "18.2.6",
|
||||||
|
"ahooks": "^3.7.8",
|
||||||
"antd": "^5.6.2",
|
"antd": "^5.6.2",
|
||||||
"autoprefixer": "10.4.14",
|
"autoprefixer": "10.4.14",
|
||||||
"axios": "^1.3.4",
|
"axios": "^1.3.4",
|
||||||
@ -32,6 +33,7 @@
|
|||||||
"cuid": "^3.0.0",
|
"cuid": "^3.0.0",
|
||||||
"eslint": "8.43.0",
|
"eslint": "8.43.0",
|
||||||
"eslint-config-next": "13.4.7",
|
"eslint-config-next": "13.4.7",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"next": "13.4.7",
|
"next": "13.4.7",
|
||||||
"next-auth": "^4.20.1",
|
"next-auth": "^4.20.1",
|
||||||
@ -49,6 +51,7 @@
|
|||||||
"zod": "^3.19.1"
|
"zod": "^3.19.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/lodash": "^4.14.195",
|
||||||
"@types/nprogress": "^0.2.0"
|
"@types/nprogress": "^0.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
datacenter/public/bg1.avif
Normal file
BIN
datacenter/public/bg1.avif
Normal file
Binary file not shown.
BIN
datacenter/public/bg2.png
Normal file
BIN
datacenter/public/bg2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 197 KiB |
@ -14,5 +14,6 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
darkMode: 'class',
|
||||||
plugins: [],
|
plugins: [],
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { NextApiRequest, NextPage } from 'next/types';
|
import { NextApiRequest, NextPage } from 'next/types';
|
||||||
import { Session } from 'next-auth';
|
import { Session } from 'next-auth';
|
||||||
|
|
||||||
export type Message = { from: 'human' | 'agent'; message: string; createdAt?: Date };
|
export type Message = { role: 'human' | 'ai'; context: string; createdAt?: Date };
|
||||||
|
|
||||||
export type AppNextApiRequest = NextApiRequest & {
|
export type AppNextApiRequest = NextApiRequest & {
|
||||||
session: Session;
|
session: Session;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import { isPlainObject } from 'lodash';
|
||||||
|
|
||||||
axios.defaults.baseURL = 'http://30.183.153.244:5000';
|
axios.defaults.baseURL = 'http://30.183.153.244:5000';
|
||||||
|
|
||||||
@ -9,6 +10,24 @@ axios.interceptors.response.use(
|
|||||||
err => Promise.reject(err)
|
err => Promise.reject(err)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const DEFAULT_HEADERS = {
|
||||||
|
'content-type': 'application/json',
|
||||||
|
};
|
||||||
|
|
||||||
|
// body 字段 trim
|
||||||
|
const sanitizeBody = (obj: Record<string, any>): string => {
|
||||||
|
// simple shallow copy to avoid changing original obj
|
||||||
|
if (!isPlainObject(obj)) return JSON.stringify(obj);
|
||||||
|
const resObj = { ...obj };
|
||||||
|
for (const key in resObj) {
|
||||||
|
const val = resObj[key];
|
||||||
|
if (typeof val === 'string') {
|
||||||
|
resObj[key] = val.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return JSON.stringify(resObj);
|
||||||
|
};
|
||||||
|
|
||||||
export const sendGetRequest = (url: string, qs?: { [key: string]: any }) => {
|
export const sendGetRequest = (url: string, qs?: { [key: string]: any }) => {
|
||||||
if (qs) {
|
if (qs) {
|
||||||
const str = Object.keys(qs)
|
const str = Object.keys(qs)
|
||||||
@ -19,13 +38,15 @@ export const sendGetRequest = (url: string, qs?: { [key: string]: any }) => {
|
|||||||
url += `?${str}`;
|
url += `?${str}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
axios.get(url, {
|
return axios.get(url, {
|
||||||
headers: {
|
headers: DEFAULT_HEADERS
|
||||||
"Content-Type": 'text/plain'
|
}).then(res => res).catch(err => Promise.reject(err));
|
||||||
}
|
|
||||||
}).then(res => {
|
|
||||||
console.log(res, 'res');
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err, 'err');
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const sendPostRequest = (url: string, body?: any) => {
|
||||||
|
const reqBody = sanitizeBody(body);
|
||||||
|
return axios.post(url, {
|
||||||
|
body: reqBody,
|
||||||
|
headers: DEFAULT_HEADERS
|
||||||
|
}).then(res => res).catch(err => Promise.reject(err));
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user