feat(Index.tsx): implement debounced tag generation for improved user experience
This commit is contained in:
@@ -98,6 +98,7 @@ const Index = () => {
|
|||||||
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 { resolvedTheme, setTheme } = useTheme();
|
const { resolvedTheme, setTheme } = useTheme();
|
||||||
|
|
||||||
@@ -240,12 +241,46 @@ const Index = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Debounced tag generation
|
||||||
|
const debouncedGenerateTags = (content: string, noteIndex?: number) => {
|
||||||
|
if (tagGenerationTimeout) {
|
||||||
|
clearTimeout(tagGenerationTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
const timeout = setTimeout(async () => {
|
||||||
|
if (content.trim() && autoGenerateTags) {
|
||||||
|
try {
|
||||||
|
addDebugInfo('Auto-generating tags...');
|
||||||
|
const tags = await generateTags(content, noteIndex);
|
||||||
|
if (noteIndex !== undefined) {
|
||||||
|
// For existing notes
|
||||||
|
const note = noteCache[noteIndex];
|
||||||
|
if (note) {
|
||||||
|
const updatedNote = { ...note, tags };
|
||||||
|
setPreviousNote(updatedNote);
|
||||||
|
setIsPreviousNoteModified(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For current note
|
||||||
|
setCurrentNoteTags(tags);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Auto tag generation failed:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 200);
|
||||||
|
|
||||||
|
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 {
|
||||||
const systemPrompt = `You are a helpful assistant that generates searchable tags for journal entries.
|
const systemPrompt = `You are a helpful assistant that generates searchable tags for journal entries.
|
||||||
|
|
||||||
Your task is to analyze the content and generate 3-8 relevant tags that would help the author find this note later.
|
Your task is to analyze the content and generate 1-3 relevant tags that would help the author find this note later.
|
||||||
|
Focus on the quality of tags, not the quantity.
|
||||||
|
|
||||||
Focus on:
|
Focus on:
|
||||||
- Programming languages, frameworks, libraries mentioned
|
- Programming languages, frameworks, libraries mentioned
|
||||||
- Technical concepts and methodologies
|
- Technical concepts and methodologies
|
||||||
@@ -468,7 +503,7 @@ ${content}${context}`;
|
|||||||
// Use current note tags or generate tags using Ollama if enabled
|
// Use current note tags or generate tags using Ollama if enabled
|
||||||
let tags: string[] = currentNoteTags;
|
let tags: string[] = currentNoteTags;
|
||||||
if (autoGenerateTags && tags.length === 0) {
|
if (autoGenerateTags && tags.length === 0) {
|
||||||
addDebugInfo('Generating tags for new note...');
|
addDebugInfo('Generating tags for new note before saving...');
|
||||||
tags = await generateTags(trimmedContent, 0); // New note will be at index 0
|
tags = await generateTags(trimmedContent, 0); // New note will be at index 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,6 +578,13 @@ ${content}${context}`;
|
|||||||
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
|
||||||
|
if (autoGenerateTags && tags.length === 0) {
|
||||||
|
addDebugInfo('No tags present, generating tags before saving...');
|
||||||
|
const noteIndex = noteCache.findIndex(n => n.id === note.id);
|
||||||
|
tags = await generateTags(trimmedContent, noteIndex);
|
||||||
|
}
|
||||||
|
|
||||||
const document = {
|
const document = {
|
||||||
id: note.id,
|
id: note.id,
|
||||||
@@ -1147,6 +1189,10 @@ ${content}${context}`;
|
|||||||
if (saveTimeoutRef.current) {
|
if (saveTimeoutRef.current) {
|
||||||
clearTimeout(saveTimeoutRef.current);
|
clearTimeout(saveTimeoutRef.current);
|
||||||
}
|
}
|
||||||
|
// Clear any pending tag generation timeout on cleanup
|
||||||
|
if (tagGenerationTimeout) {
|
||||||
|
clearTimeout(tagGenerationTimeout);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}, [currentNote, previousNote, scratchPad, isPreviousNoteModified, isSearchOpen, isGotoOpen, isCleanupOpen]);
|
}, [currentNote, previousNote, scratchPad, isPreviousNoteModified, isSearchOpen, isGotoOpen, isCleanupOpen]);
|
||||||
|
|
||||||
@@ -1778,10 +1824,12 @@ ${content}${context}`;
|
|||||||
<Textarea
|
<Textarea
|
||||||
value={previousNote.content}
|
value={previousNote.content}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const updatedNote = { ...previousNote, content: e.target.value };
|
const newContent = e.target.value;
|
||||||
|
const updatedNote = { ...previousNote, content: newContent };
|
||||||
setPreviousNote(updatedNote);
|
setPreviousNote(updatedNote);
|
||||||
setIsPreviousNoteModified(true);
|
setIsPreviousNoteModified(true);
|
||||||
if (e.target.value.trim() === '') {
|
debouncedGenerateTags(newContent, currentNoteIndex);
|
||||||
|
if (newContent.trim() === '') {
|
||||||
deleteNote(previousNote.id);
|
deleteNote(previousNote.id);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@@ -1834,7 +1882,9 @@ ${content}${context}`;
|
|||||||
ref={currentNoteRef}
|
ref={currentNoteRef}
|
||||||
value={currentNote}
|
value={currentNote}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setCurrentNote(e.target.value);
|
const newContent = e.target.value;
|
||||||
|
setCurrentNote(newContent);
|
||||||
|
debouncedGenerateTags(newContent);
|
||||||
}}
|
}}
|
||||||
onBlur={handleCurrentNoteBlur}
|
onBlur={handleCurrentNoteBlur}
|
||||||
className={`h-[calc(100%-2rem)] border-0 resize-none focus:ring-0 bg-transparent ${getTextClass('2xl')}`}
|
className={`h-[calc(100%-2rem)] border-0 resize-none focus:ring-0 bg-transparent ${getTextClass('2xl')}`}
|
||||||
|
Reference in New Issue
Block a user