Improve text debug flow
This commit is contained in:
@@ -1041,6 +1041,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 [textSessionStarted, setTextSessionStarted] = useState(false);
|
||||||
const [wsStatus, setWsStatus] = useState<'disconnected' | 'connecting' | 'ready' | 'error'>('disconnected');
|
const [wsStatus, setWsStatus] = useState<'disconnected' | 'connecting' | 'ready' | 'error'>('disconnected');
|
||||||
const [wsError, setWsError] = useState('');
|
const [wsError, setWsError] = useState('');
|
||||||
const [resolvedConfigOpen, setResolvedConfigOpen] = useState(false);
|
const [resolvedConfigOpen, setResolvedConfigOpen] = useState(false);
|
||||||
@@ -1074,7 +1075,8 @@ export const DebugDrawer: React.FC<{
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
if (mode === 'text') {
|
if (mode === 'text') {
|
||||||
setMessages([{ role: 'model', text: assistant.opener || "Hello!" }]);
|
setMessages([]);
|
||||||
|
setTextSessionStarted(false);
|
||||||
} else {
|
} else {
|
||||||
setMessages([]);
|
setMessages([]);
|
||||||
setCallStatus('idle');
|
setCallStatus('idle');
|
||||||
@@ -1240,6 +1242,21 @@ export const DebugDrawer: React.FC<{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleTextLaunch = async () => {
|
||||||
|
try {
|
||||||
|
setWsError('');
|
||||||
|
if (textTtsEnabled) await ensureAudioContext();
|
||||||
|
await ensureWsSession();
|
||||||
|
setTextSessionStarted(true);
|
||||||
|
setMessages((prev) => (prev.length > 0 ? prev : [{ role: 'model', text: assistant.opener || 'Hello!' }]));
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
setWsStatus('error');
|
||||||
|
setWsError((e as Error)?.message || 'Failed to connect');
|
||||||
|
setTextSessionStarted(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const buildLocalResolvedRuntime = () => {
|
const buildLocalResolvedRuntime = () => {
|
||||||
const warnings: string[] = [];
|
const warnings: string[] = [];
|
||||||
const services: Record<string, any> = {};
|
const services: Record<string, any> = {};
|
||||||
@@ -1371,6 +1388,7 @@ export const DebugDrawer: React.FC<{
|
|||||||
pendingResolveRef.current = null;
|
pendingResolveRef.current = null;
|
||||||
pendingRejectRef.current = null;
|
pendingRejectRef.current = null;
|
||||||
assistantDraftIndexRef.current = null;
|
assistantDraftIndexRef.current = null;
|
||||||
|
setTextSessionStarted(false);
|
||||||
clearPlaybackQueue();
|
clearPlaybackQueue();
|
||||||
if (isOpen) setWsStatus('disconnected');
|
if (isOpen) setWsStatus('disconnected');
|
||||||
};
|
};
|
||||||
@@ -1520,6 +1538,7 @@ export const DebugDrawer: React.FC<{
|
|||||||
|
|
||||||
ws.onclose = () => {
|
ws.onclose = () => {
|
||||||
wsReadyRef.current = false;
|
wsReadyRef.current = false;
|
||||||
|
setTextSessionStarted(false);
|
||||||
clearPlaybackQueue();
|
clearPlaybackQueue();
|
||||||
if (wsStatus !== 'error') setWsStatus('disconnected');
|
if (wsStatus !== 'error') setWsStatus('disconnected');
|
||||||
};
|
};
|
||||||
@@ -1586,15 +1605,48 @@ export const DebugDrawer: React.FC<{
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="shrink-0 mb-3 rounded-md border border-white/10 bg-black/20">
|
||||||
|
<button
|
||||||
|
className="w-full px-3 py-2 text-left text-xs text-muted-foreground hover:text-foreground flex items-center justify-between"
|
||||||
|
onClick={() => setResolvedConfigOpen((v) => !v)}
|
||||||
|
>
|
||||||
|
<span>Resolved Runtime Config (read-only)</span>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className="text-[10px] uppercase tracking-wider opacity-70">
|
||||||
|
{resolvedConfigOpen ? 'Collapse' : 'Expand'}
|
||||||
|
</span>
|
||||||
|
<ChevronDown className={`h-3.5 w-3.5 transition-transform ${resolvedConfigOpen ? 'rotate-180' : ''}`} />
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
{resolvedConfigOpen && (
|
||||||
|
<pre className="px-3 pb-3 text-[11px] leading-5 text-cyan-100/90 whitespace-pre-wrap break-all max-h-52 overflow-auto">
|
||||||
|
{resolvedConfigView || 'Connect to load resolved config...'}
|
||||||
|
</pre>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex-1 overflow-hidden flex flex-col min-h-0 mb-4">
|
<div className="flex-1 overflow-hidden flex flex-col min-h-0 mb-4">
|
||||||
{mode === 'text' ? (
|
{mode === 'text' ? (
|
||||||
<div className="flex flex-col gap-2 h-full min-h-0">
|
textSessionStarted ? (
|
||||||
<div className="shrink-0 rounded-md border border-white/10 bg-white/5 p-2 grid grid-cols-1 md:grid-cols-3 gap-2">
|
<div className="flex flex-col gap-2 h-full min-h-0">
|
||||||
|
<div className="shrink-0 rounded-md border border-white/10 bg-white/5 p-2 flex items-center gap-2">
|
||||||
|
<Badge variant="outline" className="text-xs">
|
||||||
|
WS: {wsStatus}
|
||||||
|
</Badge>
|
||||||
|
<Button size="sm" variant="ghost" onClick={closeWs}>
|
||||||
|
Disconnect
|
||||||
|
</Button>
|
||||||
|
{wsError && <span className="text-xs text-red-400 truncate">{wsError}</span>}
|
||||||
|
</div>
|
||||||
|
<TranscriptionLog />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex-1 flex flex-col items-center justify-center space-y-6 border border-white/5 rounded-xl bg-black/20 animate-in fade-in zoom-in-95 px-6">
|
||||||
|
<div className="w-full max-w-xl space-y-3">
|
||||||
|
<label className="text-[10px] text-muted-foreground font-black tracking-widest uppercase block">WebSocket Endpoint</label>
|
||||||
<Input value={wsUrl} onChange={(e) => setWsUrl(e.target.value)} placeholder="ws://localhost:8000/ws" />
|
<Input value={wsUrl} onChange={(e) => setWsUrl(e.target.value)} placeholder="ws://localhost:8000/ws" />
|
||||||
<div className="md:col-span-2 flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Badge variant="outline" className="text-xs">
|
<Badge variant="outline" className="text-xs">WS: {wsStatus}</Badge>
|
||||||
WS: {wsStatus}
|
|
||||||
</Badge>
|
|
||||||
<label className="inline-flex items-center gap-1 text-xs text-muted-foreground px-2 py-1 rounded border border-white/10">
|
<label className="inline-flex items-center gap-1 text-xs text-muted-foreground px-2 py-1 rounded border border-white/10">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -1604,31 +1656,18 @@ export const DebugDrawer: React.FC<{
|
|||||||
/>
|
/>
|
||||||
TTS
|
TTS
|
||||||
</label>
|
</label>
|
||||||
<Button size="sm" variant="secondary" onClick={() => ensureWsSession()} disabled={wsStatus === 'connecting'}>
|
|
||||||
Connect
|
|
||||||
</Button>
|
|
||||||
<Button size="sm" variant="ghost" onClick={closeWs}>
|
|
||||||
Disconnect
|
|
||||||
</Button>
|
|
||||||
{wsError && <span className="text-xs text-red-400 truncate">{wsError}</span>}
|
{wsError && <span className="text-xs text-red-400 truncate">{wsError}</span>}
|
||||||
</div>
|
</div>
|
||||||
<div className="md:col-span-3 rounded-md border border-white/10 bg-black/20">
|
|
||||||
<button
|
|
||||||
className="w-full px-3 py-2 text-left text-xs text-muted-foreground hover:text-foreground flex items-center justify-between"
|
|
||||||
onClick={() => setResolvedConfigOpen((v) => !v)}
|
|
||||||
>
|
|
||||||
<span>View Resolved Runtime Config (read-only)</span>
|
|
||||||
<ChevronDown className={`h-3.5 w-3.5 transition-transform ${resolvedConfigOpen ? 'rotate-180' : ''}`} />
|
|
||||||
</button>
|
|
||||||
{resolvedConfigOpen && (
|
|
||||||
<pre className="px-3 pb-3 text-[11px] leading-5 text-cyan-100/90 whitespace-pre-wrap break-all max-h-52 overflow-auto">
|
|
||||||
{resolvedConfigView || 'Connect to load resolved config...'}
|
|
||||||
</pre>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<TranscriptionLog />
|
<Button
|
||||||
</div>
|
onClick={handleTextLaunch}
|
||||||
|
disabled={wsStatus === 'connecting'}
|
||||||
|
className="w-56 h-12 rounded-full bg-green-500 hover:bg-green-600 shadow-[0_0_20px_rgba(34,197,94,0.4)] text-base font-bold"
|
||||||
|
>
|
||||||
|
<PhoneCall className="mr-2 h-5 w-5" /> 启动文本测试
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
) : callStatus === 'idle' ? (
|
) : callStatus === 'idle' ? (
|
||||||
<div className="flex-1 flex flex-col items-center justify-center space-y-6 border border-white/5 rounded-xl bg-black/20 animate-in fade-in zoom-in-95">
|
<div className="flex-1 flex flex-col items-center justify-center space-y-6 border border-white/5 rounded-xl bg-black/20 animate-in fade-in zoom-in-95">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
@@ -1696,12 +1735,14 @@ export const DebugDrawer: React.FC<{
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="shrink-0 space-y-2">
|
{(mode !== 'text' || textSessionStarted) && (
|
||||||
<div className="flex space-x-2">
|
<div className="shrink-0 space-y-2">
|
||||||
<Input value={inputText} onChange={e => setInputText(e.target.value)} placeholder={mode === 'text' ? "输入消息..." : "输入文本模拟交互..."} onKeyDown={e => e.key === 'Enter' && handleSend()} disabled={isLoading || (mode !== 'text' && callStatus !== 'active')} className="flex-1" />
|
<div className="flex space-x-2">
|
||||||
<Button size="icon" onClick={handleSend} disabled={isLoading || (mode !== 'text' && callStatus !== 'active')}><Send className="h-4 w-4" /></Button>
|
<Input value={inputText} onChange={e => setInputText(e.target.value)} placeholder={mode === 'text' ? "输入消息..." : "输入文本模拟交互..."} onKeyDown={e => e.key === 'Enter' && handleSend()} disabled={isLoading || (mode === 'text' ? !textSessionStarted : callStatus !== 'active')} className="flex-1" />
|
||||||
</div>
|
<Button size="icon" onClick={handleSend} disabled={isLoading || (mode === 'text' ? !textSessionStarted : callStatus !== 'active')}><Send className="h-4 w-4" /></Button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user