add chat moderation
This commit is contained in:
@@ -2,6 +2,89 @@ const router = require('express').Router();
|
||||
const { getSupabaseClient } = require('./supabaseClient');
|
||||
const { getIo } = require('../../../io'); // Импортируем Socket.IO
|
||||
|
||||
console.log(`📦 [Messages Module] Загружаем модуль messages.js...`);
|
||||
console.log(`📦 [Messages Module] Время загрузки: ${new Date().toISOString()}`);
|
||||
|
||||
try {
|
||||
const { moderationText } = require('./chat-ai-agent/chat-moderation'); // Импортируем функцию модерации
|
||||
console.log(`✅ [Messages Module] Функция модерации загружена успешно`);
|
||||
} catch (error) {
|
||||
console.error(`❌ [Messages Module] Ошибка загрузки функции модерации:`, error);
|
||||
}
|
||||
|
||||
try {
|
||||
const MODERATION_CONFIG = require('./chat-ai-agent/moderation-config'); // Импортируем конфигурацию модерации
|
||||
console.log(`✅ [Messages Module] Конфигурация модерации загружена:`, MODERATION_CONFIG);
|
||||
} catch (error) {
|
||||
console.error(`❌ [Messages Module] Ошибка загрузки конфигурации модерации:`, error);
|
||||
}
|
||||
|
||||
const { moderationText } = require('./chat-ai-agent/chat-moderation'); // Импортируем функцию модерации
|
||||
const MODERATION_CONFIG = require('./chat-ai-agent/moderation-config'); // Импортируем конфигурацию модерации
|
||||
|
||||
console.log(`📦 [Messages Module] Модуль messages.js загружен полностью`);
|
||||
|
||||
// Добавляем middleware для логирования всех запросов к messages роутеру
|
||||
|
||||
// Тестовый эндпоинт для проверки работы роутера
|
||||
router.get('/messages/test', (req, res) => {
|
||||
console.log(`🧪 [Messages Test] Тестовый эндпоинт вызван`);
|
||||
console.log(`🧪 [Messages Test] Время: ${new Date().toISOString()}`);
|
||||
res.json({
|
||||
status: 'OK',
|
||||
message: 'Messages router работает',
|
||||
timestamp: new Date().toISOString(),
|
||||
moderation_config: MODERATION_CONFIG
|
||||
});
|
||||
});
|
||||
|
||||
// Тестовый эндпоинт для немедленной проверки AI агента
|
||||
router.post('/messages/test-ai', async (req, res) => {
|
||||
console.log(`🧪 [AI Test] === ТЕСТИРОВАНИЕ AI АГЕНТА ===`);
|
||||
console.log(`🧪 [AI Test] Время: ${new Date().toISOString()}`);
|
||||
|
||||
const { text } = req.body;
|
||||
if (!text) {
|
||||
return res.status(400).json({ error: 'text is required' });
|
||||
}
|
||||
|
||||
console.log(`🧪 [AI Test] Тестируем текст: "${text}"`);
|
||||
console.log(`🧪 [AI Test] Функция moderationText доступна: ${typeof moderationText}`);
|
||||
|
||||
try {
|
||||
console.log(`🧪 [AI Test] Вызываем AI агент напрямую...`);
|
||||
const startTime = Date.now();
|
||||
const result = await moderationText('', text);
|
||||
const endTime = Date.now();
|
||||
|
||||
console.log(`🧪 [AI Test] Результат от AI агента:`, result);
|
||||
console.log(`🧪 [AI Test] Время выполнения: ${endTime - startTime}мс`);
|
||||
|
||||
const [comment, isApproved, finalMessage] = result;
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
text: text,
|
||||
comment: comment,
|
||||
isApproved: isApproved,
|
||||
finalMessage: finalMessage,
|
||||
processingTime: endTime - startTime,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ [AI Test] Ошибка тестирования AI агента:`, error);
|
||||
console.error(`❌ [AI Test] Stack:`, error.stack);
|
||||
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: error.message,
|
||||
stack: error.stack,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Получить все сообщения в чате с информацией о пользователе
|
||||
router.get('/messages', async (req, res) => {
|
||||
try {
|
||||
@@ -59,15 +142,40 @@ router.get('/messages', async (req, res) => {
|
||||
|
||||
// Создать новое сообщение
|
||||
router.post('/messages', async (req, res) => {
|
||||
const supabase = getSupabaseClient();
|
||||
console.log(`🚀 [Message Send] === ВХОД В POST /messages ЭНДПОИНТ ===`);
|
||||
console.log(`🚀 [Message Send] Время входа: ${new Date().toISOString()}`);
|
||||
console.log(`🚀 [Message Send] Request method: ${req.method}`);
|
||||
console.log(`🚀 [Message Send] Request URL: ${req.originalUrl || req.url}`);
|
||||
console.log(`🚀 [Message Send] Request body:`, JSON.stringify(req.body, null, 2));
|
||||
|
||||
console.log(`🔌 [Message Send] Получаем Supabase клиент...`);
|
||||
let supabase;
|
||||
try {
|
||||
supabase = getSupabaseClient();
|
||||
console.log(`✅ [Message Send] Supabase клиент получен успешно`);
|
||||
} catch (error) {
|
||||
console.error(`❌ [Message Send] Ошибка получения Supabase клиента:`, error);
|
||||
return res.status(500).json({ error: 'Database connection error' });
|
||||
}
|
||||
|
||||
const { chat_id, user_id, text } = req.body;
|
||||
|
||||
console.log(`📤 [Message Send] Получен запрос на отправку сообщения:`);
|
||||
console.log(`📤 [Message Send] Chat ID: ${chat_id}`);
|
||||
console.log(`📤 [Message Send] User ID: ${user_id}`);
|
||||
console.log(`📤 [Message Send] Text length: ${text ? text.length : 0} символов`);
|
||||
console.log(`📤 [Message Send] Text preview: "${text ? (text.length > 100 ? text.substring(0, 100) + '...' : text) : 'empty'}"`);
|
||||
|
||||
if (!chat_id || !user_id || !text) {
|
||||
console.log(`❌ [Message Send] Отклонен: отсутствуют обязательные поля`);
|
||||
console.log(`❌ [Message Send] chat_id: ${chat_id}, user_id: ${user_id}, text: ${text}`);
|
||||
return res.status(400).json({
|
||||
error: 'chat_id, user_id, and text are required'
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`💾 [Message Send] Сохраняем сообщение в Supabase...`);
|
||||
|
||||
// Создаем сообщение
|
||||
const { data: newMessage, error } = await supabase
|
||||
.from('messages')
|
||||
@@ -75,14 +183,28 @@ router.post('/messages', async (req, res) => {
|
||||
.select('*')
|
||||
.single();
|
||||
|
||||
if (error) return res.status(400).json({ error: error.message });
|
||||
if (error) {
|
||||
console.error(`❌ [Message Send] Ошибка сохранения в Supabase:`, error);
|
||||
return res.status(400).json({ error: error.message });
|
||||
}
|
||||
|
||||
console.log(`✅ [Message Send] Сообщение сохранено. ID: ${newMessage.id}`);
|
||||
console.log(`📅 [Message Send] Время создания: ${newMessage.created_at}`);
|
||||
|
||||
console.log(`👤 [Message Send] Получаем профиль пользователя ${user_id}...`);
|
||||
|
||||
// Получаем профиль пользователя
|
||||
const { data: userProfile } = await supabase
|
||||
const { data: userProfile, error: profileError } = await supabase
|
||||
.from('user_profiles')
|
||||
.select('id, full_name, avatar_url')
|
||||
.eq('id', user_id)
|
||||
.single();
|
||||
|
||||
if (profileError) {
|
||||
console.log(`⚠️ [Message Send] Профиль пользователя не найден:`, profileError);
|
||||
} else {
|
||||
console.log(`✅ [Message Send] Профиль пользователя получен: ${userProfile.full_name || 'No name'}`);
|
||||
}
|
||||
|
||||
// Объединяем сообщение с профилем
|
||||
const data = {
|
||||
@@ -90,12 +212,167 @@ router.post('/messages', async (req, res) => {
|
||||
user_profiles: userProfile || null
|
||||
};
|
||||
|
||||
console.log(`📊 [Message Send] Итоговые данные сообщения подготовлены`);
|
||||
|
||||
// === МОДЕРАЦИЯ ЧЕРЕЗ SUPABASE REAL-TIME ===
|
||||
console.log(`🔄 [Message Send] Модерация будет выполняться через Supabase Real-time подписку`);
|
||||
console.log(`🔄 [Message Send] Статус модерации: ${MODERATION_CONFIG.MODERATION_ENABLED ? 'включена' : 'отключена'}`);
|
||||
console.log(`🔄 [Message Send] Задержка модерации: ${MODERATION_CONFIG.MODERATION_DELAY}мс`);
|
||||
console.log(`🔄 [Message Send] После создания сообщения в БД сработает Supabase Real-time подписка в polling-chat.js`);
|
||||
|
||||
// Отправка через Socket.IO теперь происходит автоматически через Supabase Real-time подписку
|
||||
// Это предотвращает дублирование сообщений
|
||||
|
||||
console.log(`✅ [Message Send] Сообщение успешно отправлено. Возвращаем ответ клиенту`);
|
||||
console.log(`📤 [Message Send] === Процесс отправки сообщения завершен ===`);
|
||||
|
||||
res.json(data);
|
||||
});
|
||||
|
||||
// Функция отложенной модерации сообщения
|
||||
async function moderateMessage(messageId, messageText, chatId) {
|
||||
const moderationStartTime = Date.now();
|
||||
|
||||
try {
|
||||
console.log(`🔍 [Moderation] === НАЧАЛО МОДЕРАЦИИ СООБЩЕНИЯ ${messageId} ===`);
|
||||
console.log(`🔍 [Moderation] Chat ID: ${chatId}`);
|
||||
console.log(`🔍 [Moderation] Длина текста: ${messageText.length} символов`);
|
||||
console.log(`🔍 [Moderation] Превью текста: "${messageText.length > 100 ? messageText.substring(0, 100) + '...' : messageText}"`);
|
||||
console.log(`🔍 [Moderation] Время запуска: ${new Date().toISOString()}`);
|
||||
|
||||
// Вызываем функцию модерации
|
||||
console.log(`🔍 [Moderation] Передаем сообщение AI агенту для анализа...`);
|
||||
console.log(`🔍 [Moderation] Функция moderationText доступна: ${typeof moderationText}`);
|
||||
console.log(`🔍 [Moderation] Тип сообщения: ${typeof messageText}`);
|
||||
console.log(`🔍 [Moderation] Текст сообщения: "${messageText}"`);
|
||||
|
||||
let comment, isApproved, finalMessage;
|
||||
try {
|
||||
const result = await moderationText('', messageText);
|
||||
console.log(`🔍 [Moderation] Результат от AI агента получен:`, result);
|
||||
[comment, isApproved, finalMessage] = result;
|
||||
console.log(`🔍 [Moderation] Распакованные значения: comment="${comment}", isApproved=${isApproved}, finalMessage="${finalMessage}"`);
|
||||
} catch (moderationError) {
|
||||
console.error(`❌ [Moderation] Ошибка при вызове AI агента:`, moderationError);
|
||||
console.error(`❌ [Moderation] Stack trace:`, moderationError.stack);
|
||||
// В случае ошибки одобряем сообщение
|
||||
comment = '';
|
||||
isApproved = true;
|
||||
finalMessage = messageText;
|
||||
console.log(`⚠️ [Moderation] Используем fallback значения из-за ошибки`);
|
||||
}
|
||||
|
||||
const moderationTime = Date.now() - moderationStartTime;
|
||||
console.log(`📝 [Moderation] === РЕЗУЛЬТАТ МОДЕРАЦИИ СООБЩЕНИЯ ${messageId} ===`);
|
||||
console.log(`📝 [Moderation] Время модерации: ${moderationTime}мс`);
|
||||
console.log(`📝 [Moderation] Решение: ${isApproved ? '✅ ОДОБРЕНО' : '❌ ОТКЛОНЕНО'}`);
|
||||
console.log(`📝 [Moderation] Комментарий: "${comment || 'отсутствует'}"`);
|
||||
console.log(`📝 [Moderation] Финальный текст: "${finalMessage}"`);
|
||||
|
||||
if (isApproved) {
|
||||
console.log(`📝 [Moderation] Действие: сообщение остается без изменений`);
|
||||
} else {
|
||||
console.log(`📝 [Moderation] Действие: сообщение будет заменено в базе данных`);
|
||||
}
|
||||
|
||||
// Если сообщение не прошло модерацию, обновляем его в базе данных
|
||||
if (!isApproved) {
|
||||
console.log(`💾 [Moderation] Начинаем обновление сообщения в базе данных...`);
|
||||
|
||||
const supabase = getSupabaseClient();
|
||||
|
||||
// Сначала получаем информацию о сообщении для получения chat_id
|
||||
console.log(`💾 [Moderation] Получаем данные сообщения из базы...`);
|
||||
const { data: messageData, error: fetchError } = await supabase
|
||||
.from('messages')
|
||||
.select('chat_id, user_id')
|
||||
.eq('id', messageId)
|
||||
.single();
|
||||
|
||||
if (fetchError) {
|
||||
console.error(`❌ [Moderation] Ошибка получения данных сообщения ${messageId}:`, fetchError);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`💾 [Moderation] Данные получены. Chat ID: ${messageData.chat_id}, User ID: ${messageData.user_id}`);
|
||||
|
||||
// Обновляем текст сообщения
|
||||
console.log(`💾 [Moderation] Обновляем текст сообщения на: "${MODERATION_CONFIG.BLOCKED_MESSAGE_TEXT}"`);
|
||||
const { data: updatedMessage, error } = await supabase
|
||||
.from('messages')
|
||||
.update({ text: MODERATION_CONFIG.BLOCKED_MESSAGE_TEXT })
|
||||
.eq('id', messageId)
|
||||
.select('*')
|
||||
.single();
|
||||
|
||||
if (error) {
|
||||
console.error(`❌ [Moderation] Ошибка обновления сообщения ${messageId}:`, error);
|
||||
console.error(`❌ [Moderation] Детали ошибки:`, error);
|
||||
} else {
|
||||
console.log(`✅ [Moderation] Сообщение ${messageId} успешно обновлено в базе данных`);
|
||||
console.log(`✅ [Moderation] Старый текст заменен на: "${updatedMessage.text}"`);
|
||||
console.log(`✅ [Moderation] Время обновления: ${updatedMessage.updated_at || 'не указано'}`);
|
||||
|
||||
// Отправляем обновление через Socket.IO всем клиентам в чате
|
||||
console.log(`📡 [Moderation] Начинаем отправку обновления через Socket.IO...`);
|
||||
try {
|
||||
const io = getIo();
|
||||
if (io) {
|
||||
console.log(`📡 [Moderation] Socket.IO подключение активно`);
|
||||
|
||||
// Получаем профиль пользователя для полной информации
|
||||
console.log(`📡 [Moderation] Получаем профиль пользователя для обновления...`);
|
||||
const { data: userProfile, error: profileError } = await supabase
|
||||
.from('user_profiles')
|
||||
.select('id, full_name, avatar_url')
|
||||
.eq('id', messageData.user_id)
|
||||
.single();
|
||||
|
||||
if (profileError) {
|
||||
console.log(`⚠️ [Moderation] Ошибка получения профиля пользователя:`, profileError);
|
||||
} else {
|
||||
console.log(`✅ [Moderation] Профиль пользователя получен: ${userProfile.full_name || 'No name'}`);
|
||||
}
|
||||
|
||||
const messageWithProfile = {
|
||||
...updatedMessage,
|
||||
user_profiles: userProfile || null
|
||||
};
|
||||
|
||||
console.log(`📡 [Moderation] Отправляем обновление в комнату chat_${messageData.chat_id}...`);
|
||||
io.to(`chat_${messageData.chat_id}`).emit('message_updated', messageWithProfile);
|
||||
console.log(`📤 [Moderation] ✅ Обновление сообщения отправлено в чат ${messageData.chat_id}`);
|
||||
console.log(`📤 [Moderation] Событие: message_updated`);
|
||||
console.log(`📤 [Moderation] Получатели: все участники чата ${messageData.chat_id}`);
|
||||
} else {
|
||||
console.log(`⚠️ [Moderation] Socket.IO подключение недоступно`);
|
||||
}
|
||||
} catch (socketError) {
|
||||
console.error(`❌ [Moderation] Ошибка отправки через Socket.IO:`, socketError);
|
||||
console.error(`❌ [Moderation] Детали ошибки Socket.IO:`, socketError.message);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log(`✅ [Moderation] Сообщение ${messageId} прошло модерацию - никаких действий не требуется`);
|
||||
}
|
||||
|
||||
const totalTime = Date.now() - moderationStartTime;
|
||||
console.log(`🔍 [Moderation] === МОДЕРАЦИЯ СООБЩЕНИЯ ${messageId} ЗАВЕРШЕНА ===`);
|
||||
console.log(`🔍 [Moderation] Общее время процесса: ${totalTime}мс`);
|
||||
console.log(`🔍 [Moderation] Время завершения: ${new Date().toISOString()}`);
|
||||
|
||||
} catch (error) {
|
||||
const totalTime = Date.now() - moderationStartTime;
|
||||
console.error(`❌ [Moderation] === ОШИБКА МОДЕРАЦИИ СООБЩЕНИЯ ${messageId} ===`);
|
||||
console.error(`❌ [Moderation] Время до ошибки: ${totalTime}мс`);
|
||||
console.error(`❌ [Moderation] Тип ошибки: ${error.name || 'Unknown'}`);
|
||||
console.error(`❌ [Moderation] Сообщение ошибки: ${error.message || 'Unknown error'}`);
|
||||
console.error(`❌ [Moderation] Полная ошибка:`, error);
|
||||
console.error(`❌ [Moderation] Стек ошибки:`, error.stack);
|
||||
console.error(`❌ [Moderation] === КОНЕЦ ОБРАБОТКИ ОШИБКИ ===`);
|
||||
}
|
||||
}
|
||||
|
||||
// Получить конкретное сообщение
|
||||
router.get('/messages/:message_id', async (req, res) => {
|
||||
const supabase = getSupabaseClient();
|
||||
@@ -203,6 +480,4 @@ router.delete('/messages/:message_id', async (req, res) => {
|
||||
res.json({ success: true, message: 'Message deleted successfully' });
|
||||
});
|
||||
|
||||
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user