first commit
This commit is contained in:
@@ -0,0 +1,356 @@
|
||||
const { Conversation, Message, Plan, User } = require('../models');
|
||||
const logger = require('../utils/logger');
|
||||
const model1Service = require('../services/model1Service');
|
||||
const chatRouter = require('../services/chatRouter');
|
||||
|
||||
const createConversation = async (req, res) => {
|
||||
try {
|
||||
const { title } = req.body;
|
||||
const userId = req.user.userId;
|
||||
|
||||
const conversation = await Conversation.create({
|
||||
user_id: userId,
|
||||
title: title || 'New Conversation',
|
||||
status: 'active'
|
||||
});
|
||||
|
||||
logger.info(`New conversation created: ${conversation.id}`);
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
data: { conversation }
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Create conversation error:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Internal server error'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const getConversations = async (req, res) => {
|
||||
try {
|
||||
const userId = req.user.userId;
|
||||
const { page = 1, limit = 10, status } = req.query;
|
||||
|
||||
const whereClause = { user_id: userId };
|
||||
if (status) whereClause.status = status;
|
||||
|
||||
const conversations = await Conversation.findAndCountAll({
|
||||
where: whereClause,
|
||||
include: [
|
||||
{
|
||||
model: Message,
|
||||
limit: 1,
|
||||
order: [['created_at', 'DESC']]
|
||||
}
|
||||
],
|
||||
order: [['created_at', 'DESC']],
|
||||
limit: parseInt(limit),
|
||||
offset: (parseInt(page) - 1) * parseInt(limit)
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
conversations: conversations.rows,
|
||||
pagination: {
|
||||
page: parseInt(page),
|
||||
limit: parseInt(limit),
|
||||
total: conversations.count,
|
||||
pages: Math.ceil(conversations.count / limit)
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Get conversations error:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Internal server error'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const getConversation = async (req, res) => {
|
||||
try {
|
||||
const { conversationId } = req.params;
|
||||
const userId = req.user.userId;
|
||||
|
||||
const conversation = await Conversation.findOne({
|
||||
where: {
|
||||
id: conversationId,
|
||||
user_id: userId
|
||||
},
|
||||
include: [
|
||||
{
|
||||
model: Message,
|
||||
order: [['created_at', 'ASC']]
|
||||
},
|
||||
{
|
||||
model: Plan,
|
||||
order: [['created_at', 'DESC']]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
if (!conversation) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
error: 'Conversation not found'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: { conversation }
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Get conversation error:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Internal server error'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const sendMessage = async (req, res) => {
|
||||
try {
|
||||
const { conversationId, content, messageType = 'text' } = req.body;
|
||||
const userId = req.user.userId;
|
||||
|
||||
// Verify conversation belongs to user
|
||||
const conversation = await Conversation.findOne({
|
||||
where: {
|
||||
id: conversationId,
|
||||
user_id: userId
|
||||
}
|
||||
});
|
||||
|
||||
if (!conversation) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
error: 'Conversation not found'
|
||||
});
|
||||
}
|
||||
|
||||
// Create user message
|
||||
const userMessage = await Message.create({
|
||||
conversation_id: conversationId,
|
||||
role: 'user',
|
||||
content,
|
||||
message_type: messageType
|
||||
});
|
||||
|
||||
// Get conversation history for context
|
||||
const conversationHistory = await Message.findAll({
|
||||
where: { conversation_id: conversationId },
|
||||
order: [['created_at', 'DESC']],
|
||||
limit: 20 // Last 20 messages for context
|
||||
});
|
||||
|
||||
// Create properly ordered conversation history for context
|
||||
const orderedHistory = conversationHistory.reverse().map(msg => ({
|
||||
role: msg.role,
|
||||
content: msg.content,
|
||||
message_type: msg.message_type,
|
||||
timestamp: msg.created_at
|
||||
}));
|
||||
|
||||
// Route the message to determine response type
|
||||
const routingDecision = await chatRouter.routeMessage(content, {
|
||||
conversationId,
|
||||
userId,
|
||||
timestamp: new Date().toISOString(),
|
||||
conversationHistory: orderedHistory
|
||||
});
|
||||
|
||||
let assistantMessage;
|
||||
|
||||
if (routingDecision.responseType === 'plan_needed' && routingDecision.isEngineeringQuestion) {
|
||||
// Generate engineering plan using MODEL1
|
||||
try {
|
||||
const planData = await model1Service.generatePlan(content, {
|
||||
conversationId,
|
||||
userId,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
// Save the plan to database
|
||||
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 assistant message with plan
|
||||
assistantMessage = await Message.create({
|
||||
conversation_id: conversationId,
|
||||
plan_id: plan.id,
|
||||
role: 'assistant',
|
||||
content: planData.rawContent || `# ${planData.title}\n\n${planData.description}\n\n## Steps:\n${planData.steps.map((step, index) => `${index + 1}. ${step}`).join('\n')}`,
|
||||
message_type: 'plan',
|
||||
metadata: {
|
||||
modelType: 'MODEL1',
|
||||
processingTime: planData.processingTime,
|
||||
tokensUsed: planData.tokensUsed,
|
||||
routingDecision: routingDecision.reasoning
|
||||
}
|
||||
});
|
||||
|
||||
logger.info(`MODEL1 plan generated: ${plan.id} for conversation: ${conversationId}`);
|
||||
} catch (error) {
|
||||
logger.error('MODEL1 plan generation failed:', error);
|
||||
|
||||
// Fallback to simple response if plan generation fails
|
||||
const fallbackResponse = await chatRouter.generateSimpleResponse(content, {
|
||||
conversationHistory: orderedHistory
|
||||
});
|
||||
assistantMessage = await Message.create({
|
||||
conversation_id: conversationId,
|
||||
role: 'assistant',
|
||||
content: fallbackResponse,
|
||||
message_type: 'text',
|
||||
metadata: {
|
||||
error: error.message,
|
||||
modelType: 'FALLBACK',
|
||||
routingDecision: routingDecision.reasoning
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Generate simple conversational response
|
||||
const responseContent = routingDecision.response || await chatRouter.generateSimpleResponse(content, {
|
||||
conversationHistory: orderedHistory
|
||||
});
|
||||
|
||||
assistantMessage = await Message.create({
|
||||
conversation_id: conversationId,
|
||||
role: 'assistant',
|
||||
content: responseContent,
|
||||
message_type: 'text',
|
||||
metadata: {
|
||||
modelType: 'REASONAI',
|
||||
routingDecision: routingDecision.reasoning,
|
||||
responseType: routingDecision.responseType
|
||||
}
|
||||
});
|
||||
|
||||
logger.info(`Simple response generated for conversation: ${conversationId}`, {
|
||||
responseType: routingDecision.responseType,
|
||||
reasoning: routingDecision.reasoning
|
||||
});
|
||||
}
|
||||
|
||||
logger.info(`Message sent in conversation: ${conversationId}`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: { userMessage, assistantMessage }
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Send message error:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Internal server error'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const updateConversation = async (req, res) => {
|
||||
try {
|
||||
const { conversationId } = req.params;
|
||||
const { title, status } = req.body;
|
||||
const userId = req.user.userId;
|
||||
|
||||
const conversation = await Conversation.findOne({
|
||||
where: {
|
||||
id: conversationId,
|
||||
user_id: userId
|
||||
}
|
||||
});
|
||||
|
||||
if (!conversation) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
error: 'Conversation not found'
|
||||
});
|
||||
}
|
||||
|
||||
const updateData = {};
|
||||
if (title) updateData.title = title;
|
||||
if (status) updateData.status = status;
|
||||
|
||||
await conversation.update(updateData);
|
||||
|
||||
logger.info(`Conversation updated: ${conversationId}`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: { conversation }
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Update conversation error:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Internal server error'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const deleteConversation = async (req, res) => {
|
||||
try {
|
||||
const { conversationId } = req.params;
|
||||
const userId = req.user.userId;
|
||||
|
||||
const conversation = await Conversation.findOne({
|
||||
where: {
|
||||
id: conversationId,
|
||||
user_id: userId
|
||||
}
|
||||
});
|
||||
|
||||
if (!conversation) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
error: 'Conversation not found'
|
||||
});
|
||||
}
|
||||
|
||||
await conversation.destroy();
|
||||
|
||||
logger.info(`Conversation deleted: ${conversationId}`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Conversation deleted successfully'
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Delete conversation error:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Internal server error'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
createConversation,
|
||||
getConversations,
|
||||
getConversation,
|
||||
sendMessage,
|
||||
updateConversation,
|
||||
deleteConversation
|
||||
};
|
||||
Reference in New Issue
Block a user