diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx index 04a3eeb..39ba6d1 100644 --- a/src/pages/Index.tsx +++ b/src/pages/Index.tsx @@ -69,7 +69,7 @@ const mapHitToNote = (hit: any): Note => ({ const Index = () => { // Log component mount time immediately console.log(`Component mounted after ${Date.now() - GLOBAL_START_TIME}ms`); - + const [currentNote, setCurrentNote] = useState(''); const [currentNoteTags, setCurrentNoteTags] = useState([]); const [previousNote, setPreviousNote] = useState(null); @@ -94,7 +94,7 @@ const Index = () => { const [debugInfo, setDebugInfo] = useState([]); const [showDebugPanel, setShowDebugPanel] = useState(false); const [autoGenerateTags, setAutoGenerateTags] = useState(true); - const [ollamaStatus, setOllamaStatus] = useState<'unknown' | 'online' | 'offline'>('unknown'); + const [ollamaStatus, setOllamaStatus] = useState<'unknown' | 'online' | 'offline'>('unknown'); const [includeTagsInSearch, setIncludeTagsInSearch] = useState(true); const [tagGenerationTimeout, setTagGenerationTimeout] = useState(); const [isSettingsOpen, setIsSettingsOpen] = useState(false); @@ -139,12 +139,12 @@ $current`); const response = await fetch(url, options); const duration = Date.now() - startTime; debugTiming(operation, startTime); - + // Add network diagnostics for slow requests if (duration > 1000) { addDebugInfo(`Slow request: ${operation} took ${duration}ms`); } - + return response; } catch (error) { const duration = Date.now() - startTime; @@ -246,7 +246,7 @@ $current`); // Add timeout to prevent hanging const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 500); - + const response = await fetch(`${ollamaEndpoint}/api/tags`, { method: 'GET', headers: { @@ -254,9 +254,9 @@ $current`); }, signal: controller.signal, }); - + clearTimeout(timeoutId); - + if (response.ok) { setOllamaStatus('online'); addDebugInfo('Ollama connection successful'); @@ -286,7 +286,7 @@ $current`); if (tagGenerationTimeout) { clearTimeout(tagGenerationTimeout); } - + const timeout = setTimeout(async () => { if (content.trim() && autoGenerateTags) { try { @@ -305,14 +305,14 @@ $current`); } } }, 300); - + setTagGenerationTimeout(timeout); }; // Generate tags using Ollama const generateTags = async (content: string, noteIndex?: number): Promise => { try { - // Get context from previous notes only + // Get context from previous notes only let previousNotes = ''; if (noteIndex !== undefined && noteCache.length > 0) { const contextNotes = []; @@ -357,7 +357,7 @@ $current`); const data = await response.json(); const responseText = data.response?.trim(); - + if (!responseText) { throw new Error('Empty response from Ollama - check if model is loaded'); } @@ -367,9 +367,18 @@ $current`); .split(',') .map((tag: string) => tag.trim()) .filter((tag: string) => tag.length > 0); - - addDebugInfo(`Generated ${tags.length} tags: ${tags.join(', ')}`); - return tags; + + // Filter out tags that already exist in the content + const filteredTags = tags.filter((tag: string) => { + const tagExists = content.toLowerCase().includes(tag.toLowerCase()); + if (tagExists) { + addDebugInfo(`Removing tag "${tag}" - already exists in content`); + } + return !tagExists; + }); + + addDebugInfo(`Generated ${tags.length} tags, filtered to ${filteredTags.length}: ${filteredTags.join(', ')}`); + return filteredTags; // Last resort: return empty array addDebugInfo('Could not extract tags from Ollama response'); @@ -377,10 +386,10 @@ $current`); } catch (error) { console.error('Error generating tags:', error); const errorMessage = error instanceof Error ? error.message : 'Unknown error'; - + // More detailed error logging and user notification let userMessage = 'Failed to generate tags'; - + if (error instanceof TypeError && error.message.includes('fetch')) { addDebugInfo('Tag generation failed: Network error - Ollama not reachable at localhost:11434'); userMessage = 'Ollama not reachable - check if it\'s running on localhost:11434'; @@ -397,14 +406,14 @@ $current`); addDebugInfo(`Tag generation failed: ${errorMessage}`); userMessage = `Tag generation failed: ${errorMessage}`; } - + // Show error to user toast({ title: "Tag Generation Failed", description: userMessage, variant: "destructive", }); - + return []; } }; @@ -599,7 +608,7 @@ $current`); const noteIndex = noteCache.findIndex(n => n.id === note.id); tags = await generateTags(trimmedContent, noteIndex); } - + // Generate tags if none are present and auto-generation is enabled if (autoGenerateTags && tags.length === 0) { addDebugInfo('No tags present, generating tags before saving...'); @@ -716,31 +725,31 @@ $current`); const data = await response.json(); const notes: Note[] = data.hits.map((hit: any) => mapHitToNote(hit)); - if (offset === 0) { - setNoteCache(notes); - if (notes.length > 0) { - setPreviousNote(notes[0]); - setCurrentNoteIndex(0); - } - const loadTime = Date.now() - loadStartTime; - addDebugInfo(`Loaded ${notes.length} notes in ${loadTime}ms`); - } else { - setNoteCache(prev => [...prev, ...notes]); - const loadTime = Date.now() - loadStartTime; - addDebugInfo(`Loaded ${notes.length} additional notes in ${loadTime}ms`); + if (offset === 0) { + setNoteCache(notes); + if (notes.length > 0) { + setPreviousNote(notes[0]); + setCurrentNoteIndex(0); } - } catch (error) { - console.error('Error loading notes:', error); const loadTime = Date.now() - loadStartTime; - addDebugInfo(`Failed to load notes after ${loadTime}ms`); - toast({ - title: "Error", - description: "Failed to load notes. Please check your connection.", - variant: "destructive", - }); - } finally { - setIsLoading(false); + addDebugInfo(`Loaded ${notes.length} notes in ${loadTime}ms`); + } else { + setNoteCache(prev => [...prev, ...notes]); + const loadTime = Date.now() - loadStartTime; + addDebugInfo(`Loaded ${notes.length} additional notes in ${loadTime}ms`); } + } catch (error) { + console.error('Error loading notes:', error); + const loadTime = Date.now() - loadStartTime; + addDebugInfo(`Failed to load notes after ${loadTime}ms`); + toast({ + title: "Error", + description: "Failed to load notes. Please check your connection.", + variant: "destructive", + }); + } finally { + setIsLoading(false); + } }; // Load notes around a specific note @@ -1097,7 +1106,7 @@ $current`); try { setIsLoading(true); addDebugInfo('Regenerating tags for all notes...'); - + // Load all notes const response = await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/search`, { method: 'POST', @@ -1118,7 +1127,7 @@ $current`); const data = await response.json(); const notes: Note[] = data.hits.map((hit: any) => mapHitToNote(hit)); - + let updatedCount = 0; for (let i = 0; i < notes.length; i++) { const note = notes[i]; @@ -1134,7 +1143,7 @@ $current`); console.error(`Error updating tags for note ${note.id}:`, error); } } - + addDebugInfo(`Tag regeneration complete: ${updatedCount} notes updated`); toast({ title: "Tag regeneration complete", @@ -1203,7 +1212,7 @@ $current`); document.addEventListener('keydown', handleKeyDown); window.addEventListener('focus', handleWindowFocus); - + return () => { document.removeEventListener('keydown', handleKeyDown); window.removeEventListener('focus', handleWindowFocus); @@ -1352,19 +1361,19 @@ $current`); try { console.log('Starting initialization...'); addDebugInfo('Starting initialization...'); - + // Check all indexes in parallel for faster initialization addDebugInfo('Checking all indexes in parallel...'); const indexCheckStart = Date.now(); - + const [notesExists, scratchExists, settingsExists] = await Promise.all([ indexExists(NOTE_INDEX), - indexExists(SCRATCH_INDEX), + indexExists(SCRATCH_INDEX), indexExists(SETTINGS_INDEX) ]); - + addDebugInfo(`All index checks completed: ${Date.now() - indexCheckStart}ms`); - + // Create missing indexes const createPromises = []; if (!notesExists) { @@ -1381,7 +1390,7 @@ $current`); }), }, 'Create Notes Index')); } - + if (!scratchExists) { addDebugInfo('Creating scratch index...'); createPromises.push(fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes`, { @@ -1396,7 +1405,7 @@ $current`); }), }, 'Create Scratch Index')); } - + if (!settingsExists) { addDebugInfo('Creating settings index...'); createPromises.push(fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes`, { @@ -1411,7 +1420,7 @@ $current`); }), }, 'Create Settings Index')); } - + if (createPromises.length > 0) { await Promise.all(createPromises); addDebugInfo('All missing indexes created'); @@ -1420,7 +1429,7 @@ $current`); // Configure all indexes in parallel addDebugInfo('Configuring all indexes in parallel...'); const configStart = Date.now(); - + await Promise.all([ // Notes index configurations fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/settings/sortable-attributes`, { @@ -1431,7 +1440,7 @@ $current`); }, body: JSON.stringify(['date']), }, 'Configure Notes Sortable Attributes'), - + fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/settings/ranking-rules`, { method: 'PUT', headers: { @@ -1440,7 +1449,7 @@ $current`); }, body: JSON.stringify(['sort', 'words', 'typo', 'proximity', 'attribute', 'exactness']), }, 'Configure Notes Ranking Rules'), - + fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/settings/filterable-attributes`, { method: 'PUT', headers: { @@ -1449,7 +1458,7 @@ $current`); }, body: JSON.stringify(['date', 'topLetter', 'letterCount', 'topLetterFrequency', 'tags']), }, 'Configure Notes Filterable Attributes'), - + // Scratch index configurations fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SCRATCH_INDEX}/settings/sortable-attributes`, { method: 'PUT', @@ -1459,7 +1468,7 @@ $current`); }, body: JSON.stringify(['date']), }, 'Configure Scratch Sortable Attributes'), - + fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SCRATCH_INDEX}/settings/filterable-attributes`, { method: 'PUT', headers: { @@ -1468,7 +1477,7 @@ $current`); }, body: JSON.stringify(['date']), }, 'Configure Scratch Filterable Attributes'), - + // Settings index configurations fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SETTINGS_INDEX}/settings/filterable-attributes`, { method: 'PUT', @@ -1479,7 +1488,7 @@ $current`); body: JSON.stringify(['key', 'value']), }, 'Configure Settings Filterable Attributes'), ]); - + addDebugInfo(`All index configurations completed: ${Date.now() - configStart}ms`); setIsInitialized(true); @@ -1518,7 +1527,7 @@ $current`); currentNoteRef.current?.focus(); console.log('Focus set on current note field'); }, 100); - + return () => clearTimeout(focusTimer); }, []); @@ -1536,7 +1545,7 @@ $current`); const dataLoadStartTime = Date.now(); console.log('Starting data loading...'); addDebugInfo('Starting data loading...'); - + await loadNotes(); await loadLatestScratch(); await loadFontSizeSetting(); @@ -1547,7 +1556,7 @@ $current`); await loadIncludeTagsSetting(); await loadAllOllamaSettings(); await checkOllamaStatus(); - + // Retry Ollama connection after a delay if it failed setTimeout(async () => { if (ollamaStatus === 'offline') { @@ -1555,12 +1564,12 @@ $current`); await checkOllamaStatus(); } }, 2000); - + const totalTime = Date.now() - dataLoadStartTime; debugTiming('Total Data Loading', dataLoadStartTime); addDebugInfo(`Total Data Loading: ${totalTime}ms`); console.log('Data loading complete'); - + // Re-focus after data loading to ensure focus is maintained currentNoteRef.current?.focus(); } @@ -2270,19 +2279,19 @@ $current`); Cleanup - -