diff --git a/web/src/views/UserMemory/index.tsx b/web/src/views/UserMemory/index.tsx index 653f09b0..03ed6940 100644 --- a/web/src/views/UserMemory/index.tsx +++ b/web/src/views/UserMemory/index.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 17:53:44 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-02-03 17:54:33 + * @Last Modified time: 2026-02-10 17:52:35 */ /** * User Memory Page @@ -12,7 +12,7 @@ import { useEffect, useState, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom' -import { Row, Col, List, Skeleton } from 'antd'; +import { Row, Col, Skeleton, Form, Flex } from 'antd'; import Empty from '@/components/Empty' import type { Data } from './types' @@ -27,7 +27,9 @@ export default function UserMemory() { const { storageType } = useUser() const [loading, setLoading] = useState(false); const [data, setData] = useState([]); - const [search, setSearch] = useState(undefined); + + const [form] = Form.useForm() + const search = Form.useWatch(['search'], form) /** Fetch user memory list */ useEffect(() => { @@ -76,26 +78,27 @@ export default function UserMemory() { return (
- - - setSearch(value)} - style={{ width: '100%' }} - /> - - +
+ + + + + + + +
{loading ? : filterData.length > 0 ? ( - { + + {filterData.map((item, index) => { const { end_user, memory_num, memory_config } = item as Data; const name = end_user?.other_name && end_user?.other_name !== '' ? end_user?.other_name : end_user?.id return ( - + {name[0]}
} title={name || '-'} @@ -105,29 +108,29 @@ export default function UserMemory() { className="rb:cursor-pointer" onClick={() => handleViewDetail(end_user.id)} > -
+
{t('userMemory.capacity')}
{memory_num?.total || 0} {t('userMemory.memoryNum')}
-
-
+ +
{t('userMemory.type')}
{t(`userMemory.${item.type || 'person'}`)}
-
+ -
-
+
+ {t('userMemory.memory_config_name')}
-
+
{memory_config?.memory_config_name || '-'}
- + ) - }} - /> + })} + ) : }
diff --git a/web/src/views/UserMemoryDetail/Neo4j.tsx b/web/src/views/UserMemoryDetail/Neo4j.tsx index fb237e4a..1212a5c6 100644 --- a/web/src/views/UserMemoryDetail/Neo4j.tsx +++ b/web/src/views/UserMemoryDetail/Neo4j.tsx @@ -1,8 +1,8 @@ /* * @Author: ZhaoYing * @Date: 2026-02-03 17:57:26 - * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-02-03 17:57:26 + * @Last Modified by: ZhaoYing + * @Last Modified time: 2026-02-09 14:28:34 */ /** * Neo4j User Memory Detail View @@ -10,12 +10,12 @@ * Shows profile, interests, node statistics, relationships, and insights */ -import { type FC, useRef, useState } from 'react' -import { useParams } from 'react-router-dom' -import { Row, Col, Space, Button } from 'antd' +import { type FC, useRef, useState, type MouseEvent } from 'react' +import clsx from 'clsx' +import { useParams, useNavigate } from 'react-router-dom' +import { Flex, Popover } from 'antd' import { useTranslation } from 'react-i18next'; -import PageHeader from './components/PageHeader' import EndUserProfile from './components/EndUserProfile' import AboutMe from './components/AboutMe' import InterestDistribution from './components/InterestDistribution' @@ -28,21 +28,29 @@ import { } from '@/api/memory' const Neo4j: FC = () => { - const { t } = useTranslation(); const { id } = useParams() + const { t } = useTranslation(); + const navigate = useNavigate(); const [loading, setLoading] = useState(false) const [name, setName] = useState('') const ref = useRef(null) const memoryInsightRef = useRef(null) const aboutMeRef = useRef(null) + const [selectedKey, setSelectedKey] = useState(null) /** Update displayed name */ const handleNameUpdate = (data: { other_name?: string; id: string }) => { setName(data.other_name && data.other_name !== '' ? data.other_name : data.id) } + /** Navigate back */ + const goBack = () => { + navigate('/user-memory', { replace: true }) + } + /** Refresh analytics data */ const handleRefresh = () => { + if (loading) return; setLoading(true) analyticsRefresh(id as string) .then(res => { @@ -59,43 +67,104 @@ const Neo4j: FC = () => { }) } - + const onOpenChange = (e: MouseEvent, type: string) => { + e.preventDefault(); + e.stopPropagation(); + setSelectedKey(type) + } return ( -
- - {!loading &&
} - {t('common.refresh')} - - )} - /> -
- - - - - - - - - - - - - - - - -
+
setSelectedKey(null)}> + + + + +
+
+ + onOpenChange(e, 'userProfile')} + > +
+
+ + onOpenChange(e, 'aboutMe')} + > +
+
+ + onOpenChange(e, 'interestDistribution')} + > +
+
+ + onOpenChange(e, 'memoryInsight')} + > +
+
+
+ + +
+
+
+
+ + + + + +
+ + + +
) } diff --git a/web/src/views/UserMemoryDetail/components/AboutMe.tsx b/web/src/views/UserMemoryDetail/components/AboutMe.tsx index 2b376a03..f38ef30a 100644 --- a/web/src/views/UserMemoryDetail/components/AboutMe.tsx +++ b/web/src/views/UserMemoryDetail/components/AboutMe.tsx @@ -1,8 +1,8 @@ /* * @Author: ZhaoYing * @Date: 2026-02-03 18:34:23 - * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-02-03 18:34:23 + * @Last Modified by: ZhaoYing + * @Last Modified time: 2026-02-11 15:03:05 */ /** * About Me Component @@ -12,7 +12,8 @@ import { useEffect, useState, forwardRef, useImperativeHandle } from 'react' import { useTranslation } from 'react-i18next' import { useParams } from 'react-router-dom' -import { Skeleton } from 'antd'; +import { Skeleton, Divider } from 'antd'; +import clsx from 'clsx' import RbCard from '@/components/RbCard/Card' import Empty from '@/components/Empty'; @@ -33,7 +34,7 @@ interface Data { one_sentence: string; [key: string]: string; } -const AboutMe = forwardRef((_props, ref) => { +const AboutMe = forwardRef(({ className }, ref) => { const { t } = useTranslation() const { id } = useParams() const [loading, setLoading] = useState(false) @@ -64,7 +65,9 @@ const AboutMe = forwardRef((_props, ref) => { return ( {loading ? @@ -76,19 +79,21 @@ const AboutMe = forwardRef((_props, ref) => {
} {data.personality && <> -
{t('userMemory.personality')}
-
+ +
{t('userMemory.personality')}
+
{data.personality}
} {data.core_values && <> -
{t('userMemory.core_values')}
-
+ +
{t('userMemory.core_values')}
+
{data.core_values}
} {data.one_sentence && - {data.one_sentence} + {data.one_sentence} } : diff --git a/web/src/views/UserMemoryDetail/components/Card.tsx b/web/src/views/UserMemoryDetail/components/Card.tsx index 39b77ffb..8abad6c6 100644 --- a/web/src/views/UserMemoryDetail/components/Card.tsx +++ b/web/src/views/UserMemoryDetail/components/Card.tsx @@ -24,7 +24,7 @@ interface CardProps { const Card: FC = ({ title, children, theme = 'default', className }) => { return ( -
diff --git a/web/src/views/UserMemoryDetail/components/ConversationMemory.tsx b/web/src/views/UserMemoryDetail/components/ConversationMemory.tsx index 928b340f..2993a20c 100644 --- a/web/src/views/UserMemoryDetail/components/ConversationMemory.tsx +++ b/web/src/views/UserMemoryDetail/components/ConversationMemory.tsx @@ -59,7 +59,7 @@ const ConversationMemory:FC = () => {
diff --git a/web/src/views/UserMemoryDetail/components/EndUserProfile.tsx b/web/src/views/UserMemoryDetail/components/EndUserProfile.tsx index 43701050..d2364001 100644 --- a/web/src/views/UserMemoryDetail/components/EndUserProfile.tsx +++ b/web/src/views/UserMemoryDetail/components/EndUserProfile.tsx @@ -1,8 +1,8 @@ /* * @Author: ZhaoYing * @Date: 2026-02-03 18:33:30 - * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-02-03 18:33:30 + * @Last Modified by: ZhaoYing + * @Last Modified time: 2026-02-11 14:51:00 */ /** * End User Profile Component @@ -12,8 +12,9 @@ import { forwardRef, useImperativeHandle, useEffect, useState, useRef, useCallback } from 'react' import { useTranslation } from 'react-i18next' import { useParams } from 'react-router-dom' -import { Skeleton } from 'antd'; +import { Skeleton, Flex } from 'antd'; import dayjs from 'dayjs' +import clsx from 'clsx' import RbCard from '@/components/RbCard/Card' import { @@ -26,10 +27,11 @@ import type { EndUser, EndUserProfileModalRef, EndUserProfileRef } from '../type * Component props */ interface EndUserProfileProps { - onDataLoaded?: (data: { other_name?: string; id: string }) => void + onDataLoaded?: (data: { other_name?: string; id: string }) => void; + className?: string; } -const EndUserProfile = forwardRef(({ onDataLoaded }, ref) => { +const EndUserProfile = forwardRef(({ onDataLoaded, className }, ref) => { const { t } = useTranslation() const { id } = useParams() const endUserProfileModalRef = useRef(null) @@ -85,22 +87,24 @@ const EndUserProfile = forwardRef(({ onD onClick={handleEdit} >
} - headerClassName="rb:min-h-[46px]!" + headerClassName="rb:min-h-[46px]!! rb:font-medium!" + className={clsx("rb:bg-[#FFFFFF]! rb:shadow-[0px_2px_6px_0px_rgba(33,35,50,0.13)]! rb:absolute! rb:w-80 rb:top-29 rb:left-26", className)} + bodyClassName="rb:px-5! rb:pb-5! rb:pt-3.75! rb:max-h-[calc(100vh-176px)] rb:overflow-auto" > {loading ? - :
+ : {formatItems().map(vo => ( -
-
{vo.label}
-
{vo.children}
+
+
{vo.label}
+
{vo.children}
))} -
+
{t('userMemory.updated_at')}: {data?.updatetime_profile ? dayjs(data?.updatetime_profile).format('YYYY/MM/DD HH:mm:ss') : ''}
-
+ } { +const InterestDistribution: FC<{ className?: string; }> = ({ className }) => { const { t } = useTranslation() const { id } = useParams() const chartRef = useRef(null); const resizeScheduledRef = useRef(false) const [loading, setLoading] = useState(false) const [data, setData] = useState>>([]) - const totalValue = data.reduce((sum, item) => sum + Number(item.value), 0) useEffect(() => { getData() @@ -76,7 +75,9 @@ const InterestDistribution: FC = () => { return ( {loading ? @@ -102,61 +103,55 @@ const InterestDistribution: FC = () => { extraCssText: 'width: 36px; height: 36px; box-shadow: 0px 2px 4px 0px rgba(33,35,50,0.12);border-radius: 36px;' }, legend: { - show: false + bottom: 0, + padding: 0, + itemWidth: 12, + itemHeight: 12, + borderRadius: 2, + orient: 'horizontal', + textStyle: { + color: '#5B6167', + fontFamily: 'PingFangSC, PingFang SC', + lineHeight: 16, + } }, series: [ { - name: 'Access From', type: 'pie', radius: ['60%', '100%'], avoidLabelOverlap: false, percentPrecision: 0, - padAngle: 0, - width: 200, - height: 200, - top: 18, + padAngle: 1, + width: 180, + height: 180, left: 'center', + top: 24, itemStyle: { - borderRadius: 0 + borderRadius: 2, + shadowBlur: 4, + shadowOffsetX: 0, + shadowOffsetY: 2, + shadowColor: 'rgba(0,0,0,0.25)', }, label: { - show: false, - position: 'center' - }, - emphasis: { - label: { - show: true, - fontSize: 24, - fontWeight: 'bold', - color: '#212332', - formatter: '{d}%\n{b}', - } + fontWeight: 'bold', + color: '#171719', + formatter: '{d}%', + fontFamily: 'MiSans-Demibold', }, labelLine: { - show: false + lineStyle: { + color: '#DFE4ED' + } }, data: data } ] }} - style={{ height: '250px', width: '100%' }} + style={{ height: '320px', width: '100%' }} notMerge={true} lazyUpdate={true} /> - - {data.map((item, index) => ( -
-
- - {item.name} -
-
{totalValue > 0 ? Math.round((Number(item.value) / totalValue) * 100) : 0}%
-
- ))} -
}
) diff --git a/web/src/views/UserMemoryDetail/components/MemoryInsight.tsx b/web/src/views/UserMemoryDetail/components/MemoryInsight.tsx index d44b7c78..578c8823 100644 --- a/web/src/views/UserMemoryDetail/components/MemoryInsight.tsx +++ b/web/src/views/UserMemoryDetail/components/MemoryInsight.tsx @@ -1,8 +1,8 @@ /* * @Author: ZhaoYing * @Date: 2026-02-03 18:32:41 - * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-02-03 18:32:41 + * @Last Modified by: ZhaoYing + * @Last Modified time: 2026-02-05 18:35:01 */ /** * Memory Insight Component @@ -10,10 +10,10 @@ */ import { useEffect, useState, forwardRef, useImperativeHandle } from 'react' -import clsx from 'clsx' import { useTranslation } from 'react-i18next' import { useParams } from 'react-router-dom' -import { Skeleton, Space } from 'antd'; +import { Skeleton, Divider } from 'antd'; +import clsx from 'clsx' import RbCard from '@/components/RbCard/Card' import Empty from '@/components/Empty'; @@ -34,7 +34,7 @@ interface Data { is_cached: boolean; } -const MemoryInsight = forwardRef((_props, ref) => { +const MemoryInsight = forwardRef(({ className }, ref) => { const { t } = useTranslation() const { id } = useParams() const [loading, setLoading] = useState(false) @@ -63,24 +63,25 @@ const MemoryInsight = forwardRef((_props, ref) => { })); return ( {loading ? : Object.keys(data).length > 0 - ? - {['memory_insight', 'key_findings', 'behavior_pattern', 'growth_trajectory'].map(key => { + ?
+ {['memory_insight', 'key_findings', 'behavior_pattern', 'growth_trajectory'].map((key, index) => { const value = data[key as keyof Data]; if (Array.isArray(value) && value.length > 0 || (!Array.isArray(value) && value)) { return ( -
-
{t(`userMemory.${key}`)}
-
+
+ {index > 0 && } +
+ {t(`userMemory.${key}`)} +
+
{Array.isArray(data[key as keyof Data]) ? <> {(data[key as keyof Data] as string[])?.map((item: string, index: number) => ( @@ -98,7 +99,7 @@ const MemoryInsight = forwardRef((_props, ref) => { return null })} - +
: } diff --git a/web/src/views/UserMemoryDetail/components/NodeStatistics.tsx b/web/src/views/UserMemoryDetail/components/NodeStatistics.tsx index 787d9ab8..1e251b34 100644 --- a/web/src/views/UserMemoryDetail/components/NodeStatistics.tsx +++ b/web/src/views/UserMemoryDetail/components/NodeStatistics.tsx @@ -1,8 +1,8 @@ /* * @Author: ZhaoYing * @Date: 2026-02-03 18:32:35 - * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-02-03 18:32:35 + * @Last Modified by: ZhaoYing + * @Last Modified time: 2026-02-05 19:07:07 */ /** * Node Statistics Component @@ -13,30 +13,20 @@ import { type FC, useEffect, useState } from 'react' import clsx from 'clsx' import { useTranslation } from 'react-i18next' import { useParams, useNavigate } from 'react-router-dom' -import { Skeleton } from 'antd'; +import { Skeleton, Flex, Divider } from 'antd'; -import RbCard from '@/components/RbCard/Card' import { getNodeStatistics, } from '@/api/memory' import type { NodeStatisticsItem } from '../types' - -/** Background gradient list */ -const BG_LIST = [ - 'rb:bg-[linear-gradient(316deg,rgba(21,94,239,0.06)_0%,rgba(251,253,255,0)_100%)]', - 'rb:bg-[linear-gradient(316deg,rgba(54,159,33,0.06)_0%,rgba(251,253,255,0)_100%)]', - 'rb:bg-[linear-gradient(314deg,rgba(156,111,255,0.06)_0%,rgba(251,253,255,0)_100%)]', - 'rb:bg-[linear-gradient(332deg,rgba(255,93,52,0.06)_0%,rgba(251,253,255,0)_100%)]', - 'rb:bg-[linear-gradient(313deg,rgba(156,111,255,0.06)_0%,rgba(251,253,255,0)_100%)]', - 'rb:bg-[linear-gradient(332deg,rgba(54,159,33,0.06)_0%,rgba(251,253,255,0)_100%)]', -] /** Memory type configuration */ const typeList = [ { key: 'PERCEPTUAL_MEMORY', bg: 0 }, { key: 'WORKING_MEMORY', bg: 1 }, { key: 'EMOTIONAL_MEMORY', bg: 2 }, { key: 'SHORT_TERM_MEMORY', bg: 3 }, + { key: 'FORGET_MEMORY', bg: 5 }, { key: 'LONG_TERM_MEMORY', bg: 4, @@ -46,7 +36,6 @@ const typeList = [ { key: 'EXPLICIT_MEMORY' } ] }, - { key: 'FORGET_MEMORY', bg: 5 }, ] const NodeStatistics: FC = () => { @@ -54,7 +43,6 @@ const NodeStatistics: FC = () => { const { t } = useTranslation() const { id } = useParams() const [loading, setLoading] = useState(false) - const [total, setTotal] = useState(0) const [data, setData] = useState([]) useEffect(() => { @@ -69,9 +57,6 @@ const NodeStatistics: FC = () => { getNodeStatistics(id).then((res) => { const response = res as NodeStatisticsItem[] setData(response) - // Calculate total count - const totalCount = response.reduce((sum, item) => sum + (item.count || 0), 0) - setTotal(totalCount) setLoading(false) }) .finally(() => { @@ -83,59 +68,57 @@ const NodeStatistics: FC = () => { navigate(`/user-memory/detail/${id}/${type}`) } /** Render statistics card */ - const renderCard = (key: string, bgIndex: number | null, isChild: boolean = false) => { + const renderCard = (key: string, isChild: boolean = false) => { const item = data.find((item) => item.type === key) return ( -
handleViewDetail(key)} >
-
+
{t(`userMemory.${key}`)}
-
-
{item?.count ?? 0}
-
+ +
{item?.count ?? 0}
+
+
+ ) } return ( - {t('userMemory.nodeStatistics')} ({t('userMemory.total')}: {total})} - headerType="borderless" - headerClassName="rb:min-h-[46px]!" - > +
{loading ? - :
+ :
{typeList.map((vo) => { if (!vo.children) { - return
{renderCard(vo.key, vo.bg)}
+ return
{renderCard(vo.key)}
} return ( -
-
{t(`userMemory.${vo.key}`)}
-
- {vo.children.map((child) =>
{renderCard(child.key, null, true)}
)} +
+
{t(`userMemory.${vo.key}`)}
+
+ {vo.children.map((child, index) => + {index > 0 && } + {renderCard(child.key, true)} + )}
) })}
} - +
) } export default NodeStatistics \ No newline at end of file diff --git a/web/src/views/UserMemoryDetail/components/RelationshipNetwork.tsx b/web/src/views/UserMemoryDetail/components/RelationshipNetwork.tsx index aa8b9d7c..40b03438 100644 --- a/web/src/views/UserMemoryDetail/components/RelationshipNetwork.tsx +++ b/web/src/views/UserMemoryDetail/components/RelationshipNetwork.tsx @@ -1,8 +1,8 @@ /* * @Author: ZhaoYing * @Date: 2026-02-03 18:32:00 - * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-02-03 18:32:00 + * @Last Modified by: ZhaoYing + * @Last Modified time: 2026-02-11 15:06:05 */ /** * Relationship Network Component @@ -10,37 +10,29 @@ * Interactive force-directed graph visualization */ -import React, { type FC, useEffect, useState, useRef, useCallback } from 'react' +import React, { type FC, useEffect, useState, useCallback } from 'react' import { useTranslation } from 'react-i18next' import { useParams, useNavigate } from 'react-router-dom' -import { Col, Row, Space, Button } from 'antd' +import { Space, Flex } from 'antd' import dayjs from 'dayjs' -import ReactEcharts from 'echarts-for-react' import RbCard from '@/components/RbCard/Card' -import detailEmpty from '@/assets/images/userMemory/detail_empty.png' -import type { Node, Edge, GraphData, StatementNodeProperties, ExtractedEntityNodeProperties } from '../types' +import type { GraphData, StatementNodeProperties, ExtractedEntityNodeProperties } from '../types' import { getMemorySearchEdges, } from '@/api/memory' -import Empty from '@/components/Empty' import Tag from '@/components/Tag' +import GraphNetworkChart, { type Node, type Edge } from '@/components/Charts/GraphNetworkChart' -/** Node color palette */ -const colors = ['#155EEF', '#369F21', '#4DA8FF', '#FF5D34', '#9C6FFF', '#FF8A4C', '#8BAEF7', '#FFB048'] const RelationshipNetwork:FC = () => { const { t } = useTranslation() const { id } = useParams() - const chartRef = useRef(null) - const resizeScheduledRef = useRef(false) const [nodes, setNodes] = useState([]) const [links, setLinks] = useState([]) const [categories, setCategories] = useState<{ name: string }[]>([]) const [selectedNode, setSelectedNode] = useState(null) - // const [fullScreen, setFullScreen] = useState(false) const navigate = useNavigate() - console.log('categories', categories) /** Fetch relationship network data */ const getEdgeData = useCallback(() => { if (!id) return @@ -124,28 +116,6 @@ const RelationshipNetwork:FC = () => { if (!id) return getEdgeData() }, [id]) - - useEffect(() => { - const handleResize = () => { - if (chartRef.current && !resizeScheduledRef.current) { - resizeScheduledRef.current = true - requestAnimationFrame(() => { - chartRef.current?.getEchartsInstance().resize(); - resizeScheduledRef.current = false - }); - } - } - - const resizeObserver = new ResizeObserver(handleResize) - const chartElement = chartRef.current?.getEchartsInstance().getDom().parentElement - if (chartElement) { - resizeObserver.observe(chartElement) - } - - return () => { - resizeObserver.disconnect() - } - }, [nodes]) /** Navigate to full graph view */ const handleViewAll = () => { @@ -157,204 +127,111 @@ const RelationshipNetwork:FC = () => { }) navigate(`/user-memory/detail/${id}/GRAPH?${params.toString()}`) } - return ( - - {/* Relationship Network */} - - - //
- // {t('userMemory.fullScreen')} - //
- // } - > -
- {nodes.length === 0 ? ( - - ) : ( - ({ - name: t(`userMemory.${vo.name}`) - })) || [], - roam: true, - label: { - show: true, - position: 'right', - formatter: '{b}', - }, - lineStyle: { - color: '#5B6167', - curveness: 0.3 - }, - force: { - repulsion: 100, - // Enable category aggregation - edgeLength: 80, - gravity: 0.3, - // Nodes of the same category attract each other - layoutAnimation: true, - // Prevent layout recalculation on click - preventOverlap: true, - // Keep layout stable after node click - edgeSymbol: ['none', 'arrow'], - edgeSymbolSize: [4, 10], - // Disable force-directed after initial layout - initLayout: 'force' - }, - selectedMode: 'single', - draggable: true, - // Prevent layout recalculation on data update - animationDurationUpdate: 0, - select: { - itemStyle: { - borderWidth: 2, - borderColor: '#ffffff', - shadowBlur: 10, - } - } - } - ] - }} - style={{ height: '518px', width: '100%' }} - notMerge={false} - lazyUpdate={true} - onEvents={{ - // Node click event handler - click: (params: { dataType: string; data: Node; name: string }) => { - if (params.dataType === 'node') { - // Handle node click event - console.log('Node clicked:', params.data); - // Use functional update to avoid state dependency issues - setSelectedNode(params.data) - } - } - }} - /> - )} -
- - - {/* Memory Details */} - - + ({ + name: t(`userMemory.${vo.name}`) + })) || []} + onNodeClick={setSelectedNode} + /> + + {selectedNode && + -
- {t('userMemory.completeMemory')} - } + headerClassName="rb:min-h-[60px]!" + bodyClassName='rb:px-5! rb:pb-[76px]! rb:pt-0! rb:h-auto!' + extra={
setSelectedNode(null)}>
} > -
- {!selectedNode - ? - : <> - {selectedNode.name &&
{selectedNode.name}
} -
- <> -
{t('userMemory.memoryContent')}
-
- {['Chunk', 'Dialogue', 'MemorySummary'].includes(selectedNode.label) && 'content' in selectedNode.properties - ? selectedNode.properties.content - : selectedNode.label === 'ExtractedEntity' && 'description' in selectedNode.properties - ? selectedNode.properties.description - : selectedNode.label === 'Statement' && 'statement' in selectedNode.properties +
+ {selectedNode.name && +
+ {selectedNode.name} +
+ } + +
+
{t('userMemory.memoryContent')}
+
+ {['Chunk', 'Dialogue', 'MemorySummary'].includes(selectedNode.label) && 'content' in selectedNode.properties + ? selectedNode.properties.content + : selectedNode.label === 'ExtractedEntity' && 'description' in selectedNode.properties + ? selectedNode.properties.description + : selectedNode.label === 'Statement' && 'statement' in selectedNode.properties ? selectedNode.properties.statement : '' - } -
- -
-
{t('userMemory.created_at')}
-
- {dayjs(selectedNode?.properties.created_at).format('YYYY-MM-DD HH:mm:ss')} -
- - {selectedNode?.properties.associative_memory > 0 &&
-
{t('userMemory.associative_memory')}
-
- {selectedNode?.properties.associative_memory} {t('userMemory.unix')}{t('userMemory.associative_memory')} -
-
} - - {selectedNode.label === 'Statement' && <> - {(['emotion_keywords', 'emotion_type', 'emotion_subject', 'importance_score'] as const).map(key => { - const statementProps = selectedNode.properties as StatementNodeProperties; - if ((key === 'emotion_keywords' && statementProps[key]?.length > 0) || typeof statementProps[key] === 'string') { - console.log('statementProps[key]', statementProps[key]) - return ( -
- {t(`userMemory.Statement_${key}`)} -
- {key === 'emotion_keywords' - ? {statementProps.emotion_keywords.map((vo, index) => {vo})} - : statementProps[key] - } -
-
- ) - } - return null - })} - } - {selectedNode.label === 'ExtractedEntity' && <> - {(['name', 'entity_type', 'aliases', 'connect_strngth', 'importance_score'] as const).map(key => { - const entityProps = selectedNode.properties as ExtractedEntityNodeProperties; - if (entityProps[key]) { - return ( -
- {t(`userMemory.ExtractedEntity_${key}`)} -
- {Array.isArray(entityProps[key]) && entityProps[key].length > 0 - ? entityProps[key].map((vo, index) =>
- {vo}
) - : entityProps[key] - } -
-
- ) - } - return null - })} - } -
+ }
- - } +
+ +
+
{t('userMemory.created_at')}
+
+ {dayjs(selectedNode?.properties.created_at).format('YYYY-MM-DD HH:mm:ss')} +
+
+ + {selectedNode?.properties.associative_memory > 0 &&
+
{t('userMemory.associative_memory')}
+
+ {selectedNode?.properties.associative_memory} {t('userMemory.unix')}{t('userMemory.associative_memory')} +
+
} + + + {selectedNode.label === 'Statement' && <> + {(['emotion_keywords', 'emotion_type', 'emotion_subject', 'importance_score'] as const).map(key => { + const statementProps = selectedNode.properties as StatementNodeProperties; + if ((key === 'emotion_keywords' && statementProps[key]?.length > 0) || typeof statementProps[key] === 'string') { + return ( +
+
{t(`userMemory.Statement_${key}`)}
+
+ {key === 'emotion_keywords' + ? {statementProps.emotion_keywords.map((vo, index) => {vo})} + : statementProps[key] + } +
+
+ ) + } + return null + })} + } + + + {selectedNode.label === 'ExtractedEntity' && <> + {(['name', 'entity_type', 'aliases', 'connect_strngth', 'importance_score'] as const).map(key => { + const entityProps = selectedNode.properties as ExtractedEntityNodeProperties; + if (entityProps[key]) { + return ( +
+
{t(`userMemory.ExtractedEntity_${key}`)}
+
+ {Array.isArray(entityProps[key]) && entityProps[key].length > 0 + ? entityProps[key].map((vo, index) =>
- {vo}
) + : entityProps[key] + } +
+
+ ) + } + return null + })} + } +
+ + + {t('userMemory.completeMemory')} + - - + } +
) } /** Use React.memo to avoid unnecessary renders */