/* * @Author: ZhaoYing * @Date: 2026-02-03 17:00:12 * @Last Modified by: ZhaoYing * @Last Modified time: 2026-04-14 16:54:38 */ /** * Forgetting Engine Configuration Page * Configures memory forgetting curve parameters * Uses Ebbinghaus forgetting curve formula: R = offset + (1 - offset) × e^(-λ_time × t / λ_mem) */ import React, { useState, useEffect } from 'react'; import { Row, Col, Form, Button, Space, App, Flex, Tooltip } from 'antd'; import { useParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import RbCard from '@/components/RbCard/Card'; import LineChart from './components/LineChart' import { getMemoryForgetConfig, updateMemoryForgetConfig } from '@/api/memory' import type { ConfigForm } from './types' import SwitchFormItem from '@/components/FormItem/SwitchFormItem' import RbSlider from '@/components/RbSlider'; import DescWrapper from '@/components/FormItem/DescWrapper' import { useI18n } from '@/store/locale' /** * Configuration field definitions */ const configList = [ { key: 'minimumRetention', name: 'lambda_time', range: [0, 1], type: 'decimal', }, { key: 'forgettingRate', name: 'lambda_mem', range: [0.01, 1], type: 'decimal', }, { key: 'offset', name: 'offset', range: [0, 1], type: 'decimal', }, { key: 'decay_constant', name: 'decay_constant', range: [0, 1], type: 'decimal', hiddenDesc: true, }, { key: 'max_history_length', name: 'max_history_length', type: 'decimal', step: 1, range: [10, 1000], hiddenDesc: true, }, { key: 'forgetting_threshold', name: 'forgetting_threshold', type: 'decimal', range: [0, 1], hiddenDesc: true, }, { key: 'min_days_since_access', name: 'min_days_since_access', type: 'decimal', step: 1, range: [1, 365], hiddenDesc: true, }, { key: 'enable_llm_summary', name: 'enable_llm_summary', type: 'button', hiddenDesc: true, }, { key: 'max_merge_batch_size', name: 'max_merge_batch_size', type: 'decimal', step: 1, range: [1, 1000], hiddenDesc: true, }, { key: 'forgetting_interval_hours', name: 'forgetting_interval_hours', type: 'decimal', step: 1, range: [1, 168], hiddenDesc: true, }, ] /** * Forgetting engine configuration component */ const ForgettingEngine: React.FC = () => { const { t } = useTranslation(); const { id } = useParams(); const [configData, setConfigData] = useState(); const [form] = Form.useForm(); const { message: messageApi } = App.useApp(); const [loading, setLoading] = useState(false) const { language } = useI18n() const values = Form.useWatch([], form); useEffect(() => { document.title = [document.title.split(' - ')[0], t('memoryBear')].join(' - ') }, [language]) useEffect(() => { getConfigData() }, []) /** Fetch forgetting engine configuration */ const getConfigData = () => { getMemoryForgetConfig(id as string) .then((res) => { const response = res as ConfigForm const initialValues = { ...response, lambda_time: Number(response.lambda_time || 0), lambda_mem: Number(response.lambda_mem || 0), offset: Number(response.offset || 0), } setConfigData(initialValues); form.setFieldsValue(initialValues); }) .catch(() => { console.error('Failed to load data'); }) } /** Reset form to saved configuration */ const handleReset = () => { form.setFieldsValue(configData || {}); } /** Save forgetting engine configuration */ const handleSave = () => { setLoading(true) updateMemoryForgetConfig({ config_id: id, ...values }) .then(() => { messageApi.success(t('common.saveSuccess')) setConfigData({...(values || {})}) }) .finally(() => { setLoading(false) }) } return ( } headerType="borderless" headerClassName="rb:min-h-[54px]! rb:font-[MiSans-Bold] rb:font-bold" className="rb:h-full!" bodyClassName="rb:h-[calc(100%-54px)] rb:overflow-y-auto! rb:p-3! rb:pt-0!" >
{configList.map(config => { if (config.type === 'button') { return ( {t(`forgettingEngine.type`)}: {config.type}} className="rb:bg-[#F6F6F6] rb:rounded-xl rb:p-3!" /> ) } return (
{t(`forgettingEngine.${config.key}`)} {!config.hiddenDesc &&
}
{t(`forgettingEngine.range`)}: {config.range?.join('-')} | {t(`forgettingEngine.type`)}: {config.type} } />} className="rb:mb-0!" > {config.type === 'decimal' ? {t('emotionEngine.currentValue')}:} inputClassName="rb:w-[155px]!" /> : null }
) })}
); }; export default ForgettingEngine;