ваше сообщение коммита

This commit is contained in:
2025-06-20 15:50:13 +03:00
parent 4574af58df
commit 45cde76e85
6 changed files with 299 additions and 24 deletions

View File

@@ -341,10 +341,20 @@ router.post('/message', requireAuth, upload.array('attachments'), async (req, re
try {
// Найти или создать диалог
if (conversationId) {
const convResult = await db.getQuery()(
'SELECT * FROM conversations WHERE id = $1 AND user_id = $2',
[conversationId, userId]
);
let convResult;
if (req.session.isAdmin) {
// Админ может писать в любой диалог
convResult = await db.getQuery()(
'SELECT * FROM conversations WHERE id = $1',
[conversationId]
);
} else {
// Обычный пользователь — только в свой диалог
convResult = await db.getQuery()(
'SELECT * FROM conversations WHERE id = $1 AND user_id = $2',
[conversationId, userId]
);
}
if (convResult.rows.length === 0) {
logger.warn('Conversation not found or access denied', { conversationId, userId });
return res.status(404).json({ success: false, error: 'Диалог не найден или доступ запрещен' });
@@ -381,17 +391,29 @@ router.post('/message', requireAuth, upload.array('attachments'), async (req, re
const attachmentSize = file ? file.size : null;
const attachmentData = file ? file.buffer : null;
// Сохраняем сообщение пользователя
// Определяем user_id для сообщения: всегда user_id диалога (контакта)
const recipientId = conversation.user_id;
// Определяем sender_type
let senderType = 'user';
let role = 'user';
if (req.session.isAdmin) {
senderType = 'admin';
role = 'admin';
}
// Сохраняем сообщение
const userMessageResult = await db.getQuery()(
`INSERT INTO messages
(conversation_id, user_id, content, sender_type, role, channel,
attachment_filename, attachment_mimetype, attachment_size, attachment_data)
VALUES ($1, $2, $3, 'user', 'user', 'web', $4, $5, $6, $7)
VALUES ($1, $2, $3, $4, $5, 'web', $6, $7, $8, $9)
RETURNING *`,
[
conversationId,
userId,
recipientId, // user_id контакта
messageContent,
senderType,
role,
attachmentFilename,
attachmentMimetype,
attachmentSize,
@@ -403,7 +425,15 @@ router.post('/message', requireAuth, upload.array('attachments'), async (req, re
// Получаем ответ от ИИ, только если это было текстовое сообщение
let aiMessage = null;
if (messageContent) { // Только для текстовых сообщений
// --- Новая логика автоответа ИИ ---
let shouldGenerateAiReply = true;
if (senderType === 'admin') {
// Если админ пишет не себе, не отвечаем
if (userId !== recipientId) {
shouldGenerateAiReply = false;
}
}
if (messageContent && shouldGenerateAiReply) { // Только для текстовых сообщений и если разрешено
try {
// Получаем настройки ассистента
const aiSettings = await aiAssistantSettingsService.getSettings();
@@ -647,6 +677,46 @@ router.post('/process-guest', requireAuth, async (req, res) => {
}
});
// POST /api/chat/ai-draft — генерация черновика ответа ИИ
router.post('/ai-draft', requireAuth, async (req, res) => {
const userId = req.session.userId;
const { conversationId, messages, language } = req.body;
if (!conversationId || !Array.isArray(messages) || messages.length === 0) {
return res.status(400).json({ success: false, error: 'conversationId и messages обязательны' });
}
try {
// Получаем настройки ассистента
const aiSettings = await aiAssistantSettingsService.getSettings();
let rules = null;
if (aiSettings && aiSettings.rules_id) {
rules = await aiAssistantRulesService.getRuleById(aiSettings.rules_id);
}
// Формируем prompt из выбранных сообщений
const promptText = messages.map(m => m.content).join('\n\n');
// Получаем последние 10 сообщений из диалога для истории
const historyResult = await db.getQuery()(
'SELECT sender_type, content FROM messages WHERE conversation_id = $1 ORDER BY created_at DESC LIMIT 10',
[conversationId]
);
const history = historyResult.rows.reverse().map(msg => ({
role: msg.sender_type === 'user' ? 'user' : 'assistant',
content: msg.content
}));
const detectedLanguage = language === 'auto' ? aiAssistant.detectLanguage(promptText) : language;
const aiResponseContent = await aiAssistant.getResponse(
promptText,
detectedLanguage,
history,
aiSettings ? aiSettings.system_prompt : '',
rules ? rules.rules : null
);
res.json({ success: true, aiMessage: aiResponseContent });
} catch (error) {
logger.error('Error generating AI draft:', error);
res.status(500).json({ success: false, error: 'Ошибка генерации черновика' });
}
});
// Экспортируем маршрутизатор и функцию processGuestMessages отдельно
module.exports = router;
module.exports.processGuestMessages = processGuestMessages;

View File

@@ -6,9 +6,18 @@ const { broadcastMessagesUpdate } = require('../wsHub');
// GET /api/messages?userId=123
router.get('/', async (req, res) => {
const userId = req.query.userId;
const conversationId = req.query.conversationId;
try {
let result;
if (userId) {
if (conversationId) {
result = await db.getQuery()(
`SELECT id, user_id, sender_type, content, channel, role, direction, created_at, attachment_filename, attachment_mimetype, attachment_size, attachment_data, metadata
FROM messages
WHERE conversation_id = $1
ORDER BY created_at ASC`,
[conversationId]
);
} else if (userId) {
result = await db.getQuery()(
`SELECT id, user_id, sender_type, content, channel, role, direction, created_at, attachment_filename, attachment_mimetype, attachment_size, attachment_data, metadata
FROM messages
@@ -96,4 +105,22 @@ router.get('/read-status', async (req, res) => {
}
});
// GET /api/conversations?userId=123
router.get('/conversations', async (req, res) => {
const userId = req.query.userId;
if (!userId) return res.status(400).json({ error: 'userId required' });
try {
const result = await db.getQuery()(
'SELECT * FROM conversations WHERE user_id = $1 ORDER BY updated_at DESC, created_at DESC LIMIT 1',
[userId]
);
if (result.rows.length === 0) {
return res.status(404).json({ error: 'Conversation not found' });
}
res.json(result.rows[0]);
} catch (e) {
res.status(500).json({ error: 'DB error', details: e.message });
}
});
module.exports = router;