/** * RealtimeTranscript 实时转写展示组件 * * 在录音阶段显示讯飞/阿里实时返回的识别文字。 */ import React, { useEffect, useRef } from 'react' import type { RealtimeState, RealtimeSegment } from '../hooks/useRealtimeTranscribe' import { useTranslation } from '../i18n' interface Props { /** 实时转写状态 */ rtState: RealtimeState /** 是否可见 */ visible: boolean } /** 单个说话人分段 */ function SegmentBubble({ seg, isLatest }: { seg: RealtimeSegment; isLatest: boolean }) { const isVet = seg.speaker === '兽医' return (
{seg.speaker || '...'}
{seg.text}
) } /** 纯文本流式展示(说话人未分离时) */ function StreamingText({ text, connected }: { text: string; connected: boolean }) { const scrollRef = useRef(null) useEffect(() => { if (scrollRef.current) { scrollRef.current.scrollTop = scrollRef.current.scrollHeight } }, [text]) if (!text && !connected) return null if (!text && connected) { return (
正在聆听...
) } return (
{text} {connected && ( )}
) } export default function RealtimeTranscript({ rtState, visible }: Props) { const { t } = useTranslation() const { fullText, segments, connected, finalized, error, engine } = rtState if (!visible) return null const hasSegments = segments && segments.length > 0 const hasText = fullText && fullText.length > 0 return (
{/* 头部 */}
{finalized ? '转写完成' : connected ? '实时转写中' : '等待连接...'} {engine && ( {engine.replace('xunfei_', '讯飞·')} )}
{error && ( {error} )}
{/* 错误提示 */} {error && !hasText && (

{error}

{t('consultation.realtimeTranscribeError')}

)} {/* 分段对话模式(说话人已分离) */} {hasSegments ? (
{segments.map((seg, i) => ( ))} {connected && !finalized && (
)}
) : ( /* 流式文本模式 */ )} {/* 空状态 */} {!hasText && !hasSegments && !connected && !error && (
开始说话后,文字将实时显示
)}
) }