mirror of
https://github.com/csunny/DB-GPT.git
synced 2025-08-22 02:04:37 +00:00
feat: chat add chart mode
This commit is contained in:
parent
74deb4d9c2
commit
49a86fae6e
@ -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,10 +1,14 @@
|
|||||||
"use client"
|
"use client"
|
||||||
import { useRequest } from 'ahooks';
|
import { useRequest } from 'ahooks';
|
||||||
import { sendGetRequest, sendPostRequest } from '@/utils/request';
|
import { sendGetRequest, sendPostRequest } from '@/utils/request';
|
||||||
|
import { Card, CardContent, Typography, Grid, Table } from "@/lib/mui";
|
||||||
import useAgentChat from '@/hooks/useAgentChat';
|
import useAgentChat from '@/hooks/useAgentChat';
|
||||||
import ChatBoxComp from '@/components/chatBoxTemp';
|
import ChatBoxComp from '@/components/chatBoxTemp';
|
||||||
import { useDialogueContext } from '@/app/context/dialogue';
|
import { useDialogueContext } from '@/app/context/dialogue';
|
||||||
import { useSearchParams } from 'next/navigation';
|
import { useSearchParams } from 'next/navigation';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { Chart, LineAdvance, Interval, Tooltip, getTheme } from "bizcharts";
|
||||||
|
import lodash from 'lodash';
|
||||||
|
|
||||||
const AgentPage = () => {
|
const AgentPage = () => {
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
@ -33,8 +37,197 @@ const AgentPage = () => {
|
|||||||
initHistory: historyList?.data
|
initHistory: historyList?.data
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const chartsData = useMemo(() => {
|
||||||
|
try {
|
||||||
|
const contextTemp = history?.[history.length - 1]?.context;
|
||||||
|
const contextObj = JSON.parse(contextTemp);
|
||||||
|
return contextObj?.template_name === 'sales_report' ? contextObj?.charts : undefined;
|
||||||
|
} catch (e) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}, [history]);
|
||||||
|
|
||||||
|
const chartRows = useMemo(() => {
|
||||||
|
if (chartsData) {
|
||||||
|
let res = [];
|
||||||
|
// 若是有类型为 IndicatorValue 的,提出去,独占一行
|
||||||
|
const chartCalc = chartsData?.filter(
|
||||||
|
(item) => item.chart_type === "IndicatorValue"
|
||||||
|
);
|
||||||
|
if (chartCalc.length > 0) {
|
||||||
|
res.push({
|
||||||
|
rowIndex: res.length,
|
||||||
|
cols: chartCalc,
|
||||||
|
type: "IndicatorValue",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let otherCharts = chartsData?.filter(
|
||||||
|
(item) => item.chart_type !== "IndicatorValue"
|
||||||
|
);
|
||||||
|
let otherLength = otherCharts.length;
|
||||||
|
let curIndex = 0;
|
||||||
|
// charts 数量 3~8个,暂定每行排序
|
||||||
|
let chartLengthMap = [
|
||||||
|
[0],
|
||||||
|
[1],
|
||||||
|
[2],
|
||||||
|
[1, 2],
|
||||||
|
[1, 3],
|
||||||
|
[2, 1, 2],
|
||||||
|
[2, 1, 3],
|
||||||
|
[3, 1, 3],
|
||||||
|
[3, 2, 3],
|
||||||
|
];
|
||||||
|
let currentRowsSort = chartLengthMap[otherLength];
|
||||||
|
currentRowsSort.forEach((item) => {
|
||||||
|
if (item > 0) {
|
||||||
|
const rowsItem = otherCharts.slice(curIndex, curIndex + item);
|
||||||
|
curIndex = curIndex + item;
|
||||||
|
res.push({
|
||||||
|
rowIndex: res.length,
|
||||||
|
cols: rowsItem,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}, [chartsData]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Grid container spacing={2} className="h-full" sx={{ flexGrow: 1 }}>
|
||||||
|
{chartsData && (
|
||||||
|
<Grid xs={8} className="max-h-full">
|
||||||
|
<div className="flex flex-col gap-3 h-full">
|
||||||
|
{chartRows?.map((chartRow) => (
|
||||||
|
<div
|
||||||
|
key={chartRow.rowIndex}
|
||||||
|
className={`${
|
||||||
|
chartRow?.type !== "IndicatorValue"
|
||||||
|
? "flex flex-1 gap-3 overflow-hidden"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{chartRow.cols.map((col) => {
|
||||||
|
if (col.chart_type === "IndicatorValue") {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={col.chart_uid}
|
||||||
|
className="flex flex-row gap-3"
|
||||||
|
>
|
||||||
|
{col.values.map((item) => (
|
||||||
|
<div key={item.name} className="flex-1">
|
||||||
|
<Card>
|
||||||
|
<CardContent className="justify-around">
|
||||||
|
<Typography gutterBottom component="div">
|
||||||
|
{item.name}
|
||||||
|
</Typography>
|
||||||
|
<Typography>{item.value}</Typography>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (col.chart_type === "LineChart") {
|
||||||
|
return (
|
||||||
|
<div className="flex-1 overflow-hidden" key={col.chart_uid}>
|
||||||
|
<Card className="h-full">
|
||||||
|
<CardContent className="h-full">
|
||||||
|
<Typography gutterBottom component="div">
|
||||||
|
{col.chart_name}
|
||||||
|
</Typography>
|
||||||
|
<div className="flex-1 h-full">
|
||||||
|
<Chart
|
||||||
|
padding={[10, 20, 50, 40]}
|
||||||
|
autoFit
|
||||||
|
data={col.values}
|
||||||
|
>
|
||||||
|
<LineAdvance
|
||||||
|
shape="smooth"
|
||||||
|
point
|
||||||
|
area
|
||||||
|
position="name*value"
|
||||||
|
color="type"
|
||||||
|
/>
|
||||||
|
</Chart>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (col.chart_type === "BarChart") {
|
||||||
|
return (
|
||||||
|
<div className="flex-1" key={col.chart_uid}>
|
||||||
|
<Card className="h-full">
|
||||||
|
<CardContent className="h-full">
|
||||||
|
<Typography gutterBottom component="div">
|
||||||
|
{col.chart_name}
|
||||||
|
</Typography>
|
||||||
|
<div className="flex-1">
|
||||||
|
<Chart autoFit data={col.values}>
|
||||||
|
<Interval
|
||||||
|
position="name*value"
|
||||||
|
style={{
|
||||||
|
lineWidth: 3,
|
||||||
|
stroke: getTheme().colors10[0],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tooltip shared />
|
||||||
|
</Chart>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (col.chart_type === 'Table') {
|
||||||
|
const data = lodash.groupBy(col.values, 'type');
|
||||||
|
return (
|
||||||
|
<div className="flex-1" key={col.chart_uid}>
|
||||||
|
<Card className="h-full overflow-auto">
|
||||||
|
|
||||||
|
<CardContent className="h-full">
|
||||||
|
<Typography gutterBottom component="div">
|
||||||
|
{col.chart_name}
|
||||||
|
</Typography>
|
||||||
|
<div className="flex-1">
|
||||||
|
<Table
|
||||||
|
aria-label="basic table"
|
||||||
|
stripe="odd"
|
||||||
|
hoverRow
|
||||||
|
borderAxis="bothBetween"
|
||||||
|
>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
{Object.keys(data).map(key => (
|
||||||
|
<th key={key}>{key}</th>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{Object.values(data)?.[0]?.map((value, i) => (
|
||||||
|
<tr key={i}>
|
||||||
|
{Object.keys(data)?.map(k => (
|
||||||
|
<td key={k}>{data?.[k]?.[i].value || ''}</td>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
|
<Grid xs={chartsData ? 4 : 12} className="h-full max-h-full">
|
||||||
|
<div className='h-full' style={{ boxShadow: chartsData ? '0px 0px 9px 0px #c1c0c080' : 'unset' }}>
|
||||||
<ChatBoxComp
|
<ChatBoxComp
|
||||||
clearIntialMessage={async () => {
|
clearIntialMessage={async () => {
|
||||||
await refreshDialogList();
|
await refreshDialogList();
|
||||||
@ -43,7 +236,10 @@ const AgentPage = () => {
|
|||||||
onSubmit={handleChatSubmit}
|
onSubmit={handleChatSubmit}
|
||||||
paramsList={paramsList?.data}
|
paramsList={paramsList?.data}
|
||||||
/>
|
/>
|
||||||
</>
|
</div>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +96,6 @@ import { useDialogueContext } from '@/app/context/dialogue';
|
|||||||
throw new Error(err);
|
throw new Error(err);
|
||||||
},
|
},
|
||||||
onmessage: (event) => {
|
onmessage: (event) => {
|
||||||
console.log(event, 'e');
|
|
||||||
event.data = event.data.replaceAll('\\n', '\n');
|
event.data = event.data.replaceAll('\\n', '\n');
|
||||||
|
|
||||||
if (event.data === '[DONE]') {
|
if (event.data === '[DONE]') {
|
||||||
@ -129,7 +128,7 @@ import { useDialogueContext } from '@/app/context/dialogue';
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('---e', err);
|
console.log(err);
|
||||||
|
|
||||||
setState({
|
setState({
|
||||||
history: [
|
history: [
|
||||||
|
Loading…
Reference in New Issue
Block a user