UNPKG

@flexabrain/mcp-server

Version:

Advanced electrical schematic analysis MCP server with rail engineering expertise

230 lines 9.47 kB
import { electricalSchematicAnalyzer } from '../services/electrical-analyzer.js'; /** * MCP Tool: Extract Component Inventory * * Extracts and catalogs all electrical components from a schematic image * without performing full analysis. Optimized for inventory management * and component tracking in rail electrical systems. */ export async function extractComponentInventory(args) { try { // Configure analysis for component extraction only const analysisOptions = { analysis_depth: 'basic', focus_areas: ['performance'], // Minimal analysis for speed ...(args.component_types && { component_filter: args.component_types }) }; // Perform analysis with focus on component detection const analysisResult = await electricalSchematicAnalyzer.analyzeSchematic(args.image_path, analysisOptions); if (!analysisResult.success || !analysisResult.analysis) { throw new Error('Analysis failed: ' + (analysisResult.errors?.[0]?.message || 'Unknown error')); } const analysis = analysisResult.analysis; // Filter components by confidence threshold const confidenceThreshold = args.confidence_threshold || 0.5; const filteredComponents = analysis.components.filter((component) => component.confidence >= confidenceThreshold); // Sort components by type and confidence const sortedComponents = filteredComponents.sort((a, b) => { if (a.type !== b.type) { return a.type.localeCompare(b.type); } return b.confidence - a.confidence; // Higher confidence first }); // Format output based on requested format const format = args.export_format || 'markdown'; switch (format) { case 'json': return formatAsJSON(sortedComponents, args.include_specifications); case 'csv': return formatAsCSV(sortedComponents, args.include_specifications); case 'markdown': default: return formatAsMarkdown(sortedComponents, args.include_specifications); } } catch (error) { return `❌ **Error extracting component inventory**\n\nError: ${error instanceof Error ? error.message : String(error)}`; } } /** * Format component inventory as JSON */ function formatAsJSON(components, includeSpecs) { const inventory = { metadata: { total_components: components.length, extraction_timestamp: new Date().toISOString(), component_types: [...new Set(components.map(c => c.type))].length }, components: components.map(component => ({ id: component.id, type: component.type, confidence: component.confidence, location: component.location, safety_level: component.safety_level, ...(includeSpecs && component.specifications && { specifications: component.specifications }) })) }; return '```json\n' + JSON.stringify(inventory, null, 2) + '\n```'; } /** * Format component inventory as CSV */ function formatAsCSV(components, includeSpecs) { let csv = 'ID,Type,Confidence,X,Y,Width,Height,Safety Level'; if (includeSpecs) { csv += ',Voltage Rating,Current Rating,Power Rating,Manufacturer,Model'; } csv += '\n'; for (const component of components) { const location = component.location; let row = [ component.id, component.type, (component.confidence * 100).toFixed(1) + '%', location.x.toString(), location.y.toString(), location.width.toString(), location.height.toString(), component.safety_level ]; if (includeSpecs && component.specifications) { const specs = component.specifications; row.push(specs.voltage_rating ? `${specs.voltage_rating.max}${specs.voltage_rating.unit}` : '', specs.current_rating ? `${specs.current_rating.max}${specs.current_rating.unit}` : '', specs.power_rating ? `${specs.power_rating.max}${specs.power_rating.unit}` : '', '', // Manufacturer placeholder '' // Model placeholder ); } csv += row.map(field => `"${field}"`).join(',') + '\n'; } return '```csv\n' + csv + '\n```'; } /** * Format component inventory as Markdown */ function formatAsMarkdown(components, includeSpecs) { let output = '# 📋 Electrical Component Inventory\n\n'; // Summary statistics const stats = generateInventoryStats(components); output += '## 📊 Inventory Summary\n\n'; output += `- **Total Components**: ${stats.total}\n`; output += `- **Component Types**: ${stats.types}\n`; output += `- **Average Confidence**: ${stats.avgConfidence}%\n`; output += `- **High Confidence (>80%)**: ${stats.highConfidence}\n`; output += `- **Safety Critical Components**: ${stats.safetyCritical}\n\n`; // Component breakdown by type output += '## 🔧 Component Breakdown\n\n'; const componentsByType = groupComponentsByType(components); for (const [type, typeComponents] of Object.entries(componentsByType)) { const components = typeComponents; output += `### ${formatComponentType(type)} (${components.length})\n\n`; if (includeSpecs) { output += '| ID | Confidence | Location | Safety | Specifications |\n'; output += '|---|---|---|---|---|\n'; for (const component of components) { const specs = formatSpecifications(component); output += `| ${component.id} | ${(component.confidence * 100).toFixed(1)}% | `; output += `(${component.location.x},${component.location.y}) | `; output += `${getSafetyIcon(component.safety_level)} | ${specs} |\n`; } } else { output += '| ID | Confidence | Location | Safety Level |\n'; output += '|---|---|---|---|\n'; for (const component of components) { output += `| ${component.id} | ${(component.confidence * 100).toFixed(1)}% | `; output += `(${component.location.x},${component.location.y}) | `; output += `${getSafetyIcon(component.safety_level)} ${component.safety_level} |\n`; } } output += '\n'; } // Component distribution chart (text-based) output += '## 📈 Component Distribution\n\n'; const distribution = generateDistributionChart(componentsByType); output += distribution + '\n'; return output; } /** * Generate inventory statistics */ function generateInventoryStats(components) { const total = components.length; const types = new Set(components.map(c => c.type)).size; const avgConfidence = Math.round(components.reduce((sum, c) => sum + c.confidence, 0) / total * 100); const highConfidence = components.filter(c => c.confidence > 0.8).length; const safetyCritical = components.filter(c => ['CRITICAL', 'HIGH'].includes(c.safety_level)).length; return { total, types, avgConfidence, highConfidence, safetyCritical }; } /** * Group components by type */ function groupComponentsByType(components) { return components.reduce((acc, component) => { const type = component.type; if (!acc[type]) acc[type] = []; acc[type].push(component); return acc; }, {}); } /** * Format component type for display */ function formatComponentType(type) { return type.split('_') .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) .join(' '); } /** * Format component specifications for display */ function formatSpecifications(component) { if (!component.specifications) return 'N/A'; const specs = component.specifications; const parts = []; if (specs.voltage_rating) { parts.push(`${specs.voltage_rating.max}${specs.voltage_rating.unit}`); } if (specs.current_rating) { parts.push(`${specs.current_rating.max}${specs.current_rating.unit}`); } if (specs.power_rating) { parts.push(`${specs.power_rating.max}${specs.power_rating.unit}`); } return parts.length > 0 ? parts.join(', ') : 'N/A'; } /** * Get safety icon for component */ function getSafetyIcon(safetyLevel) { switch (safetyLevel) { case 'CRITICAL': return '🔴'; case 'HIGH': return '🟠'; case 'MEDIUM': return '🟡'; case 'LOW': return '🟢'; default: return '⚪'; } } /** * Generate text-based distribution chart */ function generateDistributionChart(componentsByType) { const maxCount = Math.max(...Object.values(componentsByType).map(arr => arr.length)); const maxBarLength = 20; let chart = '```\n'; for (const [type, components] of Object.entries(componentsByType)) { const count = components.length; const barLength = Math.round((count / maxCount) * maxBarLength); const bar = '█'.repeat(barLength) + '░'.repeat(maxBarLength - barLength); const formattedType = formatComponentType(type).padEnd(15); chart += `${formattedType} |${bar}| ${count}\n`; } chart += '```'; return chart; } //# sourceMappingURL=extract-component-inventory.js.map