contaigents
Version:
Modular AI Content Ecosystem with Audio Generation
276 lines (266 loc) • 10.4 kB
JavaScript
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;
}
}
}