refactor(Index.tsx): improve tag generation logic and Ollama status handling

This commit is contained in:
2025-08-29 13:21:59 +02:00
parent 48f3545454
commit d4dfe11cef

View File

@@ -69,7 +69,7 @@ const mapHitToNote = (hit: any): Note => ({
const Index = () => { const Index = () => {
// Log component mount time immediately // Log component mount time immediately
console.log(`Component mounted after ${Date.now() - GLOBAL_START_TIME}ms`); console.log(`Component mounted after ${Date.now() - GLOBAL_START_TIME}ms`);
const [currentNote, setCurrentNote] = useState(''); const [currentNote, setCurrentNote] = useState('');
const [currentNoteTags, setCurrentNoteTags] = useState<string[]>([]); const [currentNoteTags, setCurrentNoteTags] = useState<string[]>([]);
const [previousNote, setPreviousNote] = useState<Note | null>(null); const [previousNote, setPreviousNote] = useState<Note | null>(null);
@@ -94,7 +94,7 @@ const Index = () => {
const [debugInfo, setDebugInfo] = useState<string[]>([]); const [debugInfo, setDebugInfo] = useState<string[]>([]);
const [showDebugPanel, setShowDebugPanel] = useState(false); const [showDebugPanel, setShowDebugPanel] = useState(false);
const [autoGenerateTags, setAutoGenerateTags] = useState(true); 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 [includeTagsInSearch, setIncludeTagsInSearch] = useState(true);
const [tagGenerationTimeout, setTagGenerationTimeout] = useState<NodeJS.Timeout>(); const [tagGenerationTimeout, setTagGenerationTimeout] = useState<NodeJS.Timeout>();
const [isSettingsOpen, setIsSettingsOpen] = useState(false); const [isSettingsOpen, setIsSettingsOpen] = useState(false);
@@ -139,12 +139,12 @@ $current`);
const response = await fetch(url, options); const response = await fetch(url, options);
const duration = Date.now() - startTime; const duration = Date.now() - startTime;
debugTiming(operation, startTime); debugTiming(operation, startTime);
// Add network diagnostics for slow requests // Add network diagnostics for slow requests
if (duration > 1000) { if (duration > 1000) {
addDebugInfo(`Slow request: ${operation} took ${duration}ms`); addDebugInfo(`Slow request: ${operation} took ${duration}ms`);
} }
return response; return response;
} catch (error) { } catch (error) {
const duration = Date.now() - startTime; const duration = Date.now() - startTime;
@@ -246,7 +246,7 @@ $current`);
// Add timeout to prevent hanging // Add timeout to prevent hanging
const controller = new AbortController(); const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 500); const timeoutId = setTimeout(() => controller.abort(), 500);
const response = await fetch(`${ollamaEndpoint}/api/tags`, { const response = await fetch(`${ollamaEndpoint}/api/tags`, {
method: 'GET', method: 'GET',
headers: { headers: {
@@ -254,9 +254,9 @@ $current`);
}, },
signal: controller.signal, signal: controller.signal,
}); });
clearTimeout(timeoutId); clearTimeout(timeoutId);
if (response.ok) { if (response.ok) {
setOllamaStatus('online'); setOllamaStatus('online');
addDebugInfo('Ollama connection successful'); addDebugInfo('Ollama connection successful');
@@ -286,7 +286,7 @@ $current`);
if (tagGenerationTimeout) { if (tagGenerationTimeout) {
clearTimeout(tagGenerationTimeout); clearTimeout(tagGenerationTimeout);
} }
const timeout = setTimeout(async () => { const timeout = setTimeout(async () => {
if (content.trim() && autoGenerateTags) { if (content.trim() && autoGenerateTags) {
try { try {
@@ -305,14 +305,14 @@ $current`);
} }
} }
}, 300); }, 300);
setTagGenerationTimeout(timeout); setTagGenerationTimeout(timeout);
}; };
// Generate tags using Ollama // Generate tags using Ollama
const generateTags = async (content: string, noteIndex?: number): Promise<string[]> => { const generateTags = async (content: string, noteIndex?: number): Promise<string[]> => {
try { try {
// Get context from previous notes only // Get context from previous notes only
let previousNotes = ''; let previousNotes = '';
if (noteIndex !== undefined && noteCache.length > 0) { if (noteIndex !== undefined && noteCache.length > 0) {
const contextNotes = []; const contextNotes = [];
@@ -357,7 +357,7 @@ $current`);
const data = await response.json(); const data = await response.json();
const responseText = data.response?.trim(); const responseText = data.response?.trim();
if (!responseText) { if (!responseText) {
throw new Error('Empty response from Ollama - check if model is loaded'); throw new Error('Empty response from Ollama - check if model is loaded');
} }
@@ -367,9 +367,18 @@ $current`);
.split(',') .split(',')
.map((tag: string) => tag.trim()) .map((tag: string) => tag.trim())
.filter((tag: string) => tag.length > 0); .filter((tag: string) => tag.length > 0);
addDebugInfo(`Generated ${tags.length} tags: ${tags.join(', ')}`); // Filter out tags that already exist in the content
return tags; 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 // Last resort: return empty array
addDebugInfo('Could not extract tags from Ollama response'); addDebugInfo('Could not extract tags from Ollama response');
@@ -377,10 +386,10 @@ $current`);
} catch (error) { } catch (error) {
console.error('Error generating tags:', error); console.error('Error generating tags:', error);
const errorMessage = error instanceof Error ? error.message : 'Unknown error'; const errorMessage = error instanceof Error ? error.message : 'Unknown error';
// More detailed error logging and user notification // More detailed error logging and user notification
let userMessage = 'Failed to generate tags'; let userMessage = 'Failed to generate tags';
if (error instanceof TypeError && error.message.includes('fetch')) { if (error instanceof TypeError && error.message.includes('fetch')) {
addDebugInfo('Tag generation failed: Network error - Ollama not reachable at localhost:11434'); addDebugInfo('Tag generation failed: Network error - Ollama not reachable at localhost:11434');
userMessage = 'Ollama not reachable - check if it\'s running on localhost:11434'; userMessage = 'Ollama not reachable - check if it\'s running on localhost:11434';
@@ -397,14 +406,14 @@ $current`);
addDebugInfo(`Tag generation failed: ${errorMessage}`); addDebugInfo(`Tag generation failed: ${errorMessage}`);
userMessage = `Tag generation failed: ${errorMessage}`; userMessage = `Tag generation failed: ${errorMessage}`;
} }
// Show error to user // Show error to user
toast({ toast({
title: "Tag Generation Failed", title: "Tag Generation Failed",
description: userMessage, description: userMessage,
variant: "destructive", variant: "destructive",
}); });
return []; return [];
} }
}; };
@@ -599,7 +608,7 @@ $current`);
const noteIndex = noteCache.findIndex(n => n.id === note.id); const noteIndex = noteCache.findIndex(n => n.id === note.id);
tags = await generateTags(trimmedContent, noteIndex); tags = await generateTags(trimmedContent, noteIndex);
} }
// Generate tags if none are present and auto-generation is enabled // Generate tags if none are present and auto-generation is enabled
if (autoGenerateTags && tags.length === 0) { if (autoGenerateTags && tags.length === 0) {
addDebugInfo('No tags present, generating tags before saving...'); addDebugInfo('No tags present, generating tags before saving...');
@@ -716,31 +725,31 @@ $current`);
const data = await response.json(); const data = await response.json();
const notes: Note[] = data.hits.map((hit: any) => mapHitToNote(hit)); const notes: Note[] = data.hits.map((hit: any) => mapHitToNote(hit));
if (offset === 0) { if (offset === 0) {
setNoteCache(notes); setNoteCache(notes);
if (notes.length > 0) { if (notes.length > 0) {
setPreviousNote(notes[0]); setPreviousNote(notes[0]);
setCurrentNoteIndex(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`);
} }
} catch (error) {
console.error('Error loading notes:', error);
const loadTime = Date.now() - loadStartTime; const loadTime = Date.now() - loadStartTime;
addDebugInfo(`Failed to load notes after ${loadTime}ms`); addDebugInfo(`Loaded ${notes.length} notes in ${loadTime}ms`);
toast({ } else {
title: "Error", setNoteCache(prev => [...prev, ...notes]);
description: "Failed to load notes. Please check your connection.", const loadTime = Date.now() - loadStartTime;
variant: "destructive", addDebugInfo(`Loaded ${notes.length} additional notes in ${loadTime}ms`);
});
} finally {
setIsLoading(false);
} }
} 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 // Load notes around a specific note
@@ -1097,7 +1106,7 @@ $current`);
try { try {
setIsLoading(true); setIsLoading(true);
addDebugInfo('Regenerating tags for all notes...'); addDebugInfo('Regenerating tags for all notes...');
// Load all notes // Load all notes
const response = await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/search`, { const response = await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/search`, {
method: 'POST', method: 'POST',
@@ -1118,7 +1127,7 @@ $current`);
const data = await response.json(); const data = await response.json();
const notes: Note[] = data.hits.map((hit: any) => mapHitToNote(hit)); const notes: Note[] = data.hits.map((hit: any) => mapHitToNote(hit));
let updatedCount = 0; let updatedCount = 0;
for (let i = 0; i < notes.length; i++) { for (let i = 0; i < notes.length; i++) {
const note = notes[i]; const note = notes[i];
@@ -1134,7 +1143,7 @@ $current`);
console.error(`Error updating tags for note ${note.id}:`, error); console.error(`Error updating tags for note ${note.id}:`, error);
} }
} }
addDebugInfo(`Tag regeneration complete: ${updatedCount} notes updated`); addDebugInfo(`Tag regeneration complete: ${updatedCount} notes updated`);
toast({ toast({
title: "Tag regeneration complete", title: "Tag regeneration complete",
@@ -1203,7 +1212,7 @@ $current`);
document.addEventListener('keydown', handleKeyDown); document.addEventListener('keydown', handleKeyDown);
window.addEventListener('focus', handleWindowFocus); window.addEventListener('focus', handleWindowFocus);
return () => { return () => {
document.removeEventListener('keydown', handleKeyDown); document.removeEventListener('keydown', handleKeyDown);
window.removeEventListener('focus', handleWindowFocus); window.removeEventListener('focus', handleWindowFocus);
@@ -1352,19 +1361,19 @@ $current`);
try { try {
console.log('Starting initialization...'); console.log('Starting initialization...');
addDebugInfo('Starting initialization...'); addDebugInfo('Starting initialization...');
// Check all indexes in parallel for faster initialization // Check all indexes in parallel for faster initialization
addDebugInfo('Checking all indexes in parallel...'); addDebugInfo('Checking all indexes in parallel...');
const indexCheckStart = Date.now(); const indexCheckStart = Date.now();
const [notesExists, scratchExists, settingsExists] = await Promise.all([ const [notesExists, scratchExists, settingsExists] = await Promise.all([
indexExists(NOTE_INDEX), indexExists(NOTE_INDEX),
indexExists(SCRATCH_INDEX), indexExists(SCRATCH_INDEX),
indexExists(SETTINGS_INDEX) indexExists(SETTINGS_INDEX)
]); ]);
addDebugInfo(`All index checks completed: ${Date.now() - indexCheckStart}ms`); addDebugInfo(`All index checks completed: ${Date.now() - indexCheckStart}ms`);
// Create missing indexes // Create missing indexes
const createPromises = []; const createPromises = [];
if (!notesExists) { if (!notesExists) {
@@ -1381,7 +1390,7 @@ $current`);
}), }),
}, 'Create Notes Index')); }, 'Create Notes Index'));
} }
if (!scratchExists) { if (!scratchExists) {
addDebugInfo('Creating scratch index...'); addDebugInfo('Creating scratch index...');
createPromises.push(fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes`, { createPromises.push(fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes`, {
@@ -1396,7 +1405,7 @@ $current`);
}), }),
}, 'Create Scratch Index')); }, 'Create Scratch Index'));
} }
if (!settingsExists) { if (!settingsExists) {
addDebugInfo('Creating settings index...'); addDebugInfo('Creating settings index...');
createPromises.push(fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes`, { createPromises.push(fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes`, {
@@ -1411,7 +1420,7 @@ $current`);
}), }),
}, 'Create Settings Index')); }, 'Create Settings Index'));
} }
if (createPromises.length > 0) { if (createPromises.length > 0) {
await Promise.all(createPromises); await Promise.all(createPromises);
addDebugInfo('All missing indexes created'); addDebugInfo('All missing indexes created');
@@ -1420,7 +1429,7 @@ $current`);
// Configure all indexes in parallel // Configure all indexes in parallel
addDebugInfo('Configuring all indexes in parallel...'); addDebugInfo('Configuring all indexes in parallel...');
const configStart = Date.now(); const configStart = Date.now();
await Promise.all([ await Promise.all([
// Notes index configurations // Notes index configurations
fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/settings/sortable-attributes`, { fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/settings/sortable-attributes`, {
@@ -1431,7 +1440,7 @@ $current`);
}, },
body: JSON.stringify(['date']), body: JSON.stringify(['date']),
}, 'Configure Notes Sortable Attributes'), }, 'Configure Notes Sortable Attributes'),
fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/settings/ranking-rules`, { fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/settings/ranking-rules`, {
method: 'PUT', method: 'PUT',
headers: { headers: {
@@ -1440,7 +1449,7 @@ $current`);
}, },
body: JSON.stringify(['sort', 'words', 'typo', 'proximity', 'attribute', 'exactness']), body: JSON.stringify(['sort', 'words', 'typo', 'proximity', 'attribute', 'exactness']),
}, 'Configure Notes Ranking Rules'), }, 'Configure Notes Ranking Rules'),
fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/settings/filterable-attributes`, { fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${NOTE_INDEX}/settings/filterable-attributes`, {
method: 'PUT', method: 'PUT',
headers: { headers: {
@@ -1449,7 +1458,7 @@ $current`);
}, },
body: JSON.stringify(['date', 'topLetter', 'letterCount', 'topLetterFrequency', 'tags']), body: JSON.stringify(['date', 'topLetter', 'letterCount', 'topLetterFrequency', 'tags']),
}, 'Configure Notes Filterable Attributes'), }, 'Configure Notes Filterable Attributes'),
// Scratch index configurations // Scratch index configurations
fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SCRATCH_INDEX}/settings/sortable-attributes`, { fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SCRATCH_INDEX}/settings/sortable-attributes`, {
method: 'PUT', method: 'PUT',
@@ -1459,7 +1468,7 @@ $current`);
}, },
body: JSON.stringify(['date']), body: JSON.stringify(['date']),
}, 'Configure Scratch Sortable Attributes'), }, 'Configure Scratch Sortable Attributes'),
fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SCRATCH_INDEX}/settings/filterable-attributes`, { fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SCRATCH_INDEX}/settings/filterable-attributes`, {
method: 'PUT', method: 'PUT',
headers: { headers: {
@@ -1468,7 +1477,7 @@ $current`);
}, },
body: JSON.stringify(['date']), body: JSON.stringify(['date']),
}, 'Configure Scratch Filterable Attributes'), }, 'Configure Scratch Filterable Attributes'),
// Settings index configurations // Settings index configurations
fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SETTINGS_INDEX}/settings/filterable-attributes`, { fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SETTINGS_INDEX}/settings/filterable-attributes`, {
method: 'PUT', method: 'PUT',
@@ -1479,7 +1488,7 @@ $current`);
body: JSON.stringify(['key', 'value']), body: JSON.stringify(['key', 'value']),
}, 'Configure Settings Filterable Attributes'), }, 'Configure Settings Filterable Attributes'),
]); ]);
addDebugInfo(`All index configurations completed: ${Date.now() - configStart}ms`); addDebugInfo(`All index configurations completed: ${Date.now() - configStart}ms`);
setIsInitialized(true); setIsInitialized(true);
@@ -1518,7 +1527,7 @@ $current`);
currentNoteRef.current?.focus(); currentNoteRef.current?.focus();
console.log('Focus set on current note field'); console.log('Focus set on current note field');
}, 100); }, 100);
return () => clearTimeout(focusTimer); return () => clearTimeout(focusTimer);
}, []); }, []);
@@ -1536,7 +1545,7 @@ $current`);
const dataLoadStartTime = Date.now(); const dataLoadStartTime = Date.now();
console.log('Starting data loading...'); console.log('Starting data loading...');
addDebugInfo('Starting data loading...'); addDebugInfo('Starting data loading...');
await loadNotes(); await loadNotes();
await loadLatestScratch(); await loadLatestScratch();
await loadFontSizeSetting(); await loadFontSizeSetting();
@@ -1547,7 +1556,7 @@ $current`);
await loadIncludeTagsSetting(); await loadIncludeTagsSetting();
await loadAllOllamaSettings(); await loadAllOllamaSettings();
await checkOllamaStatus(); await checkOllamaStatus();
// Retry Ollama connection after a delay if it failed // Retry Ollama connection after a delay if it failed
setTimeout(async () => { setTimeout(async () => {
if (ollamaStatus === 'offline') { if (ollamaStatus === 'offline') {
@@ -1555,12 +1564,12 @@ $current`);
await checkOllamaStatus(); await checkOllamaStatus();
} }
}, 2000); }, 2000);
const totalTime = Date.now() - dataLoadStartTime; const totalTime = Date.now() - dataLoadStartTime;
debugTiming('Total Data Loading', dataLoadStartTime); debugTiming('Total Data Loading', dataLoadStartTime);
addDebugInfo(`Total Data Loading: ${totalTime}ms`); addDebugInfo(`Total Data Loading: ${totalTime}ms`);
console.log('Data loading complete'); console.log('Data loading complete');
// Re-focus after data loading to ensure focus is maintained // Re-focus after data loading to ensure focus is maintained
currentNoteRef.current?.focus(); currentNoteRef.current?.focus();
} }
@@ -2270,19 +2279,19 @@ $current`);
<Trash2 className="h-8 w-8" /> <Trash2 className="h-8 w-8" />
Cleanup Cleanup
</Button> </Button>
<Button <Button
onClick={() => setIsSettingsOpen(true)} onClick={() => setIsSettingsOpen(true)}
size="sm" size="sm"
variant="outline" variant="outline"
className={getTextClass('base')} className={getTextClass('base')}
> >
<Settings className="h-4 w-4 mr-2" /> <Settings className="h-4 w-4 mr-2" />
Settings Settings
</Button> </Button>
<Button <Button
onClick={() => setShowDebugPanel(!showDebugPanel)} onClick={() => setShowDebugPanel(!showDebugPanel)}
size="sm" size="sm"
variant="outline" variant="outline"
className={getTextClass('base')} className={getTextClass('base')}
> >
{showDebugPanel ? 'Hide' : 'Show'} Debug {showDebugPanel ? 'Hide' : 'Show'} Debug
@@ -2298,7 +2307,7 @@ $current`);
<div className="flex items-center gap-4 mb-3"> <div className="flex items-center gap-4 mb-3">
<div className={`${getTextClass('base')} flex items-center gap-2`}> <div className={`${getTextClass('base')} flex items-center gap-2`}>
<span>Ollama Status:</span> <span>Ollama Status:</span>
<Badge <Badge
variant={ollamaStatus === 'online' ? 'default' : ollamaStatus === 'offline' ? 'destructive' : 'secondary'} variant={ollamaStatus === 'online' ? 'default' : ollamaStatus === 'offline' ? 'destructive' : 'secondary'}
className={`${getTextClass('base')} px-2 py-1`} className={`${getTextClass('base')} px-2 py-1`}
> >
@@ -2307,7 +2316,7 @@ $current`);
</div> </div>
<div className={`${getTextClass('base')} flex items-center gap-2`}> <div className={`${getTextClass('base')} flex items-center gap-2`}>
<span>Auto-tags:</span> <span>Auto-tags:</span>
<Badge <Badge
variant={autoGenerateTags ? 'default' : 'secondary'} variant={autoGenerateTags ? 'default' : 'secondary'}
className={`${getTextClass('base')} px-2 py-1`} className={`${getTextClass('base')} px-2 py-1`}
> >
@@ -2358,16 +2367,16 @@ $current`);
className={`flex-1 border-0 bg-transparent ${getTextClass('base')} p-0 outline-none`} className={`flex-1 border-0 bg-transparent ${getTextClass('base')} p-0 outline-none`}
/> />
{!autoGenerateTags && ( {!autoGenerateTags && (
<Button <Button
onClick={async () => { onClick={async () => {
if (previousNote) { if (previousNote) {
addDebugInfo('Manually generating tags...'); addDebugInfo('Manually generating tags...');
const tags = await generateTags(previousNote.content, currentNoteIndex); const tags = await generateTags(previousNote.content, currentNoteIndex);
const updatedNote = { ...previousNote, tags }; const updatedNote = { ...previousNote, tags };
setPreviousNote(updatedNote); setPreviousNote(updatedNote);
setIsPreviousNoteModified(true); setIsPreviousNoteModified(true);
} }
}} }}
size="sm" size="sm"
variant="outline" variant="outline"
className={`${getTextClass('base')} px-2 py-1 h-6`} className={`${getTextClass('base')} px-2 py-1 h-6`}
@@ -2414,17 +2423,17 @@ $current`);
<div className="flex-1 bg-card rounded-lg border border-border shadow-sm p-6 overflow-hidden"> <div className="flex-1 bg-card rounded-lg border border-border shadow-sm p-6 overflow-hidden">
<div className={`${getTextClass('2xl')} text-muted-foreground mb-3 flex items-center gap-4`}> <div className={`${getTextClass('2xl')} text-muted-foreground mb-3 flex items-center gap-4`}>
<div>Current Entry</div> <div>Current Entry</div>
<div className="flex-1 flex items-center gap-2"> <div className="flex-1 flex items-center gap-2">
<span className={`${getTextClass('base')} text-muted-foreground`}>Tags:</span> <span className={`${getTextClass('base')} text-muted-foreground`}>Tags:</span>
<input <input
type="text" type="text"
value={currentNoteTags.join(', ')} value={currentNoteTags.join(', ')}
onChange={(e) => { onChange={(e) => {
setCurrentNoteTags([e.target.value]); setCurrentNoteTags([e.target.value]);
}} }}
className={`flex-1 border-0 bg-transparent ${getTextClass('base')} p-0 outline-none`} className={`flex-1 border-0 bg-transparent ${getTextClass('base')} p-0 outline-none`}
/> />
</div> </div>
</div> </div>
<Textarea <Textarea
ref={currentNoteRef} ref={currentNoteRef}
@@ -2603,8 +2612,8 @@ $current`);
<Button onClick={getProblematicNotes} className={`w-full ${getTextClass('2xl')} py-6`}> <Button onClick={getProblematicNotes} className={`w-full ${getTextClass('2xl')} py-6`}>
Analyze Notes Analyze Notes
</Button> </Button>
<Button <Button
onClick={regenerateAllTags} onClick={regenerateAllTags}
variant="outline" variant="outline"
className={`w-full ${getTextClass('2xl')} py-6`} className={`w-full ${getTextClass('2xl')} py-6`}
disabled={isLoading} disabled={isLoading}
@@ -2663,7 +2672,7 @@ $current`);
{/* Tag Generation Settings */} {/* Tag Generation Settings */}
<div className="space-y-6"> <div className="space-y-6">
<h3 className={`${getTextClass('2xl')} font-semibold`}>Tag Generation</h3> <h3 className={`${getTextClass('2xl')} font-semibold`}>Tag Generation</h3>
<div className="space-y-4"> <div className="space-y-4">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
@@ -2735,7 +2744,7 @@ $current`);
{/* Display Settings */} {/* Display Settings */}
<div className="space-y-6"> <div className="space-y-6">
<h3 className={`${getTextClass('2xl')} font-semibold`}>Display</h3> <h3 className={`${getTextClass('2xl')} font-semibold`}>Display</h3>
<div> <div>
<label className={`${getTextClass('xl')} font-medium mb-2 block`}>Font Size</label> <label className={`${getTextClass('xl')} font-medium mb-2 block`}>Font Size</label>
<Select value={fontSize} onValueChange={saveFontSizeSetting}> <Select value={fontSize} onValueChange={saveFontSizeSetting}>
@@ -2755,18 +2764,18 @@ $current`);
{/* Ollama Settings */} {/* Ollama Settings */}
<div className="space-y-6"> <div className="space-y-6">
<h3 className={`${getTextClass('2xl')} font-semibold`}>Ollama Configuration</h3> <h3 className={`${getTextClass('2xl')} font-semibold`}>Ollama Configuration</h3>
<div className="space-y-4"> <div className="space-y-4">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span className={`${getTextClass('base')}`}>Status:</span> <span className={`${getTextClass('base')}`}>Status:</span>
<Badge <Badge
variant={ollamaStatus === 'online' ? 'default' : ollamaStatus === 'offline' ? 'destructive' : 'secondary'} variant={ollamaStatus === 'online' ? 'default' : ollamaStatus === 'offline' ? 'destructive' : 'secondary'}
className={`${getTextClass('base')} px-2 py-1`} className={`${getTextClass('base')} px-2 py-1`}
> >
{ollamaStatus === 'online' ? 'Online' : ollamaStatus === 'offline' ? 'Offline' : 'Unknown'} {ollamaStatus === 'online' ? 'Online' : ollamaStatus === 'offline' ? 'Offline' : 'Unknown'}
</Badge> </Badge>
</div> </div>
<div> <div>
<label className={`${getTextClass('xl')} font-medium mb-2 block`}>Endpoint</label> <label className={`${getTextClass('xl')} font-medium mb-2 block`}>Endpoint</label>
<Input <Input