'use client'; import { useState } from 'react'; import { ChevronDown, ChevronUp, Database, MessageSquare, ExternalLink, FileText, Copy, Link } from 'lucide-react'; import { cn, formatDateOnly } from '@/lib/utils'; export interface ReferenceSource { id: string; type: 'dataset' | 'history' | 'document'; name: string; relevance: number; content?: string; url?: string; // URL for document linking metadata?: { conversation_title?: string; agent_name?: string; created_at?: string; chunks?: number; file_type?: string; document_id?: string; // For linking to document viewer }; } interface ReferencesPanelProps { sources: ReferenceSource[]; isVisible: boolean; onToggle: () => void; className?: string; } export function ReferencesPanel({ sources, isVisible, onToggle, className = '' }: ReferencesPanelProps) { const [expandedSources, setExpandedSources] = useState>(new Set()); const [copiedCitation, setCopiedCitation] = useState(null); const toggleSource = (sourceId: string) => { const newExpanded = new Set(expandedSources); if (newExpanded.has(sourceId)) { newExpanded.delete(sourceId); } else { newExpanded.add(sourceId); } setExpandedSources(newExpanded); }; const getSourceIcon = (type: ReferenceSource['type']) => { switch (type) { case 'dataset': return ; case 'history': return ; case 'document': return ; default: return ; } }; const getSourceTypeColor = (type: ReferenceSource['type']) => { switch (type) { case 'dataset': return 'text-blue-600 bg-blue-50 border-blue-200'; case 'history': return 'text-purple-600 bg-purple-50 border-purple-200'; case 'document': return 'text-green-600 bg-green-50 border-green-200'; default: return 'text-gray-600 bg-gray-50 border-gray-200'; } }; const formatRelevance = (relevance: number) => { return Math.round(relevance * 100); }; const generateCitation = (source: ReferenceSource) => { const date = source.metadata?.created_at ? formatDateOnly(source.metadata.created_at) : formatDateOnly(new Date()); switch (source.type) { case 'document': return `${source.name} (${source.metadata?.file_type || 'Document'}). GT 2.0 Knowledge Base. Retrieved ${date}.`; case 'dataset': return `"${source.name}" dataset. GT 2.0 Knowledge Base. Retrieved ${date}.`; case 'history': const conversation = source.metadata?.conversation_title || 'Conversation'; const agent = source.metadata?.agent_name || 'AI Assistant'; return `${agent}. "${conversation}." GT 2.0 Conversation History. ${date}.`; default: return `${source.name}. GT 2.0 Knowledge Base. Retrieved ${date}.`; } }; const copyCitation = async (source: ReferenceSource) => { const citation = generateCitation(source); try { await navigator.clipboard.writeText(citation); setCopiedCitation(source.id); setTimeout(() => setCopiedCitation(null), 2000); } catch (err) { console.error('Failed to copy citation:', err); } }; const openDocument = (source: ReferenceSource) => { // Navigate to document if it's a document type if (source.type === 'document') { if (source.url) { // Open external URL window.open(source.url, '_blank'); } else if (source.metadata?.document_id) { // Navigate to internal document viewer const documentUrl = `/documents/${source.metadata.document_id}`; window.open(documentUrl, '_blank'); } else { // Fallback - try to construct URL from ID const documentUrl = `/documents/${source.id}`; window.open(documentUrl, '_blank'); } } }; if (sources.length === 0) return null; return (
{/* Header */} {/* Content */} {isVisible && (
{sources.map((source, index) => (
{/* Source Summary */} {/* Expanded Content */} {expandedSources.has(source.id) && source.content && (
{source.content.length > 500 ? `${source.content.substring(0, 500)}...` : source.content}
{/* Citation and Actions */}
Citation: {generateCitation(source)}
{source.metadata?.created_at && ( Created: {formatDateOnly(source.metadata.created_at)} )}
{source.type === 'document' && ( )}
)}
))} {/* Footer */}
Sources ranked by relevance • Click to expand content
)}
); }