mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-20 06:34:55 +00:00
(feature)(supersonic-fe) add memory manage (#1287)
This commit is contained in:
@@ -277,7 +277,7 @@ const AgentForm: React.FC<Props> = ({ editAgent, onSaveAgent, onCreateToolBtnCli
|
|||||||
{
|
{
|
||||||
label: '记忆管理',
|
label: '记忆管理',
|
||||||
key: 'memory',
|
key: 'memory',
|
||||||
children: <MemorySection />,
|
children: <MemorySection agentId={editAgent!.id!} />,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -3,16 +3,22 @@ import { EditableProTable } from '@ant-design/pro-components';
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { MemoryType, ReviewEnum, StatusEnum } from './type';
|
import { MemoryType, ReviewEnum, StatusEnum } from './type';
|
||||||
import { getMemeoryList, saveMemory } from './service';
|
import { getMemeoryList, saveMemory } from './service';
|
||||||
import { Popover, Input, Badge, Radio } from 'antd';
|
import { Popover, Input, Badge, Radio, Select } from 'antd';
|
||||||
import styles from './style.less';
|
import styles from './style.less';
|
||||||
|
|
||||||
const { TextArea } = Input;
|
const { TextArea, Search } = Input;
|
||||||
const RadioGroup = Radio.Group;
|
const RadioGroup = Radio.Group;
|
||||||
|
|
||||||
const MemorySection = () => {
|
type Props = {
|
||||||
|
agentId: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const MemorySection = ({ agentId }: Props) => {
|
||||||
const [editableKeys, setEditableRowKeys] = useState<React.Key[]>([]);
|
const [editableKeys, setEditableRowKeys] = useState<React.Key[]>([]);
|
||||||
const [dataSource, setDataSource] = useState<readonly MemoryType[]>([]);
|
const [dataSource, setDataSource] = useState<readonly MemoryType[]>([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [filters, setFilters] = useState<any>({});
|
||||||
|
const { question, status, llmReviewRet, humanReviewRet } = filters;
|
||||||
|
|
||||||
const columns: ProColumns<MemoryType>[] = [
|
const columns: ProColumns<MemoryType>[] = [
|
||||||
{
|
{
|
||||||
@@ -23,7 +29,7 @@ const MemorySection = () => {
|
|||||||
{
|
{
|
||||||
title: 'Schema映射',
|
title: 'Schema映射',
|
||||||
dataIndex: 'dbSchema',
|
dataIndex: 'dbSchema',
|
||||||
width: 300,
|
width: 220,
|
||||||
valueType: 'textarea',
|
valueType: 'textarea',
|
||||||
renderFormItem: (_, { record }) => (
|
renderFormItem: (_, { record }) => (
|
||||||
<TextArea rows={3} disabled={record?.status === StatusEnum.ENABLED} />
|
<TextArea rows={3} disabled={record?.status === StatusEnum.ENABLED} />
|
||||||
@@ -32,7 +38,7 @@ const MemorySection = () => {
|
|||||||
{
|
{
|
||||||
title: '大模型解析SQL',
|
title: '大模型解析SQL',
|
||||||
dataIndex: 's2sql',
|
dataIndex: 's2sql',
|
||||||
width: 300,
|
width: 220,
|
||||||
valueType: 'textarea',
|
valueType: 'textarea',
|
||||||
renderFormItem: (_, { record }) => (
|
renderFormItem: (_, { record }) => (
|
||||||
<TextArea rows={3} disabled={record?.status === StatusEnum.ENABLED} />
|
<TextArea rows={3} disabled={record?.status === StatusEnum.ENABLED} />
|
||||||
@@ -42,6 +48,7 @@ const MemorySection = () => {
|
|||||||
title: '大模型评估意见',
|
title: '大模型评估意见',
|
||||||
dataIndex: 'llmReviewCmt',
|
dataIndex: 'llmReviewCmt',
|
||||||
readonly: true,
|
readonly: true,
|
||||||
|
width: 200,
|
||||||
render: (value) => {
|
render: (value) => {
|
||||||
return (
|
return (
|
||||||
<Popover trigger="hover" content={<div className={styles.commentPopover}>{value}</div>}>
|
<Popover trigger="hover" content={<div className={styles.commentPopover}>{value}</div>}>
|
||||||
@@ -155,9 +162,12 @@ const MemorySection = () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const loadMemoryList = async () => {
|
const loadMemoryList = async ({
|
||||||
|
filtersValue,
|
||||||
|
current,
|
||||||
|
}: { filtersValue?: any; current?: number } = {}) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const res = await getMemeoryList();
|
const res = await getMemeoryList(agentId, filtersValue || filters, current || 1);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
const { list, total } = res.data;
|
const { list, total } = res.data;
|
||||||
return {
|
return {
|
||||||
@@ -171,17 +181,91 @@ const MemorySection = () => {
|
|||||||
await saveMemory(data);
|
await saveMemory(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onSearch = () => {
|
||||||
|
loadMemoryList();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div className={styles.memorySection}>
|
||||||
|
<div className={styles.filterSection}>
|
||||||
|
<div className={styles.filterItem}>
|
||||||
|
<div className={styles.filterItemTitle}>用户问题</div>
|
||||||
|
<Search
|
||||||
|
className={styles.filterItemControl}
|
||||||
|
placeholder="请输入用户问题"
|
||||||
|
value={question}
|
||||||
|
onChange={(e) => {
|
||||||
|
setFilters({ ...filters, question: e.target.value });
|
||||||
|
}}
|
||||||
|
onSearch={onSearch}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={styles.filterItem}>
|
||||||
|
<div className={styles.filterItemTitle}>大模型评估结果</div>
|
||||||
|
<Select
|
||||||
|
className={styles.filterItemControl}
|
||||||
|
placeholder="请选择大模型评估结果"
|
||||||
|
options={[
|
||||||
|
{ label: '正确', value: ReviewEnum.POSITIVE },
|
||||||
|
{ label: '错误', value: ReviewEnum.NEGATIVE },
|
||||||
|
]}
|
||||||
|
value={llmReviewRet}
|
||||||
|
allowClear
|
||||||
|
onChange={(value: ReviewEnum) => {
|
||||||
|
const filtersValue = { ...filters, llmReviewRet: value };
|
||||||
|
setFilters(filtersValue);
|
||||||
|
loadMemoryList({ filtersValue });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={styles.filterItem}>
|
||||||
|
<div className={styles.filterItemTitle}>管理员评估结果</div>
|
||||||
|
<Select
|
||||||
|
className={styles.filterItemControl}
|
||||||
|
placeholder="请选择管理员评估结果"
|
||||||
|
options={[
|
||||||
|
{ label: '正确', value: ReviewEnum.POSITIVE },
|
||||||
|
{ label: '错误', value: ReviewEnum.NEGATIVE },
|
||||||
|
]}
|
||||||
|
value={humanReviewRet}
|
||||||
|
allowClear
|
||||||
|
onChange={(value: ReviewEnum) => {
|
||||||
|
const filtersValue = { ...filters, humanReviewRet: value };
|
||||||
|
setFilters(filtersValue);
|
||||||
|
loadMemoryList({ filtersValue });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={styles.filterItem}>
|
||||||
|
<div className={styles.filterItemTitle}>状态</div>
|
||||||
|
<Select
|
||||||
|
className={styles.filterItemControl}
|
||||||
|
placeholder="请选择状态"
|
||||||
|
options={[
|
||||||
|
{ label: '待定', value: StatusEnum.PENDING },
|
||||||
|
{ label: '已启用', value: StatusEnum.ENABLED },
|
||||||
|
{ label: '已禁用', value: StatusEnum.DISABLED },
|
||||||
|
]}
|
||||||
|
value={status}
|
||||||
|
allowClear
|
||||||
|
onChange={(value: ReviewEnum) => {
|
||||||
|
const filtersValue = { ...filters, status: value };
|
||||||
|
setFilters(filtersValue);
|
||||||
|
loadMemoryList({ filtersValue });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<EditableProTable<MemoryType>
|
<EditableProTable<MemoryType>
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
className={styles.memorySection}
|
|
||||||
recordCreatorProps={false}
|
recordCreatorProps={false}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
request={loadMemoryList}
|
request={loadMemoryList}
|
||||||
value={dataSource}
|
value={dataSource}
|
||||||
onChange={setDataSource}
|
onChange={setDataSource}
|
||||||
pagination={{}}
|
pagination={{ pageSize: 10 }}
|
||||||
|
sticky={{ offsetHeader: 0 }}
|
||||||
editable={{
|
editable={{
|
||||||
type: 'multiple',
|
type: 'multiple',
|
||||||
editableKeys,
|
editableKeys,
|
||||||
@@ -190,6 +274,7 @@ const MemorySection = () => {
|
|||||||
onChange: setEditableRowKeys,
|
onChange: setEditableRowKeys,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -42,12 +42,14 @@ export function testLLMConn(data: any) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMemeoryList() {
|
export function getMemeoryList(agentId: number, chatMemoryFilter: any, current: number) {
|
||||||
return request<Result<{ list: MetricType[] }>>('/api/chat/memory/pageMemories', {
|
return request<Result<{ list: MetricType[] }>>('/api/chat/memory/pageMemories', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: {
|
data: {
|
||||||
current: 1,
|
agentId,
|
||||||
pageSize: 2000,
|
chatMemoryFilter,
|
||||||
|
current,
|
||||||
|
pageSize: 10,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -325,10 +325,40 @@
|
|||||||
.ant-pro-card-body {
|
.ant-pro-card-body {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-input-search-button {
|
||||||
|
width: 42px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.filterSection {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
row-gap: 12px;
|
||||||
|
column-gap: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.filterItem {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
column-gap: 12px;
|
||||||
|
width: 22vw;
|
||||||
|
|
||||||
|
.filterItemTitle {
|
||||||
|
margin-right: 6px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filterItemControl {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.reviewComment {
|
.reviewComment {
|
||||||
white-space: nowrap;
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 4;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.filterItemControl {
|
.filterItemControl {
|
||||||
// width: 20vw;
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user