Skip to content

Commit f5fc581

Browse files
authored
Update agent.js
1 parent 2267a87 commit f5fc581

File tree

1 file changed

+90
-9
lines changed

1 file changed

+90
-9
lines changed

agent.js

Lines changed: 90 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const cors = require('cors');
1212
const path = require('path');
1313
const fs = require('fs');
1414
const { DateTime } = require('luxon');
15+
const FormData = require('form-data');
1516
require('dotenv').config();
1617

1718
// ============================================
@@ -37,6 +38,7 @@ const CONFIG = {
3738
},
3839
GOOGLE_AI_API_KEY: process.env.GOOGLE_AI_API_KEY,
3940
CALENDARIFIC_API_KEY: process.env.CALENDARIFIC_API_KEY || 'demo',
41+
IMGBB_API_KEY: process.env.IMGBB_API_KEY || 'your_imgbb_key_here', // Add IMGBB_API_KEY to .env
4042
TIMEZONE: process.env.TIMEZONE || 'Asia/Kolkata',
4143
SCHEDULE_TIME: process.env.SCHEDULE_TIME || '0 0 * * *',
4244
DASHBOARD_PORT: process.env.DASHBOARD_PORT ? Number(process.env.DASHBOARD_PORT) : 3000,
@@ -351,6 +353,48 @@ function todayDateString() {
351353
return nowInZone().toISODate();
352354
}
353355

356+
// ============================================
357+
// IMAGE UTILITIES
358+
// ============================================
359+
360+
// Function to upload image to imgbb
361+
async function uploadToImgbb(imageBuffer, filename) {
362+
if (!CONFIG.IMGBB_API_KEY || CONFIG.IMGBB_API_KEY === 'your_imgbb_key_here') {
363+
throw new Error('Imgbb API key not configured');
364+
}
365+
366+
const form = new FormData();
367+
form.append('image', imageBuffer, { filename });
368+
369+
try {
370+
const response = await axios.post(
371+
`https://api.imgbb.com/1/upload?key=${CONFIG.IMGBB_API_KEY}`,
372+
form,
373+
{ headers: form.getHeaders(), timeout: 30000 }
374+
);
375+
376+
if (response.data?.success) {
377+
return response.data.data.url;
378+
} else {
379+
throw new Error('Imgbb upload failed');
380+
}
381+
} catch (error) {
382+
log(`Imgbb upload failed: ${error.message}`, 'ERROR');
383+
throw error;
384+
}
385+
}
386+
387+
// Function to validate image URL
388+
async function validateImageUrl(url) {
389+
try {
390+
const response = await axios.head(url, { timeout: 10000 });
391+
const contentType = response.headers['content-type'];
392+
return response.status === 200 && contentType && contentType.startsWith('image/');
393+
} catch (error) {
394+
return false;
395+
}
396+
}
397+
354398
// ============================================
355399
// AI MESSAGE GENERATION (Gemini) - fallback template if no key
356400
// ============================================
@@ -443,7 +487,7 @@ Return ONLY the enhanced message. `;
443487
const response = await axios.post(
444488
`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent?key=${CONFIG.GOOGLE_AI_API_KEY}`,
445489
{
446-
contents: [{ parts: [{ text: prompt }] },
490+
contents: [{ parts: [{ text: prompt }] }],
447491
generationConfig: { temperature: 0.7, maxOutputTokens: 250 }
448492
},
449493
{ headers: { 'Content-Type': 'application/json' }, timeout: 15000 }
@@ -521,7 +565,7 @@ async function sendHolidayAnnouncement(holiday, message, imageUrl, webhookUrl, r
521565

522566
async function sendCustomAnnouncement(data) {
523567
try {
524-
const { title, message, roles, imageUrl, webhookChannel, useAI, serverInfo } = data;
568+
const { title, message, roles, imageUrl, imageFile, webhookChannel, useAI, serverInfo } = data;
525569
const channelKey = webhookChannel || 'ANNOUNCEMENTS';
526570

527571
// Get server-specific webhook or fallback to default
@@ -562,10 +606,22 @@ async function sendCustomAnnouncement(data) {
562606
},
563607
timestamp: new Date().toISOString()
564608
};
565-
// Validate image URL
566-
if (imageUrl) {
567-
if (imageUrl.startsWith('data:image') || !imageUrl.startsWith('https://')) {
568-
return { success: false, error: 'Invalid image URL. Only public HTTPS URLs are supported.' };
609+
610+
// Handle image
611+
if (imageFile && imageFile.buffer && imageFile.originalname) {
612+
// Upload file to imgbb
613+
try {
614+
const uploadedUrl = await uploadToImgbb(imageFile.buffer, imageFile.originalname);
615+
embed.image = { url: uploadedUrl };
616+
log('Image uploaded to imgbb successfully', 'SUCCESS');
617+
} catch (error) {
618+
return { success: false, error: 'Failed to upload image' };
619+
}
620+
} else if (imageUrl) {
621+
// Validate image URL
622+
const isValid = await validateImageUrl(imageUrl);
623+
if (!isValid) {
624+
return { success: false, error: 'Invalid or inaccessible image URL' };
569625
}
570626
embed.image = { url: imageUrl };
571627
}
@@ -783,6 +839,10 @@ app.use(cors());
783839
app.use(express.json());
784840
app.use(express.static('public'));
785841

842+
// Multer for file uploads
843+
const multer = require('multer');
844+
const upload = multer({ storage: multer.memoryStorage() });
845+
786846
app.get('/api/status', (req, res) => {
787847
res.json({
788848
...botStatus,
@@ -827,9 +887,17 @@ app.post('/api/trigger/holiday', async (req, res) => {
827887
}
828888
});
829889

830-
app.post('/api/announcement/send', async (req, res) => {
890+
// Updated to handle file uploads
891+
app.post('/api/announcement/send', upload.single('imageFile'), async (req, res) => {
831892
try {
832-
const result = await sendCustomAnnouncement(req.body);
893+
const data = { ...req.body };
894+
if (req.file) {
895+
data.imageFile = {
896+
buffer: req.file.buffer,
897+
originalname: req.file.originalname
898+
};
899+
}
900+
const result = await sendCustomAnnouncement(data);
833901
res.json(result);
834902
} catch (error) {
835903
res.json({ success: false, error: error.message });
@@ -1066,7 +1134,7 @@ app.post('/api/servers/:serverId/webhooks/create', async (req, res) => {
10661134
});
10671135

10681136
// Send custom announcement to specific server
1069-
app.post('/api/servers/:serverId/announcement/send', async (req, res) => {
1137+
app.post('/api/servers/:serverId/announcement/send', upload.single('imageFile'), async (req, res) => {
10701138
try {
10711139
const { serverId } = req.params;
10721140
const serverConfig = getServerConfig(serverId);
@@ -1088,6 +1156,13 @@ app.post('/api/servers/:serverId/announcement/send', async (req, res) => {
10881156
}
10891157
};
10901158

1159+
if (req.file) {
1160+
announcementData.imageFile = {
1161+
buffer: req.file.buffer,
1162+
originalname: req.file.originalname
1163+
};
1164+
}
1165+
10911166
const result = await sendCustomAnnouncement(announcementData);
10921167
res.json(result);
10931168
} catch (error) {
@@ -1308,6 +1383,12 @@ app.post('/api/generate-image', async (req, res) => {
13081383
const [width, height] = (size || '1024x1024').split('x');
13091384
const unsplashUrl = `https://source.unsplash.com/${width}x${height}/?${encodeURIComponent(keywords)}`;
13101385

1386+
// Validate the generated URL
1387+
const isValid = await validateImageUrl(unsplashUrl);
1388+
if (!isValid) {
1389+
throw new Error('Generated URL is not accessible');
1390+
}
1391+
13111392
log(`Using Unsplash image for: ${keywords}`, 'SUCCESS');
13121393
return res.json({ success: true, imageUrl: unsplashUrl });
13131394
} catch (err) {

0 commit comments

Comments
 (0)