180 lines
5.3 KiB
JavaScript
180 lines
5.3 KiB
JavaScript
import { Router } from 'express';
|
|
import prisma from '../database.js';
|
|
import { requireAuth } from '../middlewares/authMiddleware.js'; // Import the middleware
|
|
|
|
import { askGeminiChat } from '../utils/gemini.js';
|
|
|
|
import { getUserById } from './auth.js';
|
|
|
|
const router = Router();
|
|
|
|
// Apply the authentication middleware to all chat routes
|
|
router.use(requireAuth);
|
|
|
|
// POST /api/chat/threads - Create a new chat thread (optionally with a first message)
|
|
router.post('/threads', async(req, res) =>
|
|
{
|
|
const { content } = req.body; // Content is now optional
|
|
|
|
// If content is provided, validate it
|
|
if (content && (typeof content !== 'string' || content.trim().length === 0))
|
|
{
|
|
return res.status(400).json({ error: 'Message content cannot be empty if provided.' });
|
|
}
|
|
|
|
try
|
|
{
|
|
const createData = {};
|
|
if (content)
|
|
{
|
|
// If content exists, create the thread with the first message
|
|
createData.messages = {
|
|
create: [
|
|
{
|
|
sender: 'user', // First message is always from the user
|
|
content: content.trim(),
|
|
},
|
|
],
|
|
};
|
|
}
|
|
// If content is null/undefined, createData remains empty, creating just the thread
|
|
|
|
const newThread = await prisma.chatThread.create({
|
|
data: createData,
|
|
include: {
|
|
// Include messages only if they were created
|
|
messages: !!content,
|
|
},
|
|
});
|
|
|
|
if(content)
|
|
{
|
|
const user = await getUserById(req.session.loggedInUserId);
|
|
if (!user)
|
|
{
|
|
req.session.destroy(err =>
|
|
{});
|
|
return res.status(401).json({ status: 'unauthenticated' });
|
|
}
|
|
await askGeminiChat(newThread.id, `[${user.fullName || user.username}] ${content}`);
|
|
}
|
|
|
|
// Respond with the new thread ID and messages (if any)
|
|
res.status(201).json({
|
|
threadId: newThread.id,
|
|
// Ensure messages array is empty if no content was provided
|
|
messages: newThread.messages ? newThread.messages.map(msg => ({ ...msg, createdAt: msg.createdAt.toISOString() })) : []
|
|
});
|
|
}
|
|
catch (error)
|
|
{
|
|
console.error('Error creating chat thread:', error);
|
|
res.status(500).json({ error: 'Failed to create chat thread.' });
|
|
}
|
|
});
|
|
|
|
// GET /api/chat/threads/:threadId/messages - Get messages for a specific thread
|
|
router.get('/threads/:threadId/messages', async(req, res) =>
|
|
{
|
|
const { threadId } = req.params;
|
|
|
|
try
|
|
{
|
|
const messages = await prisma.chatMessage.findMany({
|
|
where: {
|
|
threadId: threadId,
|
|
},
|
|
orderBy: {
|
|
createdAt: 'asc', // Get messages in chronological order
|
|
},
|
|
});
|
|
|
|
if (!messages)
|
|
{ // Check if thread exists indirectly
|
|
// If findMany returns empty, the thread might not exist or has no messages.
|
|
// Check if thread exists explicitly
|
|
const thread = await prisma.chatThread.findUnique({ where: { id: threadId } });
|
|
if (!thread)
|
|
{
|
|
return res.status(404).json({ error: 'Chat thread not found.' });
|
|
}
|
|
}
|
|
|
|
res.status(200).json(messages.map(msg => ({ ...msg, createdAt: msg.createdAt.toISOString() })));
|
|
}
|
|
catch (error)
|
|
{
|
|
console.error(`Error fetching messages for thread ${threadId}:`, error);
|
|
// Basic error handling, check for specific Prisma errors if needed
|
|
if (error.code === 'P2023' || error.message.includes('Malformed UUID'))
|
|
{ // Example: Invalid UUID format
|
|
return res.status(400).json({ error: 'Invalid thread ID format.' });
|
|
}
|
|
res.status(500).json({ error: 'Failed to fetch messages.' });
|
|
}
|
|
});
|
|
|
|
// POST /api/chat/threads/:threadId/messages - Add a message to an existing thread
|
|
router.post('/threads/:threadId/messages', async(req, res) =>
|
|
{
|
|
const { threadId } = req.params;
|
|
const { content, sender = 'user' } = req.body; // Default sender to 'user'
|
|
|
|
if (!content || typeof content !== 'string' || content.trim().length === 0)
|
|
{
|
|
return res.status(400).json({ error: 'Message content cannot be empty.' });
|
|
}
|
|
if (sender !== 'user' && sender !== 'bot')
|
|
{
|
|
return res.status(400).json({ error: 'Invalid sender type.' });
|
|
}
|
|
|
|
try
|
|
{
|
|
// Verify thread exists first
|
|
const thread = await prisma.chatThread.findUnique({
|
|
where: { id: threadId },
|
|
});
|
|
|
|
if (!thread)
|
|
{
|
|
return res.status(404).json({ error: 'Chat thread not found.' });
|
|
}
|
|
|
|
const newMessage = await prisma.chatMessage.create({
|
|
data: {
|
|
threadId: threadId,
|
|
sender: sender,
|
|
content: content.trim(),
|
|
},
|
|
});
|
|
|
|
// Optionally: Update the thread's updatedAt timestamp
|
|
await prisma.chatThread.update({
|
|
where: { id: threadId },
|
|
data: { updatedAt: new Date() }
|
|
});
|
|
|
|
const user = await getUserById(req.session.loggedInUserId);
|
|
if (!user)
|
|
{
|
|
req.session.destroy(err =>
|
|
{});
|
|
return res.status(401).json({ status: 'unauthenticated' });
|
|
}
|
|
await askGeminiChat(threadId, `[${user.fullName || user.username}] ${content}`);
|
|
|
|
res.status(201).json({ ...newMessage, createdAt: newMessage.createdAt.toISOString() });
|
|
}
|
|
catch (error)
|
|
{
|
|
console.error(`Error adding message to thread ${threadId}:`, error);
|
|
if (error.code === 'P2023' || error.message.includes('Malformed UUID'))
|
|
{ // Example: Invalid UUID format
|
|
return res.status(400).json({ error: 'Invalid thread ID format.' });
|
|
}
|
|
res.status(500).json({ error: 'Failed to add message.' });
|
|
}
|
|
});
|
|
|
|
export default router;
|