| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| const ML_API_URL = process.env.ML_API_URL || 'http://localhost:7860'; |
|
|
| class ALWASMLClient { |
| constructor(baseUrl = ML_API_URL) { |
| this.baseUrl = baseUrl; |
| } |
|
|
| async _post(endpoint, data) { |
| const response = await fetch(`${this.baseUrl}${endpoint}`, { |
| method: 'POST', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify(data), |
| }); |
| if (!response.ok) { |
| throw new Error(`ML API error: ${response.status} ${await response.text()}`); |
| } |
| return response.json(); |
| } |
|
|
| async _get(endpoint) { |
| const response = await fetch(`${this.baseUrl}${endpoint}`); |
| if (!response.ok) { |
| throw new Error(`ML API error: ${response.status}`); |
| } |
| return response.json(); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| async estimateBlock(block) { |
| return this._post('/predict/estimate', block); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| async predictBottleneck(block) { |
| return this._post('/predict/bottleneck', block); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| async predictCompletion(block) { |
| return this._post('/predict/completion', block); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| async bulkEstimate(blocks) { |
| return this._post('/predict/bulk-estimate', { blocks }); |
| } |
|
|
| |
| |
| |
| |
| async getMetrics() { |
| return this._get('/model/metrics'); |
| } |
|
|
| |
| |
| |
| |
| async getSupportedValues() { |
| return this._get('/model/supported-values'); |
| } |
|
|
| |
| |
| |
| |
| async healthCheck() { |
| return this._get('/health'); |
| } |
|
|
| |
| |
| |
| |
| |
| static formatForEstimate(mongoBlock) { |
| return { |
| block_type: mongoBlock.type || mongoBlock.blockType, |
| tech_node: mongoBlock.techNode || mongoBlock.tech_node, |
| priority: mongoBlock.priority || 'P3-Medium', |
| transistor_count: mongoBlock.transistorCount || mongoBlock.transistor_count, |
| has_dependencies: (mongoBlock.dependencies?.length || 0) > 0, |
| num_dependencies: mongoBlock.dependencies?.length || 0, |
| constraint_complexity: mongoBlock.constraintComplexity || 1.0, |
| drc_iterations: mongoBlock.drcIterations || 2, |
| engineer_skill_factor: 1.0, |
| }; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| static formatForBottleneck(mongoBlock, daysSinceLastTransition) { |
| return { |
| block_type: mongoBlock.type || mongoBlock.blockType, |
| tech_node: mongoBlock.techNode || mongoBlock.tech_node, |
| priority: mongoBlock.priority || 'P3-Medium', |
| estimated_hours: mongoBlock.estimatedHours || 20, |
| hours_logged: mongoBlock.hoursLogged || 0, |
| drc_iterations: mongoBlock.drcIterations || 2, |
| drc_violations_total: mongoBlock.drcViolations || 0, |
| lvs_mismatches_total: mongoBlock.lvsMismatches || 0, |
| current_stage: mongoBlock.status, |
| days_in_current_stage: daysSinceLastTransition, |
| engineer_skill_factor: 1.0, |
| is_overdue: mongoBlock.dueDate ? new Date() > new Date(mongoBlock.dueDate) : false, |
| }; |
| } |
|
|
| |
| |
| |
| |
| |
| static formatForCompletion(mongoBlock) { |
| const startDate = new Date(mongoBlock.createdAt || mongoBlock.startDate); |
| const now = new Date(); |
| const daysSinceStart = (now - startDate) / (1000 * 60 * 60 * 24); |
|
|
| return { |
| block_type: mongoBlock.type || mongoBlock.blockType, |
| tech_node: mongoBlock.techNode || mongoBlock.tech_node, |
| priority: mongoBlock.priority || 'P3-Medium', |
| estimated_hours: mongoBlock.estimatedHours || 20, |
| engineer_skill_factor: 1.0, |
| drc_iterations: mongoBlock.drcIterations || 2, |
| current_stage: mongoBlock.status, |
| cumulative_hours: mongoBlock.hoursLogged || 0, |
| cumulative_days: daysSinceStart, |
| cumulative_drc_violations: mongoBlock.drcViolations || 0, |
| cumulative_lvs_mismatches: mongoBlock.lvsMismatches || 0, |
| }; |
| } |
| } |
|
|
| module.exports = new ALWASMLClient(); |
| module.exports.ALWASMLClient = ALWASMLClient; |
|
|