Files
AI-VideoAssistant/web/components/debug-transcript/MessageText.tsx
2026-03-13 07:11:48 +08:00

68 lines
2.1 KiB
TypeScript

import React from 'react';
import { cn } from '@/lib/utils';
import { Badge } from '@/components/UI';
import type { DebugTranscriptTextRow } from './types';
const roleLabelMap: Record<DebugTranscriptTextRow['role'], string> = {
user: 'Me',
assistant: 'AI',
notice: 'Debug',
};
const MessageText: React.FC<{
row: DebugTranscriptTextRow;
}> = ({ row }) => {
if (row.role === 'notice') {
return (
<div className="flex justify-start">
<div className="max-w-full rounded-md border border-white/10 bg-black/25 px-3 py-2 text-[11px] text-muted-foreground">
<div className="mb-1 flex items-center gap-2">
<span className="uppercase tracking-[0.14em] opacity-70">{roleLabelMap[row.role]}</span>
</div>
<div className="whitespace-pre-wrap break-words">{row.text}</div>
</div>
</div>
);
}
const isUser = row.role === 'user';
return (
<div className={cn('flex', isUser ? 'justify-end' : 'justify-start')}>
<div
className={cn(
'max-w-[85%] rounded-lg px-3 py-2 text-sm',
isUser
? 'bg-primary text-primary-foreground'
: 'bg-card border border-white/10 shadow-sm text-foreground'
)}
>
<div className="mb-1 flex flex-wrap items-center gap-1.5">
<span className="text-[10px] uppercase tracking-wider opacity-70">
{roleLabelMap[row.role]}
</span>
{row.role === 'assistant' &&
typeof row.ttfbMs === 'number' &&
Number.isFinite(row.ttfbMs) && (
<Badge
variant="outline"
className="border-cyan-300/40 bg-cyan-500/10 px-1.5 py-0.5 text-[10px] text-cyan-200"
>
TTFB {Math.round(row.ttfbMs)}ms
</Badge>
)}
{row.role === 'assistant' && row.isStreaming && (
<span className="inline-flex h-2 w-2 animate-pulse rounded-full bg-primary/80" />
)}
</div>
<div className="whitespace-pre-wrap break-words">{row.text}</div>
</div>
</div>
);
};
export default React.memo(MessageText);