diff --git a/src/components/playground/PhoneSimulator.tsx b/src/components/playground/PhoneSimulator.tsx index a8ed4f0..cf81601 100644 --- a/src/components/playground/PhoneSimulator.tsx +++ b/src/components/playground/PhoneSimulator.tsx @@ -715,7 +715,7 @@ export function PhoneSimulator({ > - Call Agent + 呼叫智能体
@@ -725,7 +725,7 @@ export function PhoneSimulator({ > - {currentVoiceId === "BV001_streaming" ? "Female Voice" : "Male Voice"} + {currentVoiceId === "BV001_streaming" ? "女性声音" : "男性声音"} {showVoiceMenu && ( @@ -745,7 +745,7 @@ export function PhoneSimulator({ : "text-white" }`} > - Female Voice + 女性声音 {currentVoiceId === "BV001_streaming" && }
)} + + {/* Fallback: Show End Call Button when in push-to-talk mode but no agent/audio */} + {phoneMode === "normal" && + isPushToTalkMode && + !voiceAssistant.agent && ( +
+ +
+ )} ) diff --git a/src/components/playground/PlaygroundTile.tsx b/src/components/playground/PlaygroundTile.tsx index e21edcc..9b3b0d9 100644 --- a/src/components/playground/PlaygroundTile.tsx +++ b/src/components/playground/PlaygroundTile.tsx @@ -100,7 +100,18 @@ export const PlaygroundTabbedTile: React.FC = ({ padding: `${contentPadding * 4}px`, }} > - {tabs[activeTab].content} + {tabs.map((tab, index) => ( +
+ {tab.content} +
+ ))} ); diff --git a/src/transcriptions/TranscriptionTile.tsx b/src/transcriptions/TranscriptionTile.tsx index f2129d3..98f0288 100644 --- a/src/transcriptions/TranscriptionTile.tsx +++ b/src/transcriptions/TranscriptionTile.tsx @@ -11,7 +11,7 @@ import { Track, TranscriptionSegment, } from "livekit-client"; -import { useEffect, useState } from "react"; +import { useEffect, useState, useRef } from "react"; export function TranscriptionTile({ agentAudioTrack, @@ -30,39 +30,51 @@ export function TranscriptionTile({ participant: localParticipant.localParticipant, }); - const [transcripts, setTranscripts] = useState>( - new Map(), - ); const [messages, setMessages] = useState([]); const { chatMessages, send: sendChat } = useChat(); + const transcriptMapRef = useRef>(new Map()); - // store transcripts + // Build messages from segments and chat - always rebuild from current state useEffect(() => { + const transcriptMap = transcriptMapRef.current; + + // Process agent segments - update existing or add new if (agentAudioTrack) { - agentMessages.segments.forEach((s) => - transcripts.set( + agentMessages.segments.forEach((s) => { + const existing = transcriptMap.get(s.id); + transcriptMap.set( s.id, segmentToChatMessage( s, - transcripts.get(s.id), + existing, agentAudioTrack.participant, ), - ), - ); + ); + }); } - localMessages.segments.forEach((s) => - transcripts.set( + // Process local segments - update existing or add new + localMessages.segments.forEach((s) => { + const existing = transcriptMap.get(s.id); + transcriptMap.set( s.id, segmentToChatMessage( s, - transcripts.get(s.id), + existing, localParticipant.localParticipant, ), - ), - ); + ); + }); - const allMessages = Array.from(transcripts.values()); + // Build all messages + const allMessages: ChatMessageType[] = []; + + // Add all transcript messages + transcriptMap.forEach((msg) => { + allMessages.push(msg); + }); + + // Add chat messages for (const msg of chatMessages) { const isAgent = agentAudioTrack ? msg.from?.identity === agentAudioTrack.participant?.identity @@ -79,6 +91,7 @@ export function TranscriptionTile({ name = "Unknown"; } } + allMessages.push({ name, message: msg.message, @@ -86,10 +99,11 @@ export function TranscriptionTile({ isSelf: isSelf, }); } + + // Sort by timestamp allMessages.sort((a, b) => a.timestamp - b.timestamp); setMessages(allMessages); }, [ - transcripts, chatMessages, localParticipant.localParticipant, agentAudioTrack?.participant,