(feature)(supersonic-fe) add memory manage (#1287)

This commit is contained in:
williamhliu
2024-06-29 19:55:35 +08:00
committed by GitHub
parent a3f17b3b68
commit fbe4114775
5 changed files with 147 additions and 31 deletions

View File

@@ -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!} />,
}, },
]; ];

View File

@@ -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,25 +181,100 @@ const MemorySection = () => {
await saveMemory(data); await saveMemory(data);
}; };
const onSearch = () => {
loadMemoryList();
};
return ( return (
<EditableProTable<MemoryType> <div className={styles.memorySection}>
rowKey="id" <div className={styles.filterSection}>
className={styles.memorySection} <div className={styles.filterItem}>
recordCreatorProps={false} <div className={styles.filterItemTitle}></div>
loading={loading} <Search
columns={columns} className={styles.filterItemControl}
request={loadMemoryList} placeholder="请输入用户问题"
value={dataSource} value={question}
onChange={setDataSource} onChange={(e) => {
pagination={{}} setFilters({ ...filters, question: e.target.value });
editable={{ }}
type: 'multiple', onSearch={onSearch}
editableKeys, />
actionRender: (row, config, defaultDom) => [defaultDom.save, defaultDom.cancel], </div>
onSave, <div className={styles.filterItem}>
onChange: setEditableRowKeys, <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>
rowKey="id"
recordCreatorProps={false}
loading={loading}
columns={columns}
request={loadMemoryList}
value={dataSource}
onChange={setDataSource}
pagination={{ pageSize: 10 }}
sticky={{ offsetHeader: 0 }}
editable={{
type: 'multiple',
editableKeys,
actionRender: (row, config, defaultDom) => [defaultDom.save, defaultDom.cancel],
onSave,
onChange: setEditableRowKeys,
}}
/>
</div>
); );
}; };

View File

@@ -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,
}, },
}); });
} }

View File

@@ -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;
} }

View File

@@ -22,7 +22,6 @@
} }
.filterItemControl { .filterItemControl {
// width: 20vw;
flex: 1; flex: 1;
} }
} }