refactor(Index.tsx): improve tag generation logic and Ollama status handling
This commit is contained in:
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user