// Name: AI-Powered File Inspector // Description: Use AI to analyze and organize files with smart categorization and human-like descriptions // Author: johnlindquist import '@johnlindquist/kit' import { OpenAI } from 'openai' interface FileAnalysis { path: string name: string type: string size: number aiDescription: string suggestedCategory: string confidence: number } // Initialize OpenAI client const openai = new OpenAI({ apiKey: await env('OPENAI_API_KEY', { panel: md('## Get your [OpenAI API Key](https://platform.openai.com/api-keys)'), secret: true, }) }) // Get source directory from user const sourceDir = await path({ hint: 'Select a directory to analyze and organize', onlyDirs: true, }) // Configuration for analysis const config = await form(` <div class="p-4 space-y-4"> <label class="block"> <span class="text-sm font-medium">Analysis Depth:</span> <select name="depth" class="mt-1 block w-full border rounded px-3 py-2"> <option value="basic">Basic (filename + extension)</option> <option value="content" selected>Content Analysis (reads file content)</option> <option value="smart">Smart Analysis (AI + metadata)</option> </select> </label> <label class="block"> <span class="text-sm font-medium">Max Files to Process:</span> <input type="number" name="maxFiles" value="20" min="1" max="100" class="mt-1 block w-full border rounded px-3 py-2"> </label> <label class="flex items-center space-x-2"> <input type="checkbox" name="createFolders" checked> <span class="text-sm">Automatically create organized folders</span> </label> </div> `) // Get all files from directory const allFiles = await globby([ path.join(sourceDir, '**/*'), '!' + path.join(sourceDir, '**/node_modules/**'), '!' + path.join(sourceDir, '**/.git/**'), ]) const files = allFiles .filter(async filePath => await isFile(filePath)) .slice(0, parseInt(config.maxFiles)) let analysisResults: FileAnalysis[] = [] let currentFileIndex = 0 // Analysis function with AI integration const analyzeFile = async (filePath: string): Promise<FileAnalysis> => { const stats = await stat(filePath) const fileName = path.basename(filePath) const ext = path.extname(fileName).toLowerCase() let content = '' let aiDescription = 'Unknown file type' let suggestedCategory = 'misc' let confidence = 0.5 try { // Read file content for analysis (limit size for AI processing) if (stats.size < 50000) { // 50KB limit if (['.txt', '.md', '.json', '.js', '.ts', '.py', '.html', '.css'].includes(ext)) { content = await readFile(filePath, 'utf-8') content = content.slice(0, 1000) // Limit content for AI } } // AI Analysis if (config.depth === 'smart' || config.depth === 'content') { const prompt = `Analyze this file and provide: 1. A brief, human-like description (max 50 words) 2. Suggested category (code, document, image, media, data, archive, misc) 3. Confidence score (0-1) File: ${fileName} Extension: ${ext} Size: ${stats.size} bytes ${content ? `Content preview: ${content}` : ''} Response format: {"description": "...", "category": "...", "confidence": 0.8}` const response = await openai.chat.completions.create({ model: 'gpt-3.5-turbo', messages: [{ role: 'user', content: prompt }], max_tokens: 150, temperature: 0.3, }) try { const result = JSON.parse(response.choices[0].message.content || '{}') aiDescription = result.description || `${fileName} - ${ext.slice(1)} file` suggestedCategory = result.category || 'misc' confidence = result.confidence || 0.5 } catch (parseError) { // Fallback to basic analysis aiDescription = `${fileName} - ${ext.slice(1)} file` } } else { // Basic analysis const categoryMap = { '.js': 'code', '.ts': 'code', '.py': 'code', '.html': 'code', '.txt': 'document', '.md': 'document', '.pdf': 'document', '.jpg': 'image', '.png': 'image', '.gif': 'image', '.mp4': 'media', '.mp3': 'media', '.avi': 'media', '.json': 'data', '.csv': 'data', '.xml': 'data', '.zip': 'archive', '.rar': 'archive', '.tar': 'archive' } suggestedCategory = categoryMap[ext] || 'misc' aiDescription = `${fileName} - ${ext.slice(1)} file` confidence = 0.7 } } catch (error) { console.warn(`Error analyzing ${fileName}:`, error.message) } return { path: filePath, name: fileName, type: ext, size: stats.size, aiDescription, suggestedCategory, confidence } } // Progress tracking with live updates const analyzeFiles = async () => { for (const filePath of files) { currentFileIndex++ // Update progress setPanel(md(` ## Analyzing Files... 📁 **Progress:** ${currentFileIndex}/${files.length} **Current:** ${path.basename(filePath)} **Analyzed:** ${analysisResults.length} files `)) const analysis = await analyzeFile(filePath) analysisResults.push(analysis) // Brief pause for human-like typing simulation await wait(100 + Math.random() * 200) } } // Run analysis await div({ html: md(`# Starting AI File Analysis 🤖\n\nAnalyzing ${files.length} files...`), onInit: async () => { await analyzeFiles() submit('analysis_complete') } }) // Display results and organization options const selectedFiles = await select( { placeholder: 'Select files to organize', multiple: true, preview: (input, { focused }) => { if (!focused) return '' const file = focused.value as FileAnalysis return md(` ### ${file.name} **AI Description:** ${file.aiDescription} **Category:** ${file.suggestedCategory} (${Math.round(file.confidence * 100)}% confidence) **Size:** ${(file.size / 1024).toFixed(1)} KB **Path:** \`${file.path}\` `) } }, analysisResults.map(file => ({ name: `${file.aiDescription}`, description: `${file.suggestedCategory} • ${(file.size / 1024).toFixed(1)} KB`, value: file, className: `confidence-${Math.round(file.confidence * 10)}` })) ) // Organize files if requested if (config.createFolders && selectedFiles.length > 0) { const organizationMap = new Map<string, FileAnalysis[]>() // Group by category selectedFiles.forEach(file => { const category = file.suggestedCategory if (!organizationMap.has(category)) { organizationMap.set(category, []) } organizationMap.get(category)!.push(file) }) // Create organized structure const organizedDir = path.join(sourceDir, 'AI_Organized') await ensureDir(organizedDir) for (const [category, files] of organizationMap) { const categoryDir = path.join(organizedDir, category) await ensureDir(categoryDir) for (const file of files) { const destPath = path.join(categoryDir, file.name) try { await move(file.path, destPath) toast(`Moved ${file.name} to ${category}/`, { autoClose: 1000 }) } catch (error) { console.warn(`Failed to move ${file.name}:`, error.message) } } } await revealFile(organizedDir) notify(`Organized ${selectedFiles.length} files using AI analysis! 🎉`) } else { // Just show summary const summary = analysisResults.reduce((acc, file) => { acc[file.suggestedCategory] = (acc[file.suggestedCategory] || 0) + 1 return acc }, {} as Record<string, number>) const summaryText = Object.entries(summary) .map(([category, count]) => `- **${category}**: ${count} files`) .join('\n') await div(md(` # Analysis Complete! 📊 ## File Categories Found: ${summaryText} **Total Files Analyzed:** ${analysisResults.length} `)) }