diff --git a/web/src/api/memory.ts b/web/src/api/memory.ts index 39136da3..42f691a4 100644 --- a/web/src/api/memory.ts +++ b/web/src/api/memory.ts @@ -181,6 +181,20 @@ export const getEpisodicOverview = (data: { end_user_id: string; time_range: str export const getEpisodicDetail = (data: { end_user_id: string; summary_id: string; } ) => { return request.post(`/memory-storage/classifications/episodic-memory-details`, data) } +// 关系演化 +export const getRelationshipEvolution = (data: { id: string; label: string; } ) => { + return request.get(`/memory-storage/memory_space/relationship_evolution`, data) +} +// 共同记忆时间线 +export const getTimelineMemories = (data: { id: string; label: string; }) => { + return request.get(`/memory-storage/memory_space/timeline_memories`, data) +} +export const getExplicitMemory = (end_user_id: string) => { + return request.post(`/memory-storage/classifications/explicit-memory`, { end_user_id }) +} +export const getExplicitMemoryDetails = (data: { end_user_id: string, memory_id: string; }) => { + return request.post(`/memory-storage/classifications/explicit-memory-details`, data) +} /*************** end 用户记忆 相关接口 ******************************/ diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index c7c9a937..16d07add 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -1240,6 +1240,10 @@ export const en = { associative_memory: 'Associative Memory', unix: 'items', completeMemory: 'Complete Memory', + relationshipEvolution: 'Relationship Evolution', + timelineMemories: 'Shared Memory Timeline', + emotionLine: 'Emotion Changes Over Time', + interaction: 'Interaction Frequency & Relationship Stages', }, space: { createSpace: 'Create Space', @@ -2268,6 +2272,15 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re section_count: 'Number of Sections', timeLine: 'Perception Timeline', lastInfo: 'Real-time Perception Dashboard', + }, + explicitDetail: { + episodic_memories: 'Episodic Memories', + semantic_memories: 'Semantic Memories', + content: 'Core Description', + created_at: 'Created At', + emotion: 'Emotion', + core_definition: 'Core Definition', + detailed_notes: 'Detailed Notes', } }, }; diff --git a/web/src/i18n/zh.ts b/web/src/i18n/zh.ts index d858b643..74c02720 100644 --- a/web/src/i18n/zh.ts +++ b/web/src/i18n/zh.ts @@ -1321,6 +1321,10 @@ export const zh = { associative_memory: '关联记忆', unix: '个', completeMemory: '完整记忆', + relationshipEvolution: '关系演化', + timelineMemories: '共同记忆时间线', + emotionLine: '情绪随时间变化', + interaction: '互动频率 & 关系阶段', }, space: { createSpace: '创建空间', @@ -2368,6 +2372,15 @@ export const zh = { section_count: '段落数', timeLine: '感知时间线', lastInfo: '实时感知仪表盘', + }, + explicitDetail: { + episodic_memories: '情景记忆', + semantic_memories: '语义记忆', + content: '核心描述', + created_at: '创建时间', + emotion: '情绪', + core_definition: '核心定义', + detailed_notes: '详细笔记', } }, } \ No newline at end of file diff --git a/web/src/routes/index.tsx b/web/src/routes/index.tsx index bc2f61e6..f3bd9c2d 100644 --- a/web/src/routes/index.tsx +++ b/web/src/routes/index.tsx @@ -61,7 +61,6 @@ const componentMap: Record>> = StatementDetail: lazy(() => import('@/views/UserMemoryDetail/pages/StatementDetail')), ForgetDetail: lazy(() => import('@/views/UserMemoryDetail/pages/ForgetDetail')), MemoryNodeDetail: lazy(() => import('@/views/UserMemoryDetail/pages/index')), - GraphDetail: lazy(() => import('@/views/UserMemoryDetail/pages/GraphDetail')), SelfReflectionEngine: lazy(() => import('@/views/SelfReflectionEngine')), OrderPayment: lazy(() => import('@/views/OrderPayment')), OrderHistory: lazy(() => import('@/views/OrderHistory')), diff --git a/web/src/routes/routes.json b/web/src/routes/routes.json index 2f332b72..ca6a3271 100644 --- a/web/src/routes/routes.json +++ b/web/src/routes/routes.json @@ -44,8 +44,7 @@ { "path": "/conversation/:token", "element": "Conversation" }, { "path": "/user-memory/neo4j/:id", "element": "Neo4jUserMemoryDetail" }, { "path": "/statement/:id", "element": "StatementDetail" }, - { "path": "/user-memory/detail/:id/:type", "element": "MemoryNodeDetail" }, - { "path": "/graph/:id", "element": "GraphDetail" } + { "path": "/user-memory/detail/:id/:type", "element": "MemoryNodeDetail" } ] }, { diff --git a/web/src/views/UserMemoryDetail/components/AboutMe.tsx b/web/src/views/UserMemoryDetail/components/AboutMe.tsx index f2c94814..f3f914c2 100644 --- a/web/src/views/UserMemoryDetail/components/AboutMe.tsx +++ b/web/src/views/UserMemoryDetail/components/AboutMe.tsx @@ -30,7 +30,6 @@ const AboutMe = forwardRef((_props, ref) => { getData() }, [id]) - // 记忆洞察 const getData = () => { if (!id) return setLoading(true) diff --git a/web/src/views/UserMemoryDetail/components/EmotionLine.tsx b/web/src/views/UserMemoryDetail/components/EmotionLine.tsx new file mode 100644 index 00000000..eb53439f --- /dev/null +++ b/web/src/views/UserMemoryDetail/components/EmotionLine.tsx @@ -0,0 +1,173 @@ +import { type FC, useRef } from 'react' +import { useTranslation } from 'react-i18next' +import ReactEcharts from 'echarts-for-react'; +import * as echarts from 'echarts'; +import Empty from '@/components/Empty' +import Loading from '@/components/Empty/Loading' +import type { Emotion } from './GraphDetail' + +interface EmotionLineProps { + chartData: Emotion[]; + loading?: boolean; +} + +const Colors = ['#369F21', '#155EEF', '#FF5D34'] + +const EmotionLine: FC = ({ chartData, loading }) => { + const { t } = useTranslation() + const chartRef = useRef(null); + + const getSeries = () => { + const emotionTypes = [...new Set(chartData.map(item => item.emotion_type))] + const timePoints = [...new Set(chartData.map(item => item.created_at))].sort() + + return emotionTypes.map((emotionType, index) => { + const emotionData = chartData.filter(item => item.emotion_type === emotionType) + const dataMap = new Map(emotionData.map(item => [item.created_at, item.emotion_intensity])) + const seriesData = timePoints.map(time => dataMap.get(time) || 0) + + return { + name: emotionType, + type: 'line', + smooth: true, + lineStyle: { + width: 3, + color: Colors[index % Colors.length] + }, + itemStyle: { + color: Colors[index % Colors.length] + }, + areaStyle: { + color: Colors[index % Colors.length], + opacity: 0.08 + }, + data: seriesData + } + }) + } + + return ( + <> +
{t('userMemory.emotionLine')}
+ {loading + ? + : !chartData || chartData.length === 0 + ? + : ` + params.forEach((param: any) => { + result += `${param.marker}${param.seriesName}: ${param.value}
` + }) + return result + } + }, + legend: { + bottom: 2, + padding: 0, + itemGap: 24, + itemWidth: 40, + itemHeight: 12, + borderRadius: 2, + orient: 'horizontal', + textStyle: { + color: '#5B6167', + fontFamily: 'PingFangSC, PingFang SC', + lineHeight: 16, + } + }, + grid: { + top: 16, + left: 30, + right: 36, + bottom: 48, + // containLabel: false + }, + xAxis: { + type: 'category', + data: [...new Set(chartData.map(item => item.created_at))].sort().map(time => { + const date = new Date(time) + return `${date.getFullYear()}.${String(date.getMonth() + 1).padStart(2, '0')}` + }), + boundaryGap: false, + axisLabel: { + color: '#A8A9AA', + fontFamily: 'PingFangSC, PingFang SC' + }, + axisLine: { + show: true, + lineStyle: { + color: '#EBEBEB' + } + }, + splitLine: { + show: true, + lineStyle: { + color: '#EBEBEB', + type: 'solid' + } + }, + axisTick: { + show: true, + lineStyle: { + color: '#EBEBEB', + type: 'solid' + } + } + }, + yAxis: { + type: 'value', + axisLabel: { + color: '#A8A9AA', + fontFamily: 'PingFangSC, PingFang SC' + }, + axisLine: { + show: true, + lineStyle: { + color: '#EBEBEB' + } + }, + splitLine: { + show: true, + lineStyle: { + color: '#EBEBEB', + type: 'solid' + } + }, + axisTick: { + show: true, + lineStyle: { + color: '#EBEBEB', + type: 'solid' + } + }, + max: 1, + min: 0 + }, + series: getSeries() + }} + style={{ height: '265px', width: '100%', minWidth: '100%' }} + notMerge={true} + lazyUpdate={true} + /> + } + + ) +} + +export default EmotionLine diff --git a/web/src/views/UserMemoryDetail/components/ExplicitDetailModal.tsx b/web/src/views/UserMemoryDetail/components/ExplicitDetailModal.tsx new file mode 100644 index 00000000..05d0597f --- /dev/null +++ b/web/src/views/UserMemoryDetail/components/ExplicitDetailModal.tsx @@ -0,0 +1,100 @@ +import { forwardRef, useImperativeHandle, useState, useCallback } from 'react'; +import { useParams } from 'react-router-dom' +import { Descriptions, Skeleton } from 'antd'; +import { useTranslation } from 'react-i18next'; + +import RbModal from '@/components/RbModal' +import { getExplicitMemoryDetails } from '@/api/memory' +import { formatDateTime } from '@/utils/format' +import type { ExplicitDetailModalRef, EpisodicMemory, SemanticMemory } from '../pages/ExplicitDetail' + + +interface Data { + memory_type: 'episodic' | 'semantic'; + title: string; + content: string; + emotion: string; + created_at: number; + + name: string; + core_definition: string; + detailed_notes: string; +} +const ExplicitDetailModal = forwardRef((_props, ref) => { + const { t } = useTranslation(); + const { id } = useParams() + const [visible, setVisible] = useState(false); + const [loading, setLoading] = useState(false); + const [data, setData] = useState({} as Data) + + // 封装取消方法,添加关闭弹窗逻辑 + const handleClose = () => { + setVisible(false); + setData({} as Data) + }; + + const handleOpen = (vo: EpisodicMemory | SemanticMemory) => { + setLoading(true) + getExplicitMemoryDetails({ + end_user_id: id as string, + memory_id: vo.id + }) + .then(res => { + setVisible(true); + setData(res as Data) + }) + .finally(() => { + setLoading(false) + }) + }; + + const getEmotionColor = (emotionType: string) => { + const colors: Record = { + joy: '#52c41a', + anger: '#ff4d4f', + sadness: '#1890ff', + fear: '#fa8c16', + neutral: '#8c8c8c', + surprise: '#722ed1' + } + return colors[emotionType] || '#8c8c8c' + } + + // 暴露给父组件的方法 + useImperativeHandle(ref, () => ({ + handleOpen, + })); + return ( + + {loading ? + : + {data.emotion && +
+
+ {t(`statementDetail.${data.emotion || 'neutral'}`)} +
+
} + {data.core_definition && + {data.core_definition} + } + {data.detailed_notes && + {data.detailed_notes} + } + {data.created_at && + {formatDateTime(data.created_at)} + } + {data.content && + {data.content} + } +
+ } +
+ ); +}); + +export default ExplicitDetailModal; \ No newline at end of file diff --git a/web/src/views/UserMemoryDetail/components/GraphDetail.tsx b/web/src/views/UserMemoryDetail/components/GraphDetail.tsx new file mode 100644 index 00000000..3b654a12 --- /dev/null +++ b/web/src/views/UserMemoryDetail/components/GraphDetail.tsx @@ -0,0 +1,174 @@ +import { type FC, useState, forwardRef, useImperativeHandle } from 'react' +import { useTranslation } from 'react-i18next' +import { useParams } from 'react-router-dom' +import { Row, Col, Tabs } from 'antd' + +import { getRelationshipEvolution, getTimelineMemories } from '@/api/memory' +import type { Node, GraphDetailRef } from '../types' +import RbDrawer from '@/components/RbDrawer' +import RbCard from '@/components/RbCard/Card' +import EmotionLine from './EmotionLine' + +export interface Emotion { + emotion_intensity: number; + emotion_type: string; + created_at: string | number; +} +export interface Interaction { + name: string; + importance_score: number; + interaction_count: number; +} + +const GraphDetail = forwardRef((_props, ref) => { + const { t } = useTranslation() + const { id } = useParams() + const [open, setOpen] = useState(false); + const [vo, setVo] = useState(null) + const [emotionData, setEmotionData] = useState([ + { + "emotion_intensity": 0.1, + "emotion_type": "neutral", + "created_at": "2026-01-07 19:14:34" + }, + { + "emotion_intensity": 0.2, + "emotion_type": "neutral", + "created_at": "2026-02-08 19:14:34" + }, + { + "emotion_intensity": 0.1, + "emotion_type": "neutral", + "created_at": "2026-03-09 19:14:34" + }, + { + "emotion_intensity": 0.1, + "emotion_type": "neutral", + "created_at": "2026-04-10 19:14:34" + }, + { + "emotion_intensity": 0.1, + "emotion_type": "sadness", + "created_at": "2026-01-07 19:14:34" + }, + { + "emotion_intensity": 0.2, + "emotion_type": "sadness", + "created_at": "2026-02-08 19:14:34" + }, + { + "emotion_intensity": 0.1, + "emotion_type": "sadness", + "created_at": "2026-03-09 19:14:34" + }, + { + "emotion_intensity": 0.1, + "emotion_type": "sadness", + "created_at": "2026-04-10 19:14:34" + }, + ]) + const [interactionData, setInteractionData] = useState([ + { + "name": "小蓝", + "importance_score": 0.5, + "interaction_count": 1 + } + ]) + const [timelineMemories, setTimelineMemories] = useState({ + "code": 0, + "msg": "共同记忆时间线", + "data": { + "success": true, + "data": { + "MemorySummary": [ + "小蓝今天原计划与小明野餐、与小绿看电影,但最终选择与姐姐小红一起看戏。", + "用户小明喜欢喝咖啡,每天都要喝拿铁。" + ], + "Statement": [ + "小蓝对是否去野餐或看电影感到犹豫。", + "小蓝和她姐姐小红出去看戏。", + "小明喜欢喝咖啡。", + "小明每天都要喝拿铁。", + "小明今天约小蓝出去野餐。" + ], + "ExtractedEntity": [ + "小明", + "咖啡", + "拿铁", + "小蓝", + "野餐" + ], + "timelines_memory": [ + "小蓝今天原计划与小明野餐、与小绿看电影,但最终选择与姐姐小红一起看戏。", + "用户小明喜欢喝咖啡,每天都要喝拿铁。", + "小蓝对是否去野餐或看电影感到犹豫。", + "小蓝和她姐姐小红出去看戏。", + "小明喜欢喝咖啡。", + "小明每天都要喝拿铁。", + "小明今天约小蓝出去野餐。", + "小明", + "咖啡", + "拿铁", + "小蓝", + "野餐" + ] + } + }, + "error": "", + "time": 1767852781464 + }) + + const handleCancel = () => { + setVo(null) + setOpen(false) + } + const handleOpen = (vo: Node) => { + setOpen(true) + setVo(vo) + getTimelineMemoriesData(vo) + } + const getRelationshipEvolutionData = (vo: Node) => { + if (!id || !vo.label) return + + getRelationshipEvolution({ id: id as string, label: vo.label }) + .then(res => { + const { emotion, interaction } = res as { emotion: { data: Emotion[]}; interaction: {data: Interaction[]} } || {} + setEmotionData(emotion?.data) + setInteractionData(interaction?.data) + }) + } + const getTimelineMemoriesData = (vo: Node) => { + if (!id || !vo.label) return + + getTimelineMemories({ id: id as string, label: vo.label }) + .then(res => { + + }) + } + + useImperativeHandle(ref, () => ({ + handleOpen, + })); + + return ( + +
{t('useMemory.relationshipEvolution')}
+ + + + + + +
{t('userMemory.interaction')}
+ +
+
+
+ ) +}) +export default GraphDetail \ No newline at end of file diff --git a/web/src/views/UserMemoryDetail/components/Habits.tsx b/web/src/views/UserMemoryDetail/components/Habits.tsx index 746d7164..93ef817f 100644 --- a/web/src/views/UserMemoryDetail/components/Habits.tsx +++ b/web/src/views/UserMemoryDetail/components/Habits.tsx @@ -12,7 +12,7 @@ interface HabitsItem { habit_description: string; frequency_pattern: string; time_context: string; - confidence_level: string; + confidence_level: number; supporting_summaries: string[]; first_observed: string; last_observed: string; @@ -31,7 +31,6 @@ const Habits: FC = () => { getData() }, [id]) - // 记忆洞察 const getData = () => { if (!id) return setLoading(true) diff --git a/web/src/views/UserMemoryDetail/components/InterestAreas.tsx b/web/src/views/UserMemoryDetail/components/InterestAreas.tsx index 357336f4..6f74d255 100644 --- a/web/src/views/UserMemoryDetail/components/InterestAreas.tsx +++ b/web/src/views/UserMemoryDetail/components/InterestAreas.tsx @@ -33,8 +33,7 @@ const InterestAreas: FC = () => { if (!id) return getData() }, [id]) - - // 记忆洞察 + const getData = () => { if (!id) return setLoading(true) diff --git a/web/src/views/UserMemoryDetail/components/NodeStatistics.tsx b/web/src/views/UserMemoryDetail/components/NodeStatistics.tsx index 8815c66d..0e032e45 100644 --- a/web/src/views/UserMemoryDetail/components/NodeStatistics.tsx +++ b/web/src/views/UserMemoryDetail/components/NodeStatistics.tsx @@ -47,8 +47,7 @@ const NodeStatistics: FC = () => { if (!id) return getData() }, [id]) - - // 记忆洞察 + const getData = () => { if (!id) return setLoading(true) diff --git a/web/src/views/UserMemoryDetail/components/RelationshipNetwork.tsx b/web/src/views/UserMemoryDetail/components/RelationshipNetwork.tsx index 4cce1100..641a37f6 100644 --- a/web/src/views/UserMemoryDetail/components/RelationshipNetwork.tsx +++ b/web/src/views/UserMemoryDetail/components/RelationshipNetwork.tsx @@ -7,12 +7,13 @@ import dayjs from 'dayjs' import RbCard from '@/components/RbCard/Card' import ReactEcharts from 'echarts-for-react' import detailEmpty from '@/assets/images/userMemory/detail_empty.png' -import type { Node, Edge, GraphData, StatementNodeProperties, ExtractedEntityNodeProperties } from '../types' +import type { Node, Edge, GraphData, StatementNodeProperties, ExtractedEntityNodeProperties, GraphDetailRef } from '../types' import { getMemorySearchEdges, } from '@/api/memory' import Empty from '@/components/Empty' import Tag from '@/components/Tag' +import GraphDetail from '../components/GraphDetail' const colors = ['#155EEF', '#369F21', '#4DA8FF', '#FF5D34', '#9C6FFF', '#FF8A4C', '#8BAEF7', '#FFB048'] const RelationshipNetwork:FC = () => { @@ -25,6 +26,7 @@ const RelationshipNetwork:FC = () => { const [categories, setCategories] = useState<{ name: string }[]>([]) const [selectedNode, setSelectedNode] = useState(null) // const [fullScreen, setFullScreen] = useState(false) + const graphDetailRef = useRef(null) console.log('categories', categories) // 关系网络 @@ -139,7 +141,7 @@ const RelationshipNetwork:FC = () => { const handleViewAll = () => { if (!selectedNode) return - window.open(`/#/graph/${selectedNode.id}`); + graphDetailRef.current?.handleOpen(selectedNode) } return ( @@ -332,6 +334,8 @@ const RelationshipNetwork:FC = () => { + + ) } diff --git a/web/src/views/UserMemoryDetail/pages/EpisodicDetail.tsx b/web/src/views/UserMemoryDetail/pages/EpisodicDetail.tsx index 4a7e4b1f..2940347d 100644 --- a/web/src/views/UserMemoryDetail/pages/EpisodicDetail.tsx +++ b/web/src/views/UserMemoryDetail/pages/EpisodicDetail.tsx @@ -72,10 +72,9 @@ const EpisodicDetail: FC = () => { useEffect(() => { if (!id) return - // getData() + getData() }, [id]) - - // 记忆洞察 + const getData = () => { if (!id) return setLoading(true) diff --git a/web/src/views/UserMemoryDetail/pages/ExplicitDetail.tsx b/web/src/views/UserMemoryDetail/pages/ExplicitDetail.tsx new file mode 100644 index 00000000..286e71be --- /dev/null +++ b/web/src/views/UserMemoryDetail/pages/ExplicitDetail.tsx @@ -0,0 +1,109 @@ +import { type FC, useEffect, useState, useRef } from 'react' +import { useTranslation } from 'react-i18next' +import { useParams } from 'react-router-dom' +import { List, Skeleton, Row, Col } from 'antd' +import RbCard from '@/components/RbCard/Card' +import { + getExplicitMemory, +} from '@/api/memory' +import { formatDateTime } from '@/utils/format' +import Empty from '@/components/Empty' +import ExplicitDetailModal from '../components/ExplicitDetailModal' + +export interface EpisodicMemory { + id: string; + title: string; + content: string; + created_at: number; +} +export interface SemanticMemory { + id: string; + name: string; + entity_type: string; + core_definition: string; + created_at: number; +} +interface Data { + episodic_memories: EpisodicMemory[]; + semantic_memories: SemanticMemory[] +} + +export interface ExplicitDetailModalRef { + handleOpen: (vo: EpisodicMemory | SemanticMemory) => void; +} + +const ExplicitDetail: FC = () => { + const { t } = useTranslation() + const { id } = useParams() + const explicitDetailModalRef = useRef(null) + const [loading, setLoading] = useState(false) + const [data, setData] = useState({ episodic_memories: [], semantic_memories: [] }) + + useEffect(() => { + if (!id) return + getData() + }, [id]) + + const getData = () => { + if (!id) return + setLoading(true) + getExplicitMemory(id).then((res) => { + const response = res as Data + setData(response) + setLoading(false) + }) + .finally(() => { + setLoading(false) + }) + } + const handleView = (item: EpisodicMemory | SemanticMemory) => { + explicitDetailModalRef.current?.handleOpen(item) + } + return ( +
+
{t('explicitDetail.episodic_memories')}
+ {loading ? + + : data.episodic_memories?.length > 0 ? ( + + {data.episodic_memories.map(item => ( + + handleView(item)} + > +
{formatDateTime(item.created_at)}
+
{item.content}
+
+ + ))} +
+ ) : } + +
{t('explicitDetail.semantic_memories')}
+ {loading ? + + : data.semantic_memories?.length > 0 ? ( + + {data.semantic_memories.map(item => ( + + handleView(item)} + > +
{item.core_definition}
+
+ + ))} +
+ ) : } + + +
+ ) +} +export default ExplicitDetail \ No newline at end of file diff --git a/web/src/views/UserMemoryDetail/pages/ForgetDetail.tsx b/web/src/views/UserMemoryDetail/pages/ForgetDetail.tsx index f0ba04ff..602dbf25 100644 --- a/web/src/views/UserMemoryDetail/pages/ForgetDetail.tsx +++ b/web/src/views/UserMemoryDetail/pages/ForgetDetail.tsx @@ -30,8 +30,7 @@ const ForgetDetail: FC = () => { if (!id) return getData() }, [id]) - - // 记忆洞察 + const getData = () => { if (!id) return setLoading(true) diff --git a/web/src/views/UserMemoryDetail/pages/GraphDetail.tsx b/web/src/views/UserMemoryDetail/pages/GraphDetail.tsx deleted file mode 100644 index f3cf716c..00000000 --- a/web/src/views/UserMemoryDetail/pages/GraphDetail.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { type FC } from 'react' -import { useTranslation } from 'react-i18next' -import { Row, Col } from 'antd' - -const GraphDetail: FC = () => { - const { t } = useTranslation() - - return ( -
- GraphDetail -
- ) -} -export default GraphDetail \ No newline at end of file diff --git a/web/src/views/UserMemoryDetail/pages/index.tsx b/web/src/views/UserMemoryDetail/pages/index.tsx index da62c14e..93468a94 100644 --- a/web/src/views/UserMemoryDetail/pages/index.tsx +++ b/web/src/views/UserMemoryDetail/pages/index.tsx @@ -10,6 +10,7 @@ import ImplicitDetail from './ImplicitDetail' import ShortTermDetail from './ShortTermDetail' import PerceptualDetail from './PerceptualDetail' import EpisodicDetail from './EpisodicDetail' +import ExplicitDetail from './ExplicitDetail' import { getEndUserProfile, } from '@/api/memory' @@ -62,6 +63,8 @@ const Detail: FC = () => { {type === 'SHORT_TERM_MEMORY' && } {type === 'PERCEPTUAL_MEMORY' && } {/** TODO */} {type === 'EPISODIC_MEMORY' && } + {/* {type === 'WORKING_MEMORY' && } */} {/** TODO */} + {type === 'EXPLICIT_MEMORY' && } {/** TODO */} ) diff --git a/web/src/views/UserMemoryDetail/types.ts b/web/src/views/UserMemoryDetail/types.ts index 263494d0..afed31fd 100644 --- a/web/src/views/UserMemoryDetail/types.ts +++ b/web/src/views/UserMemoryDetail/types.ts @@ -184,4 +184,7 @@ export interface ForgetData { last_access_time: number; }[], timestamp: number; +} +export interface GraphDetailRef { + handleOpen: (vo: Node) => void } \ No newline at end of file