mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-02-01 08:05:07 +08:00
Features: Memory page rendering and other bug fixes (#11784)
### What problem does this PR solve? Features: Memory page rendering and other bug fixes - Rendering of the Memory list page - Rendering of the message list page in Memory - Fixed an issue where the empty state was incorrectly displayed when search criteria were applied - Added a web link for the API-Key - modifying the index_mode attribute of the Confluence data source. ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue) - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
75
web/src/pages/memories/add-or-edit-modal.tsx
Normal file
75
web/src/pages/memories/add-or-edit-modal.tsx
Normal file
@ -0,0 +1,75 @@
|
||||
import { DynamicForm, DynamicFormRef } from '@/components/dynamic-form';
|
||||
import { useModelOptions } from '@/components/llm-setting-items/llm-form-field';
|
||||
import { HomeIcon } from '@/components/svg-icon';
|
||||
import { Modal } from '@/components/ui/modal/modal';
|
||||
import { t } from 'i18next';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { createMemoryFields } from './constants';
|
||||
import { IMemory } from './interface';
|
||||
|
||||
type IProps = {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
onSubmit?: (data: any) => void;
|
||||
initialMemory: IMemory;
|
||||
loading?: boolean;
|
||||
};
|
||||
export const AddOrEditModal = (props: IProps) => {
|
||||
const { open, onClose, onSubmit, initialMemory } = props;
|
||||
// const [fields, setFields] = useState<FormFieldConfig[]>(createMemoryFields);
|
||||
// const formRef = useRef<DynamicFormRef>(null);
|
||||
const [formInstance, setFormInstance] = useState<DynamicFormRef | null>(null);
|
||||
|
||||
const formCallbackRef = useCallback((node: DynamicFormRef | null) => {
|
||||
if (node) {
|
||||
// formRef.current = node;
|
||||
setFormInstance(node);
|
||||
}
|
||||
}, []);
|
||||
const { modelOptions } = useModelOptions();
|
||||
|
||||
useEffect(() => {
|
||||
if (initialMemory && initialMemory.id) {
|
||||
formInstance?.onFieldUpdate('memory_type', { hidden: true });
|
||||
formInstance?.onFieldUpdate('embedding', { hidden: true });
|
||||
formInstance?.onFieldUpdate('llm', { hidden: true });
|
||||
} else {
|
||||
formInstance?.onFieldUpdate('llm', { options: modelOptions as any });
|
||||
}
|
||||
}, [modelOptions, formInstance, initialMemory]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={open}
|
||||
onOpenChange={onClose}
|
||||
className="!w-[480px]"
|
||||
title={
|
||||
<div className="flex flex-col">
|
||||
<div>
|
||||
<HomeIcon name="memory" width={'24'} />
|
||||
</div>
|
||||
{t('memory.createMemory')}
|
||||
</div>
|
||||
}
|
||||
showfooter={false}
|
||||
confirmLoading={props.loading}
|
||||
>
|
||||
<DynamicForm.Root
|
||||
ref={formCallbackRef}
|
||||
fields={createMemoryFields}
|
||||
onSubmit={() => {}}
|
||||
defaultValues={initialMemory}
|
||||
>
|
||||
<div className="flex justify-end gap-2 pb-5">
|
||||
<DynamicForm.CancelButton handleCancel={onClose} />
|
||||
<DynamicForm.SavingButton
|
||||
submitLoading={false}
|
||||
submitFunc={(data) => {
|
||||
onSubmit?.(data);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</DynamicForm.Root>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
41
web/src/pages/memories/constants/index.tsx
Normal file
41
web/src/pages/memories/constants/index.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import { FormFieldConfig, FormFieldType } from '@/components/dynamic-form';
|
||||
import { EmbeddingSelect } from '@/pages/dataset/dataset-setting/configuration/common-item';
|
||||
import { t } from 'i18next';
|
||||
|
||||
export const createMemoryFields = [
|
||||
{
|
||||
name: 'memory_name',
|
||||
label: t('memory.name'),
|
||||
placeholder: t('memory.memoryNamePlaceholder'),
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'memory_type',
|
||||
label: t('memory.memoryType'),
|
||||
type: FormFieldType.MultiSelect,
|
||||
placeholder: t('memory.descriptionPlaceholder'),
|
||||
options: [
|
||||
{ label: 'Raw', value: 'raw' },
|
||||
{ label: 'Semantic', value: 'semantic' },
|
||||
{ label: 'Episodic', value: 'episodic' },
|
||||
{ label: 'Procedural', value: 'procedural' },
|
||||
],
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'embedding',
|
||||
label: t('memory.embeddingModel'),
|
||||
placeholder: t('memory.selectModel'),
|
||||
required: true,
|
||||
// hideLabel: true,
|
||||
// type: 'custom',
|
||||
render: (field) => <EmbeddingSelect field={field} isEdit={false} />,
|
||||
},
|
||||
{
|
||||
name: 'llm',
|
||||
label: t('memory.llm'),
|
||||
placeholder: t('memory.selectModel'),
|
||||
required: true,
|
||||
type: FormFieldType.Select,
|
||||
},
|
||||
] as FormFieldConfig[];
|
||||
288
web/src/pages/memories/hooks.ts
Normal file
288
web/src/pages/memories/hooks.ts
Normal file
@ -0,0 +1,288 @@
|
||||
// src/pages/next-memoryes/hooks.ts
|
||||
|
||||
import message from '@/components/ui/message';
|
||||
import { useSetModalState } from '@/hooks/common-hooks';
|
||||
import { useHandleSearchChange } from '@/hooks/logic-hooks';
|
||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||
import memoryService, { updateMemoryById } from '@/services/memory-service';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useDebounce } from 'ahooks';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useParams, useSearchParams } from 'umi';
|
||||
import {
|
||||
CreateMemoryResponse,
|
||||
DeleteMemoryProps,
|
||||
DeleteMemoryResponse,
|
||||
ICreateMemoryProps,
|
||||
IMemory,
|
||||
IMemoryAppDetailProps,
|
||||
MemoryDetailResponse,
|
||||
MemoryListResponse,
|
||||
} from './interface';
|
||||
|
||||
export const useCreateMemory = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const {
|
||||
data,
|
||||
isError,
|
||||
mutateAsync: createMemoryMutation,
|
||||
} = useMutation<CreateMemoryResponse, Error, ICreateMemoryProps>({
|
||||
mutationKey: ['createMemory'],
|
||||
mutationFn: async (props) => {
|
||||
const { data: response } = await memoryService.createMemory(props);
|
||||
if (response.code !== 0) {
|
||||
throw new Error(response.message || 'Failed to create memory');
|
||||
}
|
||||
return response.data;
|
||||
},
|
||||
onSuccess: () => {
|
||||
message.success(t('message.created'));
|
||||
},
|
||||
onError: (error) => {
|
||||
message.error(t('message.error', { error: error.message }));
|
||||
},
|
||||
});
|
||||
|
||||
const createMemory = useCallback(
|
||||
(props: ICreateMemoryProps) => {
|
||||
return createMemoryMutation(props);
|
||||
},
|
||||
[createMemoryMutation],
|
||||
);
|
||||
|
||||
return { data, isError, createMemory };
|
||||
};
|
||||
|
||||
export const useFetchMemoryList = () => {
|
||||
const { handleInputChange, searchString, pagination, setPagination } =
|
||||
useHandleSearchChange();
|
||||
const debouncedSearchString = useDebounce(searchString, { wait: 500 });
|
||||
const { data, isLoading, isError, refetch } = useQuery<
|
||||
MemoryListResponse,
|
||||
Error
|
||||
>({
|
||||
queryKey: [
|
||||
'memoryList',
|
||||
{
|
||||
debouncedSearchString,
|
||||
...pagination,
|
||||
},
|
||||
],
|
||||
queryFn: async () => {
|
||||
const { data: response } = await memoryService.getMemoryList(
|
||||
{
|
||||
params: {
|
||||
keywords: debouncedSearchString,
|
||||
page_size: pagination.pageSize,
|
||||
page: pagination.current,
|
||||
},
|
||||
data: {},
|
||||
},
|
||||
true,
|
||||
);
|
||||
if (response.code !== 0) {
|
||||
throw new Error(response.message || 'Failed to fetch memory list');
|
||||
}
|
||||
console.log(response);
|
||||
return response;
|
||||
},
|
||||
});
|
||||
|
||||
// const setMemoryListParams = (newParams: MemoryListParams) => {
|
||||
// setMemoryParams((prevParams) => ({
|
||||
// ...prevParams,
|
||||
// ...newParams,
|
||||
// }));
|
||||
// };
|
||||
|
||||
return {
|
||||
data,
|
||||
isLoading,
|
||||
isError,
|
||||
pagination,
|
||||
searchString,
|
||||
handleInputChange,
|
||||
setPagination,
|
||||
refetch,
|
||||
};
|
||||
};
|
||||
|
||||
export const useFetchMemoryDetail = (tenantId?: string) => {
|
||||
const { id } = useParams();
|
||||
|
||||
const [memoryParams] = useSearchParams();
|
||||
const shared_id = memoryParams.get('shared_id');
|
||||
const memoryId = id || shared_id;
|
||||
let param: { id: string | null; tenant_id?: string } = {
|
||||
id: memoryId,
|
||||
};
|
||||
if (shared_id) {
|
||||
param = {
|
||||
id: memoryId,
|
||||
tenant_id: tenantId,
|
||||
};
|
||||
}
|
||||
const fetchMemoryDetailFunc = shared_id
|
||||
? memoryService.getMemoryDetailShare
|
||||
: memoryService.getMemoryDetail;
|
||||
|
||||
const { data, isLoading, isError } = useQuery<MemoryDetailResponse, Error>({
|
||||
queryKey: ['memoryDetail', memoryId],
|
||||
enabled: !shared_id || !!tenantId,
|
||||
queryFn: async () => {
|
||||
const { data: response } = await fetchMemoryDetailFunc(param);
|
||||
if (response.code !== 0) {
|
||||
throw new Error(response.message || 'Failed to fetch memory detail');
|
||||
}
|
||||
return response;
|
||||
},
|
||||
});
|
||||
|
||||
return { data: data?.data, isLoading, isError };
|
||||
};
|
||||
|
||||
export const useDeleteMemory = () => {
|
||||
const { t } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
const {
|
||||
data,
|
||||
isError,
|
||||
mutateAsync: deleteMemoryMutation,
|
||||
} = useMutation<DeleteMemoryResponse, Error, DeleteMemoryProps>({
|
||||
mutationKey: ['deleteMemory'],
|
||||
mutationFn: async (props) => {
|
||||
const { data: response } = await memoryService.deleteMemory(props);
|
||||
if (response.code !== 0) {
|
||||
throw new Error(response.message || 'Failed to delete memory');
|
||||
}
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: ['memoryList'] });
|
||||
return response;
|
||||
},
|
||||
onSuccess: () => {
|
||||
message.success(t('message.deleted'));
|
||||
},
|
||||
onError: (error) => {
|
||||
message.error(t('message.error', { error: error.message }));
|
||||
},
|
||||
});
|
||||
|
||||
const deleteMemory = useCallback(
|
||||
(props: DeleteMemoryProps) => {
|
||||
return deleteMemoryMutation(props);
|
||||
},
|
||||
[deleteMemoryMutation],
|
||||
);
|
||||
|
||||
return { data, isError, deleteMemory };
|
||||
};
|
||||
|
||||
export const useUpdateMemory = () => {
|
||||
const { t } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
const {
|
||||
data,
|
||||
isError,
|
||||
mutateAsync: updateMemoryMutation,
|
||||
} = useMutation<any, Error, IMemoryAppDetailProps>({
|
||||
mutationKey: ['updateMemory'],
|
||||
mutationFn: async (formData) => {
|
||||
const { data: response } = await updateMemoryById(formData.id, formData);
|
||||
if (response.code !== 0) {
|
||||
throw new Error(response.message || 'Failed to update memory');
|
||||
}
|
||||
return response.data;
|
||||
},
|
||||
onSuccess: (data, variables) => {
|
||||
message.success(t('message.updated'));
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['memoryDetail', variables.id],
|
||||
});
|
||||
},
|
||||
onError: (error) => {
|
||||
message.error(t('message.error', { error: error.message }));
|
||||
},
|
||||
});
|
||||
|
||||
const updateMemory = useCallback(
|
||||
(formData: IMemoryAppDetailProps) => {
|
||||
return updateMemoryMutation(formData);
|
||||
},
|
||||
[updateMemoryMutation],
|
||||
);
|
||||
|
||||
return { data, isError, updateMemory };
|
||||
};
|
||||
|
||||
export const useRenameMemory = () => {
|
||||
const [memory, setMemory] = useState<IMemory>({} as IMemory);
|
||||
const { navigateToMemory } = useNavigatePage();
|
||||
const {
|
||||
visible: openCreateModal,
|
||||
hideModal: hideChatRenameModal,
|
||||
showModal: showChatRenameModal,
|
||||
} = useSetModalState();
|
||||
const { updateMemory } = useUpdateMemory();
|
||||
const { createMemory } = useCreateMemory();
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleShowChatRenameModal = useCallback(
|
||||
(record?: IMemory) => {
|
||||
if (record) {
|
||||
setMemory(record);
|
||||
}
|
||||
showChatRenameModal();
|
||||
},
|
||||
[showChatRenameModal],
|
||||
);
|
||||
|
||||
const handleHideModal = useCallback(() => {
|
||||
hideChatRenameModal();
|
||||
setMemory({} as IMemory);
|
||||
}, [hideChatRenameModal]);
|
||||
|
||||
const onMemoryRenameOk = useCallback(
|
||||
async (data: ICreateMemoryProps, callBack?: () => void) => {
|
||||
let res;
|
||||
setLoading(true);
|
||||
if (memory?.id) {
|
||||
try {
|
||||
// const reponse = await memoryService.getMemoryDetail({
|
||||
// id: memory?.id,
|
||||
// });
|
||||
// const detail = reponse.data?.data;
|
||||
// console.log('detail-->', detail);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
// const { id, created_by, update_time, ...memoryDataTemp } = detail;
|
||||
res = await updateMemory({
|
||||
// ...memoryDataTemp,
|
||||
name: data.memory_name,
|
||||
id: memory?.id,
|
||||
} as unknown as IMemoryAppDetailProps);
|
||||
} catch (e) {
|
||||
console.error('error', e);
|
||||
}
|
||||
} else {
|
||||
res = await createMemory(data);
|
||||
}
|
||||
if (res && !memory?.id) {
|
||||
navigateToMemory(res?.id)();
|
||||
}
|
||||
callBack?.();
|
||||
setLoading(false);
|
||||
handleHideModal();
|
||||
},
|
||||
[memory, createMemory, handleHideModal, navigateToMemory, updateMemory],
|
||||
);
|
||||
return {
|
||||
memoryRenameLoading: loading,
|
||||
initialMemory: memory,
|
||||
onMemoryRenameOk,
|
||||
openCreateModal,
|
||||
hideMemoryModal: handleHideModal,
|
||||
showMemoryRenameModal: handleShowChatRenameModal,
|
||||
};
|
||||
};
|
||||
163
web/src/pages/memories/index.tsx
Normal file
163
web/src/pages/memories/index.tsx
Normal file
@ -0,0 +1,163 @@
|
||||
import { CardContainer } from '@/components/card-container';
|
||||
import { EmptyCardType } from '@/components/empty/constant';
|
||||
import { EmptyAppCard } from '@/components/empty/empty';
|
||||
import ListFilterBar from '@/components/list-filter-bar';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { pick } from 'lodash';
|
||||
import { Plus } from 'lucide-react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useSearchParams } from 'umi';
|
||||
import { AddOrEditModal } from './add-or-edit-modal';
|
||||
import { useFetchMemoryList, useRenameMemory } from './hooks';
|
||||
import { ICreateMemoryProps } from './interface';
|
||||
import { MemoryCard } from './memory-card';
|
||||
|
||||
export default function MemoryList() {
|
||||
// const { data } = useFetchFlowList();
|
||||
const { t } = useTranslate('memory');
|
||||
// const [isEdit, setIsEdit] = useState(false);
|
||||
const {
|
||||
data: list,
|
||||
pagination,
|
||||
searchString,
|
||||
handleInputChange,
|
||||
setPagination,
|
||||
refetch: refetchList,
|
||||
} = useFetchMemoryList();
|
||||
|
||||
const {
|
||||
openCreateModal,
|
||||
showMemoryRenameModal,
|
||||
hideMemoryModal,
|
||||
searchRenameLoading,
|
||||
onMemoryRenameOk,
|
||||
initialMemory,
|
||||
} = useRenameMemory();
|
||||
|
||||
const onMemoryConfirm = (data: ICreateMemoryProps) => {
|
||||
onMemoryRenameOk(data, () => {
|
||||
refetchList();
|
||||
});
|
||||
};
|
||||
const openCreateModalFun = useCallback(() => {
|
||||
// setIsEdit(false);
|
||||
showMemoryRenameModal();
|
||||
}, [showMemoryRenameModal]);
|
||||
const handlePageChange = useCallback(
|
||||
(page: number, pageSize?: number) => {
|
||||
setPagination({ page, pageSize });
|
||||
},
|
||||
[setPagination],
|
||||
);
|
||||
|
||||
const [searchUrl, setMemoryUrl] = useSearchParams();
|
||||
const isCreate = searchUrl.get('isCreate') === 'true';
|
||||
useEffect(() => {
|
||||
if (isCreate) {
|
||||
openCreateModalFun();
|
||||
searchUrl.delete('isCreate');
|
||||
setMemoryUrl(searchUrl);
|
||||
}
|
||||
}, [isCreate, openCreateModalFun, searchUrl, setMemoryUrl]);
|
||||
|
||||
return (
|
||||
<section className="w-full h-full flex flex-col">
|
||||
{(!list?.data?.memory_list?.length ||
|
||||
list?.data?.memory_list?.length <= 0) &&
|
||||
!searchString && (
|
||||
<div className="flex w-full items-center justify-center h-[calc(100vh-164px)]">
|
||||
<EmptyAppCard
|
||||
showIcon
|
||||
size="large"
|
||||
className="w-[480px] p-14"
|
||||
isSearch={!!searchString}
|
||||
type={EmptyCardType.Memory}
|
||||
onClick={() => openCreateModalFun()}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{(!!list?.data?.memory_list?.length || searchString) && (
|
||||
<>
|
||||
<div className="px-8 pt-8">
|
||||
<ListFilterBar
|
||||
icon="memory"
|
||||
title={t('memory')}
|
||||
showFilter={false}
|
||||
onSearchChange={handleInputChange}
|
||||
searchString={searchString}
|
||||
>
|
||||
<Button
|
||||
variant={'default'}
|
||||
onClick={() => {
|
||||
openCreateModalFun();
|
||||
}}
|
||||
>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
{t('createMemory')}
|
||||
</Button>
|
||||
</ListFilterBar>
|
||||
</div>
|
||||
{(!list?.data?.memory_list?.length ||
|
||||
list?.data?.memory_list?.length <= 0) &&
|
||||
searchString && (
|
||||
<div className="flex w-full items-center justify-center h-[calc(100vh-164px)]">
|
||||
<EmptyAppCard
|
||||
showIcon
|
||||
size="large"
|
||||
className="w-[480px] p-14"
|
||||
isSearch={!!searchString}
|
||||
type={EmptyCardType.Memory}
|
||||
onClick={() => openCreateModalFun()}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex-1">
|
||||
<CardContainer className="max-h-[calc(100dvh-280px)] overflow-auto px-8">
|
||||
{list?.data.memory_list.map((x) => {
|
||||
return (
|
||||
<MemoryCard
|
||||
key={x.id}
|
||||
data={x}
|
||||
showMemoryRenameModal={() => {
|
||||
showMemoryRenameModal(x);
|
||||
}}
|
||||
></MemoryCard>
|
||||
);
|
||||
})}
|
||||
</CardContainer>
|
||||
</div>
|
||||
{list?.data.total && list?.data.total > 0 && (
|
||||
<div className="px-8 mb-4">
|
||||
<RAGFlowPagination
|
||||
{...pick(pagination, 'current', 'pageSize')}
|
||||
// total={pagination.total}
|
||||
total={list?.data.total}
|
||||
onChange={handlePageChange}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{/* {openCreateModal && (
|
||||
<RenameDialog
|
||||
hideModal={hideMemoryRenameModal}
|
||||
onOk={onMemoryRenameConfirm}
|
||||
initialName={initialMemoryName}
|
||||
loading={searchRenameLoading}
|
||||
title={<HomeIcon name="memory" width={'24'} />}
|
||||
></RenameDialog>
|
||||
)} */}
|
||||
{openCreateModal && (
|
||||
<AddOrEditModal
|
||||
initialMemory={initialMemory}
|
||||
open={openCreateModal}
|
||||
loading={searchRenameLoading}
|
||||
onClose={hideMemoryModal}
|
||||
onSubmit={onMemoryConfirm}
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
121
web/src/pages/memories/interface.ts
Normal file
121
web/src/pages/memories/interface.ts
Normal file
@ -0,0 +1,121 @@
|
||||
export interface ICreateMemoryProps {
|
||||
memory_name: string;
|
||||
memory_type: Array<string>;
|
||||
embedding: string;
|
||||
llm: string;
|
||||
}
|
||||
|
||||
export interface CreateMemoryResponse {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export interface MemoryListParams {
|
||||
keywords?: string;
|
||||
parser_id?: string;
|
||||
page?: number;
|
||||
page_size?: number;
|
||||
orderby?: string;
|
||||
desc?: boolean;
|
||||
owner_ids?: string;
|
||||
}
|
||||
export type MemoryType = 'raw' | 'semantic' | 'episodic' | 'procedural';
|
||||
export type StorageType = 'table' | 'graph';
|
||||
export type Permissions = 'me' | 'team';
|
||||
export type ForgettingPolicy = 'fifo' | 'lru';
|
||||
|
||||
export interface IMemory {
|
||||
id: string;
|
||||
name: string;
|
||||
avatar: string;
|
||||
tenant_id: string;
|
||||
owner_name: string;
|
||||
memory_type: MemoryType[];
|
||||
storage_type: StorageType;
|
||||
embedding: string;
|
||||
llm: string;
|
||||
permissions: Permissions;
|
||||
description: string;
|
||||
memory_size: number;
|
||||
forgetting_policy: ForgettingPolicy;
|
||||
temperature: string;
|
||||
system_prompt: string;
|
||||
user_prompt: string;
|
||||
}
|
||||
export interface MemoryListResponse {
|
||||
code: number;
|
||||
data: {
|
||||
memory_list: Array<IMemory>;
|
||||
total: number;
|
||||
};
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface DeleteMemoryProps {
|
||||
memory_id: string;
|
||||
}
|
||||
|
||||
export interface DeleteMemoryResponse {
|
||||
code: number;
|
||||
data: boolean;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface IllmSettingProps {
|
||||
llm_id: string;
|
||||
parameter: string;
|
||||
temperature?: number;
|
||||
top_p?: number;
|
||||
frequency_penalty?: number;
|
||||
presence_penalty?: number;
|
||||
}
|
||||
interface IllmSettingEnableProps {
|
||||
temperatureEnabled?: boolean;
|
||||
topPEnabled?: boolean;
|
||||
presencePenaltyEnabled?: boolean;
|
||||
frequencyPenaltyEnabled?: boolean;
|
||||
}
|
||||
export interface IMemoryAppDetailProps {
|
||||
avatar: any;
|
||||
created_by: string;
|
||||
description: string;
|
||||
id: string;
|
||||
name: string;
|
||||
memory_config: {
|
||||
cross_languages: string[];
|
||||
doc_ids: string[];
|
||||
chat_id: string;
|
||||
highlight: boolean;
|
||||
kb_ids: string[];
|
||||
keyword: boolean;
|
||||
query_mindmap: boolean;
|
||||
related_memory: boolean;
|
||||
rerank_id: string;
|
||||
use_rerank?: boolean;
|
||||
similarity_threshold: number;
|
||||
summary: boolean;
|
||||
llm_setting: IllmSettingProps & IllmSettingEnableProps;
|
||||
top_k: number;
|
||||
use_kg: boolean;
|
||||
vector_similarity_weight: number;
|
||||
web_memory: boolean;
|
||||
chat_settingcross_languages: string[];
|
||||
meta_data_filter?: {
|
||||
method: string;
|
||||
manual: { key: string; op: string; value: string }[];
|
||||
};
|
||||
};
|
||||
tenant_id: string;
|
||||
update_time: number;
|
||||
}
|
||||
|
||||
export interface MemoryDetailResponse {
|
||||
code: number;
|
||||
data: IMemoryAppDetailProps;
|
||||
message: string;
|
||||
}
|
||||
|
||||
// export type IUpdateMemoryProps = Omit<IMemoryAppDetailProps, 'id'> & {
|
||||
// id: string;
|
||||
// };
|
||||
32
web/src/pages/memories/memory-card.tsx
Normal file
32
web/src/pages/memories/memory-card.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
import { HomeCard } from '@/components/home-card';
|
||||
import { MoreButton } from '@/components/more-button';
|
||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||
import { IMemory } from './interface';
|
||||
import { MemoryDropdown } from './memory-dropdown';
|
||||
|
||||
interface IProps {
|
||||
data: IMemory;
|
||||
showMemoryRenameModal: (data: IMemory) => void;
|
||||
}
|
||||
export function MemoryCard({ data, showMemoryRenameModal }: IProps) {
|
||||
const { navigateToMemory } = useNavigatePage();
|
||||
|
||||
return (
|
||||
<HomeCard
|
||||
data={{
|
||||
name: data?.name,
|
||||
avatar: data?.avatar,
|
||||
description: data?.description,
|
||||
}}
|
||||
moreDropdown={
|
||||
<MemoryDropdown
|
||||
dataset={data}
|
||||
showMemoryRenameModal={showMemoryRenameModal}
|
||||
>
|
||||
<MoreButton></MoreButton>
|
||||
</MemoryDropdown>
|
||||
}
|
||||
onClick={navigateToMemory(data?.id)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
74
web/src/pages/memories/memory-dropdown.tsx
Normal file
74
web/src/pages/memories/memory-dropdown.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
import {
|
||||
ConfirmDeleteDialog,
|
||||
ConfirmDeleteDialogNode,
|
||||
} from '@/components/confirm-delete-dialog';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { PenLine, Trash2 } from 'lucide-react';
|
||||
import { MouseEventHandler, PropsWithChildren, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { IMemoryAppProps, useDeleteMemory } from './hooks';
|
||||
|
||||
export function MemoryDropdown({
|
||||
children,
|
||||
dataset,
|
||||
showMemoryRenameModal,
|
||||
}: PropsWithChildren & {
|
||||
dataset: IMemoryAppProps;
|
||||
showMemoryRenameModal: (dataset: IMemoryAppProps) => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const { deleteMemory } = useDeleteMemory();
|
||||
const handleShowChatRenameModal: MouseEventHandler<HTMLDivElement> =
|
||||
useCallback(
|
||||
(e) => {
|
||||
e.stopPropagation();
|
||||
showMemoryRenameModal(dataset);
|
||||
},
|
||||
[dataset, showMemoryRenameModal],
|
||||
);
|
||||
const handleDelete: MouseEventHandler<HTMLDivElement> = useCallback(() => {
|
||||
deleteMemory({ search_id: dataset.id });
|
||||
}, [dataset.id, deleteMemory]);
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>{children}</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem onClick={handleShowChatRenameModal}>
|
||||
{t('common.rename')} <PenLine />
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<ConfirmDeleteDialog
|
||||
onOk={handleDelete}
|
||||
title={t('deleteModal.delMemory')}
|
||||
content={{
|
||||
node: (
|
||||
<ConfirmDeleteDialogNode
|
||||
avatar={{ avatar: dataset.avatar, name: dataset.name }}
|
||||
name={dataset.name}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
>
|
||||
<DropdownMenuItem
|
||||
className="text-state-error"
|
||||
onSelect={(e) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
{t('common.delete')} <Trash2 />
|
||||
</DropdownMenuItem>
|
||||
</ConfirmDeleteDialog>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user