@flexabrain/mcp-server
Version:
Advanced electrical schematic analysis MCP server with rail engineering expertise
230 lines • 9.47 kB
JavaScript
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