/* * @Author: ZhaoYing * @Date: 2026-02-03 18:32:23 * @Last Modified by: ZhaoYing * @Last Modified time: 2026-03-17 17:15:14 */ import { type FC, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import { useParams } from 'react-router-dom' import { Skeleton, Space, Tooltip, Image } from 'antd'; import RbCard from '@/components/RbCard/Card' import { getPerceptualLastVisual, getPerceptualLastListen, getPerceptualLastText, } from '@/api/memory' /** * Perceptual last info item structure * @property {string} id - Item ID * @property {string} file_name - File name * @property {string} file_ext - File extension * @property {string} file_path - File path URL * @property {number} storage_type - Storage type * @property {string} summary - Content summary * @property {string[]} keywords - Keywords * @property {string} topic - Topic * @property {string} domain - Domain * @property {number | string} created_time - Creation time * @property {string[]} scene - Scene information * @property {number} speaker_count - Speaker count * @property {number} section_count - Section count */ interface PerceptualLastInfoItem { id: string; file_name: string; file_ext: string; file_path: string; storage_type: number; summary: string; keywords: string[]; topic: string; domain: string; created_time: number | string; scene: string[] speaker_count: number; section_count: number; } /** * Field keys for different perceptual types */ const KEYS = { last_visual: ['summary', 'keywords', 'topic', 'domain', 'scene'], last_listen: ['summary', 'keywords', 'topic', 'domain', 'speaker_count'], last_text: ['summary', 'keywords', 'topic', 'domain', 'section_count'], } /** * PerceptualLastInfo Component * Displays the last perceptual memory (visual, audio, or text) * Shows file preview and metadata based on perceptual type */ const PerceptualLastInfo: FC<{ type: 'last_visual' | 'last_listen' | 'last_text' }> = ({ type }) => { const { t } = useTranslation() const { id } = useParams() const [loading, setLoading] = useState(false) const [data, setData] = useState({} as PerceptualLastInfoItem) useEffect(() => { if (!id) return getData() }, [id, type]) const getData = () => { if (!id || !type) return setLoading(true) const request = type === 'last_visual' ? getPerceptualLastVisual(id) : type === 'last_listen' ? getPerceptualLastListen(id) : getPerceptualLastText(id) request.then((res) => { const response = res as PerceptualLastInfoItem setData(response) setLoading(false) }) .finally(() => { setLoading(false) }) } const handleDownload = async () => { if (!data.file_path) return if (data.file_path.includes('.redbearai.') || data.file_path.includes('.memorybear.')) { try { const res = await fetch(data.file_path) const blob = await res.blob() const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = data.file_name || 'download' a.click() URL.revokeObjectURL(url) } catch { window.open(data.file_path, '_blank') } } else { window.open(data.file_path, '_blank') } } return ( {loading ? :
{data.file_path ? ( type === 'last_visual' ? ( /\.(mp4|webm|ogg|mov)$/i.test(data.file_name) ? ( ) : /\.(jpg|jpeg|png|gif|webp|svg)$/i.test(data.file_name) ? ( {data.file_name} // {data.file_name} ) : (
{data.file_name}
) ) : type === 'last_listen' && /\.(mp3|wav|ogg|m4a|aac)$/i.test(data.file_name) ? ( ) : (
{data.file_name}
) ) : (
{t('empty.tableEmpty')}
)}
{KEYS[type].map(key => { const value = (data as any)[key] return (
{t(`perceptualDetail.${key}`)}
{key === 'summary' ? (
{typeof value === 'string' ? value : Array.isArray(value) ? value.join('、') : '-'}
) :
{typeof value === 'string' ? value : Array.isArray(value) ? value.join('、') : '-'}
}
) })}
}
) } export default PerceptualLastInfo