UNPKG

contaigents

Version:

Modular AI Content Ecosystem with Audio Generation

276 lines (266 loc) 10.4 kB
import { FileService } from './fileService.js'; import { LLMFactory } from './llm/LLMFactory.js'; import path from 'path'; export class IntelligentFileService { constructor(baseDir) { this.llm = null; this.fileService = new FileService(baseDir); this.initializeLLM(); } async initializeLLM() { try { this.llm = await LLMFactory.getConfiguredProvider(); if (!this.llm) { console.warn('No LLM provider configured. Intelligent features will be limited.'); } } catch (error) { console.warn('Failed to initialize LLM provider:', error); } } // Basic file operations (delegate to FileService) async readFile(filePath) { return await this.fileService.readFile(filePath); } async saveFile(params) { return await this.fileService.saveFile(params); } async fileExists(filePath) { return await this.fileService.fileExists(filePath); } async listFiles(dirPath) { return await this.fileService.listFiles(dirPath); } async getFileTree() { return await this.fileService.getFileTree(); } // Intelligent file operations async analyzeFile(filePath) { const content = await this.readFile(filePath); const basicMetadata = await this.extractBasicMetadata(filePath, content); if (!this.llm) { return { metadata: basicMetadata, content, analysis: { purpose: 'Unable to analyze - no LLM configured', mainTopics: [], complexity: 'medium', readability: 'moderate' } }; } const analysis = await this.performLLMAnalysis(content, filePath); return { metadata: { ...basicMetadata, summary: analysis.summary, keywords: analysis.keywords }, content, analysis: { purpose: analysis.purpose, mainTopics: analysis.mainTopics, complexity: analysis.complexity, readability: analysis.readability, suggestions: analysis.suggestions } }; } async classifyFile(filePath) { const content = await this.readFile(filePath); if (!this.llm) { return this.basicClassification(filePath, content); } const prompt = `Analyze this file and classify its type and purpose: File: ${filePath} Content: ${content.substring(0, 2000)}${content.length > 2000 ? '...' : ''} Classify this file into one of these categories: - documentation (README, guides, tutorials) - code (source code files) - configuration (config files, settings) - content (blog posts, articles, stories) - data (JSON, CSV, structured data) - template (boilerplate, templates) - test (test files, specs) Respond with just the category name.`; try { const response = await this.llm.executePrompt(prompt); return response.content.toLowerCase().trim(); } catch (error) { console.warn('LLM classification failed, using basic classification:', error); return this.basicClassification(filePath, content); } } async summarizeFile(filePath, maxLength = 200) { const content = await this.readFile(filePath); if (!this.llm) { return content.substring(0, maxLength) + (content.length > maxLength ? '...' : ''); } const prompt = `Summarize the following file content in ${maxLength} characters or less: File: ${filePath} Content: ${content} Provide a concise summary that captures the main purpose and key points of this file.`; try { const response = await this.llm.executePrompt(prompt); return response.content.substring(0, maxLength); } catch (error) { console.warn('LLM summarization failed, using truncation:', error); return content.substring(0, maxLength) + (content.length > maxLength ? '...' : ''); } } async readPartialFile(filePath, operation) { const content = await this.readFile(filePath); const lines = content.split('\n'); if (operation.startLine !== undefined && operation.endLine !== undefined) { const start = Math.max(0, operation.startLine - 1); const end = Math.min(lines.length, operation.endLine); return lines.slice(start, end).join('\n'); } if (operation.section && this.llm) { return await this.extractSection(content, operation.section, filePath); } if (operation.searchPattern) { const matchingLines = lines.filter(line => line.toLowerCase().includes(operation.searchPattern.toLowerCase())); return matchingLines.join('\n'); } return content; } async extractBasicMetadata(filePath, content) { const ext = path.extname(filePath).toLowerCase(); const size = Buffer.byteLength(content, 'utf8'); let contentType = 'unknown'; let language; if (ext === '.md' || ext === '.mdx') { contentType = 'markdown'; } else if (['.js', '.ts', '.py', '.java', '.cpp', '.c', '.go', '.rs'].includes(ext)) { contentType = 'code'; language = ext.substring(1); } else if (['.json', '.yaml', '.yml', '.toml', '.ini'].includes(ext)) { contentType = 'configuration'; } else if (ext === '.txt') { contentType = 'text'; } const structure = this.analyzeStructure(content, contentType); return { path: filePath, size, type: ext, contentType, language, structure, lastAnalyzed: Date.now() }; } analyzeStructure(content, contentType) { const structure = {}; if (contentType === 'markdown') { const headings = content.match(/^#+\s+.+$/gm) || []; structure.headings = headings.map(h => h.replace(/^#+\s+/, '')); structure.sections = headings.length; structure.codeBlocks = (content.match(/```/g) || []).length / 2; structure.links = (content.match(/\[.*?\]\(.*?\)/g) || []).length; } return structure; } basicClassification(filePath, content) { const ext = path.extname(filePath).toLowerCase(); const fileName = path.basename(filePath).toLowerCase(); if (fileName.includes('readme') || fileName.includes('doc')) return 'documentation'; if (fileName.includes('config') || fileName.includes('setting')) return 'configuration'; if (fileName.includes('test') || fileName.includes('spec')) return 'test'; if (['.md', '.mdx'].includes(ext)) return 'content'; if (['.js', '.ts', '.py', '.java'].includes(ext)) return 'code'; if (['.json', '.yaml', '.yml'].includes(ext)) return 'configuration'; return 'unknown'; } async performLLMAnalysis(content, filePath) { const prompt = `Analyze this file and provide structured information: File: ${filePath} Content: ${content.substring(0, 3000)}${content.length > 3000 ? '...' : ''} Please provide analysis in this format: PURPOSE: [What is the main purpose of this file?] TOPICS: [List 3-5 main topics/themes, separated by commas] COMPLEXITY: [low/medium/high - based on technical complexity] READABILITY: [easy/moderate/difficult - based on how easy it is to understand] SUMMARY: [2-3 sentence summary] KEYWORDS: [5-10 relevant keywords, separated by commas] SUGGESTIONS: [2-3 improvement suggestions, separated by semicolons]`; try { const response = await this.llm.executePrompt(prompt); return this.parseLLMAnalysis(response.content); } catch (error) { console.warn('LLM analysis failed:', error); return { purpose: 'Analysis unavailable', mainTopics: [], complexity: 'medium', readability: 'moderate', summary: 'Unable to generate summary', keywords: [], suggestions: [] }; } } parseLLMAnalysis(response) { const lines = response.split('\n'); const result = {}; for (const line of lines) { if (line.startsWith('PURPOSE:')) { result.purpose = line.replace('PURPOSE:', '').trim(); } else if (line.startsWith('TOPICS:')) { result.mainTopics = line.replace('TOPICS:', '').split(',').map(t => t.trim()); } else if (line.startsWith('COMPLEXITY:')) { result.complexity = line.replace('COMPLEXITY:', '').trim().toLowerCase(); } else if (line.startsWith('READABILITY:')) { result.readability = line.replace('READABILITY:', '').trim().toLowerCase(); } else if (line.startsWith('SUMMARY:')) { result.summary = line.replace('SUMMARY:', '').trim(); } else if (line.startsWith('KEYWORDS:')) { result.keywords = line.replace('KEYWORDS:', '').split(',').map(k => k.trim()); } else if (line.startsWith('SUGGESTIONS:')) { result.suggestions = line.replace('SUGGESTIONS:', '').split(';').map(s => s.trim()); } } return result; } async extractSection(content, sectionName, filePath) { if (!this.llm) { return content; } const prompt = `Extract the "${sectionName}" section from this file: File: ${filePath} Content: ${content} Please return only the content of the "${sectionName}" section, without any additional commentary.`; try { const response = await this.llm.executePrompt(prompt); return response.content; } catch (error) { console.warn('Section extraction failed:', error); return content; } } }