import React, { useState, useEffect } from 'react' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog' import { Badge } from '@/components/ui/badge' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Alert, AlertDescription } from '@/components/ui/alert' import { Progress } from '@/components/ui/progress' import { Memory } from '@/types' import { Shield, WifiOff, Tabs } from 'lucide-react' interface AIEnhancementProps { memories: Memory[] onEnhanceMemory: (memory: Memory) => Promise onEnhanceAll: () => Promise enhancingMemories: Set isEnhancing: boolean llmProvider: "openai" | "anthropic" | "ollama" | "none" llmApiKey: string onProviderChange: (provider: "openai" | "anthropic" | "ollama" | "none") => void onApiKeyChange: (key: string) => void onSaveSettings: () => void websocket?: WebSocket enhancementDisabled?: boolean enhancementFailures?: number } interface EnhancementProgress { completed: number total: number currentMemoryId?: string stage: 'analyzing' | 'generating' | 'completing' | 'idle' errors: Array<{ memoryId: string; error: string }> startTime?: Date estimatedTimeRemaining?: number } interface AIInsight { type: 'categorization' | 'tagging' | 'relationship' | 'summary' | 'quality' title: string description: string memories: Memory[] action?: string } export function AIEnhancement({ memories, onEnhanceMemory, onEnhanceAll, enhancingMemories, isEnhancing, llmProvider, llmApiKey, onProviderChange, onApiKeyChange, onSaveSettings, websocket, enhancementDisabled = false, enhancementFailures = 0 }: AIEnhancementProps) { const [showSettings, setShowSettings] = useState(false) const [selectedInsight, setSelectedInsight] = useState(null) const [enhancementProgress, setEnhancementProgress] = useState({ completed: 0, total: 0, stage: 'idle', errors: [] }) const [showProgressDetails, setShowProgressDetails] = useState(false) // Generate AI insights about the memory collection const generateInsights = (): AIInsight[] => { const insights: AIInsight[] = [] // Find untagged memories const untagged = memories.filter(m => !m.tags || m.tags.length === 0) if (untagged.length > 0) { insights.push({ type: 'tagging', title: 'Untagged Memories', description: `${untagged.length} memories could benefit from AI-generated tags for better organization.`, memories: untagged, action: 'Generate Tags' }) } // Find uncategorized memories const uncategorized = memories.filter(m => !m.category) if (uncategorized.length > 0) { insights.push({ type: 'categorization', title: 'Uncategorized Memories', description: `${uncategorized.length} memories need category assignment for better organization.`, memories: uncategorized, action: 'Auto-Categorize' }) } // Find memories without AI enhancement const unenhanced = memories.filter(m => { const tags = m.tags || [] return !tags.some(tag => tag.startsWith('title:')) }) if (unenhanced.length > 0) { insights.push({ type: 'summary', title: 'Enhancement Opportunities', description: `${unenhanced.length} memories could get AI-generated titles and summaries.`, memories: unenhanced, action: 'Enhance All' }) } // Find potential relationships const tagGroups = new Map() memories.forEach(memory => { const tags = memory.tags || [] tags.forEach(tag => { if (!tag.startsWith('title:') && !tag.startsWith('summary:')) { if (!tagGroups.has(tag)) tagGroups.set(tag, []) tagGroups.get(tag)!.push(memory) } }) }) const relatedMemories = Array.from(tagGroups.entries()) .filter(([, memories]) => memories.length > 1) .flatMap(([, memories]) => memories) .filter((memory, index, self) => self.findIndex(m => m.id === memory.id) === index) if (relatedMemories.length > 0) { insights.push({ type: 'relationship', title: 'Related Memories', description: `${relatedMemories.length} memories share common tags and could be linked together.`, memories: relatedMemories, action: 'Create Links' }) } // Find low-quality memories (very short or no content) const lowQuality = memories.filter(m => m.content.trim().length < 20 || m.content.trim().split(' ').length < 5 ) if (lowQuality.length > 0) { insights.push({ type: 'quality', title: 'Quality Improvements', description: `${lowQuality.length} memories are very short and might need expansion.`, memories: lowQuality, action: 'Suggest Improvements' }) } return insights } const insights = generateInsights() // Update progress tracking when enhancing memories changes React.useEffect(() => { if (isEnhancing && enhancingMemories.size > 0) { const totalToEnhance = enhancementProgress.total || enhancingMemories.size const completed = totalToEnhance - enhancingMemories.size setEnhancementProgress(prev => ({ ...prev, completed, total: totalToEnhance, stage: enhancingMemories.size > 0 ? 'generating' : 'completing', currentMemoryId: Array.from(enhancingMemories)[0], estimatedTimeRemaining: enhancingMemories.size * 3 // 3 seconds per memory estimate })) } else if (!isEnhancing && enhancementProgress.stage !== 'idle') { setEnhancementProgress(prev => ({ ...prev, stage: 'idle', currentMemoryId: undefined, estimatedTimeRemaining: undefined })) } }, [isEnhancing, enhancingMemories, enhancementProgress.total]) // Calculate enhancement statistics const enhancementStats = React.useMemo(() => { const enhanced = memories.filter(m => (m.tags || []).some(tag => tag.startsWith('title:'))) const tagged = memories.filter(m => m.tags && m.tags.length > 0) const categorized = memories.filter(m => m.category) const withSummary = memories.filter(m => (m.tags || []).some(tag => tag.startsWith('summary:'))) return { enhanced: { count: enhanced.length, percentage: (enhanced.length / memories.length) * 100 }, tagged: { count: tagged.length, percentage: (tagged.length / memories.length) * 100 }, categorized: { count: categorized.length, percentage: (categorized.length / memories.length) * 100 }, withSummary: { count: withSummary.length, percentage: (withSummary.length / memories.length) * 100 }, total: memories.length } }, [memories]) const formatTimeRemaining = (seconds: number) => { if (seconds < 60) return `${seconds}s` const minutes = Math.floor(seconds / 60) const remainingSeconds = seconds % 60 return `${minutes}m ${remainingSeconds}s` } const getInsightIcon = (type: string) => { const icons = { categorization: '📂', tagging: '🏷️', relationship: '🔗', summary: '✨', quality: '⭐' } return icons[type as keyof typeof icons] || '💡' } const getInsightColor = (type: string) => { const colors = { categorization: 'bg-blue-600', tagging: 'bg-green-600', relationship: 'bg-purple-600', summary: 'bg-yellow-600', quality: 'bg-red-600' } return colors[type as keyof typeof colors] || 'bg-gray-600' } const handleBulkAction = async (insight: AIInsight) => { if (insight.type === 'summary' && insight.action === 'Enhance All') { await onEnhanceAll() } else if (insight.type === 'tagging' && insight.action === 'Generate Tags') { for (const memory of insight.memories) { if (!enhancingMemories.has(memory.id)) { await onEnhanceMemory(memory) } } } else if (insight.type === 'categorization' && insight.action === 'Auto-Categorize') { // This would require backend support for auto-categorization alert('Auto-categorization coming soon!') } } return (
{/* AI Settings */}

🤖 AI Enhancement

{llmProvider === 'none' ? 'Configure AI to enhance your memories with titles, summaries, and insights' : llmProvider === 'ollama' ? 'Using Ollama Local AI for privacy-focused memory enhancement' : `Using ${llmProvider === 'openai' ? 'OpenAI GPT' : 'Anthropic Claude'} for memory enhancement` }

AI Enhancement Settings
{llmProvider === "ollama" && (
Privacy-Focused Local AI

• No data sent to external servers

• Unlimited processing with no API costs

• Requires Ollama running locally

📖 Setup: Install Ollama and run ollama pull llama3.1:8b

)} {llmProvider !== "none" && llmProvider !== "ollama" && (
onApiKeyChange(e.target.value)} placeholder="Enter your API key" className="bg-gray-700 border-gray-600 text-white" />
)}
{llmProvider !== "none" && ( )}
{/* Enhancement Disabled Warning */} {enhancementDisabled && llmProvider === 'ollama' && ( Ollama Enhancement Disabled
Enhancement has been temporarily disabled after {enhancementFailures} failed attempts. Please ensure Ollama is running and click "Save Settings" to re-enable enhancement.
)} {/* AI Insights */} {llmProvider !== 'none' && insights.length > 0 && ( 💡 AI Insights & Recommendations
{insights.map((insight, index) => ( setSelectedInsight(insight)} >
{getInsightIcon(insight.type)}
{insight.title}

{insight.description}

{insight.action && ( )}
))}
)} {/* Enhanced Progress Tracking */} {(isEnhancing || enhancingMemories.size > 0) && (
🔄
Enhancement Progress
{/* Progress Bar */}
{enhancementProgress.completed} of {enhancementProgress.total} memories processed {enhancementProgress.total > 0 ? Math.round((enhancementProgress.completed / enhancementProgress.total) * 100) : 0}%
0 ? (enhancementProgress.completed / enhancementProgress.total) * 100 : 0} className="h-2" />
{/* Current Status */}
{enhancementProgress.stage === 'analyzing' && 'Analyzing memory content...'} {enhancementProgress.stage === 'generating' && 'Generating AI enhancements...'} {enhancementProgress.stage === 'completing' && 'Finalizing enhancements...'} {enhancementProgress.stage === 'idle' && 'Enhancement complete'}
{enhancementProgress.estimatedTimeRemaining && ( ~{formatTimeRemaining(enhancementProgress.estimatedTimeRemaining)} remaining )}
{/* Detailed Progress */} {showProgressDetails && (
Processing Details
{/* Currently Processing */} {enhancementProgress.currentMemoryId && (
Current memory: {enhancementProgress.currentMemoryId}
)} {/* Queue Status */}
{enhancementProgress.completed}
Completed
{enhancingMemories.size}
In Progress
{enhancementProgress.total - enhancementProgress.completed - enhancingMemories.size}
Pending
{/* Error Summary */} {enhancementProgress.errors.length > 0 && (
{enhancementProgress.errors.length} error(s) encountered
{enhancementProgress.errors.slice(0, 3).map((error, index) => (
Memory {error.memoryId}: {error.error}
))} {enhancementProgress.errors.length > 3 && (
And {enhancementProgress.errors.length - 3} more errors...
)}
)} {/* Performance Stats */} {enhancementProgress.startTime && (
Started: {enhancementProgress.startTime.toLocaleTimeString()}
)}
)}
)} {/* Enhanced Stats Dashboard */}
AI Enhanced
{enhancementStats.enhanced.count} / {enhancementStats.total}
{enhancementStats.enhanced.percentage.toFixed(1)}% complete
🏷️
Tagged
{enhancementStats.tagged.count} / {enhancementStats.total}
{enhancementStats.tagged.percentage.toFixed(1)}% tagged
📂
Categorized
{enhancementStats.categorized.count} / {enhancementStats.total}
{enhancementStats.categorized.percentage.toFixed(1)}% categorized
📝
Summarized
{enhancementStats.withSummary.count} / {enhancementStats.total}
{enhancementStats.withSummary.percentage.toFixed(1)}% summarized
{/* Overall Progress Summary */} {enhancementStats.total > 0 && ( Overall Enhancement Progress
{Math.round((enhancementStats.enhanced.percentage + enhancementStats.tagged.percentage + enhancementStats.categorized.percentage) / 3)}%
Average completion across all enhancement categories
{enhancementStats.enhanced.count}
Enhanced
{enhancementStats.tagged.count}
Tagged
{enhancementStats.categorized.count}
Categorized
{enhancementStats.withSummary.count}
Summarized
{/* Quality Score */}
Memory Collection Quality Score 80 ? 'default' : enhancementStats.enhanced.percentage > 50 ? 'secondary' : 'outline' }> {enhancementStats.enhanced.percentage > 80 ? 'Excellent' : enhancementStats.enhanced.percentage > 50 ? 'Good' : 'Needs Improvement'}
)} {/* Insight Detail Modal */} {selectedInsight && ( setSelectedInsight(null)}> {getInsightIcon(selectedInsight.type)} {selectedInsight.title}

{selectedInsight.description}

{selectedInsight.memories.slice(0, 10).map((memory) => (
{memory.content.substring(0, 100)}...
{memory.tags && memory.tags.length > 0 && (
{memory.tags.slice(0, 3).map((tag, i) => ( {tag} ))}
)}
))} {selectedInsight.memories.length > 10 && (
And {selectedInsight.memories.length - 10} more memories...
)}
{selectedInsight.action && ( )}
)}
) }