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>
|
||||
</Grid>
|
||||
<Grid xs={4}>
|
||||
<ChatBoxComp messages={history} onSubmit={handleChatSubmit}/>
|
||||
<ChatBoxComp messages={[]} onSubmit={handleChatSubmit}/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</div>
|
||||
|
@ -32,7 +32,7 @@ const ChunkList = () => {
|
||||
}, [])
|
||||
return (
|
||||
<div className="p-4">
|
||||
<Table sx={{ '& thead th:nth-child(1)': { width: '40%' } }}>
|
||||
<Table color="neutral" stripe="odd" variant="outlined">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
|
@ -10,11 +10,25 @@ import {
|
||||
Box,
|
||||
Stack,
|
||||
Input,
|
||||
Chip,
|
||||
styled
|
||||
} from '@/lib/mui'
|
||||
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 = [
|
||||
'Choose a Datasource type',
|
||||
'Setup the Datasource'
|
||||
@ -36,16 +50,6 @@ const documentTypeList = [
|
||||
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 router = useRouter()
|
||||
@ -53,9 +57,25 @@ const Documents = () => {
|
||||
const [isAddDocumentModalShow, setIsAddDocumentModalShow] =
|
||||
useState<boolean>(false)
|
||||
const [activeStep, setActiveStep] = useState<number>(0)
|
||||
const [documentType, setDocumentType] = useState<string>('')
|
||||
const [documents, setDocuments] = useState<any>([])
|
||||
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(() => {
|
||||
async function fetchDocuments() {
|
||||
const res = await fetch(
|
||||
@ -90,7 +110,7 @@ const Documents = () => {
|
||||
+ Add Datasource
|
||||
</Button>
|
||||
</Sheet>
|
||||
<Table sx={{ '& thead th:nth-child(1)': { width: '40%' } }}>
|
||||
<Table color="neutral" stripe="odd" variant="outlined">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
@ -108,12 +128,30 @@ const Documents = () => {
|
||||
<td>{row.doc_type}</td>
|
||||
<td>{row.chunk_size}</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>
|
||||
{
|
||||
<>
|
||||
<Button
|
||||
variant="outlined"
|
||||
size="sm"
|
||||
onClick={async () => {
|
||||
const res = await fetch(
|
||||
`http://localhost:8000/knowledge/${spaceName}/document/sync`,
|
||||
@ -139,6 +177,7 @@ const Documents = () => {
|
||||
</Button>
|
||||
<Button
|
||||
variant="outlined"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
router.push(
|
||||
`/datastores/documents/chunklist?spacename=${spaceName}&documentid=${row.id}`
|
||||
@ -204,9 +243,8 @@ const Documents = () => {
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
onClick={() => {
|
||||
if (item.type === 'webPage') {
|
||||
setDocumentType(item.type)
|
||||
setActiveStep(1)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Sheet sx={{ fontSize: '20px', fontWeight: 'bold' }}>
|
||||
@ -226,11 +264,37 @@ const Documents = () => {
|
||||
onChange={(e: any) => setDocumentName(e.target.value)}
|
||||
sx={{ marginBottom: '20px' }}
|
||||
/>
|
||||
Web Page URL:
|
||||
{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>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
@ -238,6 +302,7 @@ const Documents = () => {
|
||||
message.error('Please input the name')
|
||||
return
|
||||
}
|
||||
if (documentType === 'webPage') {
|
||||
if (webPageUrl === '') {
|
||||
message.error('Please input the Web Page URL')
|
||||
return
|
||||
@ -277,6 +342,44 @@ const Documents = () => {
|
||||
} 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')
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
Finish
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
import { useRouter } from 'next/navigation'
|
||||
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 {
|
||||
Modal,
|
||||
Button,
|
||||
@ -14,6 +16,8 @@ import {
|
||||
styled
|
||||
} from '@/lib/mui'
|
||||
|
||||
const { Dragger } = Upload
|
||||
|
||||
const Item = styled(Sheet)(({ theme }) => ({
|
||||
width: '33%',
|
||||
backgroundColor:
|
||||
@ -51,12 +55,28 @@ const documentTypeList = [
|
||||
const Index = () => {
|
||||
const router = useRouter()
|
||||
const [activeStep, setActiveStep] = useState<number>(0)
|
||||
const [documentType, setDocumentType] = useState<string>('')
|
||||
const [knowledgeSpaceList, setKnowledgeSpaceList] = useState<any>([])
|
||||
const [isAddKnowledgeSpaceModalShow, setIsAddKnowledgeSpaceModalShow] =
|
||||
useState<boolean>(false)
|
||||
const [knowledgeSpaceName, setKnowledgeSpaceName] = 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(() => {
|
||||
async function fetchData() {
|
||||
const res = await fetch('http://localhost:8000/knowledge/space/list', {
|
||||
@ -75,14 +95,21 @@ const Index = () => {
|
||||
}, [])
|
||||
return (
|
||||
<>
|
||||
<Sheet sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between"
|
||||
}} className="p-4">
|
||||
<Sheet sx={{
|
||||
<Sheet
|
||||
sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between'
|
||||
}}
|
||||
className="p-4"
|
||||
>
|
||||
<Sheet
|
||||
sx={{
|
||||
fontSize: '30px',
|
||||
fontWeight: 'bold'
|
||||
}}>Knowledge Spaces</Sheet>
|
||||
}}
|
||||
>
|
||||
Knowledge Spaces
|
||||
</Sheet>
|
||||
<Button
|
||||
onClick={() => setIsAddKnowledgeSpaceModalShow(true)}
|
||||
variant="outlined"
|
||||
@ -91,7 +118,7 @@ const Index = () => {
|
||||
</Button>
|
||||
</Sheet>
|
||||
<div className="page-body p-4">
|
||||
<Table sx={{ '& thead th:nth-child(1)': { width: '40%' } }}>
|
||||
<Table color="neutral" stripe="odd" variant="outlined">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
@ -228,12 +255,13 @@ const Index = () => {
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
onClick={() => {
|
||||
if (item.type === 'webPage') {
|
||||
setActiveStep(2);
|
||||
}
|
||||
setDocumentType(item.type)
|
||||
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>
|
||||
))}
|
||||
@ -248,21 +276,47 @@ const Index = () => {
|
||||
onChange={(e: any) => setDocumentName(e.target.value)}
|
||||
sx={{ marginBottom: '20px' }}
|
||||
/>
|
||||
{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>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
if (documentName === '') {
|
||||
message.error('Please input the name');
|
||||
return;
|
||||
message.error('Please input the name')
|
||||
return
|
||||
}
|
||||
if (documentType === 'webPage') {
|
||||
if (webPageUrl === '') {
|
||||
message.error('Please input the Web Page URL');
|
||||
return;
|
||||
message.error('Please input the Web Page URL')
|
||||
return
|
||||
}
|
||||
const res = await fetch(
|
||||
`http://localhost:8000/knowledge/${knowledgeSpaceName}/document/add`,
|
||||
@ -285,6 +339,30 @@ const Index = () => {
|
||||
} 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')
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
Finish
|
||||
|
@ -10,7 +10,7 @@ export const joyTheme = extendTheme({
|
||||
...colors.purple,
|
||||
},
|
||||
neutral: {
|
||||
plainColor: '#25252D',
|
||||
plainColor: '#4d4d4d',
|
||||
plainHoverColor: '#131318',
|
||||
plainHoverBg: '#EBEBEF',
|
||||
plainActiveBg: '#D8D8DF',
|
||||
@ -42,7 +42,7 @@ export const joyTheme = extendTheme({
|
||||
primary: '#EBEBEF'
|
||||
},
|
||||
background: {
|
||||
body: '#09090D',
|
||||
body: '#0f172a',
|
||||
surface: '#1e293b40'
|
||||
}
|
||||
},
|
||||
|
@ -2,9 +2,6 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
a {
|
||||
color: #1677ff;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
|
@ -11,17 +11,18 @@ export default function RootLayout({
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
|
||||
return (
|
||||
<html lang="en" className="min-h-full font-sans">
|
||||
<body className={`min-h-screen font-sans`}>
|
||||
<html lang="en" className="h-full font-sans">
|
||||
<body className={`h-full font-sans`}>
|
||||
<ThemeProvider theme={joyTheme}>
|
||||
<CssVarsProvider theme={joyTheme} defaultMode="light">
|
||||
<TopProgressBar />
|
||||
<div className='min-h-screen flex flex-col'>
|
||||
<div className="flex flex-1 flex-row">
|
||||
<div className={`contents h-full`}>
|
||||
<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 />
|
||||
<div className='flex-1 overflow-auto'>{children}</div>
|
||||
<div className='relative min-h-0 min-w-0'>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CssVarsProvider>
|
||||
|
@ -1,267 +1,98 @@
|
||||
"use client";
|
||||
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import { Collapse } from 'antd';
|
||||
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
|
||||
import { Box, Slider, Input, Tabs, TabList, Typography, TabPanel, Tab, RadioGroup, Radio, tabClasses, useColorScheme, radioClasses } from '@/lib/mui';
|
||||
import { sendGetRequest } from '@/utils/request';
|
||||
import { useEffect, useState } from 'react';
|
||||
import ChatBoxComp from '@/components/chatBox';
|
||||
import useAgentChat from '@/hooks/useAgentChat';
|
||||
import { useState } from 'react';
|
||||
import { Button, Input, useColorScheme } from '@/lib/mui';
|
||||
import IconButton from '@mui/joy/IconButton';
|
||||
import SendRoundedIcon from '@mui/icons-material/SendRounded';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
import { sendPostRequest } from '@/utils/request';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useQueryDialog } from '@/hooks/useQueryDialogue';
|
||||
|
||||
export default function Home() {
|
||||
const [temperatureNum, setTemperatureNum] = useState(3);
|
||||
const [tokenSize, setTokenSize] = useState(0);
|
||||
const { mode, setMode } = useColorScheme();
|
||||
|
||||
const { handleChatSubmit, history } = useAgentChat({
|
||||
queryAgentURL: `/api/agents/query`,
|
||||
const Schema = z.object({ query: z.string().min(1) });
|
||||
const router = useRouter();
|
||||
const { mode } = useColorScheme();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const methods = useForm<z.infer<typeof Schema>>({
|
||||
resolver: zodResolver(Schema),
|
||||
defaultValues: {},
|
||||
});
|
||||
|
||||
const handleGetD = () => {
|
||||
sendGetRequest('/v1/chat/dialogue/list', {
|
||||
})
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
handleGetD();
|
||||
}, []);
|
||||
return (
|
||||
<div className='p-6 w-full h-full text-sm flex flex-col gap-4'>
|
||||
<ReactMarkdown linkTarget={'_blank'}>
|
||||
[DB-GPT](https://github.com/csunny/DB-GPT) 是一个开源的以数据库为基础的GPT实验项目,使用本地化的GPT大模型与您的数据和环境进行交互,无数据泄露风险,100% 私密,100% 安全。
|
||||
</ReactMarkdown>
|
||||
<Box
|
||||
sx={{
|
||||
'& .ant-collapse': {
|
||||
backgroundColor: 'var(--joy-palette-background-level1)',
|
||||
color: 'var(--joy-palette-neutral-plainColor)'
|
||||
},
|
||||
'& .ant-collapse>.ant-collapse-item >.ant-collapse-header, & .ant-collapse .ant-collapse-content': {
|
||||
color: 'var(--joy-palette-neutral-plainColor)'
|
||||
},
|
||||
'& .ant-collapse .ant-collapse-content>.ant-collapse-content-box': {
|
||||
paddingTop: 0
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Collapse
|
||||
collapsible="header"
|
||||
defaultActiveKey={['1']}
|
||||
ghost
|
||||
bordered
|
||||
expandIcon={({ isActive }) => (
|
||||
<div className={`text-2xl cursor-pointer ${isActive ? 'rotate-0' : 'rotate-90'}`}>
|
||||
<ArrowDropDownIcon />
|
||||
</div>
|
||||
)}
|
||||
expandIconPosition="end"
|
||||
items={[
|
||||
{
|
||||
key: '1',
|
||||
label: 'This panel can only be collapsed by clicking text',
|
||||
children: (
|
||||
<>
|
||||
<Box
|
||||
className="p-4 border"
|
||||
sx={{
|
||||
borderColor: 'var(--joy-palette-background-level2)',
|
||||
}}
|
||||
>
|
||||
<div className='flex flex-row justify-between items-center'>
|
||||
<span>Temperature</span>
|
||||
<Input
|
||||
size='sm'
|
||||
type="number"
|
||||
value={temperatureNum / 10}
|
||||
onChange={(e) => {
|
||||
setTemperatureNum(Number(e.target.value) * 10);
|
||||
}}
|
||||
slotProps={{
|
||||
input: {
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.1,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<div className={`${mode} absolute z-20 top-0 inset-x-0 flex justify-center overflow-hidden pointer-events-none`}>
|
||||
<div className='w-[108rem] flex-none flex justify-end'>
|
||||
<picture>
|
||||
<source srcSet='/bg1.avif' type='image/avif'></source>
|
||||
<img srcSet='/bg2.png' alt="" className='w-[71.75rem] flex-none max-w-none '/>
|
||||
</picture>
|
||||
</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
|
||||
sx={{
|
||||
'--ListItem-radius': '0px',
|
||||
borderRadius: 0,
|
||||
bgcolor: 'background.body',
|
||||
[`& .${tabClasses.root}`]: {
|
||||
fontWeight: 'lg',
|
||||
flex: 'unset',
|
||||
position: 'relative',
|
||||
[`&.${tabClasses.selected}`]: {
|
||||
border: '1px solid var(--joy-palette-background-level2)',
|
||||
borderTopLeftRadius: '8px',
|
||||
borderTopRightRadius: '8px',
|
||||
},
|
||||
[`&.${tabClasses.selected}:before`]: {
|
||||
content: '""',
|
||||
display: 'block',
|
||||
position: 'absolute',
|
||||
bottom: -4,
|
||||
<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'>
|
||||
<div className='lg:my-auto grid gap-8 lg:grid-cols-3'>
|
||||
<div className='lg:col-span-3 lg:mt-12'>
|
||||
<p className='mb-3'>Scenes</p>
|
||||
<div className='grid gap-2 lg:grid-cols-4 lg:gap-5'>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='h-60 flex-none'></div>
|
||||
</div>
|
||||
<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'>
|
||||
<form
|
||||
style={{
|
||||
maxWidth: '100%',
|
||||
width: '100%',
|
||||
height: 6,
|
||||
bgcolor: mode == 'dark' ? '#000' : 'var(--joy-palette-background-surface)',
|
||||
},
|
||||
[`&.${tabClasses.focusVisible}`]: {
|
||||
outlineOffset: '-3px',
|
||||
},
|
||||
},
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
marginTop: 'auto',
|
||||
overflow: 'visible',
|
||||
background: 'none',
|
||||
justifyContent: 'center',
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
}}
|
||||
onSubmit={(e) => {
|
||||
methods.handleSubmit(submit)(e);
|
||||
}}
|
||||
>
|
||||
<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)',
|
||||
}}
|
||||
<Input
|
||||
sx={{ width: '100%' }}
|
||||
variant="outlined"
|
||||
placeholder='Ask anything'
|
||||
endDecorator={
|
||||
<IconButton type="submit" disabled={isLoading}>
|
||||
<SendRoundedIcon />
|
||||
</IconButton>
|
||||
}
|
||||
{...methods.register('query')}
|
||||
/>
|
||||
</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}/>
|
||||
</form>
|
||||
</div>
|
||||
</>
|
||||
|
||||
)
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ type Props = {
|
||||
messages: Message[];
|
||||
onSubmit: (message: string) => Promise<any>;
|
||||
messageTemplates?: string[];
|
||||
initialMessage?: string;
|
||||
initialMessage?: Message;
|
||||
readOnly?: boolean;
|
||||
};
|
||||
|
||||
@ -63,7 +63,7 @@ const ChatBoxComp = ({
|
||||
React.useEffect(() => {
|
||||
setTimeout(() => {
|
||||
setFirstMsg(
|
||||
initialMessage ? { from: 'agent', message: initialMessage } : undefined
|
||||
initialMessage ? initialMessage : undefined
|
||||
);
|
||||
}, 0);
|
||||
}, [initialMessage]);
|
||||
@ -112,7 +112,7 @@ const ChatBoxComp = ({
|
||||
whiteSpace: 'pre-wrap',
|
||||
}}
|
||||
>
|
||||
{firstMsg?.message}
|
||||
{firstMsg?.context}
|
||||
</Card>
|
||||
)}
|
||||
|
||||
@ -120,17 +120,17 @@ const ChatBoxComp = ({
|
||||
<Stack
|
||||
key={index}
|
||||
sx={{
|
||||
mr: each.from === 'agent' ? 'auto' : 'none',
|
||||
ml: each.from === 'human' ? 'auto' : 'none',
|
||||
mr: each.role === 'ai' ? 'auto' : 'none',
|
||||
ml: each.role === 'human' ? 'auto' : 'none',
|
||||
}}
|
||||
>
|
||||
<Card
|
||||
size="sm"
|
||||
variant={'outlined'}
|
||||
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) => ({
|
||||
px: 2,
|
||||
'ol, ul': {
|
||||
@ -153,7 +153,7 @@ const ChatBoxComp = ({
|
||||
})}
|
||||
>
|
||||
<ReactMarkdown remarkPlugins={[remarkGfm]} linkTarget={'_blank'}>
|
||||
{each.message}
|
||||
{each.context}
|
||||
</ReactMarkdown>
|
||||
</Card>
|
||||
</Stack>
|
||||
|
@ -3,42 +3,26 @@ import React, { useMemo, useState } from 'react';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import Link from 'next/link';
|
||||
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 StorageRoundedIcon from '@mui/icons-material/StorageRounded';
|
||||
import DarkModeIcon from '@mui/icons-material/DarkMode';
|
||||
import WbSunnyIcon from '@mui/icons-material/WbSunny';
|
||||
|
||||
const mockHistory = [{
|
||||
id: 1,
|
||||
summary: "chat1",
|
||||
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'
|
||||
}]
|
||||
}];
|
||||
import HomeIcon from '@mui/icons-material/Home';
|
||||
import MenuIcon from '@mui/icons-material/Menu';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import { useQueryDialog } from '@/hooks/useQueryDialogue';
|
||||
|
||||
const LeftSider = () => {
|
||||
const pathname = usePathname();
|
||||
const { mode, setMode } = useColorScheme();
|
||||
const [chatSelect, setChatSelect] = useState();
|
||||
const { dialogueList } = useQueryDialog();
|
||||
|
||||
const menus = useMemo(() => {
|
||||
return [{
|
||||
label: 'Home',
|
||||
icon: <SmartToyRoundedIcon fontSize="small" />,
|
||||
icon: <HomeIcon fontSize="small" />,
|
||||
route: '/',
|
||||
active: pathname === '/',
|
||||
}, {
|
||||
@ -63,6 +47,17 @@ const LeftSider = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<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'>
|
||||
<div>
|
||||
<MenuIcon />
|
||||
</div>
|
||||
<span className='truncate px-4'>New Chat</span>
|
||||
<a href='javascript: void(0)' className='-mr-3 flex h-9 w-9 shrink-0 items-center justify-center'>
|
||||
<AddIcon />
|
||||
</a>
|
||||
</nav>
|
||||
<nav className="grid max-h-screen h-full max-md:hidden">
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
@ -86,11 +81,11 @@ const LeftSider = () => {
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<div className='flex items-center justify-center gap-3'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<Image
|
||||
src="/databerry-logo-icon.png"
|
||||
width="200"
|
||||
height="200"
|
||||
width="100"
|
||||
height="100"
|
||||
className='w-12'
|
||||
alt="Databerry"
|
||||
/>
|
||||
@ -126,16 +121,23 @@ const LeftSider = () => {
|
||||
'& .JoyListItemButton-root': { p: '8px' },
|
||||
}}
|
||||
>
|
||||
{mockHistory.map((each, index) => (
|
||||
<ListItem key={index}>
|
||||
{dialogueList?.data?.map((each) => (
|
||||
<ListItem key={each.conv_uid}>
|
||||
<ListItemButton
|
||||
selected={chatSelect === each.id}
|
||||
variant={chatSelect === each.id ? 'soft' : 'plain'}
|
||||
selected={chatSelect === each.conv_uid}
|
||||
variant={chatSelect === each.conv_uid ? 'soft' : 'plain'}
|
||||
onClick={() => {
|
||||
setChatSelect(each.id);
|
||||
setChatSelect(each.conv_uid);
|
||||
}}
|
||||
>
|
||||
<ListItemContent>{each.summary}</ListItemContent>
|
||||
<ListItemContent>
|
||||
<Link href={`/agents/${each.conv_uid}`}>
|
||||
<Typography fontSize={14} noWrap={true}>
|
||||
{each?.user_name || each?.user_input || 'undefined'}
|
||||
</Typography>
|
||||
</Link>
|
||||
|
||||
</ListItemContent>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
))}
|
||||
@ -176,6 +178,7 @@ const LeftSider = () => {
|
||||
color="neutral"
|
||||
selected={each.active}
|
||||
variant={each.active ? 'soft' : 'plain'}
|
||||
onClick={() => { setChatSelect(undefined); }}
|
||||
>
|
||||
<ListItemDecorator
|
||||
sx={{
|
||||
@ -208,8 +211,9 @@ const LeftSider = () => {
|
||||
</List>
|
||||
</Box>
|
||||
</div>
|
||||
|
||||
</Box>
|
||||
</nav>
|
||||
</>
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -21,22 +21,22 @@ import {
|
||||
}: Props) => {
|
||||
const [state, setState] = useStateReducer({
|
||||
history: [{
|
||||
from: 'human',
|
||||
message: 'hello',
|
||||
role: 'human',
|
||||
context: 'hello',
|
||||
}, {
|
||||
from: 'agent',
|
||||
message: 'Hello! How can I assist you today?',
|
||||
}] as { from: 'human' | 'agent'; message: string; id?: string }[],
|
||||
role: 'agent',
|
||||
context: 'Hello! How can I assist you today?',
|
||||
}] as { role: 'human' | 'agent'; context: string; id?: string }[],
|
||||
});
|
||||
|
||||
const { visitorId } = useVisitorId();
|
||||
|
||||
const handleChatSubmit = async (message: string) => {
|
||||
if (!message) {
|
||||
const handleChatSubmit = async (context: string) => {
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
|
||||
const history = [...state.history, { from: 'human', message }];
|
||||
const history = [...state.history, { role: 'human', context }];
|
||||
const nextIndex = history.length;
|
||||
|
||||
setState({
|
||||
@ -61,7 +61,7 @@ import {
|
||||
body: JSON.stringify({
|
||||
...queryBody,
|
||||
streaming: true,
|
||||
query: message,
|
||||
query: context,
|
||||
visitorId: visitorId,
|
||||
channel,
|
||||
}),
|
||||
@ -112,8 +112,8 @@ import {
|
||||
history: [
|
||||
...history,
|
||||
{
|
||||
from: 'agent',
|
||||
message: event.data.replace('[ERROR]', ''),
|
||||
role: 'agent',
|
||||
context: event.data.replace('[ERROR]', ''),
|
||||
} as any,
|
||||
],
|
||||
});
|
||||
@ -121,9 +121,9 @@ import {
|
||||
buffer += decodeURIComponent(event.data) as string;
|
||||
const h = [...history];
|
||||
if (h?.[nextIndex]) {
|
||||
h[nextIndex].message = `${buffer}`;
|
||||
h[nextIndex].context = `${buffer}`;
|
||||
} else {
|
||||
h.push({ from: 'agent', message: buffer });
|
||||
h.push({ role: 'agent', context: buffer });
|
||||
}
|
||||
setState({
|
||||
history: h as any,
|
||||
@ -136,7 +136,7 @@ import {
|
||||
setState({
|
||||
history: [
|
||||
...history,
|
||||
{ from: 'agent', message: answer || '请求出错' as string },
|
||||
{ role: 'agent', context: answer || '请求出错' as string },
|
||||
] as any,
|
||||
});
|
||||
// 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/react": "18.2.14",
|
||||
"@types/react-dom": "18.2.6",
|
||||
"ahooks": "^3.7.8",
|
||||
"antd": "^5.6.2",
|
||||
"autoprefixer": "10.4.14",
|
||||
"axios": "^1.3.4",
|
||||
@ -31,6 +32,7 @@
|
||||
"cuid": "^3.0.0",
|
||||
"eslint": "8.43.0",
|
||||
"eslint-config-next": "13.4.7",
|
||||
"lodash": "^4.17.21",
|
||||
"moment": "^2.29.4",
|
||||
"next": "13.4.7",
|
||||
"next-auth": "^4.20.1",
|
||||
@ -48,6 +50,7 @@
|
||||
"zod": "^3.19.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.14.195",
|
||||
"@types/nprogress": "^0.2.0"
|
||||
}
|
||||
},
|
||||
@ -2244,11 +2247,22 @@
|
||||
"@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": {
|
||||
"version": "0.0.29",
|
||||
"resolved": "https://registry.npmmirror.com/@types/json5/-/json5-0.0.29.tgz",
|
||||
"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": {
|
||||
"version": "3.0.11",
|
||||
"resolved": "https://registry.npmmirror.com/@types/mdast/-/mdast-3.0.11.tgz",
|
||||
@ -2443,6 +2457,34 @@
|
||||
"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": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
|
||||
@ -4566,6 +4608,11 @@
|
||||
"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": {
|
||||
"version": "1.1.1",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@ -5018,7 +5070,7 @@
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"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=="
|
||||
},
|
||||
"node_modules/lodash.debounce": {
|
||||
@ -7308,6 +7360,14 @@
|
||||
"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": {
|
||||
"version": "3.0.10",
|
||||
"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/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": {
|
||||
"version": "0.0.29",
|
||||
"resolved": "https://registry.npmmirror.com/@types/json5/-/json5-0.0.29.tgz",
|
||||
"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": {
|
||||
"version": "3.0.11",
|
||||
"resolved": "https://registry.npmmirror.com/@types/mdast/-/mdast-3.0.11.tgz",
|
||||
@ -10049,6 +10120,28 @@
|
||||
"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": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
|
||||
@ -11763,6 +11856,11 @@
|
||||
"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": {
|
||||
"version": "1.1.1",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@ -12106,7 +12209,7 @@
|
||||
},
|
||||
"lodash": {
|
||||
"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=="
|
||||
},
|
||||
"lodash.debounce": {
|
||||
@ -13904,6 +14007,11 @@
|
||||
"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": {
|
||||
"version": "3.0.10",
|
||||
"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/react": "18.2.14",
|
||||
"@types/react-dom": "18.2.6",
|
||||
"ahooks": "^3.7.8",
|
||||
"antd": "^5.6.2",
|
||||
"autoprefixer": "10.4.14",
|
||||
"axios": "^1.3.4",
|
||||
@ -32,6 +33,7 @@
|
||||
"cuid": "^3.0.0",
|
||||
"eslint": "8.43.0",
|
||||
"eslint-config-next": "13.4.7",
|
||||
"lodash": "^4.17.21",
|
||||
"moment": "^2.29.4",
|
||||
"next": "13.4.7",
|
||||
"next-auth": "^4.20.1",
|
||||
@ -49,6 +51,7 @@
|
||||
"zod": "^3.19.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.14.195",
|
||||
"@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: [],
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { NextApiRequest, NextPage } from 'next/types';
|
||||
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 & {
|
||||
session: Session;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import axios from 'axios';
|
||||
import { isPlainObject } from 'lodash';
|
||||
|
||||
axios.defaults.baseURL = 'http://30.183.153.244:5000';
|
||||
|
||||
@ -9,6 +10,24 @@ axios.interceptors.response.use(
|
||||
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 }) => {
|
||||
if (qs) {
|
||||
const str = Object.keys(qs)
|
||||
@ -19,13 +38,15 @@ export const sendGetRequest = (url: string, qs?: { [key: string]: any }) => {
|
||||
url += `?${str}`;
|
||||
}
|
||||
}
|
||||
axios.get(url, {
|
||||
headers: {
|
||||
"Content-Type": 'text/plain'
|
||||
return axios.get(url, {
|
||||
headers: DEFAULT_HEADERS
|
||||
}).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