162 lines
6.8 KiB
JavaScript
162 lines
6.8 KiB
JavaScript
const router = require('express').Router();
|
||
const { moderationText } = require('./initiatives-ai-agents/moderation.ts');
|
||
const { generatePicture } = require('./initiatives-ai-agents/picture.ts');
|
||
const { getSupabaseClient } = require('./supabaseClient');
|
||
const { getGigaAuth } = require('./get-constants');
|
||
|
||
async function getGigaKey() {
|
||
const GIGA_AUTH = await getGigaAuth();
|
||
return GIGA_AUTH;
|
||
}
|
||
|
||
// Обработчик для модерации и создания инициативы
|
||
router.post('/moderate', async (req, res) => {
|
||
|
||
const GIGA_AUTH = await getGigaKey();
|
||
|
||
try {
|
||
const { title, description, building_id, creator_id, target_amount, status } = req.body;
|
||
|
||
if (!title || !description) {
|
||
res.status(400).json({ error: 'Заголовок и описание обязательны' });
|
||
return;
|
||
}
|
||
|
||
if (!building_id || !creator_id) {
|
||
res.status(400).json({ error: 'ID дома и создателя обязательны' });
|
||
return;
|
||
}
|
||
|
||
// Валидация статуса, если передан
|
||
const validStatuses = ['moderation', 'review', 'fundraising', 'approved', 'rejected'];
|
||
if (status && !validStatuses.includes(status)) {
|
||
res.status(400).json({ error: `Недопустимый статус. Допустимые значения: ${validStatuses.join(', ')}` });
|
||
return;
|
||
}
|
||
|
||
console.log('Запрос на модерацию:', { title: title.substring(0, 50), description: description.substring(0, 100) });
|
||
|
||
// Модерация текста (передаем title и description как body)
|
||
const [comment, fixedText, isApproved] = await moderationText(title, description, GIGA_AUTH);
|
||
|
||
// Если модерация не прошла, возвращаем undefined
|
||
if (!isApproved) {
|
||
if (!comment || comment.trim() === '') {
|
||
console.warn('Обнаружен некорректный результат модерации - пустой комментарий при отклонении');
|
||
}
|
||
|
||
res.json({
|
||
comment,
|
||
fixedText,
|
||
isApproved,
|
||
initiative: undefined
|
||
});
|
||
return;
|
||
}
|
||
|
||
// Модерация прошла, генерируем изображение используя заголовок как промпт
|
||
console.log('Модерация прошла, генерируем изображение с промптом:', title);
|
||
|
||
const imageBuffer = await generatePicture(title, GIGA_AUTH);
|
||
|
||
if (!imageBuffer || imageBuffer.length === 0) {
|
||
res.status(500).json({ error: 'Получен пустой буфер изображения' });
|
||
return;
|
||
}
|
||
|
||
// Получаем Supabase клиент и создаем имя файла
|
||
const supabase = getSupabaseClient();
|
||
const timestamp = Date.now();
|
||
const filename = `image_${creator_id}_${timestamp}.jpg`;
|
||
|
||
// Загружаем изображение в Supabase Storage
|
||
let uploadResult;
|
||
let retries = 0;
|
||
const maxRetries = 5;
|
||
|
||
while (retries < maxRetries) {
|
||
try {
|
||
uploadResult = await supabase.storage
|
||
.from('images')
|
||
.upload(filename, imageBuffer, {
|
||
contentType: 'image/jpeg',
|
||
upsert: true
|
||
});
|
||
|
||
if (!uploadResult.error) {
|
||
break; // Успешная загрузка
|
||
}
|
||
|
||
retries++;
|
||
|
||
if (retries < maxRetries) {
|
||
// Ждем перед повторной попыткой
|
||
await new Promise(resolve => setTimeout(resolve, 1000 * retries));
|
||
}
|
||
} catch (error) {
|
||
console.warn(`Попытка загрузки ${retries + 1} неудачна (исключение):`, error.message);
|
||
retries++;
|
||
|
||
if (retries < maxRetries) {
|
||
// Ждем перед повторной попыткой
|
||
await new Promise(resolve => setTimeout(resolve, 1000 * retries));
|
||
} else {
|
||
throw error; // Перебрасываем ошибку после всех попыток
|
||
}
|
||
}
|
||
}
|
||
|
||
if (uploadResult?.error) {
|
||
console.error('Supabase storage error after all retries:', uploadResult.error);
|
||
res.status(500).json({ error: 'Ошибка при сохранении изображения после нескольких попыток' });
|
||
return;
|
||
}
|
||
|
||
console.log('Изображение успешно загружено в Supabase Storage:', filename);
|
||
|
||
// Получаем публичный URL
|
||
const { data: urlData } = supabase.storage
|
||
.from('images')
|
||
.getPublicUrl(filename);
|
||
|
||
// Определяем статус: если передан в запросе, используем его, иначе 'review'
|
||
const finalStatus = status || 'review';
|
||
|
||
// Создаем инициативу в базе данных
|
||
const { data: initiative, error: initiativeError } = await supabase
|
||
.from('initiatives')
|
||
.insert([{
|
||
building_id,
|
||
creator_id,
|
||
title: fixedText || title,
|
||
description,
|
||
status: finalStatus,
|
||
target_amount: target_amount || null,
|
||
current_amount: 0,
|
||
image_url: urlData.publicUrl
|
||
}])
|
||
.select()
|
||
.single();
|
||
|
||
if (initiativeError) {
|
||
console.error('Ошибка создания инициативы:', initiativeError);
|
||
res.status(500).json({ error: 'Ошибка при создании инициативы', details: initiativeError.message });
|
||
return;
|
||
}
|
||
|
||
console.log('Инициатива успешно создана:', initiative.id);
|
||
|
||
res.json({
|
||
comment,
|
||
fixedText,
|
||
isApproved,
|
||
initiative
|
||
});
|
||
|
||
} catch (error) {
|
||
console.error('Error in moderation and initiative creation:', error);
|
||
res.status(500).json({ error: 'Внутренняя ошибка сервера', details: error.message });
|
||
}
|
||
});
|
||
|
||
module.exports = router;
|