// Smart Memory Content Analyzer export interface ContentAnalysis { contentType: 'text' | 'code' | 'structured' suggestedCategory: string | null suggestedTags: string[] suggestedPriority: 'low' | 'medium' | 'high' title: string | null summary: string | null language?: string // for code content confidence: number // 0-1 score } export interface CategoryPattern { category: string keywords: string[] patterns: RegExp[] weight: number } export interface TagPattern { tag: string patterns: RegExp[] weight: number } // Category detection patterns const CATEGORY_PATTERNS: CategoryPattern[] = [ { category: 'work', keywords: ['meeting', 'client', 'project', 'deadline', 'sprint', 'standup', 'review', 'business'], patterns: [ /\b(meeting|attendees|action items?|agenda|client|deadline|sprint|standup|scrum)\b/i, /\b(quarterly|q[1-4]|revenue|budget|roi|kpi|metrics)\b/i ], weight: 1.0 }, { category: 'code', keywords: ['function', 'class', 'bug', 'fix', 'error', 'debug', 'api', 'database'], patterns: [ /\b(function|class|const|let|var|import|export|if|else|for|while)\b/, /\b(bug|error|exception|debug|fix|issue|patch)\b/i, /\b(api|endpoint|database|query|schema|migration)\b/i, /```[\s\S]*?```/, /`[^`]+`/ ], weight: 1.2 }, { category: 'research', keywords: ['study', 'research', 'analysis', 'findings', 'hypothesis', 'experiment'], patterns: [ /\b(research|study|analysis|findings|hypothesis|experiment|survey|data)\b/i, /\b(conclusion|methodology|results|abstract|references?)\b/i, /\b(according to|studies show|research indicates)\b/i ], weight: 1.0 }, { category: 'personal', keywords: ['personal', 'reminder', 'todo', 'note', 'idea', 'thought'], patterns: [ /\b(personal|private|reminder|todo|note|idea|thought|journal)\b/i, /\b(remember to|don't forget|need to)\b/i ], weight: 0.8 }, { category: 'conversations', keywords: ['conversation', 'discussion', 'chat', 'call', 'talk'], patterns: [ /\b(conversation|discussion|chat|call|talk|spoke with|talked to)\b/i, /\b(said|mentioned|suggested|agreed|disagreed)\b/i, /^[A-Za-z\s]+:\s/m // Speaker format "John: Hello" ], weight: 1.0 } ] // Tag detection patterns const TAG_PATTERNS: TagPattern[] = [ { tag: 'urgent', patterns: [/\b(urgent|asap|critical|emergency|immediate)\b/i], weight: 1.0 }, { tag: 'important', patterns: [/\b(important|crucial|vital|key|essential)\b/i], weight: 0.8 }, { tag: 'todo', patterns: [/\b(todo|task|action item|need to|should)\b/i, /- \[ \]/], weight: 0.9 }, { tag: 'meeting', patterns: [/\b(meeting|standup|scrum|review|sync)\b/i], weight: 1.0 }, { tag: 'bug', patterns: [/\b(bug|error|issue|problem|broken)\b/i], weight: 1.0 }, { tag: 'feature', patterns: [/\b(feature|enhancement|improvement|new)\b/i], weight: 0.8 }, { tag: 'api', patterns: [/\b(api|endpoint|rest|graphql|webhook)\b/i], weight: 1.0 }, { tag: 'database', patterns: [/\b(database|db|sql|query|table|schema)\b/i], weight: 1.0 }, { tag: 'frontend', patterns: [/\b(frontend|ui|ux|react|vue|angular|css|html)\b/i], weight: 0.9 }, { tag: 'backend', patterns: [/\b(backend|server|node|python|java|api)\b/i], weight: 0.9 }, { tag: 'documentation', patterns: [/\b(docs|documentation|readme|guide|tutorial)\b/i], weight: 0.8 }, { tag: 'security', patterns: [/\b(security|auth|authentication|authorization|vulnerability)\b/i], weight: 1.0 }, { tag: 'performance', patterns: [/\b(performance|optimization|speed|slow|fast|cache)\b/i], weight: 0.9 }, { tag: 'testing', patterns: [/\b(test|testing|spec|unit|integration|e2e)\b/i], weight: 0.9 } ] // Programming language detection const LANGUAGE_PATTERNS: { [key: string]: RegExp[] } = { javascript: [ /\b(const|let|var|function|=>|import|export|require)\b/, /\.(js|jsx|ts|tsx)$/, /console\.log|document\.|window\./ ], python: [ /\b(def|class|import|from|if __name__|print\()\b/, /\.py$/, /^\s*(def|class|import|from)\s/m ], java: [ /\b(public|private|class|interface|extends|implements)\b/, /\.java$/, /System\.out\.println/ ], go: [ /\b(func|package|import|var|const|type|interface)\b/, /\.go$/, /fmt\.Print/ ], rust: [ /\b(fn|let|mut|struct|enum|impl|trait)\b/, /\.rs$/, /println!/ ], sql: [ /\b(SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP)\b/i, /\.sql$/, /FROM|WHERE|JOIN|GROUP BY|ORDER BY/i ] } export function analyzeContent(content: string): ContentAnalysis { const text = content.trim() if (!text) { return { contentType: 'text', suggestedCategory: null, suggestedTags: [], suggestedPriority: 'medium', title: null, summary: null, confidence: 0 } } const analysis: ContentAnalysis = { contentType: detectContentType(text), suggestedCategory: detectCategory(text), suggestedTags: detectTags(text), suggestedPriority: detectPriority(text), title: extractTitle(text), summary: extractSummary(text), confidence: 0 } // Detect programming language for code content if (analysis.contentType === 'code') { analysis.language = detectLanguage(text) } // Calculate confidence score analysis.confidence = calculateConfidence(text, analysis) return analysis } function detectContentType(text: string): 'text' | 'code' | 'structured' { // Check for code blocks if (text.includes('```') || text.match(/^```/m)) { return 'code' } // Check for inline code const inlineCodeCount = (text.match(/`[^`]+`/g) || []).length if (inlineCodeCount > 2) { return 'code' } // Check for programming keywords const codeKeywords = ['function', 'const', 'let', 'var', 'class', 'import', 'export', 'def', 'public', 'private'] const codeKeywordCount = codeKeywords.filter(keyword => new RegExp(`\\b${keyword}\\b`, 'i').test(text) ).length if (codeKeywordCount > 2) { return 'code' } // Check for structured content const structuredIndicators = [ /^#{1,6}\s/m, // Markdown headers /^[-*+]\s/m, // Lists /^(\d+\.)\s/m, // Numbered lists /^- \[[ x]\]/m, // Checkboxes /^\|.*\|/m, // Tables /^>.*$/m, // Blockquotes ] const structuredCount = structuredIndicators.filter(pattern => pattern.test(text)).length if (structuredCount > 1) { return 'structured' } // Check for multiple sections/paragraphs const paragraphs = text.split('\n\n').filter(p => p.trim().length > 20) if (paragraphs.length > 2 && text.includes('\n\n')) { return 'structured' } return 'text' } function detectCategory(text: string): string | null { const scores: { [category: string]: number } = {} const lowerText = text.toLowerCase() for (const pattern of CATEGORY_PATTERNS) { let score = 0 // Check keywords for (const keyword of pattern.keywords) { const regex = new RegExp(`\\b${keyword}\\b`, 'gi') const matches = lowerText.match(regex) || [] score += matches.length * 0.5 } // Check patterns for (const regex of pattern.patterns) { const matches = text.match(regex) || [] score += matches.length * 1.0 } // Apply category weight score *= pattern.weight if (score > 0) { scores[pattern.category] = (scores[pattern.category] || 0) + score } } // Return category with highest score, if above threshold const entries = Object.entries(scores).sort(([,a], [,b]) => b - a) const topScore = entries[0]?.[1] || 0 return topScore > 1.0 ? entries[0][0] : null } function detectTags(text: string): string[] { const tags = new Set() const lowerText = text.toLowerCase() // Extract hashtags const hashtagMatches = text.match(/#(\w+)/g) || [] hashtagMatches.forEach(match => tags.add(match.substring(1).toLowerCase())) // Pattern-based tag detection for (const tagPattern of TAG_PATTERNS) { let score = 0 for (const pattern of tagPattern.patterns) { const matches = text.match(pattern) || [] score += matches.length * tagPattern.weight } if (score >= 1.0) { tags.add(tagPattern.tag) } } // Content-specific tags if (text.includes('TODO') || text.includes('FIXME')) { tags.add('todo') } if (text.match(/\b(note|reminder|remember)\b/i)) { tags.add('note') } // Priority indicators if (text.match(/\b(urgent|asap|critical)\b/i)) { tags.add('urgent') } return Array.from(tags).slice(0, 8) // Limit to 8 tags } function detectPriority(text: string): 'low' | 'medium' | 'high' { const lowerText = text.toLowerCase() // High priority indicators if (lowerText.match(/\b(urgent|asap|critical|emergency|immediate|deadline|tomorrow)\b/)) { return 'high' } // Low priority indicators if (lowerText.match(/\b(someday|maybe|nice to have|optional|when time permits)\b/)) { return 'low' } // Medium priority indicators or default return 'medium' } function detectLanguage(text: string): string | undefined { for (const [language, patterns] of Object.entries(LANGUAGE_PATTERNS)) { let score = 0 for (const pattern of patterns) { if (pattern.test(text)) { score++ } } if (score >= 2) { return language } } return undefined } function extractTitle(text: string): string | null { const lines = text.split('\n').filter(line => line.trim()) // Check for markdown headers const headerMatch = text.match(/^#{1,6}\s+(.+)$/m) if (headerMatch) { return headerMatch[1].trim() } // Check for first non-empty line const firstLine = lines[0]?.trim() if (firstLine && firstLine.length > 5 && firstLine.length < 100) { // Avoid using lines that look like code or have special formatting if (!firstLine.match(/^[\[\{]/) && !firstLine.includes('()') && !firstLine.startsWith('//')) { return firstLine } } return null } function extractSummary(text: string): string | null { // Remove markdown headers and code blocks const cleanText = text .replace(/^#{1,6}\s+.*$/gm, '') // Headers .replace(/```[\s\S]*?```/g, '') // Code blocks .replace(/`[^`]+`/g, '') // Inline code .trim() if (!cleanText) return null // Get first few sentences const sentences = cleanText.split(/[.!?]+/).filter(s => s.trim().length > 10) if (sentences.length === 0) return null const summary = sentences.slice(0, 2).join('. ').trim() if (summary.length < 20) { // If too short, take more content const words = cleanText.split(/\s+/).slice(0, 25) return words.join(' ') + (cleanText.split(/\s+/).length > 25 ? '...' : '') } return summary.length > 150 ? summary.substring(0, 147) + '...' : summary } function calculateConfidence(text: string, analysis: ContentAnalysis): number { let confidence = 0.5 // Base confidence // Content type confidence if (analysis.contentType === 'code' && (text.includes('```') || text.includes('function'))) { confidence += 0.2 } else if (analysis.contentType === 'structured' && text.includes('#')) { confidence += 0.15 } // Category confidence if (analysis.suggestedCategory) { confidence += 0.15 } // Tags confidence if (analysis.suggestedTags.length > 0) { confidence += Math.min(analysis.suggestedTags.length * 0.05, 0.2) } // Title extraction confidence if (analysis.title) { confidence += 0.1 } return Math.min(confidence, 1.0) } // Utility function for template variable replacement export function applyTemplate(template: string, variables: Record): string { let result = template for (const [key, value] of Object.entries(variables)) { const placeholder = `{{${key}}}` result = result.replaceAll(placeholder, value) } // Replace any remaining placeholders with defaults result = result.replace(/{{(\w+)}}/g, (match, key) => { const defaults: Record = { date: new Date().toLocaleDateString(), time: new Date().toLocaleTimeString(), title: 'Title', topic: 'Topic', language: 'javascript' } return defaults[key] || match }) return result }