291 lines
9.2 KiB
JavaScript
291 lines
9.2 KiB
JavaScript
|
|
const groqService = require('./groqService');
|
||
|
|
const { Plan, Message, Conversation } = require('../models');
|
||
|
|
const logger = require('../utils/logger');
|
||
|
|
|
||
|
|
class Model1Service {
|
||
|
|
constructor() {
|
||
|
|
this.modelType = 'MODEL1';
|
||
|
|
this.systemPrompt = `You are MODEL1, an expert engineering reasoning system. Your primary function is to analyze complex engineering problems and create detailed, step-by-step plans to solve them.
|
||
|
|
|
||
|
|
Your capabilities include:
|
||
|
|
- Structural engineering analysis
|
||
|
|
- Mechanical engineering design
|
||
|
|
- Electrical engineering systems
|
||
|
|
- Civil engineering projects
|
||
|
|
- Computer Enginnering
|
||
|
|
- Safety and compliance considerations
|
||
|
|
- Cost estimation and feasibility analysis
|
||
|
|
- Risk assessment and mitigation
|
||
|
|
- All other engineering related courses
|
||
|
|
|
||
|
|
When creating plans, always:
|
||
|
|
1. Break down complex problems into clear, actionable steps
|
||
|
|
2. Consider safety, feasibility, and best practices
|
||
|
|
3. Include relevant calculations, standards, and regulations
|
||
|
|
4. Suggest appropriate tools and resources
|
||
|
|
5. Provide time estimates for each step
|
||
|
|
6. Consider potential challenges and mitigation strategies
|
||
|
|
7. DO NOT give the answer, your job is to plan
|
||
|
|
8. Only give plan when the user ask about actionable questions
|
||
|
|
|
||
|
|
Format your response as a structured plan with:
|
||
|
|
- Title: Clear, descriptive title
|
||
|
|
- Description: Brief overview of the problem and approach
|
||
|
|
- Steps: Numbered list of detailed steps
|
||
|
|
- Tools Required: List of tools needed
|
||
|
|
- Estimated Duration: Total time estimate
|
||
|
|
- Complexity Score: 1-10 scale
|
||
|
|
- Safety Considerations: Key safety points
|
||
|
|
- Quality Checks: Verification steps`;
|
||
|
|
}
|
||
|
|
|
||
|
|
async generatePlan(query, context = {}) {
|
||
|
|
try {
|
||
|
|
const startTime = Date.now();
|
||
|
|
|
||
|
|
// Prepare context for the model
|
||
|
|
const enhancedContext = {
|
||
|
|
...context,
|
||
|
|
timestamp: new Date().toISOString(),
|
||
|
|
modelType: this.modelType
|
||
|
|
};
|
||
|
|
|
||
|
|
// Generate the plan using Groq
|
||
|
|
const response = await groqService.generateEngineeringPlan(query, enhancedContext);
|
||
|
|
|
||
|
|
const endTime = Date.now();
|
||
|
|
const processingTime = (endTime - startTime) / 1000;
|
||
|
|
|
||
|
|
// Parse the response to extract structured plan data
|
||
|
|
const planData = this.parsePlanResponse(response.content);
|
||
|
|
|
||
|
|
logger.info(`MODEL1 plan generated in ${processingTime}s for query: ${query.substring(0, 100)}...`);
|
||
|
|
|
||
|
|
return {
|
||
|
|
...planData,
|
||
|
|
processingTime,
|
||
|
|
tokensUsed: response.usage.total_tokens,
|
||
|
|
model: response.model,
|
||
|
|
finishReason: response.finishReason
|
||
|
|
};
|
||
|
|
} catch (error) {
|
||
|
|
logger.error('MODEL1 plan generation error:', error);
|
||
|
|
throw new Error(`MODEL1 plan generation failed: ${error.message}`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
parsePlanResponse(content) {
|
||
|
|
try {
|
||
|
|
// Extract structured data from the response
|
||
|
|
const lines = content.split('\n');
|
||
|
|
let title = '';
|
||
|
|
let description = '';
|
||
|
|
let steps = [];
|
||
|
|
let toolsRequired = [];
|
||
|
|
let estimatedDuration = 0;
|
||
|
|
let complexityScore = 5;
|
||
|
|
let safetyConsiderations = [];
|
||
|
|
let qualityChecks = [];
|
||
|
|
|
||
|
|
let currentSection = '';
|
||
|
|
|
||
|
|
for (const line of lines) {
|
||
|
|
const trimmedLine = line.trim();
|
||
|
|
|
||
|
|
if (trimmedLine.toLowerCase().includes('title:')) {
|
||
|
|
title = trimmedLine.split(':')[1]?.trim() || 'Engineering Plan';
|
||
|
|
} else if (trimmedLine.toLowerCase().includes('description:')) {
|
||
|
|
description = trimmedLine.split(':')[1]?.trim() || '';
|
||
|
|
} else if (trimmedLine.toLowerCase().includes('steps:')) {
|
||
|
|
currentSection = 'steps';
|
||
|
|
} else if (trimmedLine.toLowerCase().includes('tools required:')) {
|
||
|
|
currentSection = 'tools';
|
||
|
|
} else if (trimmedLine.toLowerCase().includes('estimated duration:')) {
|
||
|
|
const duration = trimmedLine.split(':')[1]?.trim();
|
||
|
|
estimatedDuration = this.parseDuration(duration);
|
||
|
|
} else if (trimmedLine.toLowerCase().includes('complexity score:')) {
|
||
|
|
const score = trimmedLine.split(':')[1]?.trim();
|
||
|
|
complexityScore = parseInt(score) || 5;
|
||
|
|
} else if (trimmedLine.toLowerCase().includes('safety considerations:')) {
|
||
|
|
currentSection = 'safety';
|
||
|
|
} else if (trimmedLine.toLowerCase().includes('quality checks:')) {
|
||
|
|
currentSection = 'quality';
|
||
|
|
} else if (trimmedLine.match(/^\d+\./)) {
|
||
|
|
if (currentSection === 'steps') {
|
||
|
|
steps.push(trimmedLine);
|
||
|
|
}
|
||
|
|
} else if (trimmedLine.startsWith('-')) {
|
||
|
|
if (currentSection === 'tools') {
|
||
|
|
toolsRequired.push(trimmedLine.substring(1).trim());
|
||
|
|
} else if (currentSection === 'safety') {
|
||
|
|
safetyConsiderations.push(trimmedLine.substring(1).trim());
|
||
|
|
} else if (currentSection === 'quality') {
|
||
|
|
qualityChecks.push(trimmedLine.substring(1).trim());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// If no structured data found, create a basic plan
|
||
|
|
if (!title) {
|
||
|
|
title = 'Engineering Plan';
|
||
|
|
description = content.substring(0, 200) + '...';
|
||
|
|
steps = [content];
|
||
|
|
}
|
||
|
|
|
||
|
|
return {
|
||
|
|
title,
|
||
|
|
description,
|
||
|
|
steps,
|
||
|
|
toolsRequired,
|
||
|
|
estimatedDuration,
|
||
|
|
complexityScore,
|
||
|
|
safetyConsiderations,
|
||
|
|
qualityChecks,
|
||
|
|
rawContent: content
|
||
|
|
};
|
||
|
|
} catch (error) {
|
||
|
|
logger.error('Error parsing plan response:', error);
|
||
|
|
return {
|
||
|
|
title: 'Engineering Plan',
|
||
|
|
description: content,
|
||
|
|
steps: [content],
|
||
|
|
toolsRequired: [],
|
||
|
|
estimatedDuration: 60,
|
||
|
|
complexityScore: 5,
|
||
|
|
safetyConsiderations: [],
|
||
|
|
qualityChecks: [],
|
||
|
|
rawContent: content
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
parseDuration(duration) {
|
||
|
|
if (!duration) return 60;
|
||
|
|
|
||
|
|
const match = duration.match(/(\d+)\s*(hour|hr|minute|min|day|d)/i);
|
||
|
|
if (match) {
|
||
|
|
const value = parseInt(match[1]);
|
||
|
|
const unit = match[2].toLowerCase();
|
||
|
|
|
||
|
|
switch (unit) {
|
||
|
|
case 'hour':
|
||
|
|
case 'hr':
|
||
|
|
return value * 60;
|
||
|
|
case 'minute':
|
||
|
|
case 'min':
|
||
|
|
return value;
|
||
|
|
case 'day':
|
||
|
|
case 'd':
|
||
|
|
return value * 24 * 60;
|
||
|
|
default:
|
||
|
|
return 60;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return 60; // Default to 60 minutes
|
||
|
|
}
|
||
|
|
|
||
|
|
async savePlan(planData, conversationId, userId) {
|
||
|
|
try {
|
||
|
|
const plan = await Plan.create({
|
||
|
|
conversation_id: conversationId,
|
||
|
|
title: planData.title,
|
||
|
|
description: planData.description,
|
||
|
|
steps: planData.steps,
|
||
|
|
status: 'draft',
|
||
|
|
tools_required: planData.toolsRequired,
|
||
|
|
estimated_duration: planData.estimatedDuration,
|
||
|
|
complexity_score: planData.complexityScore,
|
||
|
|
metadata: {
|
||
|
|
safetyConsiderations: planData.safetyConsiderations,
|
||
|
|
qualityChecks: planData.qualityChecks,
|
||
|
|
processingTime: planData.processingTime,
|
||
|
|
tokensUsed: planData.tokensUsed,
|
||
|
|
model: planData.model
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// Create a message record for the plan
|
||
|
|
await Message.create({
|
||
|
|
conversation_id: conversationId,
|
||
|
|
plan_id: plan.id,
|
||
|
|
role: 'assistant',
|
||
|
|
content: planData.rawContent,
|
||
|
|
message_type: 'plan',
|
||
|
|
metadata: {
|
||
|
|
modelType: this.modelType,
|
||
|
|
processingTime: planData.processingTime,
|
||
|
|
tokensUsed: planData.tokensUsed
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
logger.info(`Plan saved: ${plan.id} for conversation: ${conversationId}`);
|
||
|
|
|
||
|
|
return plan;
|
||
|
|
} catch (error) {
|
||
|
|
logger.error('Error saving plan:', error);
|
||
|
|
throw new Error(`Failed to save plan: ${error.message}`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async validatePlan(planId, feedback = []) {
|
||
|
|
try {
|
||
|
|
const plan = await Plan.findByPk(planId);
|
||
|
|
if (!plan) {
|
||
|
|
throw new Error('Plan not found');
|
||
|
|
}
|
||
|
|
|
||
|
|
const validationResponse = await groqService.validatePlan(plan.description, feedback);
|
||
|
|
|
||
|
|
// Update plan with validation results
|
||
|
|
await plan.update({
|
||
|
|
status: validationResponse.content.includes('valid') ? 'approved' : 'rejected',
|
||
|
|
approval_feedback: validationResponse.content,
|
||
|
|
metadata: {
|
||
|
|
...plan.metadata,
|
||
|
|
validation: {
|
||
|
|
response: validationResponse.content,
|
||
|
|
tokensUsed: validationResponse.usage.total_tokens,
|
||
|
|
processingTime: validationResponse.processingTime
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
logger.info(`Plan validated: ${planId}, status: ${plan.status}`);
|
||
|
|
|
||
|
|
return {
|
||
|
|
plan,
|
||
|
|
validation: validationResponse
|
||
|
|
};
|
||
|
|
} catch (error) {
|
||
|
|
logger.error('Plan validation error:', error);
|
||
|
|
throw new Error(`Plan validation failed: ${error.message}`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async getModelStatus() {
|
||
|
|
try {
|
||
|
|
const groqInfo = await groqService.getModelInfo();
|
||
|
|
const connectionTest = await groqService.testConnection();
|
||
|
|
|
||
|
|
return {
|
||
|
|
modelType: this.modelType,
|
||
|
|
status: connectionTest.success ? 'active' : 'error',
|
||
|
|
groqInfo,
|
||
|
|
connectionTest,
|
||
|
|
lastChecked: new Date().toISOString()
|
||
|
|
};
|
||
|
|
} catch (error) {
|
||
|
|
logger.error('MODEL1 status check error:', error);
|
||
|
|
return {
|
||
|
|
modelType: this.modelType,
|
||
|
|
status: 'error',
|
||
|
|
error: error.message,
|
||
|
|
lastChecked: new Date().toISOString()
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
module.exports = new Model1Service();
|