Compare commits
2 Commits
e4ccec6cc1
...
47293ac46d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47293ac46d | ||
|
|
373be4eb97 |
@@ -219,14 +219,14 @@ export const Drawer: React.FC<DrawerProps> = ({ isOpen, onClose, title, classNam
|
|||||||
<div className="fixed inset-0 bg-black/60 backdrop-blur-sm transition-opacity" onClick={onClose} />
|
<div className="fixed inset-0 bg-black/60 backdrop-blur-sm transition-opacity" onClick={onClose} />
|
||||||
|
|
||||||
{/* Drawer Content */}
|
{/* Drawer Content */}
|
||||||
<div className={`relative ml-auto flex h-full w-full flex-col overflow-y-auto bg-background/95 border-l border-white/10 p-6 shadow-2xl animate-in slide-in-from-right ${className || 'max-w-md sm:max-w-lg'}`}>
|
<div className={`relative ml-auto flex h-full w-full flex-col bg-background/95 border-l border-white/10 p-6 shadow-2xl animate-in slide-in-from-right ${className || 'max-w-md sm:max-w-lg'}`}>
|
||||||
<div className="flex items-center justify-between mb-4">
|
<div className="flex items-center justify-between mb-4 shrink-0">
|
||||||
<h2 className="text-lg font-semibold text-foreground">{title}</h2>
|
<h2 className="text-lg font-semibold text-foreground">{title}</h2>
|
||||||
<Button variant="ghost" size="icon" onClick={onClose}>
|
<Button variant="ghost" size="icon" onClick={onClose}>
|
||||||
<X className="h-4 w-4" />
|
<X className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1">
|
<div className="flex-1 min-h-0 overflow-y-auto">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2315,7 +2315,6 @@ const TranscriptionLog: React.FC<{
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
{isLoading && <div className="text-xs text-muted-foreground ml-2 animate-pulse">Thinking...</div>}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -2380,6 +2379,7 @@ export const DebugDrawer: React.FC<{
|
|||||||
const [inputText, setInputText] = useState('');
|
const [inputText, setInputText] = useState('');
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [callStatus, setCallStatus] = useState<'idle' | 'calling' | 'active'>('idle');
|
const [callStatus, setCallStatus] = useState<'idle' | 'calling' | 'active'>('idle');
|
||||||
|
const [agentState, setAgentState] = useState<'listening' | 'thinking' | 'speaking'>('listening');
|
||||||
const [textPromptDialog, setTextPromptDialog] = useState<DebugTextPromptDialogState>({
|
const [textPromptDialog, setTextPromptDialog] = useState<DebugTextPromptDialogState>({
|
||||||
open: false,
|
open: false,
|
||||||
message: '',
|
message: '',
|
||||||
@@ -2562,6 +2562,7 @@ export const DebugDrawer: React.FC<{
|
|||||||
clearResponseTracking();
|
clearResponseTracking();
|
||||||
setMessages([]);
|
setMessages([]);
|
||||||
setCallStatus('idle');
|
setCallStatus('idle');
|
||||||
|
setAgentState('listening');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setMode('text');
|
setMode('text');
|
||||||
@@ -2585,6 +2586,7 @@ export const DebugDrawer: React.FC<{
|
|||||||
setSettingsDrawerOpen(false);
|
setSettingsDrawerOpen(false);
|
||||||
setIsSwapped(false);
|
setIsSwapped(false);
|
||||||
setCallStatus('idle');
|
setCallStatus('idle');
|
||||||
|
setAgentState('listening');
|
||||||
}
|
}
|
||||||
}, [isOpen, assistant, mode]);
|
}, [isOpen, assistant, mode]);
|
||||||
|
|
||||||
@@ -3110,6 +3112,7 @@ export const DebugDrawer: React.FC<{
|
|||||||
console.error(e);
|
console.error(e);
|
||||||
stopVoiceCapture();
|
stopVoiceCapture();
|
||||||
setCallStatus('idle');
|
setCallStatus('idle');
|
||||||
|
setAgentState('listening');
|
||||||
const err = e as Error & { __dynamicVariables?: boolean };
|
const err = e as Error & { __dynamicVariables?: boolean };
|
||||||
if (err.__dynamicVariables) {
|
if (err.__dynamicVariables) {
|
||||||
setWsStatus('disconnected');
|
setWsStatus('disconnected');
|
||||||
@@ -3135,6 +3138,7 @@ export const DebugDrawer: React.FC<{
|
|||||||
stopMedia();
|
stopMedia();
|
||||||
closeWs();
|
closeWs();
|
||||||
setCallStatus('idle');
|
setCallStatus('idle');
|
||||||
|
setAgentState('listening');
|
||||||
clearResponseTracking();
|
clearResponseTracking();
|
||||||
setMessages([]);
|
setMessages([]);
|
||||||
setTextPromptDialog({ open: false, message: '', promptType: 'text' });
|
setTextPromptDialog({ open: false, message: '', promptType: 'text' });
|
||||||
@@ -3500,6 +3504,7 @@ export const DebugDrawer: React.FC<{
|
|||||||
setChoicePromptDialog({ open: false, question: '', options: [] });
|
setChoicePromptDialog({ open: false, question: '', options: [] });
|
||||||
setTextSessionStarted(false);
|
setTextSessionStarted(false);
|
||||||
stopPlaybackImmediately();
|
stopPlaybackImmediately();
|
||||||
|
setAgentState('waiting');
|
||||||
if (isOpen) setWsStatus('disconnected');
|
if (isOpen) setWsStatus('disconnected');
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3580,6 +3585,12 @@ export const DebugDrawer: React.FC<{
|
|||||||
if (type === 'output.audio.start') {
|
if (type === 'output.audio.start') {
|
||||||
// New utterance audio starts: cancel old queued/playing audio to avoid overlap.
|
// New utterance audio starts: cancel old queued/playing audio to avoid overlap.
|
||||||
stopPlaybackImmediately();
|
stopPlaybackImmediately();
|
||||||
|
setAgentState('speaking');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'output.audio.end') {
|
||||||
|
setAgentState('listening');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3595,6 +3606,7 @@ export const DebugDrawer: React.FC<{
|
|||||||
assistantDraftIndexRef.current = null;
|
assistantDraftIndexRef.current = null;
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
stopPlaybackImmediately();
|
stopPlaybackImmediately();
|
||||||
|
setAgentState('waiting');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3878,6 +3890,7 @@ export const DebugDrawer: React.FC<{
|
|||||||
if (type === 'session.started') {
|
if (type === 'session.started') {
|
||||||
wsReadyRef.current = true;
|
wsReadyRef.current = true;
|
||||||
setWsStatus('ready');
|
setWsStatus('ready');
|
||||||
|
setAgentState('waiting');
|
||||||
pendingResolveRef.current?.();
|
pendingResolveRef.current?.();
|
||||||
pendingResolveRef.current = null;
|
pendingResolveRef.current = null;
|
||||||
pendingRejectRef.current = null;
|
pendingRejectRef.current = null;
|
||||||
@@ -3899,11 +3912,13 @@ export const DebugDrawer: React.FC<{
|
|||||||
|
|
||||||
if (type === 'input.speech_started') {
|
if (type === 'input.speech_started') {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
setAgentState('listening');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'input.speech_stopped') {
|
if (type === 'input.speech_stopped') {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
|
setAgentState('thinking');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4500,13 +4515,33 @@ export const DebugDrawer: React.FC<{
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-center z-10">
|
<div className="text-center z-10">
|
||||||
<h3 className="text-xl font-bold text-white mb-2 tracking-tight">通话进行中</h3>
|
<h3 className="text-xl font-bold text-white mb-2 tracking-tight">
|
||||||
|
{agentState === 'thinking' ? '思考中...' :
|
||||||
|
agentState === 'speaking' ? '正在回复...' :
|
||||||
|
'正在倾听...'}
|
||||||
|
</h3>
|
||||||
<div className="flex items-center justify-center gap-2">
|
<div className="flex items-center justify-center gap-2">
|
||||||
<span className="relative flex h-2.5 w-2.5">
|
<span className="relative flex h-2.5 w-2.5">
|
||||||
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
|
<span className={`animate-ping absolute inline-flex h-full w-full rounded-full opacity-75 ${
|
||||||
<span className="relative inline-flex rounded-full h-2.5 w-2.5 bg-green-500"></span>
|
agentState === 'thinking' ? 'bg-yellow-400' :
|
||||||
|
agentState === 'speaking' ? 'bg-green-400' :
|
||||||
|
'bg-blue-400'
|
||||||
|
}`}></span>
|
||||||
|
<span className={`relative inline-flex rounded-full h-2.5 w-2.5 ${
|
||||||
|
agentState === 'thinking' ? 'bg-yellow-500' :
|
||||||
|
agentState === 'speaking' ? 'bg-green-500' :
|
||||||
|
'bg-blue-500'
|
||||||
|
}`}></span>
|
||||||
</span>
|
</span>
|
||||||
<p className="text-sm font-medium text-green-400">已连接</p>
|
<p className={`text-sm font-medium ${
|
||||||
|
agentState === 'thinking' ? 'text-yellow-400' :
|
||||||
|
agentState === 'speaking' ? 'text-green-400' :
|
||||||
|
'text-blue-400'
|
||||||
|
}`}>
|
||||||
|
{agentState === 'thinking' ? 'Thinking' :
|
||||||
|
agentState === 'speaking' ? 'Speaking' :
|
||||||
|
'Listening'}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user