/* * @Author: ZhaoYing * @Date: 2026-01-12 14:42:02 * @Last Modified by: ZhaoYing * @Last Modified time: 2026-03-16 15:10:17 */ import { type FC, useEffect, useState, useMemo } from 'react' import clsx from 'clsx' import { useTranslation } from 'react-i18next' import { useParams } from 'react-router-dom' import { Row, Col, Skeleton, Button, Divider, Tooltip, Flex } from 'antd' import RbCard from '@/components/RbCard/Card' import { getConversations, getConversationMessages, getConversationDetail, } from '@/api/memory' import { formatDateTime } from '@/utils/format' import Empty from '@/components/Empty' import ChatContent from '@/components/Chat/ChatContent' import type { ChatItem } from '@/components/Chat/types' import PageLoading from '@/components/Empty/PageLoading' /** A conversation session entry in the sidebar list. */ interface Conversation { title: string; id: string; } /** * AI-generated insight for a conversation, including key takeaways, * open questions, and an overall summary. */ interface Detail { theme: string; theme_intro: string; /** Core insight summary of the conversation. */ summary: string; /** Open questions or pitfalls identified during the conversation. */ question: string[]; /** Successful experiences / key takeaways extracted from the conversation. */ takeaways: string[]; /** Information quality score. */ info_score: number; } /** * WorkingDetail – Three-column working-memory view for a user's conversations. * * Left column (360px): scrollable list of conversation sessions. * Centre column (fluid): real-time chat message stream for the selected conversation, * with a refresh button and time-range indicator. * Right column (360px): AI-generated conversation insights – successful experiences * (takeaways), open questions / pitfalls, and a core summary. * * Route param `id` is the end-user ID. */ const WorkingDetail: FC = () => { const { t } = useTranslation() const { id } = useParams() const [loading, setLoading] = useState(false) const [data, setData] = useState([]) const [messagesLoading, setMessagesLoading] = useState(false) const [messages, setMessages] = useState([]) const [detailLoading, setDetailLoading] = useState(false) const [detail, setDetail] = useState(null) const [selected, setSelected] = useState(null) /* Fetch conversation list whenever the route user ID changes. */ useEffect(() => { if (!id) return getData() }, [id]) /** Load all conversations for the current user and auto-select the first one. */ const getData = () => { if (!id) return setLoading(true) setSelected(null) setDetail(null) setData([]) getConversations(id).then((res) => { const response = res as Conversation[] setData(response) setSelected(response[0] || null) }) .finally(() => { setLoading(false) }) } /* Load messages and AI insight whenever the selected conversation changes. */ useEffect(() => { if (!id || !selected || !selected.id) return getDetail(selected.id) }, [id, selected]) /** * Fetch both the chat messages and the AI-generated insight for a conversation. * Both requests run in parallel. */ const getDetail = (conversationId: string) => { if (!id || !conversationId) return setDetail(null) setMessages([]) setDetailLoading(true) setMessagesLoading(true) getConversationMessages(id, conversationId) .then(res => { setMessages(res as ChatItem[]) }) .finally(() => { setMessagesLoading(false) }) getConversationDetail(id, conversationId) .then(res => { setDetail(res as Detail) }) .finally(() => { setDetailLoading(false) }) } /** Derive a human-readable date range (e.g. "2024.01 - 2024.03") from message timestamps. */ const timeRange = useMemo(() => { const times = messages.filter(m => m.created_at).map(m => Number(m.created_at)) if (times.length === 0) return '' const minTime = Math.min(...times) const maxTime = Math.max(...times) return `${formatDateTime(minTime, 'YYYY.MM')} - ${formatDateTime(maxTime, 'YYYY.MM')}` }, [messages]) return ( <> {loading ? : data.length === 0 ? :( {data.map(item => ( setSelected(item)} >
{item.title}
))}
{selected && <>
{timeRange}
{t('workingDetail.conversationStream')} {messagesLoading ? : messages.length === 0 ? : ( formatDateTime(item.created_at)} /> ) }
{detailLoading ? : detail ? <> {detail.takeaways.length > 0 ? (
    {detail.takeaways.map(vo =>
  • {vo}
  • )}
) : } <>
{t('workingDetail.question')}
{detail.question.length > 0 ? (
    {detail.question.map(vo =>
  • {vo}
  • )}
) : } <>
{t('workingDetail.summary')}
{detail.summary ?
{detail.summary}
: } : }
}
) } ) } export default WorkingDetail