UNPKG

contaigents

Version:

Modular AI Content Ecosystem with Audio Generation

416 lines (409 loc) 17.9 kB
import { BaseTool } from '../base/BaseTool.js'; import { IntelligentFileService } from '../../services/IntelligentFileService.js'; import path from 'path'; export class ClassifyFileTool extends BaseTool { constructor(context) { super('classify_file', 'Intelligently classify files by type, purpose, audience, and relationships using AI analysis', context); // Predefined classification categories this.defaultCategories = [ 'documentation', 'code', 'configuration', 'content', 'data', 'template', 'test', 'build', 'deployment', 'security' ]; this.contentTypes = [ 'technical', 'creative', 'documentation', 'configuration', 'data', 'mixed' ]; this.complexityLevels = [ 'beginner', 'intermediate', 'advanced', 'expert' ]; this.intelligentFileService = new IntelligentFileService(context.workingDirectory); } async execute(params) { try { const { filePath, includeRelationships = false, includeConfidence = true, customCategories = [] } = params; if (!filePath) { return this.createErrorResult('File path is required'); } // Check if file exists const exists = await this.intelligentFileService.fileExists(filePath); if (!exists) { return this.createErrorResult(`File not found: ${filePath}`); } const content = await this.intelligentFileService.readFile(filePath); const classification = await this.performClassification(filePath, content, [...this.defaultCategories, ...customCategories]); if (includeRelationships) { classification.relationships = await this.analyzeFileRelationships(filePath, content); } if (!includeConfidence) { const { confidence, ...classificationWithoutConfidence } = classification; if (classification.relationships) { classification.relationships = classification.relationships.map(rel => { const { confidence: relConfidence, ...relWithoutConfidence } = rel; return relWithoutConfidence; }); } Object.assign(classification, classificationWithoutConfidence); } return this.createSuccessResult(classification, { timestamp: Date.now(), includeRelationships, includeConfidence, categoriesUsed: [...this.defaultCategories, ...customCategories] }); } catch (error) { return this.createErrorResult(`Classification failed: ${error instanceof Error ? error.message : 'Unknown error'}`); } } async performClassification(filePath, content, categories) { const basicClassification = this.performBasicClassification(filePath, content); if (!this.context.llm) { return { ...basicClassification, confidence: 0.6, // Lower confidence for basic classification metadata: { ...basicClassification.metadata, lastClassified: Date.now() } }; } const aiClassification = await this.performAIClassification(filePath, content, categories); // Merge basic and AI classifications return { filePath, primaryCategory: aiClassification.primaryCategory || basicClassification.primaryCategory, secondaryCategories: [ ...new Set([...basicClassification.secondaryCategories, ...(aiClassification.secondaryCategories || [])]) ], purpose: aiClassification.purpose || basicClassification.purpose, audience: aiClassification.audience || basicClassification.audience, contentType: aiClassification.contentType || basicClassification.contentType, complexity: aiClassification.complexity || basicClassification.complexity, confidence: aiClassification.confidence || 0.8, tags: [...new Set([...basicClassification.tags, ...(aiClassification.tags || [])])], metadata: { ...basicClassification.metadata, ...aiClassification.metadata, lastClassified: Date.now() } }; } performBasicClassification(filePath, content) { const ext = path.extname(filePath).toLowerCase(); const fileName = path.basename(filePath).toLowerCase(); const lines = content.split('\n'); let primaryCategory = 'unknown'; const secondaryCategories = []; const tags = []; // File extension-based classification if (['.md', '.mdx', '.txt', '.rst'].includes(ext)) { primaryCategory = 'documentation'; if (fileName.includes('readme')) secondaryCategories.push('readme'); if (fileName.includes('guide')) secondaryCategories.push('guide'); if (fileName.includes('tutorial')) secondaryCategories.push('tutorial'); } else if (['.js', '.ts', '.py', '.java', '.cpp', '.c', '.go', '.rs', '.php'].includes(ext)) { primaryCategory = 'code'; if (fileName.includes('test') || fileName.includes('spec')) { primaryCategory = 'test'; secondaryCategories.push('unit-test'); } if (fileName.includes('config')) secondaryCategories.push('configuration'); } else if (['.json', '.yaml', '.yml', '.toml', '.ini', '.env'].includes(ext)) { primaryCategory = 'configuration'; if (fileName.includes('package')) secondaryCategories.push('dependencies'); if (fileName.includes('docker')) secondaryCategories.push('containerization'); } else if (['.csv', '.xml', '.sql'].includes(ext)) { primaryCategory = 'data'; } // Content-based classification const contentLower = content.toLowerCase(); // Detect frameworks and technologies const frameworks = { 'react': /import.*react|from ['"]react['"]/i, 'vue': /import.*vue|from ['"]vue['"]/i, 'angular': /@angular|import.*@angular/i, 'express': /import.*express|require\(['"]express['"]\)/i, 'django': /from django|import django/i, 'flask': /from flask|import flask/i, 'spring': /@spring|import.*springframework/i }; for (const [framework, pattern] of Object.entries(frameworks)) { if (pattern.test(content)) { tags.push(framework); } } // Determine content type let contentType = 'mixed'; if (primaryCategory === 'code') contentType = 'technical'; else if (primaryCategory === 'documentation') contentType = 'documentation'; else if (primaryCategory === 'configuration') contentType = 'configuration'; else if (primaryCategory === 'data') contentType = 'data'; else if (content.includes('story') || content.includes('narrative')) contentType = 'creative'; // Determine complexity let complexity = 'intermediate'; const complexityIndicators = { beginner: ['hello world', 'getting started', 'introduction', 'basic'], intermediate: ['tutorial', 'guide', 'example'], advanced: ['optimization', 'performance', 'architecture', 'design pattern'], expert: ['internals', 'deep dive', 'advanced concepts', 'research'] }; for (const [level, indicators] of Object.entries(complexityIndicators)) { if (indicators.some(indicator => contentLower.includes(indicator))) { complexity = level; break; } } // Determine audience let audience = 'general'; if (contentLower.includes('developer') || contentLower.includes('programmer')) audience = 'developers'; else if (contentLower.includes('user') || contentLower.includes('end-user')) audience = 'end-users'; else if (contentLower.includes('admin') || contentLower.includes('administrator')) audience = 'administrators'; else if (contentLower.includes('beginner') || contentLower.includes('newcomer')) audience = 'beginners'; return { filePath, primaryCategory, secondaryCategories, purpose: this.inferPurpose(fileName, content, primaryCategory), audience, contentType, complexity, tags, metadata: { language: this.detectLanguage(ext, content), framework: tags.length > 0 ? tags[0] : undefined, domain: this.inferDomain(content), lastClassified: 0 // Will be set by caller } }; } async performAIClassification(filePath, content, categories) { const prompt = `Classify this file comprehensively: File: ${filePath} Content: ${content.substring(0, 3000)}${content.length > 3000 ? '...' : ''} Available categories: ${categories.join(', ')} Content types: ${this.contentTypes.join(', ')} Complexity levels: ${this.complexityLevels.join(', ')} Please provide classification in this format: PRIMARY_CATEGORY: [choose from available categories] SECONDARY_CATEGORIES: [comma-separated list of relevant secondary categories] PURPOSE: [what is this file's main purpose?] AUDIENCE: [who is the intended audience?] CONTENT_TYPE: [choose from content types] COMPLEXITY: [choose from complexity levels] CONFIDENCE: [0.0-1.0 confidence score] TAGS: [comma-separated relevant tags/keywords] LANGUAGE: [programming language if applicable] FRAMEWORK: [framework/library if applicable] DOMAIN: [application domain/field]`; try { const response = await this.context.llm.executePrompt(prompt); return this.parseAIClassification(response.content); } catch (error) { console.warn('AI classification failed:', error); return {}; } } parseAIClassification(response) { const lines = response.split('\n'); const result = {}; for (const line of lines) { const [key, ...valueParts] = line.split(':'); const value = valueParts.join(':').trim(); switch (key.trim().toUpperCase()) { case 'PRIMARY_CATEGORY': result.primaryCategory = value.toLowerCase(); break; case 'SECONDARY_CATEGORIES': result.secondaryCategories = value.split(',').map(s => s.trim().toLowerCase()); break; case 'PURPOSE': result.purpose = value; break; case 'AUDIENCE': result.audience = value.toLowerCase(); break; case 'CONTENT_TYPE': result.contentType = value.toLowerCase(); break; case 'COMPLEXITY': result.complexity = value.toLowerCase(); break; case 'CONFIDENCE': result.confidence = parseFloat(value) || 0.5; break; case 'TAGS': result.tags = value.split(',').map(s => s.trim().toLowerCase()); break; case 'LANGUAGE': if (!result.metadata) result.metadata = {}; result.metadata.language = value.toLowerCase(); break; case 'FRAMEWORK': if (!result.metadata) result.metadata = {}; result.metadata.framework = value.toLowerCase(); break; case 'DOMAIN': if (!result.metadata) result.metadata = {}; result.metadata.domain = value.toLowerCase(); break; } } return result; } async analyzeFileRelationships(filePath, content) { const relationships = []; // Basic pattern matching for imports and references const patterns = { imports: [ /import\s+.*\s+from\s+['"]([^'"]+)['"]/g, /require\(['"]([^'"]+)['"]\)/g, /#include\s*[<"]([^>"]+)[>"]/g ], references: [ /\[.*?\]\(([^)]+\.md[^)]*)\)/g, // Markdown links /href=['"]([^'"]+\.html?[^'"]*)['"]/g, // HTML links /src=['"]([^'"]+)['"]/g // Source references ] }; for (const [type, patternList] of Object.entries(patterns)) { for (const pattern of patternList) { let match; while ((match = pattern.exec(content)) !== null) { relationships.push({ type: type, targetFile: match[1], description: `${type} relationship detected`, confidence: 0.8 }); } } } // AI-enhanced relationship analysis if LLM is available if (this.context.llm && relationships.length < 5) { const aiRelationships = await this.analyzeRelationshipsWithAI(filePath, content); relationships.push(...aiRelationships); } return relationships; } async analyzeRelationshipsWithAI(filePath, content) { const prompt = `Analyze file relationships in this content: File: ${filePath} Content: ${content.substring(0, 2000)}${content.length > 2000 ? '...' : ''} Identify relationships to other files, modules, or resources. For each relationship, provide: RELATIONSHIP: [type]|[target]|[description]|[confidence 0.0-1.0] Types: imports, references, extends, includes, links-to, depends-on`; try { const response = await this.context.llm.executePrompt(prompt); return this.parseAIRelationships(response.content); } catch (error) { return []; } } parseAIRelationships(response) { const relationships = []; const lines = response.split('\n'); for (const line of lines) { if (line.startsWith('RELATIONSHIP:')) { const parts = line.replace('RELATIONSHIP:', '').split('|'); if (parts.length >= 3) { relationships.push({ type: parts[0].trim(), targetFile: parts[1].trim(), description: parts[2].trim(), confidence: parseFloat(parts[3]) || 0.5 }); } } } return relationships; } inferPurpose(fileName, content, category) { const contentLower = content.toLowerCase(); if (fileName.includes('readme')) return 'Project documentation and setup instructions'; if (fileName.includes('config')) return 'Configuration settings and parameters'; if (fileName.includes('test')) return 'Testing and quality assurance'; if (fileName.includes('index')) return 'Entry point or main module'; if (category === 'documentation') { if (contentLower.includes('api')) return 'API documentation'; if (contentLower.includes('tutorial')) return 'Educational tutorial'; if (contentLower.includes('guide')) return 'User guide or manual'; return 'General documentation'; } if (category === 'code') { if (contentLower.includes('class')) return 'Class definition and implementation'; if (contentLower.includes('function')) return 'Function definitions and utilities'; if (contentLower.includes('component')) return 'UI component implementation'; return 'Source code implementation'; } return 'General purpose file'; } detectLanguage(ext, content) { const languageMap = { '.js': 'javascript', '.ts': 'typescript', '.py': 'python', '.java': 'java', '.cpp': 'cpp', '.c': 'c', '.go': 'go', '.rs': 'rust', '.php': 'php', '.rb': 'ruby', '.swift': 'swift', '.kt': 'kotlin' }; return languageMap[ext]; } inferDomain(content) { const domains = { 'web-development': ['html', 'css', 'javascript', 'react', 'vue', 'angular'], 'data-science': ['pandas', 'numpy', 'matplotlib', 'tensorflow', 'pytorch'], 'mobile-development': ['android', 'ios', 'react-native', 'flutter'], 'devops': ['docker', 'kubernetes', 'jenkins', 'terraform'], 'machine-learning': ['sklearn', 'keras', 'neural', 'model'], 'backend-development': ['api', 'server', 'database', 'microservice'] }; const contentLower = content.toLowerCase(); for (const [domain, keywords] of Object.entries(domains)) { if (keywords.some(keyword => contentLower.includes(keyword))) { return domain; } } return undefined; } }