mirror of
https://github.com/csunny/DB-GPT.git
synced 2025-08-14 06:26:18 +00:00
代码清理
This commit is contained in:
parent
ad4fd6c0fe
commit
3f733a302b
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "next/core-web-vitals"
|
|
||||||
}
|
|
35
datacenter/.gitignore
vendored
35
datacenter/.gitignore
vendored
@ -1,35 +0,0 @@
|
|||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
/.pnp
|
|
||||||
.pnp.js
|
|
||||||
|
|
||||||
# testing
|
|
||||||
/coverage
|
|
||||||
|
|
||||||
# next.js
|
|
||||||
/.next/
|
|
||||||
/out/
|
|
||||||
|
|
||||||
# production
|
|
||||||
/build
|
|
||||||
|
|
||||||
# misc
|
|
||||||
.DS_Store
|
|
||||||
*.pem
|
|
||||||
|
|
||||||
# debug
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
|
|
||||||
# local env files
|
|
||||||
.env.prod
|
|
||||||
|
|
||||||
# vercel
|
|
||||||
.vercel
|
|
||||||
|
|
||||||
# typescript
|
|
||||||
*.tsbuildinfo
|
|
||||||
next-env.d.ts
|
|
@ -1,34 +0,0 @@
|
|||||||
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
|
|
||||||
|
|
||||||
## Getting Started
|
|
||||||
|
|
||||||
First, run the development server:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run dev
|
|
||||||
# or
|
|
||||||
yarn dev
|
|
||||||
# or
|
|
||||||
pnpm dev
|
|
||||||
```
|
|
||||||
|
|
||||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
|
||||||
|
|
||||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
|
||||||
|
|
||||||
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
|
|
||||||
|
|
||||||
## Learn More
|
|
||||||
|
|
||||||
To learn more about Next.js, take a look at the following resources:
|
|
||||||
|
|
||||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
|
||||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
|
||||||
|
|
||||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
|
|
||||||
|
|
||||||
## Deploy on Vercel
|
|
||||||
|
|
||||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
|
||||||
|
|
||||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
|
@ -1,13 +0,0 @@
|
|||||||
import { Box } from '@/lib/mui';
|
|
||||||
|
|
||||||
export default function RootLayout({
|
|
||||||
children,
|
|
||||||
}: {
|
|
||||||
children: React.ReactNode
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{children}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,214 +0,0 @@
|
|||||||
"use client"
|
|
||||||
import ChatBoxComp from '@/components/chatBox';
|
|
||||||
import { Chart, LineAdvance, Interval, Tooltip, getTheme } from 'bizcharts';
|
|
||||||
import { Card, CardContent, Typography, Grid, styled, Sheet } from '@/lib/mui';
|
|
||||||
import { Stack } from '@mui/material';
|
|
||||||
import useAgentChat from '@/hooks/useAgentChat';
|
|
||||||
|
|
||||||
|
|
||||||
const Item = styled(Sheet)(({ theme }) => ({
|
|
||||||
...theme.typography.body2,
|
|
||||||
padding: theme.spacing(1),
|
|
||||||
textAlign: 'center',
|
|
||||||
borderRadius: 4,
|
|
||||||
color: theme.vars.palette.text.secondary,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const Agents = () => {
|
|
||||||
const { handleChatSubmit, history } = useAgentChat({
|
|
||||||
queryAgentURL: `/v1/chat/completions`,
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = [
|
|
||||||
{
|
|
||||||
month: "Jan",
|
|
||||||
city: "Tokyo",
|
|
||||||
temperature: 7
|
|
||||||
},
|
|
||||||
{
|
|
||||||
month: "Feb",
|
|
||||||
city: "Tokyo",
|
|
||||||
temperature: 13
|
|
||||||
},
|
|
||||||
{
|
|
||||||
month: "Mar",
|
|
||||||
city: "Tokyo",
|
|
||||||
temperature: 16.5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
month: "Apr",
|
|
||||||
city: "Tokyo",
|
|
||||||
temperature: 14.5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
month: "May",
|
|
||||||
city: "Tokyo",
|
|
||||||
temperature: 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
month: "Jun",
|
|
||||||
city: "Tokyo",
|
|
||||||
temperature: 7.5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
month: "Jul",
|
|
||||||
city: "Tokyo",
|
|
||||||
temperature: 9.2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
month: "Aug",
|
|
||||||
city: "Tokyo",
|
|
||||||
temperature: 14.5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
month: "Sep",
|
|
||||||
city: "Tokyo",
|
|
||||||
temperature: 9.3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
month: "Oct",
|
|
||||||
city: "Tokyo",
|
|
||||||
temperature: 8.3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
month: "Nov",
|
|
||||||
city: "Tokyo",
|
|
||||||
temperature: 8.9
|
|
||||||
},
|
|
||||||
{
|
|
||||||
month: "Dec",
|
|
||||||
city: "Tokyo",
|
|
||||||
temperature: 5.6
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const d1 = [
|
|
||||||
{ year: '1951 年', sales: 0 },
|
|
||||||
{ year: '1952 年', sales: 52 },
|
|
||||||
{ year: '1956 年', sales: 61 },
|
|
||||||
{ year: '1957 年', sales: 45 },
|
|
||||||
{ year: '1958 年', sales: 48 },
|
|
||||||
{ year: '1959 年', sales: 38 },
|
|
||||||
{ year: '1960 年', sales: 38 },
|
|
||||||
{ year: '1962 年', sales: 38 },
|
|
||||||
];
|
|
||||||
|
|
||||||
const topCard = [{
|
|
||||||
label: 'Revenue Won',
|
|
||||||
value: '$7,811,851'
|
|
||||||
}, {
|
|
||||||
label: 'Close %',
|
|
||||||
value: '37.7%'
|
|
||||||
}, {
|
|
||||||
label: 'AVG Days to Close',
|
|
||||||
value: '121'
|
|
||||||
}, {
|
|
||||||
label: 'Opportunities Won',
|
|
||||||
value: '526'
|
|
||||||
}];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='p-4 flex flex-row gap-6 min-h-full w-full'>
|
|
||||||
<div className='flex w-full'>
|
|
||||||
<Grid container spacing={2} sx={{ flexGrow: 1 }}>
|
|
||||||
<Grid xs={8}>
|
|
||||||
<Stack spacing={2} className='h-full'>
|
|
||||||
<Item>
|
|
||||||
<Grid container spacing={2}>
|
|
||||||
{topCard.map((item) => (
|
|
||||||
<Grid key={item.label} xs={3}>
|
|
||||||
<Card className="flex-1 h-full">
|
|
||||||
<CardContent className="justify-around">
|
|
||||||
<Typography gutterBottom component="div">
|
|
||||||
{item.label}
|
|
||||||
</Typography>
|
|
||||||
<Typography>
|
|
||||||
{item.value}
|
|
||||||
</Typography>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</Grid>
|
|
||||||
))}
|
|
||||||
</Grid>
|
|
||||||
</Item>
|
|
||||||
<Item className='flex-1'>
|
|
||||||
<Card className='h-full'>
|
|
||||||
<CardContent className='h-full'>
|
|
||||||
<Typography gutterBottom component="div">
|
|
||||||
Revenue Won by Month
|
|
||||||
</Typography>
|
|
||||||
<div className='flex-1'>
|
|
||||||
<Chart padding={[10, 20, 50, 40]} autoFit data={data} >
|
|
||||||
<LineAdvance
|
|
||||||
shape="smooth"
|
|
||||||
point
|
|
||||||
area
|
|
||||||
position="month*temperature"
|
|
||||||
color="city"
|
|
||||||
/>
|
|
||||||
</Chart>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</Item>
|
|
||||||
<Item className='flex-1'>
|
|
||||||
<Grid container spacing={2} className='h-full'>
|
|
||||||
<Grid xs={4} className='h-full'>
|
|
||||||
<Card className='flex-1 h-full'>
|
|
||||||
<CardContent className='h-full'>
|
|
||||||
<Typography gutterBottom component="div">
|
|
||||||
Close % by Month
|
|
||||||
</Typography>
|
|
||||||
<div className='flex-1'>
|
|
||||||
<Chart autoFit data={d1} >
|
|
||||||
<Interval position="year*sales" style={{ lineWidth: 3, stroke: getTheme().colors10[0] }} />
|
|
||||||
<Tooltip shared />
|
|
||||||
</Chart>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</Grid>
|
|
||||||
<Grid xs={4} className='h-full'>
|
|
||||||
<Card className='flex-1 h-full'>
|
|
||||||
<CardContent className='h-full'>
|
|
||||||
<Typography gutterBottom component="div">
|
|
||||||
Close % by Month
|
|
||||||
</Typography>
|
|
||||||
<div className='flex-1'>
|
|
||||||
<Chart autoFit data={d1} >
|
|
||||||
<Interval position="year*sales" style={{ lineWidth: 3, stroke: getTheme().colors10[0] }} />
|
|
||||||
<Tooltip shared />
|
|
||||||
</Chart>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</Grid>
|
|
||||||
<Grid xs={4} className='h-full'>
|
|
||||||
<Card className='flex-1 h-full'>
|
|
||||||
<CardContent className='h-full'>
|
|
||||||
<Typography gutterBottom component="div">
|
|
||||||
Close % by Month
|
|
||||||
</Typography>
|
|
||||||
<div className='flex-1'>
|
|
||||||
<Chart autoFit data={d1} >
|
|
||||||
<Interval position="year*sales" style={{ lineWidth: 3, stroke: getTheme().colors10[0] }} />
|
|
||||||
<Tooltip shared />
|
|
||||||
</Chart>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Item>
|
|
||||||
</Stack>
|
|
||||||
</Grid>
|
|
||||||
<Grid xs={4}>
|
|
||||||
<ChatBoxComp messages={history} onSubmit={handleChatSubmit}/>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Agents;
|
|
@ -1,50 +0,0 @@
|
|||||||
"use client"
|
|
||||||
import { useRequest } from 'ahooks';
|
|
||||||
import { sendGetRequest, sendPostRequest } from '@/utils/request';
|
|
||||||
import useAgentChat from '@/hooks/useAgentChat';
|
|
||||||
import ChatBoxComp from '@/components/chatBoxTemp';
|
|
||||||
import { useDialogueContext } from '@/app/context/dialogue';
|
|
||||||
import { useSearchParams } from 'next/navigation';
|
|
||||||
|
|
||||||
const AgentPage = () => {
|
|
||||||
const searchParams = useSearchParams();
|
|
||||||
const { refreshDialogList } = useDialogueContext();
|
|
||||||
const id = searchParams.get('id');
|
|
||||||
const scene = searchParams.get('scene');
|
|
||||||
|
|
||||||
const { data: historyList } = useRequest(async () => await sendGetRequest('/v1/chat/dialogue/messages/history', {
|
|
||||||
con_uid: id
|
|
||||||
}), {
|
|
||||||
ready: !!id,
|
|
||||||
refreshDeps: [id]
|
|
||||||
});
|
|
||||||
|
|
||||||
const { data: paramsList } = useRequest(async () => await sendPostRequest(`/v1/chat/mode/params/list?chat_mode=${scene}`), {
|
|
||||||
ready: !!scene,
|
|
||||||
refreshDeps: [id, scene]
|
|
||||||
});
|
|
||||||
|
|
||||||
const { history, handleChatSubmit } = useAgentChat({
|
|
||||||
queryAgentURL: `/v1/chat/completions`,
|
|
||||||
queryBody: {
|
|
||||||
conv_uid: id,
|
|
||||||
chat_mode: scene || 'chat_normal',
|
|
||||||
},
|
|
||||||
initHistory: historyList?.data
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<ChatBoxComp
|
|
||||||
clearIntialMessage={async () => {
|
|
||||||
await refreshDialogList();
|
|
||||||
}}
|
|
||||||
messages={history || []}
|
|
||||||
onSubmit={handleChatSubmit}
|
|
||||||
paramsList={paramsList?.data}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AgentPage;
|
|
@ -1,37 +0,0 @@
|
|||||||
import { useRequest } from 'ahooks';
|
|
||||||
import { sendGetRequest } from '@/utils/request';
|
|
||||||
import { createCtx } from '@/utils/ctx-helper';
|
|
||||||
import { AxiosResponse } from 'axios';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
export const [useDialogueContext, DialogueProvider] = createCtx<{
|
|
||||||
dialogueList?: void | AxiosResponse<any, any> | undefined;
|
|
||||||
queryDialogueList: () => void;
|
|
||||||
refreshDialogList: () => void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const DialogueContext = ({ children }: {
|
|
||||||
children: React.ReactElement
|
|
||||||
}) => {
|
|
||||||
const {
|
|
||||||
run: queryDialogueList,
|
|
||||||
data: dialogueList,
|
|
||||||
refresh: refreshDialogList,
|
|
||||||
} = useRequest(async () => await sendGetRequest('/v1/chat/dialogue/list'), {
|
|
||||||
manual: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DialogueProvider
|
|
||||||
value={{
|
|
||||||
dialogueList,
|
|
||||||
queryDialogueList,
|
|
||||||
refreshDialogList
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</DialogueProvider>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DialogueContext;
|
|
@ -1,173 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import { useSearchParams, useRouter } from 'next/navigation'
|
|
||||||
import React, { useState, useEffect } from 'react'
|
|
||||||
import {
|
|
||||||
useColorScheme,
|
|
||||||
Table,
|
|
||||||
Stack,
|
|
||||||
Typography,
|
|
||||||
Breadcrumbs,
|
|
||||||
Link
|
|
||||||
} from '@/lib/mui'
|
|
||||||
import { Popover, Pagination } from 'antd'
|
|
||||||
import { sendSpacePostRequest } from '@/utils/request'
|
|
||||||
const page_size = 20
|
|
||||||
|
|
||||||
const ChunkList = () => {
|
|
||||||
const router = useRouter()
|
|
||||||
const { mode } = useColorScheme()
|
|
||||||
const spaceName = useSearchParams().get('spacename')
|
|
||||||
const documentId = useSearchParams().get('documentid')
|
|
||||||
const [total, setTotal] = useState<number>(0)
|
|
||||||
const [current, setCurrent] = useState<number>(0)
|
|
||||||
const [chunkList, setChunkList] = useState<any>([])
|
|
||||||
useEffect(() => {
|
|
||||||
async function fetchChunks() {
|
|
||||||
const data = await sendSpacePostRequest(
|
|
||||||
`/knowledge/${spaceName}/chunk/list`,
|
|
||||||
{
|
|
||||||
document_id: documentId,
|
|
||||||
page: 1,
|
|
||||||
page_size
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if (data.success) {
|
|
||||||
setChunkList(data.data.data)
|
|
||||||
setTotal(data.data.total)
|
|
||||||
setCurrent(data.data.page)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fetchChunks()
|
|
||||||
}, [])
|
|
||||||
return (
|
|
||||||
<div className="p-4">
|
|
||||||
<Stack
|
|
||||||
direction="row"
|
|
||||||
justifyContent="flex-start"
|
|
||||||
alignItems="center"
|
|
||||||
sx={{ marginBottom: '20px' }}
|
|
||||||
>
|
|
||||||
<Breadcrumbs aria-label="breadcrumbs">
|
|
||||||
<Link
|
|
||||||
onClick={() => {
|
|
||||||
router.push('/datastores')
|
|
||||||
}}
|
|
||||||
key="Knowledge Space"
|
|
||||||
underline="hover"
|
|
||||||
color="neutral"
|
|
||||||
fontSize="inherit"
|
|
||||||
>
|
|
||||||
Knowledge Space
|
|
||||||
</Link>
|
|
||||||
<Link
|
|
||||||
onClick={() => {
|
|
||||||
router.push(`/datastores/documents?name=${spaceName}`)
|
|
||||||
}}
|
|
||||||
key="Knowledge Space"
|
|
||||||
underline="hover"
|
|
||||||
color="neutral"
|
|
||||||
fontSize="inherit"
|
|
||||||
>
|
|
||||||
Documents
|
|
||||||
</Link>
|
|
||||||
<Typography fontSize="inherit">Chunks</Typography>
|
|
||||||
</Breadcrumbs>
|
|
||||||
</Stack>
|
|
||||||
<div className="p-4">
|
|
||||||
{chunkList.length ? (
|
|
||||||
<>
|
|
||||||
<Table
|
|
||||||
color="primary"
|
|
||||||
variant="plain"
|
|
||||||
size="lg"
|
|
||||||
sx={{
|
|
||||||
'& tbody tr: hover': {
|
|
||||||
backgroundColor:
|
|
||||||
mode === 'light' ? 'rgb(246, 246, 246)' : 'rgb(33, 33, 40)'
|
|
||||||
},
|
|
||||||
'& tbody tr: hover a': {
|
|
||||||
textDecoration: 'underline'
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Content</th>
|
|
||||||
<th>Meta Data</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{chunkList.map((row: any) => (
|
|
||||||
<tr key={row.id}>
|
|
||||||
<td>{row.doc_name}</td>
|
|
||||||
<td>
|
|
||||||
{
|
|
||||||
<Popover content={row.content} trigger="hover">
|
|
||||||
{row.content.length > 10
|
|
||||||
? `${row.content.slice(0, 10)}...`
|
|
||||||
: row.content}
|
|
||||||
</Popover>
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{
|
|
||||||
<Popover
|
|
||||||
content={JSON.stringify(
|
|
||||||
row.meta_info || '{}',
|
|
||||||
null,
|
|
||||||
2
|
|
||||||
)}
|
|
||||||
trigger="hover"
|
|
||||||
>
|
|
||||||
{row.meta_info.length > 10
|
|
||||||
? `${row.meta_info.slice(0, 10)}...`
|
|
||||||
: row.meta_info}
|
|
||||||
</Popover>
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</Table>
|
|
||||||
<Stack
|
|
||||||
direction="row"
|
|
||||||
justifyContent="flex-end"
|
|
||||||
sx={{
|
|
||||||
marginTop: '20px'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Pagination
|
|
||||||
defaultPageSize={20}
|
|
||||||
showSizeChanger={false}
|
|
||||||
current={current}
|
|
||||||
total={total}
|
|
||||||
onChange={async (page) => {
|
|
||||||
const data = await sendSpacePostRequest(
|
|
||||||
`/knowledge/${spaceName}/chunk/list`,
|
|
||||||
{
|
|
||||||
document_id: documentId,
|
|
||||||
page,
|
|
||||||
page_size
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if (data.success) {
|
|
||||||
setChunkList(data.data.data)
|
|
||||||
setTotal(data.data.total)
|
|
||||||
setCurrent(data.data.page)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
hideOnSinglePage
|
|
||||||
/>
|
|
||||||
</Stack>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ChunkList
|
|
@ -1,602 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import { useRouter, useSearchParams } from 'next/navigation'
|
|
||||||
import React, { useState, useEffect } from 'react'
|
|
||||||
import {
|
|
||||||
useColorScheme,
|
|
||||||
Button,
|
|
||||||
Table,
|
|
||||||
Sheet,
|
|
||||||
Modal,
|
|
||||||
Box,
|
|
||||||
Stack,
|
|
||||||
Input,
|
|
||||||
Textarea,
|
|
||||||
Chip,
|
|
||||||
Switch,
|
|
||||||
Typography,
|
|
||||||
Breadcrumbs,
|
|
||||||
Link,
|
|
||||||
styled
|
|
||||||
} from '@/lib/mui'
|
|
||||||
import moment from 'moment'
|
|
||||||
import { InboxOutlined } from '@ant-design/icons'
|
|
||||||
import CheckCircleOutlinedIcon from '@mui/icons-material/CheckCircleOutlined'
|
|
||||||
import CachedIcon from '@mui/icons-material/Cached'
|
|
||||||
import type { UploadProps } from 'antd'
|
|
||||||
import { Upload, Pagination, Popover, message } from 'antd'
|
|
||||||
import {
|
|
||||||
sendSpacePostRequest,
|
|
||||||
sendSpaceUploadPostRequest
|
|
||||||
} from '@/utils/request'
|
|
||||||
|
|
||||||
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'
|
|
||||||
]
|
|
||||||
const documentTypeList = [
|
|
||||||
{
|
|
||||||
type: 'text',
|
|
||||||
title: 'Text',
|
|
||||||
subTitle: 'Fill your raw text'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'webPage',
|
|
||||||
title: 'URL',
|
|
||||||
subTitle: 'Fetch the content of a URL'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'file',
|
|
||||||
title: 'Document',
|
|
||||||
subTitle:
|
|
||||||
'Upload a document, document type can be PDF, CSV, Text, PowerPoint, Word, Markdown'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
const page_size = 20
|
|
||||||
|
|
||||||
const Documents = () => {
|
|
||||||
const router = useRouter()
|
|
||||||
const spaceName = useSearchParams().get('name')
|
|
||||||
const { mode } = useColorScheme()
|
|
||||||
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<any>('')
|
|
||||||
const [textSource, setTextSource] = useState<string>('')
|
|
||||||
const [text, setText] = useState<string>('')
|
|
||||||
const [originFileObj, setOriginFileObj] = useState<any>(null)
|
|
||||||
const [total, setTotal] = useState<number>(0)
|
|
||||||
const [current, setCurrent] = useState<number>(0)
|
|
||||||
const [synchChecked, setSynchChecked] = useState<boolean>(true)
|
|
||||||
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 data = await sendSpacePostRequest(
|
|
||||||
`/knowledge/${spaceName}/document/list`,
|
|
||||||
{
|
|
||||||
page: 1,
|
|
||||||
page_size
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if (data.success) {
|
|
||||||
setDocuments(data.data.data)
|
|
||||||
setTotal(data.data.total)
|
|
||||||
setCurrent(data.data.page)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fetchDocuments()
|
|
||||||
}, [])
|
|
||||||
return (
|
|
||||||
<div className="p-4">
|
|
||||||
<Stack
|
|
||||||
direction="row"
|
|
||||||
justifyContent="space-between"
|
|
||||||
alignItems="center"
|
|
||||||
sx={{ marginBottom: '20px' }}
|
|
||||||
>
|
|
||||||
<Breadcrumbs aria-label="breadcrumbs">
|
|
||||||
<Link
|
|
||||||
onClick={() => {
|
|
||||||
router.push('/datastores')
|
|
||||||
}}
|
|
||||||
key="Knowledge Space"
|
|
||||||
underline="hover"
|
|
||||||
color="neutral"
|
|
||||||
fontSize="inherit"
|
|
||||||
>
|
|
||||||
Knowledge Space
|
|
||||||
</Link>
|
|
||||||
<Typography fontSize="inherit">Documents</Typography>
|
|
||||||
</Breadcrumbs>
|
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
onClick={() => setIsAddDocumentModalShow(true)}
|
|
||||||
>
|
|
||||||
+ Add Datasource
|
|
||||||
</Button>
|
|
||||||
</Stack>
|
|
||||||
{documents.length ? (
|
|
||||||
<>
|
|
||||||
<Table
|
|
||||||
color="primary"
|
|
||||||
variant="plain"
|
|
||||||
size="lg"
|
|
||||||
sx={{
|
|
||||||
'& tbody tr: hover': {
|
|
||||||
backgroundColor:
|
|
||||||
mode === 'light' ? 'rgb(246, 246, 246)' : 'rgb(33, 33, 40)'
|
|
||||||
},
|
|
||||||
'& tbody tr: hover a': {
|
|
||||||
textDecoration: 'underline'
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Type</th>
|
|
||||||
<th>Size</th>
|
|
||||||
<th>Last Synch</th>
|
|
||||||
<th>Status</th>
|
|
||||||
<th>Result</th>
|
|
||||||
<th>Operation</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{documents.map((row: any) => (
|
|
||||||
<tr key={row.id}>
|
|
||||||
<td>{row.doc_name}</td>
|
|
||||||
<td>
|
|
||||||
<Chip variant="solid" color="neutral" sx={{ opacity: 0.5 }}>
|
|
||||||
{row.doc_type}
|
|
||||||
</Chip>
|
|
||||||
</td>
|
|
||||||
<td>{row.chunk_size} chunks</td>
|
|
||||||
<td>{moment(row.last_sync).format('YYYY-MM-DD HH:MM:SS')}</td>
|
|
||||||
<td>
|
|
||||||
<Chip
|
|
||||||
sx={{ opacity: 0.5 }}
|
|
||||||
variant="solid"
|
|
||||||
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>
|
|
||||||
{(function () {
|
|
||||||
if (row.status === 'TODO' || row.status === 'RUNNING') {
|
|
||||||
return ''
|
|
||||||
} else if (row.status === 'FINISHED') {
|
|
||||||
return (
|
|
||||||
<Popover content={row.result} trigger="hover">
|
|
||||||
<Chip
|
|
||||||
variant="solid"
|
|
||||||
color="success"
|
|
||||||
sx={{ opacity: 0.5 }}
|
|
||||||
>
|
|
||||||
SUCCESS
|
|
||||||
</Chip>
|
|
||||||
</Popover>
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<Popover content={row.result} trigger="hover">
|
|
||||||
<Chip
|
|
||||||
variant="solid"
|
|
||||||
color="danger"
|
|
||||||
sx={{ opacity: 0.5 }}
|
|
||||||
>
|
|
||||||
FAILED
|
|
||||||
</Chip>
|
|
||||||
</Popover>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})()}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{
|
|
||||||
<>
|
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
size="sm"
|
|
||||||
sx={{
|
|
||||||
marginRight: '20px'
|
|
||||||
}}
|
|
||||||
onClick={async () => {
|
|
||||||
const data = await sendSpacePostRequest(
|
|
||||||
`/knowledge/${spaceName}/document/sync`,
|
|
||||||
{
|
|
||||||
doc_ids: [row.id]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if (data.success) {
|
|
||||||
message.success('success')
|
|
||||||
} else {
|
|
||||||
message.error(data.err_msg || 'failed')
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Synch
|
|
||||||
<CachedIcon />
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => {
|
|
||||||
router.push(
|
|
||||||
`/datastores/documents/chunklist?spacename=${spaceName}&documentid=${row.id}`
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Details
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</Table>
|
|
||||||
<Stack
|
|
||||||
direction="row"
|
|
||||||
justifyContent="flex-end"
|
|
||||||
sx={{
|
|
||||||
marginTop: '20px'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Pagination
|
|
||||||
defaultPageSize={20}
|
|
||||||
showSizeChanger={false}
|
|
||||||
current={current}
|
|
||||||
total={total}
|
|
||||||
onChange={async (page) => {
|
|
||||||
const data = await sendSpacePostRequest(
|
|
||||||
`/knowledge/${spaceName}/document/list`,
|
|
||||||
{
|
|
||||||
page,
|
|
||||||
page_size
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if (data.success) {
|
|
||||||
setDocuments(data.data.data)
|
|
||||||
setTotal(data.data.total)
|
|
||||||
setCurrent(data.data.page)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
hideOnSinglePage
|
|
||||||
/>
|
|
||||||
</Stack>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
|
||||||
<Modal
|
|
||||||
sx={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
'z-index': 1000
|
|
||||||
}}
|
|
||||||
open={isAddDocumentModalShow}
|
|
||||||
onClose={() => setIsAddDocumentModalShow(false)}
|
|
||||||
>
|
|
||||||
<Sheet
|
|
||||||
variant="outlined"
|
|
||||||
sx={{
|
|
||||||
width: 800,
|
|
||||||
borderRadius: 'md',
|
|
||||||
p: 3,
|
|
||||||
boxShadow: 'lg'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box sx={{ width: '100%' }}>
|
|
||||||
<Stack spacing={2} direction="row">
|
|
||||||
{stepsOfAddingDocument.map((item: any, index: number) => (
|
|
||||||
<Item
|
|
||||||
key={item}
|
|
||||||
sx={{
|
|
||||||
fontWeight: activeStep === index ? 'bold' : '',
|
|
||||||
color: activeStep === index ? '#2AA3FF' : ''
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{index < activeStep ? (
|
|
||||||
<CheckCircleOutlinedIcon />
|
|
||||||
) : (
|
|
||||||
`${index + 1}.`
|
|
||||||
)}
|
|
||||||
{`${item}`}
|
|
||||||
</Item>
|
|
||||||
))}
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
|
||||||
{activeStep === 0 ? (
|
|
||||||
<>
|
|
||||||
<Box sx={{ margin: '30px auto' }}>
|
|
||||||
{documentTypeList.map((item: any) => (
|
|
||||||
<Sheet
|
|
||||||
key={item.type}
|
|
||||||
sx={{
|
|
||||||
boxSizing: 'border-box',
|
|
||||||
height: '80px',
|
|
||||||
padding: '12px',
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
border: '1px solid gray',
|
|
||||||
borderRadius: '6px',
|
|
||||||
marginBottom: '20px',
|
|
||||||
cursor: 'pointer'
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
setDocumentType(item.type)
|
|
||||||
setActiveStep(1)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Sheet sx={{ fontSize: '20px', fontWeight: 'bold' }}>
|
|
||||||
{item.title}
|
|
||||||
</Sheet>
|
|
||||||
<Sheet>{item.subTitle}</Sheet>
|
|
||||||
</Sheet>
|
|
||||||
))}
|
|
||||||
</Box>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<Box sx={{ margin: '30px auto' }}>
|
|
||||||
Name:
|
|
||||||
<Input
|
|
||||||
placeholder="Please input the name"
|
|
||||||
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>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
Text Source(Optional):
|
|
||||||
<Input
|
|
||||||
placeholder="Please input the text source"
|
|
||||||
onChange={(e: any) => setTextSource(e.target.value)}
|
|
||||||
sx={{ marginBottom: '20px' }}
|
|
||||||
/>
|
|
||||||
Text:
|
|
||||||
<Textarea
|
|
||||||
onChange={(e: any) => setText(e.target.value)}
|
|
||||||
minRows={4}
|
|
||||||
sx={{ marginBottom: '20px' }}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<Typography
|
|
||||||
component="label"
|
|
||||||
sx={{
|
|
||||||
marginTop: '20px'
|
|
||||||
}}
|
|
||||||
endDecorator={
|
|
||||||
<Switch
|
|
||||||
checked={synchChecked}
|
|
||||||
onChange={(event: any) =>
|
|
||||||
setSynchChecked(event.target.checked)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Synch:
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
<Stack
|
|
||||||
direction="row"
|
|
||||||
justifyContent="flex-start"
|
|
||||||
alignItems="center"
|
|
||||||
sx={{ marginBottom: '20px' }}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
sx={{ marginRight: '20px' }}
|
|
||||||
onClick={() => setActiveStep(0)}
|
|
||||||
>
|
|
||||||
{'< Back'}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
onClick={async () => {
|
|
||||||
if (documentName === '') {
|
|
||||||
message.error('Please input the name')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (documentType === 'webPage') {
|
|
||||||
if (webPageUrl === '') {
|
|
||||||
message.error('Please input the Web Page URL')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const data = await sendSpacePostRequest(
|
|
||||||
`/knowledge/${spaceName}/document/add`,
|
|
||||||
{
|
|
||||||
doc_name: documentName,
|
|
||||||
content: webPageUrl,
|
|
||||||
doc_type: 'URL'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
data.success &&
|
|
||||||
synchChecked &&
|
|
||||||
sendSpacePostRequest(
|
|
||||||
`/knowledge/${spaceName}/document/sync`,
|
|
||||||
{
|
|
||||||
doc_ids: [data.data]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if (data.success) {
|
|
||||||
message.success('success')
|
|
||||||
setIsAddDocumentModalShow(false)
|
|
||||||
const data = await sendSpacePostRequest(
|
|
||||||
`/knowledge/${spaceName}/document/list`,
|
|
||||||
{
|
|
||||||
page: current,
|
|
||||||
page_size
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if (data.success) {
|
|
||||||
setDocuments(data.data.data)
|
|
||||||
setTotal(data.data.total)
|
|
||||||
setCurrent(data.data.page)
|
|
||||||
}
|
|
||||||
} 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 data = await sendSpaceUploadPostRequest(
|
|
||||||
`/knowledge/${spaceName}/document/upload`,
|
|
||||||
formData
|
|
||||||
)
|
|
||||||
data.success &&
|
|
||||||
synchChecked &&
|
|
||||||
sendSpacePostRequest(
|
|
||||||
`/knowledge/${spaceName}/document/sync`,
|
|
||||||
{
|
|
||||||
doc_ids: [data.data]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if (data.success) {
|
|
||||||
message.success('success')
|
|
||||||
setIsAddDocumentModalShow(false)
|
|
||||||
const data = await sendSpacePostRequest(
|
|
||||||
`/knowledge/${spaceName}/document/list`,
|
|
||||||
{
|
|
||||||
page: current,
|
|
||||||
page_size
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if (data.success) {
|
|
||||||
setDocuments(data.data.data)
|
|
||||||
setTotal(data.data.total)
|
|
||||||
setCurrent(data.data.page)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
message.error(data.err_msg || 'failed')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (text === '') {
|
|
||||||
message.error('Please input the text')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const data = await sendSpacePostRequest(
|
|
||||||
`/knowledge/${spaceName}/document/add`,
|
|
||||||
{
|
|
||||||
doc_name: documentName,
|
|
||||||
source: textSource,
|
|
||||||
content: text,
|
|
||||||
doc_type: 'TEXT'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
data.success &&
|
|
||||||
synchChecked &&
|
|
||||||
sendSpacePostRequest(
|
|
||||||
`/knowledge/${spaceName}/document/sync`,
|
|
||||||
{
|
|
||||||
doc_ids: [data.data]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if (data.success) {
|
|
||||||
message.success('success')
|
|
||||||
setIsAddDocumentModalShow(false)
|
|
||||||
const data = await sendSpacePostRequest(
|
|
||||||
`/knowledge/${spaceName}/document/list`,
|
|
||||||
{
|
|
||||||
page: current,
|
|
||||||
page_size
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if (data.success) {
|
|
||||||
setDocuments(data.data.data)
|
|
||||||
setTotal(data.data.total)
|
|
||||||
setCurrent(data.data.page)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
message.error(data.err_msg || 'failed')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Finish
|
|
||||||
</Button>
|
|
||||||
</Stack>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Sheet>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Documents
|
|
@ -1,601 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import { useRouter } from 'next/navigation'
|
|
||||||
import React, { useState, useEffect } from 'react'
|
|
||||||
import { InboxOutlined } from '@ant-design/icons'
|
|
||||||
import CheckCircleOutlinedIcon from '@mui/icons-material/CheckCircleOutlined'
|
|
||||||
import ContentPasteSearchOutlinedIcon from '@mui/icons-material/ContentPasteSearchOutlined'
|
|
||||||
import type { UploadProps } from 'antd'
|
|
||||||
import { message, Upload } from 'antd'
|
|
||||||
import {
|
|
||||||
useColorScheme,
|
|
||||||
Modal,
|
|
||||||
Button,
|
|
||||||
Sheet,
|
|
||||||
Stack,
|
|
||||||
Box,
|
|
||||||
Input,
|
|
||||||
Textarea,
|
|
||||||
Switch,
|
|
||||||
Typography,
|
|
||||||
styled
|
|
||||||
} from '@/lib/mui'
|
|
||||||
import {
|
|
||||||
sendSpacePostRequest,
|
|
||||||
sendSpaceUploadPostRequest
|
|
||||||
} from '@/utils/request'
|
|
||||||
|
|
||||||
const { Dragger } = Upload
|
|
||||||
|
|
||||||
const Item = styled(Sheet)(({ theme }) => ({
|
|
||||||
width: '33%',
|
|
||||||
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 stepsOfAddingSpace = [
|
|
||||||
'Knowledge Space Config',
|
|
||||||
'Choose a Datasource type',
|
|
||||||
'Setup the Datasource'
|
|
||||||
]
|
|
||||||
const documentTypeList = [
|
|
||||||
{
|
|
||||||
type: 'text',
|
|
||||||
title: 'Text',
|
|
||||||
subTitle: 'Fill your raw text'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'webPage',
|
|
||||||
title: 'URL',
|
|
||||||
subTitle: 'Fetch the content of a URL'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'file',
|
|
||||||
title: 'Document',
|
|
||||||
subTitle:
|
|
||||||
'Upload a document, document type can be PDF, CSV, Text, PowerPoint, Word, Markdown'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const Index = () => {
|
|
||||||
const router = useRouter()
|
|
||||||
const { mode } = useColorScheme()
|
|
||||||
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 [owner, setOwner] = useState<string>('')
|
|
||||||
const [description, setDescription] = useState<string>('')
|
|
||||||
const [webPageUrl, setWebPageUrl] = useState<string>('')
|
|
||||||
const [documentName, setDocumentName] = useState<any>('')
|
|
||||||
const [textSource, setTextSource] = useState<string>('')
|
|
||||||
const [text, setText] = useState<string>('')
|
|
||||||
const [originFileObj, setOriginFileObj] = useState<any>(null)
|
|
||||||
const [synchChecked, setSynchChecked] = useState<boolean>(true)
|
|
||||||
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 data = await sendSpacePostRequest('/knowledge/space/list', {})
|
|
||||||
if (data.success) {
|
|
||||||
setKnowledgeSpaceList(data.data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fetchData()
|
|
||||||
}, [])
|
|
||||||
return (
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
width: '100%',
|
|
||||||
height: '100%'
|
|
||||||
}}
|
|
||||||
className="bg-[#F1F2F5] dark:bg-[#212121]"
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
className="page-body p-4"
|
|
||||||
sx={{
|
|
||||||
'&': {
|
|
||||||
height: '90%',
|
|
||||||
overflow: 'auto'
|
|
||||||
},
|
|
||||||
'&::-webkit-scrollbar': {
|
|
||||||
display: 'none'
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Stack
|
|
||||||
direction="row"
|
|
||||||
justifyContent="space-between"
|
|
||||||
alignItems="center"
|
|
||||||
flexWrap="wrap"
|
|
||||||
sx={{
|
|
||||||
'& i': {
|
|
||||||
width: '430px',
|
|
||||||
marginRight: '30px'
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: 'flex',
|
|
||||||
alignContent: 'start',
|
|
||||||
boxSizing: 'content-box',
|
|
||||||
width: '390px',
|
|
||||||
height: '79px',
|
|
||||||
padding: '33px 20px 40px',
|
|
||||||
marginRight: '30px',
|
|
||||||
marginBottom: '30px',
|
|
||||||
fontSize: '18px',
|
|
||||||
fontWeight: 'bold',
|
|
||||||
color: 'black',
|
|
||||||
flexShrink: 0,
|
|
||||||
flexGrow: 0,
|
|
||||||
cursor: 'pointer',
|
|
||||||
borderRadius: '16px',
|
|
||||||
'&: hover': {
|
|
||||||
boxShadow:
|
|
||||||
'0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);'
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onClick={() => setIsAddKnowledgeSpaceModalShow(true)}
|
|
||||||
className="bg-[#E9EBEE] dark:bg-[#484848]"
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
width: '32px',
|
|
||||||
height: '32px',
|
|
||||||
lineHeight: '28px',
|
|
||||||
border: '1px solid #2AA3FF',
|
|
||||||
textAlign: 'center',
|
|
||||||
borderRadius: '5px',
|
|
||||||
marginRight: '5px',
|
|
||||||
fontWeight: '300',
|
|
||||||
color: '#2AA3FF'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
+
|
|
||||||
</Box>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
fontSize: '16px'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
space
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
{knowledgeSpaceList.map((item: any, index: number) => (
|
|
||||||
<Box
|
|
||||||
key={index}
|
|
||||||
sx={{
|
|
||||||
padding: '30px 20px 40px',
|
|
||||||
marginRight: '30px',
|
|
||||||
marginBottom: '30px',
|
|
||||||
borderTop: '4px solid rgb(84, 164, 248)',
|
|
||||||
flexShrink: 0,
|
|
||||||
flexGrow: 0,
|
|
||||||
cursor: 'pointer',
|
|
||||||
borderRadius: '10px',
|
|
||||||
'&: hover': {
|
|
||||||
boxShadow:
|
|
||||||
'0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);'
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
router.push(`/datastores/documents?name=${item.name}`)
|
|
||||||
}}
|
|
||||||
className="bg-[#FFFFFF] dark:bg-[#484848]"
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
fontSize: '18px',
|
|
||||||
marginBottom: '10px',
|
|
||||||
fontWeight: 'bold',
|
|
||||||
color: 'black'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ContentPasteSearchOutlinedIcon
|
|
||||||
sx={{ marginRight: '5px', color: '#2AA3FF' }}
|
|
||||||
/>
|
|
||||||
{item.name}
|
|
||||||
</Box>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'flex-start'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
width: '130px',
|
|
||||||
flexGrow: 0,
|
|
||||||
flexShrink: 0
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
color: '#2AA3FF'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{item.vector_type}
|
|
||||||
</Box>
|
|
||||||
<Box sx={{ fontSize: '12px', color: 'black' }}>Vector</Box>
|
|
||||||
</Box>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
width: '130px',
|
|
||||||
flexGrow: 0,
|
|
||||||
flexShrink: 0
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
color: '#2AA3FF'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{item.owner}
|
|
||||||
</Box>
|
|
||||||
<Box sx={{ fontSize: '12px', color: 'black' }}>Owner</Box>
|
|
||||||
</Box>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
width: '130px',
|
|
||||||
flexGrow: 0,
|
|
||||||
flexShrink: 0
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
color: '#2AA3FF'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{item.docs || 0}
|
|
||||||
</Box>
|
|
||||||
<Box sx={{ fontSize: '12px', color: 'black' }}>Docs</Box>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
))}
|
|
||||||
<i></i>
|
|
||||||
<i></i>
|
|
||||||
<i></i>
|
|
||||||
<i></i>
|
|
||||||
<i></i>
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
|
||||||
<Modal
|
|
||||||
sx={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
'z-index': 1000
|
|
||||||
}}
|
|
||||||
open={isAddKnowledgeSpaceModalShow}
|
|
||||||
onClose={() => setIsAddKnowledgeSpaceModalShow(false)}
|
|
||||||
>
|
|
||||||
<Sheet
|
|
||||||
variant="outlined"
|
|
||||||
sx={{
|
|
||||||
width: 800,
|
|
||||||
borderRadius: 'md',
|
|
||||||
p: 3,
|
|
||||||
boxShadow: 'lg'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box sx={{ width: '100%' }}>
|
|
||||||
<Stack spacing={2} direction="row">
|
|
||||||
{stepsOfAddingSpace.map((item: any, index: number) => (
|
|
||||||
<Item
|
|
||||||
key={item}
|
|
||||||
sx={{
|
|
||||||
fontWeight: activeStep === index ? 'bold' : '',
|
|
||||||
color: activeStep === index ? '#2AA3FF' : ''
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{index < activeStep ? (
|
|
||||||
<CheckCircleOutlinedIcon />
|
|
||||||
) : (
|
|
||||||
`${index + 1}.`
|
|
||||||
)}
|
|
||||||
{`${item}`}
|
|
||||||
</Item>
|
|
||||||
))}
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
|
||||||
{activeStep === 0 ? (
|
|
||||||
<>
|
|
||||||
<Box sx={{ margin: '30px auto' }}>
|
|
||||||
Knowledge Space Name:
|
|
||||||
<Input
|
|
||||||
placeholder="Please input the name"
|
|
||||||
onChange={(e: any) => setKnowledgeSpaceName(e.target.value)}
|
|
||||||
sx={{ marginBottom: '20px' }}
|
|
||||||
/>
|
|
||||||
Owner:
|
|
||||||
<Input
|
|
||||||
placeholder="Please input the owner"
|
|
||||||
onChange={(e: any) => setOwner(e.target.value)}
|
|
||||||
sx={{ marginBottom: '20px' }}
|
|
||||||
/>
|
|
||||||
Description:
|
|
||||||
<Input
|
|
||||||
placeholder="Please input the description"
|
|
||||||
onChange={(e: any) => setDescription(e.target.value)}
|
|
||||||
sx={{ marginBottom: '20px' }}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
onClick={async () => {
|
|
||||||
if (knowledgeSpaceName === '') {
|
|
||||||
message.error('please input the name')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (owner === '') {
|
|
||||||
message.error('please input the owner')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (description === '') {
|
|
||||||
message.error('please input the description')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const data = await sendSpacePostRequest(
|
|
||||||
`/knowledge/space/add`,
|
|
||||||
{
|
|
||||||
name: knowledgeSpaceName,
|
|
||||||
vector_type: 'Chroma',
|
|
||||||
owner,
|
|
||||||
desc: description
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if (data.success) {
|
|
||||||
message.success('success')
|
|
||||||
setActiveStep(1)
|
|
||||||
const data = await sendSpacePostRequest(
|
|
||||||
'/knowledge/space/list',
|
|
||||||
{}
|
|
||||||
)
|
|
||||||
if (data.success) {
|
|
||||||
setKnowledgeSpaceList(data.data)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
message.error(data.err_msg || 'failed')
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Next
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
) : activeStep === 1 ? (
|
|
||||||
<>
|
|
||||||
<Box sx={{ margin: '30px auto' }}>
|
|
||||||
{documentTypeList.map((item: any) => (
|
|
||||||
<Sheet
|
|
||||||
key={item.type}
|
|
||||||
sx={{
|
|
||||||
boxSizing: 'border-box',
|
|
||||||
height: '80px',
|
|
||||||
padding: '12px',
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
border: '1px solid gray',
|
|
||||||
borderRadius: '6px',
|
|
||||||
marginBottom: '20px',
|
|
||||||
cursor: 'pointer'
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
setDocumentType(item.type)
|
|
||||||
setActiveStep(2)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Sheet sx={{ fontSize: '20px', fontWeight: 'bold' }}>
|
|
||||||
{item.title}
|
|
||||||
</Sheet>
|
|
||||||
<Sheet>{item.subTitle}</Sheet>
|
|
||||||
</Sheet>
|
|
||||||
))}
|
|
||||||
</Box>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<Box sx={{ margin: '30px auto' }}>
|
|
||||||
Name:
|
|
||||||
<Input
|
|
||||||
placeholder="Please input the name"
|
|
||||||
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>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
Text Source(Optional):
|
|
||||||
<Input
|
|
||||||
placeholder="Please input the text source"
|
|
||||||
onChange={(e: any) => setTextSource(e.target.value)}
|
|
||||||
sx={{ marginBottom: '20px' }}
|
|
||||||
/>
|
|
||||||
Text:
|
|
||||||
<Textarea
|
|
||||||
onChange={(e: any) => setText(e.target.value)}
|
|
||||||
minRows={4}
|
|
||||||
sx={{ marginBottom: '20px' }}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<Typography
|
|
||||||
component="label"
|
|
||||||
sx={{
|
|
||||||
marginTop: '20px'
|
|
||||||
}}
|
|
||||||
endDecorator={
|
|
||||||
<Switch
|
|
||||||
checked={synchChecked}
|
|
||||||
onChange={(event: any) =>
|
|
||||||
setSynchChecked(event.target.checked)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Synch:
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
<Stack
|
|
||||||
direction="row"
|
|
||||||
justifyContent="flex-start"
|
|
||||||
alignItems="center"
|
|
||||||
sx={{ marginBottom: '20px' }}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
sx={{ marginRight: '20px' }}
|
|
||||||
onClick={() => setActiveStep(1)}
|
|
||||||
>
|
|
||||||
{'< Back'}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
onClick={async () => {
|
|
||||||
if (documentName === '') {
|
|
||||||
message.error('Please input the name')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (documentType === 'webPage') {
|
|
||||||
if (webPageUrl === '') {
|
|
||||||
message.error('Please input the Web Page URL')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const data = await sendSpacePostRequest(
|
|
||||||
`/knowledge/${knowledgeSpaceName}/document/add`,
|
|
||||||
{
|
|
||||||
doc_name: documentName,
|
|
||||||
content: webPageUrl,
|
|
||||||
doc_type: 'URL'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if (data.success) {
|
|
||||||
message.success('success')
|
|
||||||
setIsAddKnowledgeSpaceModalShow(false)
|
|
||||||
synchChecked &&
|
|
||||||
sendSpacePostRequest(
|
|
||||||
`/knowledge/${knowledgeSpaceName}/document/sync`,
|
|
||||||
{
|
|
||||||
doc_ids: [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 data = await sendSpaceUploadPostRequest(
|
|
||||||
`/knowledge/${knowledgeSpaceName}/document/upload`,
|
|
||||||
formData
|
|
||||||
)
|
|
||||||
if (data.success) {
|
|
||||||
message.success('success')
|
|
||||||
setIsAddKnowledgeSpaceModalShow(false)
|
|
||||||
synchChecked &&
|
|
||||||
sendSpacePostRequest(
|
|
||||||
`/knowledge/${knowledgeSpaceName}/document/sync`,
|
|
||||||
{
|
|
||||||
doc_ids: [data.data]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
message.error(data.err_msg || 'failed')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (text === '') {
|
|
||||||
message.error('Please input the text')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const data = await sendSpacePostRequest(
|
|
||||||
`/knowledge/${knowledgeSpaceName}/document/add`,
|
|
||||||
{
|
|
||||||
doc_name: documentName,
|
|
||||||
source: textSource,
|
|
||||||
content: text,
|
|
||||||
doc_type: 'TEXT'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if (data.success) {
|
|
||||||
message.success('success')
|
|
||||||
setIsAddKnowledgeSpaceModalShow(false)
|
|
||||||
synchChecked &&
|
|
||||||
sendSpacePostRequest(
|
|
||||||
`/knowledge/${knowledgeSpaceName}/document/sync`,
|
|
||||||
{
|
|
||||||
doc_ids: [data.data]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
message.error(data.err_msg || 'failed')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Finish
|
|
||||||
</Button>
|
|
||||||
</Stack>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Sheet>
|
|
||||||
</Modal>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Index
|
|
Binary file not shown.
Before Width: | Height: | Size: 25 KiB |
@ -1,34 +0,0 @@
|
|||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
color: var(--joy-palette-text-primary, var(--joy-palette-neutral-800, #25252D));
|
|
||||||
font-family: var(--joy-fontFamily-body, var(--joy-Josefin Sans, sans-serif));
|
|
||||||
font-size: var(--joy-fontSize-md, 1rem);
|
|
||||||
line-height: var(--joy-lineHeight-md, 1.5);
|
|
||||||
background-color: var(--joy-palette-background-body);
|
|
||||||
}
|
|
||||||
|
|
||||||
body .ant-btn-primary {
|
|
||||||
background-color: #1677ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-pagination .ant-pagination-prev * {
|
|
||||||
color: rgb(145, 35, 167) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-pagination .ant-pagination-next * {
|
|
||||||
color: rgb(145, 35, 167) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-pagination .ant-pagination-item {
|
|
||||||
border-color: rgb(145, 35, 167) !important;
|
|
||||||
background-color: rgb(145, 35, 167) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-pagination .ant-pagination-item.ant-pagination-item-active a {
|
|
||||||
color: white !important;
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
"use client"
|
|
||||||
import './globals.css'
|
|
||||||
import '@/nprogress.css';
|
|
||||||
import React from 'react';
|
|
||||||
import LeftSider from '@/components/leftSider';
|
|
||||||
import { CssVarsProvider, ThemeProvider } from '@mui/joy/styles';
|
|
||||||
import { useColorScheme } from '@/lib/mui';
|
|
||||||
import { joyTheme } from '@/defaultTheme';
|
|
||||||
import TopProgressBar from '@/components/topProgressBar';
|
|
||||||
import DialogueContext from './context/dialogue';
|
|
||||||
import { useEffect } from 'react';
|
|
||||||
|
|
||||||
function CssWrapper({
|
|
||||||
children
|
|
||||||
}: {
|
|
||||||
children: React.ReactNode
|
|
||||||
}) {
|
|
||||||
const { mode } = useColorScheme();
|
|
||||||
const ref = React.useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (ref?.current && mode) {
|
|
||||||
ref?.current?.classList?.add(mode);
|
|
||||||
if (mode === 'light') {
|
|
||||||
ref?.current?.classList?.remove('dark');
|
|
||||||
} else {
|
|
||||||
ref?.current?.classList?.remove('light');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [ref, mode]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div ref={ref} className='h-full'>
|
|
||||||
<TopProgressBar />
|
|
||||||
<DialogueContext>
|
|
||||||
<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='relative min-h-0 min-w-0'>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</DialogueContext>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function RootLayout({
|
|
||||||
children,
|
|
||||||
}: {
|
|
||||||
children: React.ReactNode
|
|
||||||
}) {
|
|
||||||
|
|
||||||
return (
|
|
||||||
<html lang="en" className="h-full font-sans">
|
|
||||||
<body className={`h-full font-sans`}>
|
|
||||||
<ThemeProvider theme={joyTheme}>
|
|
||||||
<CssVarsProvider theme={joyTheme} defaultMode="light">
|
|
||||||
<CssWrapper>
|
|
||||||
{children}
|
|
||||||
</CssWrapper>
|
|
||||||
</CssVarsProvider>
|
|
||||||
</ThemeProvider>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default RootLayout;
|
|
@ -1,122 +0,0 @@
|
|||||||
"use client";
|
|
||||||
import { useRequest } from 'ahooks';
|
|
||||||
import { useState } from 'react';
|
|
||||||
import { Button, Input, Box, buttonClasses, Divider, Typography } 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';
|
|
||||||
|
|
||||||
export default function Home() {
|
|
||||||
const Schema = z.object({ query: z.string().min(1) });
|
|
||||||
const router = useRouter();
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const methods = useForm<z.infer<typeof Schema>>({
|
|
||||||
resolver: zodResolver(Schema),
|
|
||||||
defaultValues: {},
|
|
||||||
});
|
|
||||||
const { data: scenesList } = useRequest(async () => await sendPostRequest('/v1/chat/dialogue/scenes'));
|
|
||||||
|
|
||||||
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(`/chat?id=${res?.data?.conv_uid}&initMessage=${query}`);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className='mx-auto h-full justify-center flex max-w-3xl flex-col gap-8 px-5 pt-6 xl:max-w-4xl'>
|
|
||||||
<div className='max-w-xs my-0 mx-auto'>
|
|
||||||
<Typography level="h3" className="text-center">DB-GPT</Typography>
|
|
||||||
<Typography level="body1" className="text-center pt-4">
|
|
||||||
Revolutionizing Database Interactions with Private LLM Technology
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
<div className='grid gap-8 lg:grid-cols-3'>
|
|
||||||
<div className='lg:col-span-3'>
|
|
||||||
<Divider className="text-[#878c93]">Quick Start</Divider>
|
|
||||||
<Box
|
|
||||||
className='grid pt-7 rounded-xl gap-2 lg:grid-cols-3 lg:gap-6'
|
|
||||||
sx={{
|
|
||||||
[`& .${buttonClasses.root}`]: {
|
|
||||||
color: 'var(--joy-palette-primary-solidColor)',
|
|
||||||
backgroundColor: 'var(--joy-palette-primary-solidBg)',
|
|
||||||
height: '52px',
|
|
||||||
'&: hover': {
|
|
||||||
backgroundColor: 'var(--joy-palette-primary-solidHoverBg)',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{scenesList?.data?.map(scene => (
|
|
||||||
<Button
|
|
||||||
key={scene['chat_scene']}
|
|
||||||
size="md"
|
|
||||||
variant="solid"
|
|
||||||
className='text-base rounded-none'
|
|
||||||
onClick={async () => {
|
|
||||||
const res = await sendPostRequest('/v1/chat/dialogue/new', {
|
|
||||||
chat_mode: scene['chat_scene']
|
|
||||||
});
|
|
||||||
if (res?.success && res?.data?.conv_uid) {
|
|
||||||
router.push(`/chat?id=${res?.data?.conv_uid}&scene=${scene['chat_scene']}`);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{scene['scene_name']
|
|
||||||
}</Button>
|
|
||||||
))}
|
|
||||||
</Box>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='mt-6 mb-[10%] pointer-events-none inset-x-0 bottom-0 z-0 mx-auto flex w-full max-w-3xl flex-col items-center justify-center max-md:border-t xl:max-w-4xl [&>*]:pointer-events-auto'>
|
|
||||||
<form
|
|
||||||
style={{
|
|
||||||
maxWidth: '100%',
|
|
||||||
width: '100%',
|
|
||||||
position: 'relative',
|
|
||||||
display: 'flex',
|
|
||||||
marginTop: 'auto',
|
|
||||||
overflow: 'visible',
|
|
||||||
background: 'none',
|
|
||||||
justifyContent: 'center',
|
|
||||||
marginLeft: 'auto',
|
|
||||||
marginRight: 'auto',
|
|
||||||
height: '52px'
|
|
||||||
}}
|
|
||||||
onSubmit={(e) => {
|
|
||||||
methods.handleSubmit(submit)(e);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
sx={{ width: '100%' }}
|
|
||||||
variant="outlined"
|
|
||||||
placeholder='Ask anything'
|
|
||||||
endDecorator={
|
|
||||||
<IconButton type="submit" disabled={isLoading}>
|
|
||||||
<SendRoundedIcon />
|
|
||||||
</IconButton>
|
|
||||||
}
|
|
||||||
{...methods.register('query')}
|
|
||||||
/>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</>
|
|
||||||
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,267 +0,0 @@
|
|||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
|
||||||
import SendRoundedIcon from '@mui/icons-material/SendRounded';
|
|
||||||
import { Card, CircularProgress, IconButton, Input, Stack, Select, Option, Tooltip } from '@/lib/mui';
|
|
||||||
import React, { useState } from 'react';
|
|
||||||
import { useForm } from 'react-hook-form';
|
|
||||||
import { z } from 'zod';
|
|
||||||
import { Message } from '@/types';
|
|
||||||
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
|
|
||||||
import Markdown from 'markdown-to-jsx';
|
|
||||||
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
|
||||||
import { okaidia } from 'react-syntax-highlighter/dist/esm/styles/prism';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
messages: Message[];
|
|
||||||
onSubmit: (message: string, otherQueryBody?: any) => Promise<any>;
|
|
||||||
initialMessage?: string;
|
|
||||||
readOnly?: boolean;
|
|
||||||
paramsList?: { [key: string]: string };
|
|
||||||
clearIntialMessage?: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Schema = z.object({ query: z.string().min(1) });
|
|
||||||
|
|
||||||
const ChatBoxComp = ({
|
|
||||||
messages,
|
|
||||||
onSubmit,
|
|
||||||
initialMessage,
|
|
||||||
readOnly,
|
|
||||||
paramsList,
|
|
||||||
clearIntialMessage
|
|
||||||
}: Props) => {
|
|
||||||
const scrollableRef = React.useRef<HTMLDivElement>(null);
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const [firstMsg, setFirstMsg] = useState<Message>();
|
|
||||||
const [currentParam, setCurrentParam] = useState<string | undefined | null>();
|
|
||||||
|
|
||||||
const methods = useForm<z.infer<typeof Schema>>({
|
|
||||||
resolver: zodResolver(Schema),
|
|
||||||
defaultValues: {},
|
|
||||||
});
|
|
||||||
|
|
||||||
const submit = async ({ query }: z.infer<typeof Schema>) => {
|
|
||||||
try {
|
|
||||||
setIsLoading(true);
|
|
||||||
methods.reset();
|
|
||||||
await onSubmit(query, {
|
|
||||||
select_param: paramsList?.[currentParam]
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleInitMessage = async () => {
|
|
||||||
try {
|
|
||||||
const searchParams = new URLSearchParams(window.location.search);
|
|
||||||
searchParams.delete('initMessage');
|
|
||||||
window.history.replaceState(null, null, `?${searchParams.toString()}`);
|
|
||||||
await submit({ query: (initialMessage as string) });
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
} finally {
|
|
||||||
clearIntialMessage?.();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
overrides: {
|
|
||||||
code: ({ children }) => (
|
|
||||||
<SyntaxHighlighter language="javascript" style={okaidia}>
|
|
||||||
{children}
|
|
||||||
</SyntaxHighlighter>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (!scrollableRef.current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollableRef.current.scrollTo(0, scrollableRef.current.scrollHeight);
|
|
||||||
}, [messages?.length]);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (initialMessage && messages.length <= 0) {
|
|
||||||
handleInitMessage();
|
|
||||||
}
|
|
||||||
}, [initialMessage]);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (paramsList && Object.keys(paramsList || {})?.length > 0) {
|
|
||||||
setCurrentParam(Object.keys(paramsList || {})?.[0]);
|
|
||||||
}
|
|
||||||
}, [paramsList]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='mx-auto flex h-full max-w-3xl flex-col gap-6 px-5 py-6 sm:gap-8 xl:max-w-5xl'>
|
|
||||||
<Stack
|
|
||||||
direction={'column'}
|
|
||||||
gap={2}
|
|
||||||
sx={{
|
|
||||||
display: 'flex',
|
|
||||||
flex: 1,
|
|
||||||
flexBasis: '100%',
|
|
||||||
width: '100%',
|
|
||||||
height: '100%',
|
|
||||||
maxHeight: '100%',
|
|
||||||
minHeight: '100%',
|
|
||||||
mx: 'auto',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Stack
|
|
||||||
ref={scrollableRef}
|
|
||||||
direction={'column'}
|
|
||||||
gap={2}
|
|
||||||
sx={{
|
|
||||||
boxSizing: 'border-box',
|
|
||||||
maxWidth: '100%',
|
|
||||||
width: '100%',
|
|
||||||
mx: 'auto',
|
|
||||||
flex: 1,
|
|
||||||
maxHeight: '100%',
|
|
||||||
overflowY: 'auto',
|
|
||||||
p: 2,
|
|
||||||
border: '1px solid',
|
|
||||||
borderColor: 'var(--joy-palette-divider)'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{firstMsg && (
|
|
||||||
<Card
|
|
||||||
size="sm"
|
|
||||||
variant={'outlined'}
|
|
||||||
color={'primary'}
|
|
||||||
className="message-agent"
|
|
||||||
sx={{
|
|
||||||
mr: 'auto',
|
|
||||||
ml: 'none',
|
|
||||||
whiteSpace: 'pre-wrap',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{firstMsg?.context}
|
|
||||||
</Card>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{messages.filter(item => ['view', 'human'].includes(item.role)).map((each, index) => (
|
|
||||||
<Stack
|
|
||||||
key={index}
|
|
||||||
sx={{
|
|
||||||
mr: each.role === 'view' ? 'auto' : 'none',
|
|
||||||
ml: each.role === 'human' ? 'auto' : 'none',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Card
|
|
||||||
size="sm"
|
|
||||||
variant={'outlined'}
|
|
||||||
className={
|
|
||||||
each.role === 'view' ? 'message-agent' : 'message-human'
|
|
||||||
}
|
|
||||||
color={each.role === 'view' ? 'primary' : 'neutral'}
|
|
||||||
sx={(theme) => ({
|
|
||||||
px: 2,
|
|
||||||
'ol, ul': {
|
|
||||||
my: 0,
|
|
||||||
pl: 2,
|
|
||||||
},
|
|
||||||
ol: {
|
|
||||||
listStyle: 'numeric',
|
|
||||||
},
|
|
||||||
ul: {
|
|
||||||
listStyle: 'disc',
|
|
||||||
mb: 2,
|
|
||||||
},
|
|
||||||
li: {
|
|
||||||
my: 1,
|
|
||||||
},
|
|
||||||
a: {
|
|
||||||
textDecoration: 'underline',
|
|
||||||
},
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<Markdown options={options}>
|
|
||||||
{each.context?.replaceAll('\\n', '\n')}
|
|
||||||
</Markdown>
|
|
||||||
</Card>
|
|
||||||
</Stack>
|
|
||||||
))}
|
|
||||||
|
|
||||||
{isLoading && (
|
|
||||||
<CircularProgress
|
|
||||||
variant="soft"
|
|
||||||
color="neutral"
|
|
||||||
size="sm"
|
|
||||||
sx={{ mx: 'auto', my: 2 }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
{!readOnly && (
|
|
||||||
<form
|
|
||||||
style={{
|
|
||||||
maxWidth: '100%',
|
|
||||||
width: '100%',
|
|
||||||
position: 'relative',
|
|
||||||
display: 'flex',
|
|
||||||
marginTop: 'auto',
|
|
||||||
overflow: 'visible',
|
|
||||||
background: 'none',
|
|
||||||
justifyContent: 'center',
|
|
||||||
marginLeft: 'auto',
|
|
||||||
marginRight: 'auto',
|
|
||||||
flexDirection: 'column',
|
|
||||||
gap: '12px'
|
|
||||||
}}
|
|
||||||
onSubmit={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
methods.handleSubmit(submit)(e);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{(Object.keys(paramsList || {}).length > 0) && (
|
|
||||||
<div className='flex items-center gap-3'>
|
|
||||||
<Select
|
|
||||||
value={currentParam}
|
|
||||||
onChange={(e, newValue) => {
|
|
||||||
setCurrentParam(newValue);
|
|
||||||
}}
|
|
||||||
className='max-w-xs'
|
|
||||||
>
|
|
||||||
{Object.keys(paramsList || {}).map(paramItem => (
|
|
||||||
<Option
|
|
||||||
key={paramItem}
|
|
||||||
value={paramItem}
|
|
||||||
>
|
|
||||||
{paramsList?.[paramItem]}
|
|
||||||
</Option>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
<Tooltip
|
|
||||||
className="cursor-pointer"
|
|
||||||
title={currentParam}
|
|
||||||
placement="top"
|
|
||||||
variant="outlined"
|
|
||||||
>
|
|
||||||
<InfoOutlinedIcon />
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Input
|
|
||||||
sx={{ width: '100%' }}
|
|
||||||
variant="outlined"
|
|
||||||
endDecorator={
|
|
||||||
<IconButton type="submit" disabled={isLoading}>
|
|
||||||
<SendRoundedIcon />
|
|
||||||
</IconButton>
|
|
||||||
}
|
|
||||||
{...methods.register('query')}
|
|
||||||
/>
|
|
||||||
</form>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ChatBoxComp;
|
|
@ -1,253 +0,0 @@
|
|||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
|
||||||
import SendRoundedIcon from '@mui/icons-material/SendRounded';
|
|
||||||
import { Card, CircularProgress, IconButton, Input, Stack, Select, Option, Tooltip, Box, useColorScheme } from '@/lib/mui';
|
|
||||||
import React, { useState } from 'react';
|
|
||||||
import { useForm } from 'react-hook-form';
|
|
||||||
import { z } from 'zod';
|
|
||||||
import { Message } from '@/types';
|
|
||||||
import FaceRetouchingNaturalOutlinedIcon from '@mui/icons-material/FaceRetouchingNaturalOutlined';
|
|
||||||
import SmartToyOutlinedIcon from '@mui/icons-material/SmartToyOutlined';
|
|
||||||
import Markdown from 'markdown-to-jsx';
|
|
||||||
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
|
||||||
import { okaidia } from 'react-syntax-highlighter/dist/esm/styles/prism';
|
|
||||||
import { useSearchParams } from 'next/navigation';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
messages: Message[];
|
|
||||||
onSubmit: (message: string, otherQueryBody?: any) => Promise<any>;
|
|
||||||
readOnly?: boolean;
|
|
||||||
paramsList?: { [key: string]: string };
|
|
||||||
clearIntialMessage?: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Schema = z.object({ query: z.string().min(1) });
|
|
||||||
|
|
||||||
const ChatBoxComp = ({
|
|
||||||
messages,
|
|
||||||
onSubmit,
|
|
||||||
readOnly,
|
|
||||||
paramsList,
|
|
||||||
clearIntialMessage
|
|
||||||
}: Props) => {
|
|
||||||
const searchParams = useSearchParams();
|
|
||||||
const initMessage = searchParams.get('initMessage');
|
|
||||||
const scrollableRef = React.useRef<HTMLDivElement>(null);
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const [currentParam, setCurrentParam] = useState<string | undefined | null>();
|
|
||||||
|
|
||||||
const methods = useForm<z.infer<typeof Schema>>({
|
|
||||||
resolver: zodResolver(Schema),
|
|
||||||
defaultValues: {},
|
|
||||||
});
|
|
||||||
|
|
||||||
const submit = async ({ query }: z.infer<typeof Schema>) => {
|
|
||||||
try {
|
|
||||||
console.log('submit');
|
|
||||||
setIsLoading(true);
|
|
||||||
methods.reset();
|
|
||||||
await onSubmit(query, {
|
|
||||||
select_param: paramsList?.[currentParam]
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleInitMessage = async () => {
|
|
||||||
try {
|
|
||||||
const searchParamsTemp = new URLSearchParams(window.location.search);
|
|
||||||
const initMessage = searchParamsTemp.get('initMessage');
|
|
||||||
searchParamsTemp.delete('initMessage');
|
|
||||||
window.history.replaceState(null, null, `?${searchParamsTemp.toString()}`);
|
|
||||||
await submit({ query: (initMessage as string) });
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
} finally {
|
|
||||||
clearIntialMessage?.();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
overrides: {
|
|
||||||
code: ({ children }) => (
|
|
||||||
<SyntaxHighlighter language="javascript" style={okaidia}>
|
|
||||||
{children}
|
|
||||||
</SyntaxHighlighter>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
wrapper: React.Fragment,
|
|
||||||
};
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (!scrollableRef.current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollableRef.current.scrollTo(0, scrollableRef.current.scrollHeight);
|
|
||||||
}, [messages?.length]);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (initMessage && messages.length <= 0) {
|
|
||||||
handleInitMessage();
|
|
||||||
}
|
|
||||||
}, [initMessage, messages.length]);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (paramsList && Object.keys(paramsList || {})?.length > 0) {
|
|
||||||
setCurrentParam(Object.keys(paramsList || {})?.[0]);
|
|
||||||
}
|
|
||||||
}, [paramsList]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='w-full h-full'>
|
|
||||||
<Stack
|
|
||||||
className="w-full h-full bg-[#fefefe] dark:bg-[#212121]"
|
|
||||||
sx={{
|
|
||||||
'table': {
|
|
||||||
borderCollapse: 'collapse',
|
|
||||||
border: '1px solid #ccc',
|
|
||||||
width: '100%',
|
|
||||||
},
|
|
||||||
'th, td': {
|
|
||||||
border: '1px solid #ccc',
|
|
||||||
padding: '10px',
|
|
||||||
textAlign: 'center'
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Stack
|
|
||||||
ref={scrollableRef}
|
|
||||||
direction={'column'}
|
|
||||||
sx={{
|
|
||||||
overflowY: 'auto',
|
|
||||||
maxHeight: '100%',
|
|
||||||
flex: 1
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{messages.filter(item => ['view', 'human'].includes(item.role))?.map((each, index) => {
|
|
||||||
return (
|
|
||||||
<Stack
|
|
||||||
key={index}
|
|
||||||
>
|
|
||||||
<Card
|
|
||||||
size="sm"
|
|
||||||
variant={'outlined'}
|
|
||||||
color={each.role === 'view' ? 'primary' : 'neutral'}
|
|
||||||
sx={(theme) => ({
|
|
||||||
background: each.role === 'view' ? 'var(--joy-palette-primary-softBg, var(--joy-palette-primary-100, #DDF1FF))': 'unset',
|
|
||||||
border: 'unset',
|
|
||||||
borderRadius: 'unset',
|
|
||||||
padding: '24px 0 26px 0',
|
|
||||||
lineHeight: '24px',
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<Box sx={{ width: '76%', margin: '0 auto' }} className="flex flex-row">
|
|
||||||
<div className='mr-3 inline'>
|
|
||||||
{each.role === 'view' ? (
|
|
||||||
<SmartToyOutlinedIcon />
|
|
||||||
) : (
|
|
||||||
<FaceRetouchingNaturalOutlinedIcon />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className='inline align-middle mt-0.5 max-w-full flex-1 overflow-auto'>
|
|
||||||
<Markdown options={options}>
|
|
||||||
{each.context?.replaceAll('\\n', '\n')}
|
|
||||||
</Markdown>
|
|
||||||
</div>
|
|
||||||
</Box>
|
|
||||||
</Card>
|
|
||||||
</Stack>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
{isLoading && (
|
|
||||||
<CircularProgress
|
|
||||||
variant="soft"
|
|
||||||
color="neutral"
|
|
||||||
size="sm"
|
|
||||||
sx={{ mx: 'auto', my: 2 }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
{!readOnly && (
|
|
||||||
<Box
|
|
||||||
className="bg-[#fefefe] dark:bg-[#212121] before:bg-[#fefefe] before:dark:bg-[#212121]"
|
|
||||||
sx={{
|
|
||||||
position: 'relative',
|
|
||||||
'&::before': {
|
|
||||||
content: '" "',
|
|
||||||
position: 'absolute',
|
|
||||||
top: '-18px',
|
|
||||||
left: '0',
|
|
||||||
right: '0',
|
|
||||||
width: '100%',
|
|
||||||
margin: '0 auto',
|
|
||||||
height: '20px',
|
|
||||||
filter: 'blur(10px)',
|
|
||||||
zIndex: 2,
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<form
|
|
||||||
style={{
|
|
||||||
maxWidth: '100%',
|
|
||||||
width: '76%',
|
|
||||||
position: 'relative',
|
|
||||||
display: 'flex',
|
|
||||||
marginTop: 'auto',
|
|
||||||
overflow: 'visible',
|
|
||||||
background: 'none',
|
|
||||||
justifyContent: 'center',
|
|
||||||
marginLeft: 'auto',
|
|
||||||
marginRight: 'auto',
|
|
||||||
flexDirection: 'column',
|
|
||||||
gap: '12px',
|
|
||||||
paddingBottom: '58px',
|
|
||||||
paddingTop: '20px'
|
|
||||||
}}
|
|
||||||
onSubmit={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
methods.handleSubmit(submit)(e);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{(Object.keys(paramsList || {}).length > 0) && (
|
|
||||||
<div className='flex items-center gap-3'>
|
|
||||||
<Select
|
|
||||||
value={currentParam}
|
|
||||||
onChange={(e, newValue) => {
|
|
||||||
setCurrentParam(newValue);
|
|
||||||
}}
|
|
||||||
sx={{ maxWidth: '100%' }}
|
|
||||||
>
|
|
||||||
{Object.keys(paramsList || {}).map(paramItem => (
|
|
||||||
<Option
|
|
||||||
key={paramItem}
|
|
||||||
value={paramItem}
|
|
||||||
>
|
|
||||||
{paramItem}
|
|
||||||
</Option>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Input
|
|
||||||
className='w-full h-12'
|
|
||||||
variant="outlined"
|
|
||||||
endDecorator={
|
|
||||||
<IconButton type="submit" disabled={isLoading}>
|
|
||||||
<SendRoundedIcon />
|
|
||||||
</IconButton>
|
|
||||||
}
|
|
||||||
{...methods.register('query')}
|
|
||||||
/>
|
|
||||||
</form>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ChatBoxComp;
|
|
@ -1,32 +0,0 @@
|
|||||||
import DarkModeRoundedIcon from '@mui/icons-material/DarkModeRounded';
|
|
||||||
import LightModeRoundedIcon from '@mui/icons-material/LightModeRounded';
|
|
||||||
import { IconButton,useColorScheme } from '@/lib/mui';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
export default function ColorSchemeToggle() {
|
|
||||||
const { mode, setMode } = useColorScheme();
|
|
||||||
const [mounted, setMounted] = React.useState(false);
|
|
||||||
React.useEffect(() => {
|
|
||||||
setMounted(true);
|
|
||||||
}, []);
|
|
||||||
if (!mounted) {
|
|
||||||
return <IconButton size="sm" variant="outlined" color="primary" />;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<IconButton
|
|
||||||
id="toggle-mode"
|
|
||||||
size="sm"
|
|
||||||
variant="outlined"
|
|
||||||
color="primary"
|
|
||||||
onClick={() => {
|
|
||||||
if (mode === 'light') {
|
|
||||||
setMode('dark');
|
|
||||||
} else {
|
|
||||||
setMode('light');
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{mode === 'light' ? <DarkModeRoundedIcon /> : <LightModeRoundedIcon />}
|
|
||||||
</IconButton>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
import { Box, Typography } from '@/lib/mui';
|
|
||||||
import Image from 'next/image';
|
|
||||||
import ColorSchemeToggle from './colorSchemeToggle';
|
|
||||||
|
|
||||||
const Header = () => {
|
|
||||||
return (
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
p: 2,
|
|
||||||
gap: 2,
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
alignItems: 'center',
|
|
||||||
gridColumn: '1 / -1',
|
|
||||||
borderBottom: '1px solid',
|
|
||||||
borderColor: 'divider',
|
|
||||||
position: 'sticky',
|
|
||||||
top: 0,
|
|
||||||
zIndex: 1100,
|
|
||||||
background: 'var(--joy-palette-background-body)'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<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>
|
|
||||||
<ColorSchemeToggle />
|
|
||||||
</div>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Header;
|
|
@ -1,255 +0,0 @@
|
|||||||
"use client";
|
|
||||||
import React, { useEffect, useMemo } from 'react';
|
|
||||||
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
|
||||||
import Link from 'next/link';
|
|
||||||
import { Modal } from 'antd';
|
|
||||||
import { Box, List, ListItem, ListItemButton, ListItemDecorator, ListItemContent, Typography, Button, useColorScheme, IconButton } from '@/lib/mui';
|
|
||||||
import Article from '@mui/icons-material/Article';
|
|
||||||
import DarkModeIcon from '@mui/icons-material/DarkMode';
|
|
||||||
import WbSunnyIcon from '@mui/icons-material/WbSunny';
|
|
||||||
import MenuIcon from '@mui/icons-material/Menu';
|
|
||||||
import AddIcon from '@mui/icons-material/Add';
|
|
||||||
import SmsOutlinedIcon from '@mui/icons-material/SmsOutlined';import { useDialogueContext } from '@/app/context/dialogue';
|
|
||||||
import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined';
|
|
||||||
import { sendPostRequest } from '@/utils/request';
|
|
||||||
|
|
||||||
const LeftSider = () => {
|
|
||||||
const pathname = usePathname();
|
|
||||||
const searchParams = useSearchParams();
|
|
||||||
const id = searchParams.get('id');
|
|
||||||
const router = useRouter();
|
|
||||||
const { dialogueList, queryDialogueList, refreshDialogList } = useDialogueContext();
|
|
||||||
const { mode, setMode } = useColorScheme();
|
|
||||||
|
|
||||||
const menus = useMemo(() => {
|
|
||||||
return [{
|
|
||||||
label: 'Knowledge Space',
|
|
||||||
route: '/datastores',
|
|
||||||
icon: <Article fontSize="small" />,
|
|
||||||
active: pathname === '/datastores'
|
|
||||||
}];
|
|
||||||
}, [pathname]);
|
|
||||||
|
|
||||||
const handleChangeTheme = () => {
|
|
||||||
if (mode === 'light') {
|
|
||||||
setMode('dark');
|
|
||||||
} else {
|
|
||||||
setMode('light');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
(async () => {
|
|
||||||
await queryDialogueList();
|
|
||||||
})();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<nav className='flex h-12 items-center justify-between border-b 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='' 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',
|
|
||||||
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 gap-3'>
|
|
||||||
<Typography component="h1" fontWeight="xl">
|
|
||||||
DB-GPT
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
</Box>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
px: 2
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Link href={`/`}>
|
|
||||||
<Button
|
|
||||||
color="primary"
|
|
||||||
className='w-full bg-gradient-to-r from-[#31afff] to-[#1677ff] dark:bg-gradient-to-r dark:from-[#6a6a6a] dark:to-[#80868f]'
|
|
||||||
style={{
|
|
||||||
color: '#fff'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
+ New Chat
|
|
||||||
</Button>
|
|
||||||
</Link>
|
|
||||||
</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' },
|
|
||||||
gap: '4px'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{dialogueList?.data?.map((each) => {
|
|
||||||
const isSelect = (pathname === `/chat` || pathname === '/chat/') && id === each.conv_uid;
|
|
||||||
return (
|
|
||||||
<ListItem key={each.conv_uid}>
|
|
||||||
<ListItemButton
|
|
||||||
selected={isSelect}
|
|
||||||
variant={isSelect ? 'soft' : 'plain'}
|
|
||||||
sx={{
|
|
||||||
'&:hover .del-btn': {
|
|
||||||
visibility: 'visible'
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ListItemContent>
|
|
||||||
<Link href={`/chat?id=${each.conv_uid}&scene=${each?.chat_mode}`} className="flex items-center justify-between">
|
|
||||||
<Typography fontSize={14} noWrap={true}>
|
|
||||||
<SmsOutlinedIcon style={{ marginRight: '0.5rem' }} />
|
|
||||||
{each?.user_name || each?.user_input || 'undefined'}
|
|
||||||
</Typography>
|
|
||||||
<IconButton
|
|
||||||
color="neutral"
|
|
||||||
variant="plain"
|
|
||||||
size="sm"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
Modal.confirm({
|
|
||||||
title: 'Delete Chat',
|
|
||||||
content: 'Are you sure delete this chat?',
|
|
||||||
width: '276px',
|
|
||||||
centered: true,
|
|
||||||
async onOk() {
|
|
||||||
await sendPostRequest(`/v1/chat/dialogue/delete?con_uid=${each.conv_uid}`);
|
|
||||||
await refreshDialogList();
|
|
||||||
if (pathname === `/chat` && searchParams.get('id') === each.conv_uid) {
|
|
||||||
router.push('/');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
className='del-btn invisible'
|
|
||||||
>
|
|
||||||
<DeleteOutlineOutlinedIcon />
|
|
||||||
</IconButton>
|
|
||||||
</Link>
|
|
||||||
</ListItemContent>
|
|
||||||
</ListItemButton>
|
|
||||||
</ListItem>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</List>
|
|
||||||
</ListItem>
|
|
||||||
</List>
|
|
||||||
</Box>
|
|
||||||
<div className='flex flex-col justify-between flex-1'>
|
|
||||||
<div></div>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
p: 2,
|
|
||||||
pt: 3,
|
|
||||||
pb: 6,
|
|
||||||
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"
|
|
||||||
sx={{ marginBottom: 1, height: '2.5rem' }}
|
|
||||||
selected={each.active}
|
|
||||||
variant={each.active ? 'soft' : 'plain'}
|
|
||||||
>
|
|
||||||
<ListItemDecorator
|
|
||||||
sx={{
|
|
||||||
color: each.active ? 'inherit' : 'neutral.500',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{each.icon}
|
|
||||||
</ListItemDecorator>
|
|
||||||
<ListItemContent>{each.label}</ListItemContent>
|
|
||||||
</ListItemButton>
|
|
||||||
</ListItem>
|
|
||||||
</Link>
|
|
||||||
))}
|
|
||||||
</List>
|
|
||||||
</ListItem>
|
|
||||||
<ListItem>
|
|
||||||
<ListItemButton
|
|
||||||
sx={{ height: '2.5rem' }}
|
|
||||||
onClick={handleChangeTheme}
|
|
||||||
>
|
|
||||||
<ListItemDecorator>
|
|
||||||
{mode === 'dark' ? (
|
|
||||||
<DarkModeIcon fontSize="small"/>
|
|
||||||
) : (
|
|
||||||
<WbSunnyIcon fontSize="small"/>
|
|
||||||
)}
|
|
||||||
</ListItemDecorator>
|
|
||||||
<ListItemContent>Theme</ListItemContent>
|
|
||||||
</ListItemButton>
|
|
||||||
</ListItem>
|
|
||||||
</List>
|
|
||||||
</Box>
|
|
||||||
</div>
|
|
||||||
</Box>
|
|
||||||
</nav>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
export default LeftSider;
|
|
@ -1,61 +0,0 @@
|
|||||||
import Router from 'next/router';
|
|
||||||
import NProgress from 'nprogress';
|
|
||||||
|
|
||||||
let timer: any;
|
|
||||||
let state: any;
|
|
||||||
let activeRequests = 0;
|
|
||||||
const delay = 250;
|
|
||||||
|
|
||||||
function load() {
|
|
||||||
if (state === 'loading') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
state = 'loading';
|
|
||||||
|
|
||||||
timer = setTimeout(function () {
|
|
||||||
NProgress.start();
|
|
||||||
}, delay); // only show progress bar if it takes longer than the delay
|
|
||||||
}
|
|
||||||
|
|
||||||
function stop() {
|
|
||||||
if (activeRequests > 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
state = 'stop';
|
|
||||||
|
|
||||||
clearTimeout(timer);
|
|
||||||
NProgress.done();
|
|
||||||
}
|
|
||||||
|
|
||||||
Router.events.on('routeChangeStart', load);
|
|
||||||
Router.events.on('routeChangeComplete', stop);
|
|
||||||
Router.events.on('routeChangeError', stop);
|
|
||||||
|
|
||||||
if (typeof window !== 'undefined' && typeof window?.fetch === 'function') {
|
|
||||||
const originalFetch = window.fetch;
|
|
||||||
window.fetch = async function (...args) {
|
|
||||||
if (activeRequests === 0) {
|
|
||||||
load();
|
|
||||||
}
|
|
||||||
|
|
||||||
activeRequests++;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await originalFetch(...args);
|
|
||||||
return response;
|
|
||||||
} catch (error) {
|
|
||||||
return Promise.reject(error);
|
|
||||||
} finally {
|
|
||||||
activeRequests -= 1;
|
|
||||||
if (activeRequests === 0) {
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function TopProgressBar() {
|
|
||||||
return null;
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
import { extendTheme } from '@mui/joy/styles';
|
|
||||||
import colors from '@mui/joy/colors';
|
|
||||||
|
|
||||||
export const joyTheme = extendTheme({
|
|
||||||
colorSchemes: {
|
|
||||||
light: {
|
|
||||||
palette: {
|
|
||||||
mode: 'dark',
|
|
||||||
primary: {
|
|
||||||
...colors.grey,
|
|
||||||
solidBg: '#e6f4ff',
|
|
||||||
solidColor: '#1677ff',
|
|
||||||
solidHoverBg: '#e6f4ff',
|
|
||||||
},
|
|
||||||
neutral: {
|
|
||||||
plainColor: '#4d4d4d',
|
|
||||||
plainHoverColor: '#131318',
|
|
||||||
plainHoverBg: '#EBEBEF',
|
|
||||||
plainActiveBg: '#D8D8DF',
|
|
||||||
plainDisabledColor: '#B9B9C6'
|
|
||||||
},
|
|
||||||
background: {
|
|
||||||
body: '#fff',
|
|
||||||
surface: '#fff'
|
|
||||||
},
|
|
||||||
text: {
|
|
||||||
primary: '#505050',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
dark: {
|
|
||||||
palette: {
|
|
||||||
mode: 'light',
|
|
||||||
primary: {
|
|
||||||
...colors.grey,
|
|
||||||
softBg: '#353539',
|
|
||||||
softHoverBg: '#35353978',
|
|
||||||
softDisabledBg: '#353539',
|
|
||||||
solidBg: '#51525beb',
|
|
||||||
solidHoverBg: '#51525beb',
|
|
||||||
},
|
|
||||||
neutral: {
|
|
||||||
plainColor: '#D8D8DF',
|
|
||||||
plainHoverColor: '#F7F7F8',
|
|
||||||
plainHoverBg: '#353539',
|
|
||||||
plainActiveBg: '#434356',
|
|
||||||
plainDisabledColor: '#434356',
|
|
||||||
outlinedBorder: '#353539',
|
|
||||||
outlinedHoverBorder: '#454651'
|
|
||||||
},
|
|
||||||
text: {
|
|
||||||
primary: '#EBEBEF'
|
|
||||||
},
|
|
||||||
background: {
|
|
||||||
body: '#212121',
|
|
||||||
surface: '#51525beb',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
fontFamily: {
|
|
||||||
body: 'Josefin Sans, sans-serif',
|
|
||||||
display: 'Josefin Sans, sans-serif',
|
|
||||||
},
|
|
||||||
typography: {
|
|
||||||
display1: {
|
|
||||||
background:
|
|
||||||
'linear-gradient(-30deg, var(--joy-palette-primary-900), var(--joy-palette-primary-400))',
|
|
||||||
WebkitBackgroundClip: 'text',
|
|
||||||
WebkitTextFillColor: 'transparent',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,170 +0,0 @@
|
|||||||
import {
|
|
||||||
EventStreamContentType,
|
|
||||||
fetchEventSource,
|
|
||||||
} from '@microsoft/fetch-event-source';
|
|
||||||
import useStateReducer from './useStateReducer';
|
|
||||||
import { Message } from '@/types';
|
|
||||||
import { useEffect } from 'react';
|
|
||||||
import { useDialogueContext } from '@/app/context/dialogue';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
queryAgentURL: string;
|
|
||||||
channel?: "dashboard" | "website" | "slack" | "crisp";
|
|
||||||
queryBody?: any;
|
|
||||||
initHistory?: Message[];
|
|
||||||
};
|
|
||||||
|
|
||||||
const useAgentChat = ({
|
|
||||||
queryAgentURL,
|
|
||||||
channel,
|
|
||||||
queryBody,
|
|
||||||
initHistory
|
|
||||||
}: Props) => {
|
|
||||||
const [state, setState] = useStateReducer({
|
|
||||||
history: (initHistory || []) as { role: 'human' | 'view'; context: string; id?: string }[],
|
|
||||||
});
|
|
||||||
|
|
||||||
const { refreshDialogList } = useDialogueContext();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (initHistory) setState({ history: initHistory });
|
|
||||||
}, [initHistory]);
|
|
||||||
|
|
||||||
const handleChatSubmit = async (context: string, otherQueryBody?: any) => {
|
|
||||||
if (!context) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const history = [...state.history, { role: 'human', context }];
|
|
||||||
const nextIndex = history.length;
|
|
||||||
|
|
||||||
setState({
|
|
||||||
history: history as any,
|
|
||||||
});
|
|
||||||
|
|
||||||
let answer = '';
|
|
||||||
let error = '';
|
|
||||||
|
|
||||||
try {
|
|
||||||
const ctrl = new AbortController();
|
|
||||||
let buffer = '';
|
|
||||||
|
|
||||||
await fetchEventSource(`${process.env.API_BASE_URL ? process.env.API_BASE_URL : ''}${"/api" + queryAgentURL}`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
...otherQueryBody,
|
|
||||||
...queryBody,
|
|
||||||
user_input: context,
|
|
||||||
channel,
|
|
||||||
}),
|
|
||||||
signal: ctrl.signal,
|
|
||||||
|
|
||||||
async onopen(response) {
|
|
||||||
if (history.length <= 1) {
|
|
||||||
refreshDialogList();
|
|
||||||
const searchParams = new URLSearchParams(window.location.search);
|
|
||||||
searchParams.delete('initMessage');
|
|
||||||
window.history.replaceState(null, null, `?${searchParams.toString()}`);
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
response.ok &&
|
|
||||||
response.headers.get('content-type') === EventStreamContentType
|
|
||||||
) {
|
|
||||||
return; // everything's good
|
|
||||||
} else if (
|
|
||||||
response.status >= 400 &&
|
|
||||||
response.status < 500 &&
|
|
||||||
response.status !== 429
|
|
||||||
) {
|
|
||||||
if (response.status === 402) {
|
|
||||||
//throw new ApiError(ApiErrorType.USAGE_LIMIT);
|
|
||||||
}
|
|
||||||
// client-side errors are usually non-retriable:
|
|
||||||
//throw new FatalError();
|
|
||||||
} else {
|
|
||||||
//throw new RetriableError();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onclose() {
|
|
||||||
// if the server closes the connection unexpectedly, retry:
|
|
||||||
console.log('onclose');
|
|
||||||
},
|
|
||||||
onerror(err) {
|
|
||||||
throw new Error(err);
|
|
||||||
},
|
|
||||||
onmessage: (event) => {
|
|
||||||
console.log(event, 'e');
|
|
||||||
event.data = event.data.replaceAll('\\n', '\n');
|
|
||||||
|
|
||||||
if (event.data === '[DONE]') {
|
|
||||||
ctrl.abort();
|
|
||||||
} else if (event.data?.startsWith('[ERROR]')) {
|
|
||||||
ctrl.abort();
|
|
||||||
setState({
|
|
||||||
history: [
|
|
||||||
...history,
|
|
||||||
{
|
|
||||||
role: 'view',
|
|
||||||
context: event.data.replace('[ERROR]', ''),
|
|
||||||
} as any,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const h = [...history];
|
|
||||||
if (event.data) {
|
|
||||||
if (h?.[nextIndex]) {
|
|
||||||
h[nextIndex].context = `${event.data}`;
|
|
||||||
} else {
|
|
||||||
h.push({ role: 'view', context: event.data });
|
|
||||||
}
|
|
||||||
setState({
|
|
||||||
history: h as any,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
console.log('---e', err);
|
|
||||||
|
|
||||||
setState({
|
|
||||||
history: [
|
|
||||||
...history,
|
|
||||||
{ role: 'view', context: answer || '请求出错' as string },
|
|
||||||
] as any,
|
|
||||||
});
|
|
||||||
// if (err instanceof ApiError) {
|
|
||||||
// if (err?.message) {
|
|
||||||
// error = err?.message;
|
|
||||||
|
|
||||||
// if (error === ApiErrorType.USAGE_LIMIT) {
|
|
||||||
// answer =
|
|
||||||
// 'Usage limit reached. Please upgrade your plan to get higher usage.';
|
|
||||||
// } else {
|
|
||||||
// answer = `Error: ${error}`;
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// answer = `Error: ${error}`;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// setState({
|
|
||||||
// history: [
|
|
||||||
// ...history,
|
|
||||||
// { from: 'ai', message: answer as string },
|
|
||||||
// ] as any,
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
handleChatSubmit,
|
|
||||||
history: state.history,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useAgentChat;
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
|
|
||||||
export const useNewChat = () => {
|
|
||||||
const [message, setMessage] = useState<string | undefined>("hello");
|
|
||||||
|
|
||||||
return {
|
|
||||||
message,
|
|
||||||
setMessage
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
import { useReducer } from 'react';
|
|
||||||
|
|
||||||
const useStateReducer = <T>(initialState: T) => {
|
|
||||||
const methods = useReducer(
|
|
||||||
(state: T, newState: Partial<T>) => ({
|
|
||||||
...state,
|
|
||||||
...newState,
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
...initialState,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return methods;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useStateReducer;
|
|
@ -1,28 +0,0 @@
|
|||||||
import React, { useEffect } from 'react';
|
|
||||||
|
|
||||||
import cuid from 'cuid';
|
|
||||||
|
|
||||||
const useVisitorId = () => {
|
|
||||||
const [visitorId, setVisitorId] = React.useState('');
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
(async () => {
|
|
||||||
if (typeof window !== 'undefined') {
|
|
||||||
let id = localStorage.getItem('visitorId');
|
|
||||||
|
|
||||||
if (!id) {
|
|
||||||
id = cuid();
|
|
||||||
localStorage.setItem('visitorId', id);
|
|
||||||
}
|
|
||||||
|
|
||||||
setVisitorId(id);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return {
|
|
||||||
visitorId,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useVisitorId;
|
|
@ -1,3 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
export * from '@mui/joy';
|
|
@ -1,16 +0,0 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
|
||||||
const nextConfig = {
|
|
||||||
output: 'export',
|
|
||||||
experimental: {
|
|
||||||
esmExternals: 'loose'
|
|
||||||
},
|
|
||||||
typescript: {
|
|
||||||
ignoreBuildErrors: true
|
|
||||||
},
|
|
||||||
env: {
|
|
||||||
API_BASE_URL: process.env.API_BASE_URL
|
|
||||||
},
|
|
||||||
trailingSlash: true
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = nextConfig
|
|
@ -1,32 +0,0 @@
|
|||||||
/* Make clicks pass-through */
|
|
||||||
#nprogress {
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#nprogress .bar {
|
|
||||||
background: var(--joy-palette-primary-500, #096BDE);
|
|
||||||
|
|
||||||
position: fixed;
|
|
||||||
z-index: 10031;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
height: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fancy blur effect */
|
|
||||||
#nprogress .peg {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
right: 0px;
|
|
||||||
width: 100px;
|
|
||||||
height: 100%;
|
|
||||||
box-shadow: 0 0 10px var(--joy-palette-primary-500, #096BDE), 0 0 5px var(--joy-palette-primary-500, #096BDE);
|
|
||||||
opacity: 1;
|
|
||||||
|
|
||||||
-webkit-transform: rotate(3deg) translate(0px, -4px);
|
|
||||||
-ms-transform: rotate(3deg) translate(0px, -4px);
|
|
||||||
transform: rotate(3deg) translate(0px, -4px);
|
|
||||||
}
|
|
||||||
|
|
14907
datacenter/package-lock.json
generated
14907
datacenter/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,62 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "datacenter",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
|
||||||
"dev": "next dev",
|
|
||||||
"build": "next build",
|
|
||||||
"build:prod": "APP_ENV=prod next build",
|
|
||||||
"start": "next start",
|
|
||||||
"lint": "next lint",
|
|
||||||
"export": "next export",
|
|
||||||
"compile": "next build && next export"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@ant-design/pro-components": "^2.6.2",
|
|
||||||
"@emotion/cache": "^11.10.5",
|
|
||||||
"@emotion/react": "^11.10.6",
|
|
||||||
"@emotion/styled": "^11.10.6",
|
|
||||||
"@hookform/resolvers": "^3.0.0",
|
|
||||||
"@microsoft/fetch-event-source": "^2.0.1",
|
|
||||||
"@mui/icons-material": "^5.11.16",
|
|
||||||
"@mui/joy": "5.0.0-alpha.72",
|
|
||||||
"@mui/lab": "5.0.0-alpha.124",
|
|
||||||
"@mui/material": "^5.13.6",
|
|
||||||
"@mui/styled-engine-sc": "^5.12.0",
|
|
||||||
"@mui/utils": "^5.11.13",
|
|
||||||
"@prisma/client": "^4.12.0",
|
|
||||||
"@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",
|
|
||||||
"bizcharts": "^4.1.22",
|
|
||||||
"cuid": "^3.0.0",
|
|
||||||
"eslint": "8.43.0",
|
|
||||||
"eslint-config-next": "13.4.7",
|
|
||||||
"lodash": "^4.17.21",
|
|
||||||
"markdown-to-jsx": "^7.2.1",
|
|
||||||
"moment": "^2.29.4",
|
|
||||||
"next": "13.4.7",
|
|
||||||
"next-auth": "^4.20.1",
|
|
||||||
"nprogress": "^0.2.0",
|
|
||||||
"postcss": "8.4.24",
|
|
||||||
"react": "18.2.0",
|
|
||||||
"react-dom": "18.2.0",
|
|
||||||
"react-hook-form": "^7.43.8",
|
|
||||||
"react-syntax-highlighter": "^15.5.0",
|
|
||||||
"remark-gfm": "^3.0.1",
|
|
||||||
"styled-components": "^5.3.11",
|
|
||||||
"swr": "^2.1.1",
|
|
||||||
"tailwindcss": "3.3.2",
|
|
||||||
"typescript": "5.1.3",
|
|
||||||
"zod": "^3.19.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/lodash": "^4.14.195",
|
|
||||||
"@types/nprogress": "^0.2.0",
|
|
||||||
"@types/react-syntax-highlighter": "^15.5.7"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
plugins: {
|
|
||||||
tailwindcss: {},
|
|
||||||
autoprefixer: {},
|
|
||||||
},
|
|
||||||
}
|
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 197 KiB |
@ -1,19 +0,0 @@
|
|||||||
const defaultTheme = require('tailwindcss/defaultTheme');
|
|
||||||
|
|
||||||
/** @type {import('tailwindcss').Config} */
|
|
||||||
module.exports = {
|
|
||||||
content: [
|
|
||||||
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
|
|
||||||
'./components/**/*.{js,ts,jsx,tsx,mdx}',
|
|
||||||
'./app/**/*.{js,ts,jsx,tsx,mdx}',
|
|
||||||
],
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
fontFamily: {
|
|
||||||
sans: ['"Josefin Sans"', ...defaultTheme.fontFamily.sans],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
darkMode: 'class',
|
|
||||||
plugins: [],
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es5",
|
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
|
||||||
"allowJs": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"strict": true,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"noEmit": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"module": "esnext",
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"isolatedModules": true,
|
|
||||||
"jsx": "preserve",
|
|
||||||
"incremental": true,
|
|
||||||
"plugins": [
|
|
||||||
{
|
|
||||||
"name": "next"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"paths": {
|
|
||||||
"@/*": ["./*"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
||||||
"exclude": ["node_modules"]
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
import { NextApiRequest, NextPage } from 'next/types';
|
|
||||||
import { Session } from 'next-auth';
|
|
||||||
|
|
||||||
export type Message = { role: 'human' | 'view'; context: string; createdAt?: Date };
|
|
||||||
|
|
||||||
export type AppNextApiRequest = NextApiRequest & {
|
|
||||||
session: Session;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface DialogueItem {
|
|
||||||
chat_mode: string;
|
|
||||||
conv_uid: string;
|
|
||||||
select_param?: string;
|
|
||||||
user_input?: string;
|
|
||||||
user_name?: string;
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
export enum ApiErrorType {
|
|
||||||
UNAUTHORIZED = 'UNAUTHORIZED',
|
|
||||||
USAGE_LIMIT = 'USAGE_LIMIT',
|
|
||||||
NOT_FOUND = 'NOT_FOUND',
|
|
||||||
INVALID_REQUEST = 'INVALID_REQUEST',
|
|
||||||
WEBPAGE_IS_SITEMAP = 'WEBPAGE_IS_SITEMAP',
|
|
||||||
EMPTY_DATASOURCE = 'EMPTY_DATASOURCE',
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ApiError extends Error {
|
|
||||||
constructor(message: ApiErrorType, public status?: number) {
|
|
||||||
super(message);
|
|
||||||
|
|
||||||
if (!status) {
|
|
||||||
switch (message) {
|
|
||||||
case ApiErrorType.UNAUTHORIZED:
|
|
||||||
this.status = 403;
|
|
||||||
break;
|
|
||||||
case ApiErrorType.USAGE_LIMIT:
|
|
||||||
this.status = 402;
|
|
||||||
break;
|
|
||||||
case ApiErrorType.NOT_FOUND:
|
|
||||||
this.status = 404;
|
|
||||||
break;
|
|
||||||
case ApiErrorType.INVALID_REQUEST:
|
|
||||||
this.status = 400;
|
|
||||||
break;
|
|
||||||
case ApiErrorType.EMPTY_DATASOURCE:
|
|
||||||
this.status = 400;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this.status = 500;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.setPrototypeOf(this, ApiError.prototype);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
|||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
const api = axios.create({
|
|
||||||
baseURL: process.env.API_BASE_URL,
|
|
||||||
});
|
|
||||||
|
|
||||||
api.defaults.timeout = 10000;
|
|
||||||
|
|
||||||
api.interceptors.response.use(
|
|
||||||
response => response.data,
|
|
||||||
err => Promise.reject(err)
|
|
||||||
);
|
|
||||||
|
|
||||||
export default api;
|
|
@ -1,15 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
export function createCtx<A>(): readonly [
|
|
||||||
() => A,
|
|
||||||
React.Provider<A | undefined>,
|
|
||||||
] {
|
|
||||||
const ctx = React.createContext<A | undefined>(undefined);
|
|
||||||
function useCtx() {
|
|
||||||
const c = React.useContext(ctx);
|
|
||||||
if (c === undefined)
|
|
||||||
throw new Error('useCtx must be inside a Provider with a value');
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
return [useCtx, ctx.Provider] as const; // 'as const' makes TypeScript infer a tuple
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
import { message } from 'antd';
|
|
||||||
import axios from './ctx-axios';
|
|
||||||
import { isPlainObject } from 'lodash';
|
|
||||||
|
|
||||||
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)
|
|
||||||
.filter(k => qs[k] !== undefined && qs[k] !== '')
|
|
||||||
.map(k => `${k}=${qs[k]}`)
|
|
||||||
.join('&');
|
|
||||||
if (str) {
|
|
||||||
url += `?${str}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return axios.get("/api" + url, {
|
|
||||||
headers: DEFAULT_HEADERS
|
|
||||||
}).then(res => res).catch(err => {
|
|
||||||
message.error(err);
|
|
||||||
Promise.reject(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const sendSpaceGetRequest = (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}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return axios.get(url, {
|
|
||||||
headers: DEFAULT_HEADERS
|
|
||||||
}).then(res => res).catch(err => {
|
|
||||||
message.error(err);
|
|
||||||
Promise.reject(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const sendPostRequest = (url: string, body?: any) => {
|
|
||||||
const reqBody = sanitizeBody(body);
|
|
||||||
return axios.post("/api" + url, {
|
|
||||||
body: reqBody,
|
|
||||||
headers: DEFAULT_HEADERS
|
|
||||||
}).then(res => res).catch(err => {
|
|
||||||
message.error(err);
|
|
||||||
Promise.reject(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const sendSpacePostRequest = (url: string, body?: any) => {
|
|
||||||
const reqBody = sanitizeBody(body);
|
|
||||||
return axios.post(url, body, {
|
|
||||||
headers: DEFAULT_HEADERS
|
|
||||||
}).then(res => res).catch(err => {
|
|
||||||
message.error(err);
|
|
||||||
Promise.reject(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const sendSpaceUploadPostRequest = (url: string, body?: any) => {
|
|
||||||
return axios.post(url, body).then(res => res).catch(err => {
|
|
||||||
message.error(err);
|
|
||||||
Promise.reject(err);
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
import axios, { AxiosRequestConfig } from 'axios';
|
|
||||||
|
|
||||||
export const postFetcher = <T>(uri: string, { arg }: { arg: T }) =>
|
|
||||||
axios(uri, {
|
|
||||||
method: 'POST',
|
|
||||||
data: arg,
|
|
||||||
}).then((r) => r.data);
|
|
||||||
|
|
||||||
export const createFetcher =
|
|
||||||
(config: AxiosRequestConfig) =>
|
|
||||||
<T>(url: string, { arg }: { arg: T }) =>
|
|
||||||
axios({
|
|
||||||
url,
|
|
||||||
...config,
|
|
||||||
data: arg,
|
|
||||||
}).then((r) => r.data);
|
|
||||||
|
|
||||||
export const fetcher = (...args: Parameters<typeof axios>) =>
|
|
||||||
axios(...args).then((r) => r.data);
|
|
BIN
pilot/xx.db
BIN
pilot/xx.db
Binary file not shown.
Loading…
Reference in New Issue
Block a user