// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: BSD 2-Clause License import { useEffect, useRef } from "react"; import { useState } from "react"; interface Props { websocket: WebSocket | null; } interface IncomingMessage { text: string; actor: string; message_id: string; } interface AugmentedMessage extends IncomingMessage { timestamp: Date; } export function Transcripts(props: Props) { const [transcripts, setTranscripts] = useState([]); const bottomRef = useRef(null); // Clear transcripts when a new WebSocket connection is established useEffect(() => { if (props.websocket) { console.log("New WebSocket connection detected, clearing old transcripts"); setTranscripts([]); } }, [props.websocket]); useEffect(() => { function onMessage(event: MessageEvent) { const message = JSON.parse(event.data) as IncomingMessage; console.log(event.data, message); setTranscripts((prev) => { const existingMessage = prev.find( (t) => t.actor === message.actor && t.message_id === message.message_id ); if (existingMessage) { existingMessage.text = message.text; } else { prev.push({ ...message, timestamp: new Date() }); } return [...prev]; }); } props.websocket?.addEventListener("message", onMessage); return () => { props.websocket?.removeEventListener("message", onMessage); }; }, [props.websocket]); useEffect(() => { // Scroll to the bottom of the transcripts every time a new transcript is added bottomRef.current?.scrollIntoView(); }, [transcripts]); const filteredTranscripts = transcripts.filter((transcript) => { const actor = transcript.actor?.toLowerCase()?.trim(); const isSystem = actor === "system"; return !isSystem; }); return filteredTranscripts.map((transcript) => (
{transcript.timestamp.toTimeString().slice(0, 8)}
{transcript.actor}
:
{transcript.text}
)); }