Spaces:
Running
Running
File size: 3,224 Bytes
575834b 1f5b714 bacb8f4 1f5b714 bacb8f4 1f5b714 bacb8f4 1f5b714 bacb8f4 1f5b714 bacb8f4 2ec0e37 bacb8f4 2ec0e37 bacb8f4 2ec0e37 bacb8f4 1f5b714 bacb8f4 1f5b714 bacb8f4 b86420d bacb8f4 b86420d 1f5b714 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
import type { ChatMessage as ChatMessageType } from '@/types/rag';
import { cn } from '@/lib/utils';
import { User, Bot, FilePlus, Edit, RefreshCw } from 'lucide-react';
import { SourceList } from './SourceList';
import { Button } from './ui/button';
import { useState } from 'react';
interface ChatMessageProps {
message: ChatMessageType;
onSourceClick: (path: string) => void;
onRefreshNeeded?: () => void;
}
export function ChatMessage({ message, onSourceClick, onRefreshNeeded }: ChatMessageProps) {
const isUser = message.role === 'user';
const [isRefreshing, setIsRefreshing] = useState(false);
const handleRefresh = async () => {
setIsRefreshing(true);
try {
console.log('[ChatMessage] Manual refresh triggered');
// Trigger the same refresh mechanism as automatic refresh
if (onRefreshNeeded) {
await onRefreshNeeded();
console.log('[ChatMessage] Refresh completed');
} else {
console.error('[ChatMessage] onRefreshNeeded is undefined');
}
} catch (err) {
console.error('[ChatMessage] Refresh failed:', err);
} finally {
setIsRefreshing(false);
}
};
return (
<div className={cn("flex gap-3 p-4", isUser ? "bg-transparent" : "bg-muted/30")}>
<div className={cn(
"h-8 w-8 rounded-full flex items-center justify-center flex-shrink-0",
isUser ? "bg-primary text-primary-foreground" : "bg-secondary text-secondary-foreground"
)}>
{isUser ? <User className="h-5 w-5" /> : <Bot className="h-5 w-5" />}
</div>
<div className="flex-1 space-y-2 overflow-hidden">
<div className="prose dark:prose-invert text-sm max-w-none whitespace-pre-wrap">
{message.content}
</div>
{!isUser && message.notes_written && message.notes_written.length > 0 && (
<div className="space-y-2">
<div className="flex flex-wrap gap-2">
{message.notes_written.map((note, i) => (
<button
key={i}
onClick={() => onSourceClick(note.path)}
className="flex items-center gap-1.5 px-2 py-1 rounded-md bg-green-500/10 text-green-600 dark:text-green-400 border border-green-500/20 hover:bg-green-500/20 text-xs transition-colors"
>
{note.action === 'created' ? <FilePlus className="h-3 w-3" /> : <Edit className="h-3 w-3" />}
<span className="font-medium">
{note.action === 'created' ? 'Created' : 'Updated'}: {note.title}
</span>
</button>
))}
</div>
<Button
onClick={handleRefresh}
disabled={isRefreshing}
size="sm"
variant="outline"
className="text-xs h-7"
>
<RefreshCw className={cn("h-3 w-3 mr-1.5", isRefreshing && "animate-spin")} />
{isRefreshing ? 'Refreshing...' : 'Refresh Views'}
</Button>
</div>
)}
{!isUser && message.sources && (
<SourceList sources={message.sources} onSourceClick={onSourceClick} />
)}
</div>
</div>
);
}
|