diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx index 3461c6b..490dff6 100644 --- a/src/pages/Index.tsx +++ b/src/pages/Index.tsx @@ -1,5 +1,5 @@ import { useState, useEffect, useCallback, useRef } from 'react'; -import { Trash2, Moon, Sun } from 'lucide-react'; +import { Trash2, Moon, Sun, Settings } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Textarea } from '@/components/ui/textarea'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; @@ -99,6 +99,23 @@ const Index = () => { const [ollamaStatus, setOllamaStatus] = useState<'unknown' | 'online' | 'offline'>('unknown'); const [includeTagsInSearch, setIncludeTagsInSearch] = useState(true); const [tagGenerationTimeout, setTagGenerationTimeout] = useState(); + const [isSettingsOpen, setIsSettingsOpen] = useState(false); + const [systemPrompt, setSystemPrompt] = useState(`You are a helpful assistant that generates searchable tags for journal entries. + +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: +- Programming languages, frameworks, libraries mentioned +- Technical concepts and methodologies +- Tools and utilities discussed +- Problem domains or contexts +- Key technical terms that someone might search for + +Return ONLY a comma-separated list of tags, no other text. Example: golang, testing, array-comparison, cmp-library + +Keep tags concise, use lowercase, and separate words with hyphens if needed.`); + const [contextSize, setContextSize] = useState(3); const { resolvedTheme, setTheme } = useTheme(); @@ -276,28 +293,12 @@ const Index = () => { // Generate tags using Ollama const generateTags = async (content: string, noteIndex?: number): Promise => { try { - const systemPrompt = `You are a helpful assistant that generates searchable tags for journal entries. - -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: -- Programming languages, frameworks, libraries mentioned -- Technical concepts and methodologies -- Tools and utilities discussed -- Problem domains or contexts -- Key technical terms that someone might search for - -Return ONLY a comma-separated list of tags, no other text. Example: golang, testing, array-comparison, cmp-library - -Keep tags concise, use lowercase, and separate words with hyphens if needed.`; - // Get context from surrounding notes let context = ''; if (noteIndex !== undefined && noteCache.length > 0) { const contextNotes = []; - const start = Math.max(0, noteIndex - 2); - const end = Math.min(noteCache.length, noteIndex + 3); + const start = Math.max(0, noteIndex - contextSize); + const end = Math.min(noteCache.length, noteIndex + contextSize + 1); for (let i = start; i < end; i++) { if (i !== noteIndex) { @@ -1519,6 +1520,8 @@ ${content}${context}`; await loadLatestScratch(); await loadFontSizeSetting(); await loadAutoGenerateTagsSetting(); + await loadSystemPromptSetting(); + await loadContextSizeSetting(); await checkOllamaStatus(); const totalTime = Date.now() - dataLoadStartTime; @@ -1602,6 +1605,60 @@ ${content}${context}`; } }; + // Load system prompt setting + const loadSystemPromptSetting = async () => { + try { + const response = await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SETTINGS_INDEX}/search`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${MEILISEARCH_API_KEY}`, + }, + body: JSON.stringify({ + q: 'systemPrompt', + filter: 'key = "systemPrompt"', + limit: 1, + }), + }, 'Load System Prompt Setting'); + + if (response.ok) { + const data = await response.json(); + if (data.hits.length > 0) { + setSystemPrompt(data.hits[0].value); + } + } + } catch (error) { + console.error('Error loading system prompt setting:', error); + } + }; + + // Load context size setting + const loadContextSizeSetting = async () => { + try { + const response = await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SETTINGS_INDEX}/search`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${MEILISEARCH_API_KEY}`, + }, + body: JSON.stringify({ + q: 'contextSize', + filter: 'key = "contextSize"', + limit: 1, + }), + }, 'Load Context Size Setting'); + + if (response.ok) { + const data = await response.json(); + if (data.hits.length > 0) { + setContextSize(Number(data.hits[0].value) || 3); + } + } + } catch (error) { + console.error('Error loading context size setting:', error); + } + }; + // Save font size setting const saveFontSizeSetting = async (newFontSize: string) => { try { @@ -1676,6 +1733,80 @@ ${content}${context}`; } }; + // Save system prompt setting + const saveSystemPromptSetting = async (newPrompt: string) => { + try { + const document = { + key: 'systemPrompt', + value: newPrompt, + updatedAt: new Date().getTime(), + }; + + const response = await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SETTINGS_INDEX}/documents`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${MEILISEARCH_API_KEY}`, + }, + body: JSON.stringify(document), + }, 'Save System Prompt Setting'); + + if (response.status !== 202) { + throw new Error('Failed to save system prompt setting'); + } + + setSystemPrompt(newPrompt); + toast({ + title: "System prompt updated", + description: "Tag generation prompt has been saved.", + }); + } catch (error) { + console.error('Error saving system prompt setting:', error); + toast({ + title: "Error", + description: "Failed to save system prompt setting.", + variant: "destructive", + }); + } + }; + + // Save context size setting + const saveContextSizeSetting = async (newSize: number) => { + try { + const document = { + key: 'contextSize', + value: newSize.toString(), + updatedAt: new Date().getTime(), + }; + + const response = await fetchWithTiming(`${MEILISEARCH_ENDPOINT}/indexes/${SETTINGS_INDEX}/documents`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${MEILISEARCH_API_KEY}`, + }, + body: JSON.stringify(document), + }, 'Save Context Size Setting'); + + if (response.status !== 202) { + throw new Error('Failed to save context size setting'); + } + + setContextSize(newSize); + toast({ + title: "Context size updated", + description: `Context size changed to ${newSize} notes.`, + }); + } catch (error) { + console.error('Error saving context size setting:', error); + toast({ + title: "Error", + description: "Failed to save context size setting.", + variant: "destructive", + }); + } + }; + return (
{/* Header */} @@ -1715,6 +1846,15 @@ ${content}${context}`; Cleanup +
+ + {/* Settings Modal */} + + + + Settings + +
+ {/* Tag Generation Settings */} +
+

Tag Generation

+ +
+
+
+ +

+ Automatically generate tags while typing and before saving +

+
+ +
+ +
+ + saveContextSizeSetting(value[0])} + max={10} + min={0} + step={1} + className="w-full h-8" + /> +

+ Number of surrounding notes to include as context for tag generation +

+
+ +
+ +