Allow text input when not final in text debug
This commit is contained in:
@@ -1027,6 +1027,27 @@ const BotIcon = ({className}: {className?: string}) => (
|
|||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Stable transcription log so the scroll container is not recreated on every render (avoids scroll jumping)
|
||||||
|
const TranscriptionLog: React.FC<{
|
||||||
|
scrollRef: React.RefObject<HTMLDivElement | null>;
|
||||||
|
messages: { role: 'user' | 'model'; text: string }[];
|
||||||
|
isLoading: boolean;
|
||||||
|
className?: string;
|
||||||
|
}> = ({ scrollRef, messages, isLoading, className = '' }) => (
|
||||||
|
<div ref={scrollRef} className={`overflow-y-auto overflow-x-hidden space-y-4 p-2 border border-white/5 rounded-md bg-black/20 min-h-0 custom-scrollbar ${className}`}>
|
||||||
|
{messages.length === 0 && <div className="text-center text-muted-foreground text-xs py-4">暂无转写记录</div>}
|
||||||
|
{messages.map((m, i) => (
|
||||||
|
<div key={i} className={`flex ${m.role === 'user' ? 'justify-end' : 'justify-start'}`}>
|
||||||
|
<div className={`max-w-[85%] rounded-lg px-3 py-2 text-sm ${m.role === 'user' ? 'bg-primary text-primary-foreground' : 'bg-card border border-white/10 shadow-sm text-foreground'}`}>
|
||||||
|
<span className="text-[10px] opacity-70 block mb-0.5 uppercase tracking-wider">{m.role === 'user' ? 'Me' : 'AI'}</span>
|
||||||
|
{m.text}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{isLoading && <div className="text-xs text-muted-foreground ml-2 animate-pulse">Thinking...</div>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
// --- Debug Drawer Component ---
|
// --- Debug Drawer Component ---
|
||||||
export const DebugDrawer: React.FC<{
|
export const DebugDrawer: React.FC<{
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@@ -1557,21 +1578,6 @@ export const DebugDrawer: React.FC<{
|
|||||||
setResolvedConfigView(JSON.stringify(localResolved, null, 2));
|
setResolvedConfigView(JSON.stringify(localResolved, null, 2));
|
||||||
}, [isOpen, assistant, voices, llmModels, asrModels]);
|
}, [isOpen, assistant, voices, llmModels, asrModels]);
|
||||||
|
|
||||||
const TranscriptionLog = ({ className = '' }: { className?: string }) => (
|
|
||||||
<div ref={scrollRef} className={`overflow-y-auto overflow-x-hidden space-y-4 p-2 border border-white/5 rounded-md bg-black/20 min-h-0 custom-scrollbar ${className}`}>
|
|
||||||
{messages.length === 0 && <div className="text-center text-muted-foreground text-xs py-4">暂无转写记录</div>}
|
|
||||||
{messages.map((m, i) => (
|
|
||||||
<div key={i} className={`flex ${m.role === 'user' ? 'justify-end' : 'justify-start'}`}>
|
|
||||||
<div className={`max-w-[85%] rounded-lg px-3 py-2 text-sm ${m.role === 'user' ? 'bg-primary text-primary-foreground' : 'bg-card border border-white/10 shadow-sm text-foreground'}`}>
|
|
||||||
<span className="text-[10px] opacity-70 block mb-0.5 uppercase tracking-wider">{m.role === 'user' ? 'Me' : 'AI'}</span>
|
|
||||||
{m.text}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
{isLoading && <div className="text-xs text-muted-foreground ml-2 animate-pulse">Thinking...</div>}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
const renderLocalVideo = (isSmall: boolean) => (
|
const renderLocalVideo = (isSmall: boolean) => (
|
||||||
<div className={`relative w-full h-full bg-black overflow-hidden ${isSmall ? 'rounded-lg border border-white/20 shadow-lg' : ''}`}>
|
<div className={`relative w-full h-full bg-black overflow-hidden ${isSmall ? 'rounded-lg border border-white/20 shadow-lg' : ''}`}>
|
||||||
<video ref={videoRef} autoPlay muted playsInline className="w-full h-full object-cover transform scale-x-[-1]" />
|
<video ref={videoRef} autoPlay muted playsInline className="w-full h-full object-cover transform scale-x-[-1]" />
|
||||||
@@ -1660,7 +1666,7 @@ export const DebugDrawer: React.FC<{
|
|||||||
textSessionStarted ? (
|
textSessionStarted ? (
|
||||||
<div className="flex-1 min-h-0 overflow-hidden animate-in fade-in flex flex-col">
|
<div className="flex-1 min-h-0 overflow-hidden animate-in fade-in flex flex-col">
|
||||||
<div className="h-[68vh] min-h-[420px] max-h-[68vh] w-full flex flex-col min-h-0 overflow-hidden">
|
<div className="h-[68vh] min-h-[420px] max-h-[68vh] w-full flex flex-col min-h-0 overflow-hidden">
|
||||||
<TranscriptionLog className="flex-1 min-h-0 h-full" />
|
<TranscriptionLog scrollRef={scrollRef} messages={messages} isLoading={isLoading} className="flex-1 min-h-0 h-full" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : wsStatus === 'connecting' ? (
|
) : wsStatus === 'connecting' ? (
|
||||||
@@ -1733,7 +1739,7 @@ export const DebugDrawer: React.FC<{
|
|||||||
<p className="text-sm relative z-10">通话中...</p>
|
<p className="text-sm relative z-10">通话中...</p>
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-xs font-medium text-muted-foreground px-1 mb-1 uppercase tracking-tight shrink-0">转写日志</h4>
|
<h4 className="text-xs font-medium text-muted-foreground px-1 mb-1 uppercase tracking-tight shrink-0">转写日志</h4>
|
||||||
<TranscriptionLog className="flex-1 min-h-0 overflow-y-auto" />
|
<TranscriptionLog scrollRef={scrollRef} messages={messages} isLoading={isLoading} className="flex-1 min-h-0 overflow-y-auto" />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col h-full min-h-0 space-y-2 animate-in fade-in">
|
<div className="flex flex-col h-full min-h-0 space-y-2 animate-in fade-in">
|
||||||
@@ -1752,7 +1758,7 @@ export const DebugDrawer: React.FC<{
|
|||||||
<button className="absolute top-2 right-2 z-20 h-8 w-8 rounded-full bg-black/50 backdrop-blur flex items-center justify-center text-white border border-white/10 hover:bg-primary/80" onClick={() => setIsSwapped(!isSwapped)}><ArrowLeftRight className="h-3.5 w-3.5" /></button>
|
<button className="absolute top-2 right-2 z-20 h-8 w-8 rounded-full bg-black/50 backdrop-blur flex items-center justify-center text-white border border-white/10 hover:bg-primary/80" onClick={() => setIsSwapped(!isSwapped)}><ArrowLeftRight className="h-3.5 w-3.5" /></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<TranscriptionLog className="flex-1 min-h-0 overflow-y-auto" />
|
<TranscriptionLog scrollRef={scrollRef} messages={messages} isLoading={isLoading} className="flex-1 min-h-0 overflow-y-auto" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<Button variant="destructive" size="sm" className="w-full h-10 font-bold" onClick={handleHangup}>
|
<Button variant="destructive" size="sm" className="w-full h-10 font-bold" onClick={handleHangup}>
|
||||||
@@ -1780,14 +1786,14 @@ export const DebugDrawer: React.FC<{
|
|||||||
onChange={e => setInputText(e.target.value)}
|
onChange={e => setInputText(e.target.value)}
|
||||||
placeholder={mode === 'text' && !textSessionStarted ? "请先发起呼叫后输入消息..." : (mode === 'text' ? "输入消息..." : "输入文本模拟交互...")}
|
placeholder={mode === 'text' && !textSessionStarted ? "请先发起呼叫后输入消息..." : (mode === 'text' ? "输入消息..." : "输入文本模拟交互...")}
|
||||||
onKeyDown={e => e.key === 'Enter' && handleSend()}
|
onKeyDown={e => e.key === 'Enter' && handleSend()}
|
||||||
disabled={isLoading || (mode === 'text' ? !textSessionStarted : callStatus !== 'active')}
|
disabled={mode === 'text' ? !textSessionStarted : (isLoading || callStatus !== 'active')}
|
||||||
className="flex-1 min-w-0"
|
className="flex-1 min-w-0"
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
size="icon"
|
size="icon"
|
||||||
className="h-9 w-9 shrink-0"
|
className="h-9 w-9 shrink-0"
|
||||||
onClick={handleSend}
|
onClick={handleSend}
|
||||||
disabled={isLoading || (mode === 'text' ? !textSessionStarted : callStatus !== 'active')}
|
disabled={mode === 'text' ? !textSessionStarted : (isLoading || callStatus !== 'active')}
|
||||||
>
|
>
|
||||||
<Send className="h-4 w-4" />
|
<Send className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
Reference in New Issue
Block a user