mirror of
https://github.com/csunny/DB-GPT.git
synced 2025-08-09 20:28:07 +00:00
feat: 布局调整&添加首页
This commit is contained in:
parent
10d6e23815
commit
7eb02a0dc2
@ -2,6 +2,10 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
a {
|
||||
color: #1677ff;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
color: var(--joy-palette-text-primary, var(--joy-palette-neutral-800, #25252D));
|
||||
|
@ -1,6 +1,5 @@
|
||||
"use client"
|
||||
import './globals.css'
|
||||
import Header from '@/components/header';
|
||||
import LeftSider from '@/components/leftSider';
|
||||
import { CssVarsProvider, ThemeProvider } from '@mui/joy/styles';
|
||||
import { joyTheme } from './defaultTheme';
|
||||
@ -16,10 +15,9 @@ export default function RootLayout({
|
||||
<ThemeProvider theme={joyTheme}>
|
||||
<CssVarsProvider theme={joyTheme} defaultMode="light">
|
||||
<div className='min-h-screen flex flex-col'>
|
||||
<Header />
|
||||
<div className="flex flex-1 flex-row">
|
||||
<LeftSider />
|
||||
<div className='flex-1'>{children}</div>
|
||||
<div className='flex-1 overflow-auto'>{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
</CssVarsProvider>
|
||||
|
@ -1,9 +1,270 @@
|
||||
import Image from 'next/image'
|
||||
"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';
|
||||
|
||||
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 handleGetD = () => {
|
||||
sendGetRequest('/v1/chat/dialogue/list', {
|
||||
})
|
||||
}
|
||||
console.log(mode, 'mode', radioClasses, 'radioClasses')
|
||||
useEffect(() => {
|
||||
handleGetD();
|
||||
}, []);
|
||||
return (
|
||||
<div>
|
||||
Hello GPT
|
||||
<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) => {
|
||||
console.log(Number(e.target.value) * 10, '===')
|
||||
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) => {
|
||||
console.log(e, 'e', value, 'v')
|
||||
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) => {
|
||||
console.log(e, 'e', value, 'v')
|
||||
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,
|
||||
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>
|
||||
|
||||
)
|
||||
}
|
||||
|
@ -76,7 +76,6 @@ const ChatBoxComp = ({
|
||||
display: 'flex',
|
||||
flex: 1,
|
||||
flexBasis: '100%',
|
||||
maxWidth: '700px',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
maxHeight: '100%',
|
||||
|
@ -1,14 +1,40 @@
|
||||
"use client";
|
||||
import React, { useMemo } from 'react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import Link from 'next/link';
|
||||
import { Box, List, ListItem, ListItemButton, ListItemDecorator, ListItemContent } from '@/lib/mui';
|
||||
import Image from 'next/image';
|
||||
import { Box, List, ListItem, ListItemButton, ListItemDecorator, ListItemContent, Typography, Button, useColorScheme } 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'
|
||||
}]
|
||||
}];
|
||||
|
||||
const LeftSider = () => {
|
||||
const pathname = usePathname();
|
||||
console.log(pathname, 'router')
|
||||
const { mode, setMode } = useColorScheme();
|
||||
const [chatSelect, setChatSelect] = useState();
|
||||
const menus = useMemo(() => {
|
||||
return [{
|
||||
label: 'Agents',
|
||||
@ -23,19 +49,111 @@ const LeftSider = () => {
|
||||
}];
|
||||
}, [pathname]);
|
||||
|
||||
const handleChangeTheme = () => {
|
||||
if (mode === 'light') {
|
||||
setMode('dark');
|
||||
} else {
|
||||
setMode('light');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={[
|
||||
{
|
||||
p: 2,
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
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>
|
||||
</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' },
|
||||
}}
|
||||
>
|
||||
{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
|
||||
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>
|
||||
@ -50,13 +168,13 @@ const LeftSider = () => {
|
||||
<Link key={each.route} href={each.route}>
|
||||
<ListItem>
|
||||
<ListItemButton
|
||||
color="neutral"
|
||||
selected={each.active}
|
||||
variant={each.active ? 'soft' : 'plain'}
|
||||
>
|
||||
<ListItemDecorator
|
||||
sx={{
|
||||
color: each.active ? 'inherit' : 'neutral.500',
|
||||
'--ListItemDecorator-size': '26px'
|
||||
}}
|
||||
>
|
||||
{each.icon}
|
||||
@ -68,8 +186,25 @@ const LeftSider = () => {
|
||||
))}
|
||||
</List>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemButton
|
||||
onClick={handleChangeTheme}
|
||||
>
|
||||
<ListItemDecorator>
|
||||
{mode === 'dark' ? (
|
||||
<DarkModeIcon fontSize="small"/>
|
||||
) : (
|
||||
<WbSunnyIcon fontSize="small"/>
|
||||
)}
|
||||
</ListItemDecorator>
|
||||
<ListItemContent>Theme</ListItemContent>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
</List>
|
||||
</Box>
|
||||
</div>
|
||||
|
||||
</Box>
|
||||
)
|
||||
};
|
||||
|
||||
|
31
datacenter/utils/request.ts
Normal file
31
datacenter/utils/request.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import axios from 'axios';
|
||||
|
||||
axios.defaults.baseURL = 'http://30.183.153.244:5000';
|
||||
|
||||
axios.defaults.timeout = 10000;
|
||||
|
||||
axios.interceptors.response.use(
|
||||
response => response.data,
|
||||
err => Promise.reject(err)
|
||||
);
|
||||
|
||||
export const sendGetRequest = (url: string, qs?: { [key: string]: any }) => {
|
||||
if (qs) {
|
||||
const str = Object.keys(qs)
|
||||
.filter(k => qs[k] !== undefined && qs[k] !== '')
|
||||
.map(k => `${k}=${qs[k]}`)
|
||||
.join('&');
|
||||
if (str) {
|
||||
url += `?${str}`;
|
||||
}
|
||||
}
|
||||
axios.get(url, {
|
||||
headers: {
|
||||
"Content-Type": 'text/plain'
|
||||
}
|
||||
}).then(res => {
|
||||
console.log(res, 'res');
|
||||
}).catch(err => {
|
||||
console.log(err, 'err');
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user