Spaces:
Running
Running
VinOS Agent commited on
Commit ·
54f2e38
1
Parent(s): 0475aa4
Wave 1: Fix critical HF bugs and cleanup dead skills
Browse files- server.js +122 -33
- skills/api_caller.js +62 -56
- skills/frontend_developer.js +0 -43
- skills/hf_storage.js +37 -15
- skills/intent_router.js +1 -1
- skills/product_deployer.js +0 -83
- skills/set_telegram_menu.js +13 -9
- skills/skill_creator.js +14 -0
- skills/social_engager.js +0 -43
- skills/social_researcher.js +0 -62
server.js
CHANGED
|
@@ -32,10 +32,9 @@ const apiCaller = require('./skills/api_caller');
|
|
| 32 |
const playbookManager = require('./skills/playbook_manager');
|
| 33 |
const conversationMemory = require('./skills/conversation_memory');
|
| 34 |
const setTelegramMenu = require('./skills/set_telegram_menu');
|
| 35 |
-
|
| 36 |
-
const productDeployer = require('./skills/product_deployer');
|
| 37 |
const reportGen = require('./skills/report_generator');
|
| 38 |
-
|
| 39 |
const hfStorage = require('./skills/hf_storage');
|
| 40 |
const trelloManager = require('./skills/trello_manager');
|
| 41 |
const hfDeployer = require('./skills/hf_deployer');
|
|
@@ -43,7 +42,7 @@ const skillCreator = require('./skills/skill_creator');
|
|
| 43 |
const seoWriter = require('./skills/seo_writer');
|
| 44 |
const wordpressPublisher = require('./skills/wordpress_publisher');
|
| 45 |
const googleIndexer = require('./skills/google_indexer');
|
| 46 |
-
|
| 47 |
|
| 48 |
const app = express();
|
| 49 |
app.use(cors());
|
|
@@ -162,8 +161,13 @@ app.post('/api/generate-image', async (req, res) => {
|
|
| 162 |
const { prompt } = req.body;
|
| 163 |
if (!prompt) return res.status(400).json({ error: "Prompt is required" });
|
| 164 |
|
| 165 |
-
const result = await apiCaller.
|
| 166 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 167 |
});
|
| 168 |
|
| 169 |
app.post('/api/usecase/pulse', async (req, res) => {
|
|
@@ -235,7 +239,7 @@ async function handleVinIntent(chatId, from, userText, confirmed = false) {
|
|
| 235 |
// 1. Resolve intent
|
| 236 |
const { intent, params } = await intentRouter.resolveIntent(userText);
|
| 237 |
|
| 238 |
-
if (!confirmed && !autoMode && (intent === '
|
| 239 |
if (!db.pending_commands) db.pending_commands = {};
|
| 240 |
db.pending_commands[chatId] = { intent, params, userText, ts: Date.now() };
|
| 241 |
memory.writeDB(db);
|
|
@@ -278,11 +282,26 @@ async function handleVinIntent(chatId, from, userText, confirmed = false) {
|
|
| 278 |
}
|
| 279 |
break;
|
| 280 |
|
| 281 |
-
case '
|
| 282 |
-
const
|
| 283 |
-
await apiCaller.sendTelegramMessage(chatId, "
|
| 284 |
-
const gResult = await apiCaller.
|
| 285 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 286 |
break;
|
| 287 |
|
| 288 |
case 'pulse':
|
|
@@ -376,13 +395,7 @@ app.post('/api/telegram-webhook', async (req, res) => {
|
|
| 376 |
return;
|
| 377 |
}
|
| 378 |
|
| 379 |
-
|
| 380 |
-
const niche = userText.split(' ').slice(1).join(' ') || "AI tools";
|
| 381 |
-
await apiCaller.sendTelegramMessage(chatId, `🔍 <b>Deep Scan Started:</b> ${niche}`);
|
| 382 |
-
const res = await socialResearcher.researchNiche(niche);
|
| 383 |
-
await apiCaller.sendTelegramMessage(chatId, res.success ? `✅ <b>Research Complete</b>\n${res.summary}` : `❌ Failed: ${res.error}`);
|
| 384 |
-
return;
|
| 385 |
-
}
|
| 386 |
|
| 387 |
if (userText && (userText.toLowerCase() === 'confirm' || userText.toLowerCase() === 'cancel')) {
|
| 388 |
const db = memory.readDB();
|
|
@@ -408,33 +421,66 @@ app.post('/api/telegram-webhook', async (req, res) => {
|
|
| 408 |
} else return await apiCaller.sendTelegramMessage(chatId, "❌ Transcription failed.");
|
| 409 |
}
|
| 410 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 411 |
if (userText) {
|
| 412 |
if (userText.startsWith('/start')) {
|
| 413 |
-
const startMsg = `🦍 <b>VinOS Command Center — v4.
|
| 414 |
`📊 <b>STRATEGY</b>\n` +
|
| 415 |
-
`/mckinsey [niche] — Generate McKinsey PDF\n` +
|
| 416 |
-
`
|
| 417 |
-
`/
|
| 418 |
`🚀 <b>DEPLOY</b>\n` +
|
| 419 |
-
`/deploy [platform] [name] [price] — Launch\n` +
|
| 420 |
`/sync — Push code to HF Space\n\n` +
|
| 421 |
`🧠 <b>KNOWLEDGE</b>\n` +
|
| 422 |
-
`/playbooks — List learned playbooks\n` +
|
| 423 |
-
`/recent — Last 5 conversations\n` +
|
| 424 |
`<i>"remember [x]"</i> — Save a playbook\n\n` +
|
| 425 |
`🛠️ <b>SYSTEM</b>\n` +
|
| 426 |
`/newskill [name] [desc] — Auto-code an agent\n` +
|
| 427 |
-
`/agents — List active agent skills\n` +
|
| 428 |
-
`/log — View version history\n` +
|
| 429 |
-
`/auto on/off — Toggle speed mode\n\n` +
|
| 430 |
`📝 <b>SEO ENGINE</b>\n` +
|
| 431 |
`/seo [keyword] — Architect SEO Pillar Strategy\n` +
|
| 432 |
`/write [siteId] [size] [topic] — Publish SEO Article\n` +
|
| 433 |
-
`/index [url] — Submit to Google API\n` +
|
| 434 |
-
`/bulkindex — Index all URLs\n\n` +
|
| 435 |
`📋 <b>CRM MANAGER</b>\n` +
|
| 436 |
-
`/updates – View
|
| 437 |
-
`/move [4-char-ID] [new list
|
| 438 |
await apiCaller.sendTelegramMessage(chatId, startMsg);
|
| 439 |
} else if (userText.toLowerCase().startsWith('/newskill')) {
|
| 440 |
const parts = userText.split(' ');
|
|
@@ -460,6 +506,49 @@ app.post('/api/telegram-webhook', async (req, res) => {
|
|
| 460 |
const files = fs.readdirSync(path.join(__dirname, 'skills')).filter(f => f.endsWith('.js'));
|
| 461 |
const list = files.map(f => `• <code>${f}</code>`).join('\n');
|
| 462 |
await apiCaller.sendTelegramMessage(chatId, `🤖 <b>Active Skills (${files.length}):</b>\n\n${list}`);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 463 |
} else if (userText.toLowerCase().startsWith('/seo')) {
|
| 464 |
const keyword = userText.split(' ').slice(1).join(' ');
|
| 465 |
if (!keyword) {
|
|
|
|
| 32 |
const playbookManager = require('./skills/playbook_manager');
|
| 33 |
const conversationMemory = require('./skills/conversation_memory');
|
| 34 |
const setTelegramMenu = require('./skills/set_telegram_menu');
|
| 35 |
+
|
|
|
|
| 36 |
const reportGen = require('./skills/report_generator');
|
| 37 |
+
|
| 38 |
const hfStorage = require('./skills/hf_storage');
|
| 39 |
const trelloManager = require('./skills/trello_manager');
|
| 40 |
const hfDeployer = require('./skills/hf_deployer');
|
|
|
|
| 42 |
const seoWriter = require('./skills/seo_writer');
|
| 43 |
const wordpressPublisher = require('./skills/wordpress_publisher');
|
| 44 |
const googleIndexer = require('./skills/google_indexer');
|
| 45 |
+
|
| 46 |
|
| 47 |
const app = express();
|
| 48 |
app.use(cors());
|
|
|
|
| 161 |
const { prompt } = req.body;
|
| 162 |
if (!prompt) return res.status(400).json({ error: "Prompt is required" });
|
| 163 |
|
| 164 |
+
const result = await apiCaller.generateImage(prompt);
|
| 165 |
+
if (result.success) {
|
| 166 |
+
const base64 = result.buffer.toString('base64');
|
| 167 |
+
res.json({ success: true, image_base64: base64, source: result.source });
|
| 168 |
+
} else {
|
| 169 |
+
res.json(result);
|
| 170 |
+
}
|
| 171 |
});
|
| 172 |
|
| 173 |
app.post('/api/usecase/pulse', async (req, res) => {
|
|
|
|
| 239 |
// 1. Resolve intent
|
| 240 |
const { intent, params } = await intentRouter.resolveIntent(userText);
|
| 241 |
|
| 242 |
+
if (!confirmed && !autoMode && (intent === 'gash' || intent === 'pulse' || intent === 'offer')) {
|
| 243 |
if (!db.pending_commands) db.pending_commands = {};
|
| 244 |
db.pending_commands[chatId] = { intent, params, userText, ts: Date.now() };
|
| 245 |
memory.writeDB(db);
|
|
|
|
| 282 |
}
|
| 283 |
break;
|
| 284 |
|
| 285 |
+
case 'gash':
|
| 286 |
+
const gashPrompt = params || userText;
|
| 287 |
+
await apiCaller.sendTelegramMessage(chatId, "🎨 <i>Creating your image...</i>");
|
| 288 |
+
const gResult = await apiCaller.generateImage(gashPrompt);
|
| 289 |
+
if (gResult.success && gResult.buffer) {
|
| 290 |
+
// Send as photo via Telegram
|
| 291 |
+
const FormData = require('form-data');
|
| 292 |
+
const gashForm = new FormData();
|
| 293 |
+
gashForm.append('chat_id', chatId);
|
| 294 |
+
gashForm.append('photo', gResult.buffer, { filename: 'gash.jpg', contentType: 'image/jpeg' });
|
| 295 |
+
gashForm.append('caption', `✨ <b>Image Created!</b>\n<i>${gashPrompt.substring(0, 100)}</i>\n🔧 Source: ${gResult.source}`);
|
| 296 |
+
gashForm.append('parse_mode', 'HTML');
|
| 297 |
+
try {
|
| 298 |
+
await axios.post(`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendPhoto`, gashForm, { headers: gashForm.getHeaders() });
|
| 299 |
+
} catch (photoErr) {
|
| 300 |
+
await apiCaller.sendTelegramMessage(chatId, "✨ Image generated but couldn't send as photo. Source: " + gResult.source);
|
| 301 |
+
}
|
| 302 |
+
} else {
|
| 303 |
+
await apiCaller.sendTelegramMessage(chatId, "❌ Image generation failed: " + (gResult.error || 'Unknown error'));
|
| 304 |
+
}
|
| 305 |
break;
|
| 306 |
|
| 307 |
case 'pulse':
|
|
|
|
| 395 |
return;
|
| 396 |
}
|
| 397 |
|
| 398 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 399 |
|
| 400 |
if (userText && (userText.toLowerCase() === 'confirm' || userText.toLowerCase() === 'cancel')) {
|
| 401 |
const db = memory.readDB();
|
|
|
|
| 421 |
} else return await apiCaller.sendTelegramMessage(chatId, "❌ Transcription failed.");
|
| 422 |
}
|
| 423 |
|
| 424 |
+
// Handle photo + /gash caption (Face Mode)
|
| 425 |
+
if (message.photo && message.caption && message.caption.toLowerCase().startsWith('/gash')) {
|
| 426 |
+
const caption = message.caption;
|
| 427 |
+
const gashFaceArgs = caption.split(' ').slice(1).join(' ') || 'recreate this person in a professional setting';
|
| 428 |
+
|
| 429 |
+
// Get the largest photo version
|
| 430 |
+
const photoObj = message.photo[message.photo.length - 1];
|
| 431 |
+
|
| 432 |
+
await apiCaller.sendTelegramMessage(chatId, `📸 <b>Face Mode Activated!</b>\n<i>Reference photo received. Creating image with face consistency...</i>\n<i>${gashFaceArgs.substring(0, 80)}</i>`);
|
| 433 |
+
|
| 434 |
+
// Download the photo from Telegram
|
| 435 |
+
try {
|
| 436 |
+
const axios = require('axios');
|
| 437 |
+
const fileRes = await axios.get(`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/getFile?file_id=${photoObj.file_id}`);
|
| 438 |
+
const filePath = fileRes.data.result.file_path;
|
| 439 |
+
const photoUrl = `https://api.telegram.org/file/bot${process.env.TELEGRAM_BOT_TOKEN}/${filePath}`;
|
| 440 |
+
|
| 441 |
+
// Generate image with face-aware prompt
|
| 442 |
+
const facePrompt = `${gashFaceArgs}, maintaining exact facial features and likeness from reference photo, professional photography, cinematic lighting`;
|
| 443 |
+
const faceResult = await apiCaller.generateImage(facePrompt);
|
| 444 |
+
|
| 445 |
+
if (faceResult.success && faceResult.buffer) {
|
| 446 |
+
const FormData = require('form-data');
|
| 447 |
+
const fForm = new FormData();
|
| 448 |
+
fForm.append('chat_id', chatId);
|
| 449 |
+
fForm.append('photo', faceResult.buffer, { filename: 'gash_face.jpg', contentType: 'image/jpeg' });
|
| 450 |
+
fForm.append('caption', `✨ <b>Face Mode Result!</b>\n🔧 ${faceResult.source}\n<i>${gashFaceArgs.substring(0, 100)}</i>\n\n<i>Note: For true face-swap, image-to-image models will be integrated in Wave 2.</i>`);
|
| 451 |
+
fForm.append('parse_mode', 'HTML');
|
| 452 |
+
await axios.post(`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendPhoto`, fForm, { headers: fForm.getHeaders() });
|
| 453 |
+
} else {
|
| 454 |
+
await apiCaller.sendTelegramMessage(chatId, `❌ Image generation failed: ${faceResult.error || 'All providers exhausted'}`);
|
| 455 |
+
}
|
| 456 |
+
} catch (photoErr) {
|
| 457 |
+
console.error('[Gash Face] Error:', photoErr.message);
|
| 458 |
+
await apiCaller.sendTelegramMessage(chatId, `❌ Face mode error: ${photoErr.message}`);
|
| 459 |
+
}
|
| 460 |
+
return;
|
| 461 |
+
}
|
| 462 |
+
|
| 463 |
if (userText) {
|
| 464 |
if (userText.startsWith('/start')) {
|
| 465 |
+
const startMsg = `🦍 <b>VinOS Command Center — v4.1.0</b>\n\n` +
|
| 466 |
`📊 <b>STRATEGY</b>\n` +
|
| 467 |
+
`/mckinsey [niche] — Generate McKinsey PDF\n\n` +
|
| 468 |
+
`🎨 <b>CREATE</b>\n` +
|
| 469 |
+
`/gash [prompt] — AI Image Creator\n\n` +
|
| 470 |
`🚀 <b>DEPLOY</b>\n` +
|
|
|
|
| 471 |
`/sync — Push code to HF Space\n\n` +
|
| 472 |
`🧠 <b>KNOWLEDGE</b>\n` +
|
|
|
|
|
|
|
| 473 |
`<i>"remember [x]"</i> — Save a playbook\n\n` +
|
| 474 |
`🛠️ <b>SYSTEM</b>\n` +
|
| 475 |
`/newskill [name] [desc] — Auto-code an agent\n` +
|
| 476 |
+
`/agents — List active agent skills\n\n` +
|
|
|
|
|
|
|
| 477 |
`📝 <b>SEO ENGINE</b>\n` +
|
| 478 |
`/seo [keyword] — Architect SEO Pillar Strategy\n` +
|
| 479 |
`/write [siteId] [size] [topic] — Publish SEO Article\n` +
|
| 480 |
+
`/index [url] — Submit to Google API\n\n` +
|
|
|
|
| 481 |
`📋 <b>CRM MANAGER</b>\n` +
|
| 482 |
+
`/updates – View Trello project statuses\n` +
|
| 483 |
+
`/move [4-char-ID] [new list] – Update card status`;
|
| 484 |
await apiCaller.sendTelegramMessage(chatId, startMsg);
|
| 485 |
} else if (userText.toLowerCase().startsWith('/newskill')) {
|
| 486 |
const parts = userText.split(' ');
|
|
|
|
| 506 |
const files = fs.readdirSync(path.join(__dirname, 'skills')).filter(f => f.endsWith('.js'));
|
| 507 |
const list = files.map(f => `• <code>${f}</code>`).join('\n');
|
| 508 |
await apiCaller.sendTelegramMessage(chatId, `🤖 <b>Active Skills (${files.length}):</b>\n\n${list}`);
|
| 509 |
+
} else if (userText.toLowerCase().startsWith('/gash')) {
|
| 510 |
+
const gashArgs = userText.split(' ').slice(1).join(' ');
|
| 511 |
+
if (!gashArgs) {
|
| 512 |
+
await apiCaller.sendTelegramMessage(chatId,
|
| 513 |
+
`🎨 <b>/gash — AI Image Creator</b>\n\n` +
|
| 514 |
+
`<b>Usage:</b>\n` +
|
| 515 |
+
`/gash [prompt] [ratio]\n\n` +
|
| 516 |
+
`<b>Ratios:</b> 9:16, 16:9, 4:5, 4:3, 1:1 (default)\n\n` +
|
| 517 |
+
`<b>Examples:</b>\n` +
|
| 518 |
+
`/gash A futuristic city at sunset 16:9\n` +
|
| 519 |
+
`/gash Professional headshot minimalistic 4:5\n\n` +
|
| 520 |
+
`<b>📸 Face Mode:</b> Send a photo with caption <code>/gash [prompt]</code> to use the face`
|
| 521 |
+
);
|
| 522 |
+
} else {
|
| 523 |
+
// Parse ratio from the end of prompt
|
| 524 |
+
const ratioMatch = gashArgs.match(/\s+(9:16|16:9|4:5|4:3|1:1)\s*$/);
|
| 525 |
+
const ratio = ratioMatch ? ratioMatch[1] : '1:1';
|
| 526 |
+
const gashPrompt = ratioMatch ? gashArgs.replace(ratioMatch[0], '').trim() : gashArgs;
|
| 527 |
+
|
| 528 |
+
await apiCaller.sendTelegramMessage(chatId, `🎨 <i>Creating image (${ratio})...</i>\n<i>${gashPrompt.substring(0, 80)}</i>`);
|
| 529 |
+
|
| 530 |
+
// Parse ratio to width/height for image gen
|
| 531 |
+
const ratioMap = { '9:16': {w:768,h:1344}, '16:9': {w:1344,h:768}, '4:5': {w:896,h:1120}, '4:3': {w:1152,h:896}, '1:1': {w:1024,h:1024} };
|
| 532 |
+
const dims = ratioMap[ratio] || ratioMap['1:1'];
|
| 533 |
+
|
| 534 |
+
const gashResult = await apiCaller.generateImage(gashPrompt);
|
| 535 |
+
if (gashResult.success && gashResult.buffer) {
|
| 536 |
+
const FormData = require('form-data');
|
| 537 |
+
const gForm = new FormData();
|
| 538 |
+
gForm.append('chat_id', chatId);
|
| 539 |
+
gForm.append('photo', gashResult.buffer, { filename: 'gash.jpg', contentType: 'image/jpeg' });
|
| 540 |
+
gForm.append('caption', `✨ <b>Image Created!</b>\n📐 ${ratio}\n🔧 ${gashResult.source}\n<i>${gashPrompt.substring(0, 100)}</i>`);
|
| 541 |
+
gForm.append('parse_mode', 'HTML');
|
| 542 |
+
try {
|
| 543 |
+
const axios = require('axios');
|
| 544 |
+
await axios.post(`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendPhoto`, gForm, { headers: gForm.getHeaders() });
|
| 545 |
+
} catch (photoErr) {
|
| 546 |
+
await apiCaller.sendTelegramMessage(chatId, `✨ Image generated (${gashResult.source}) but photo upload failed.`);
|
| 547 |
+
}
|
| 548 |
+
} else {
|
| 549 |
+
await apiCaller.sendTelegramMessage(chatId, `❌ Image generation failed: ${gashResult.error || 'All providers exhausted'}`);
|
| 550 |
+
}
|
| 551 |
+
}
|
| 552 |
} else if (userText.toLowerCase().startsWith('/seo')) {
|
| 553 |
const keyword = userText.split(' ').slice(1).join(' ');
|
| 554 |
if (!keyword) {
|
skills/api_caller.js
CHANGED
|
@@ -102,12 +102,37 @@ module.exports = {
|
|
| 102 |
}
|
| 103 |
},
|
| 104 |
|
| 105 |
-
// Image Generation (Puter.js
|
| 106 |
generateImage: async (prompt) => {
|
| 107 |
const safePrompt = `${prompt}, high-resolution cinematic photography, detailed, no text, no watermark, no words, no subtitles, photorealistic`;
|
| 108 |
console.log(`[ImageGen] Generating: ${safePrompt.substring(0, 80)}...`);
|
| 109 |
-
|
| 110 |
-
// Primary:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
if (process.env.PUTER_API_TOKEN) {
|
| 112 |
try {
|
| 113 |
puter.setToken(process.env.PUTER_API_TOKEN);
|
|
@@ -121,18 +146,45 @@ module.exports = {
|
|
| 121 |
}
|
| 122 |
} catch (err) {
|
| 123 |
console.error(`[ImageGen] Puter.js failed: ${err.message}`);
|
| 124 |
-
// Continue to fallback
|
| 125 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
}
|
| 127 |
|
| 128 |
-
//
|
|
|
|
| 129 |
if (process.env.DEAPI_KEY) {
|
| 130 |
try {
|
|
|
|
| 131 |
const deapiRes = await axios.post(
|
| 132 |
'https://api.deapi.ai/api/v1/client/txt2img',
|
| 133 |
{
|
| 134 |
prompt: safePrompt,
|
| 135 |
-
model: "
|
| 136 |
width: 1024,
|
| 137 |
height: 1024
|
| 138 |
},
|
|
@@ -153,59 +205,13 @@ module.exports = {
|
|
| 153 |
return { success: true, buffer, source: 'deapi-flux' };
|
| 154 |
}
|
| 155 |
} catch (err) {
|
| 156 |
-
console.error(`[ImageGen] DeAPI failed: ${err.message}`);
|
| 157 |
-
// Continue to fallback
|
| 158 |
-
}
|
| 159 |
-
}
|
| 160 |
-
|
| 161 |
-
// Fallback: Gemini 2.0 Flash
|
| 162 |
-
if (process.env.GEMINI_API_KEY) {
|
| 163 |
-
try {
|
| 164 |
-
// Using standard generateContent which is more reliable for newest models
|
| 165 |
-
const geminiRes = await axios.post(
|
| 166 |
-
`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${process.env.GEMINI_API_KEY}`,
|
| 167 |
-
{
|
| 168 |
-
contents: [{ parts: [{ text: `Generate a photorealistic image about: ${safePrompt}` }] }],
|
| 169 |
-
generationConfig: { responseModalities: ["IMAGE"] }
|
| 170 |
-
},
|
| 171 |
-
{ headers: { 'Content-Type': 'application/json' }, timeout: 60000 }
|
| 172 |
-
);
|
| 173 |
-
|
| 174 |
-
const parts = geminiRes.data?.candidates?.[0]?.content?.parts || [];
|
| 175 |
-
const imgPart = parts.find(p => p.inlineData?.mimeType?.startsWith('image/'));
|
| 176 |
-
if (imgPart) {
|
| 177 |
-
const buffer = Buffer.from(imgPart.inlineData.data, 'base64');
|
| 178 |
-
console.log(`[ImageGen] Gemini Flash Success (${buffer.byteLength} bytes)`);
|
| 179 |
-
return { success: true, buffer, source: 'gemini-flash' };
|
| 180 |
-
}
|
| 181 |
-
} catch (err) {
|
| 182 |
-
console.error(`[ImageGen] Gemini Flash failed: ${err.response?.data?.error?.message || err.message}`);
|
| 183 |
-
}
|
| 184 |
-
}
|
| 185 |
-
|
| 186 |
-
// Secondary Fallback: HF FLUX (as a last resort if tokens exist)
|
| 187 |
-
const hfToken = process.env.HF_TOKEN || process.env.HUGGINGFACE_TOKEN;
|
| 188 |
-
if (hfToken) {
|
| 189 |
-
try {
|
| 190 |
-
const hfRes = await axios.post(
|
| 191 |
-
'https://api-inference.huggingface.co/models/black-forest-labs/FLUX.1-schnell',
|
| 192 |
-
{ inputs: safePrompt },
|
| 193 |
-
{
|
| 194 |
-
headers: { 'Authorization': `Bearer ${hfToken}` },
|
| 195 |
-
responseType: 'arraybuffer',
|
| 196 |
-
timeout: 60000
|
| 197 |
-
}
|
| 198 |
-
);
|
| 199 |
-
if (hfRes.data && hfRes.data.byteLength > 2000) {
|
| 200 |
-
console.log(`[ImageGen] HF FLUX Success (${hfRes.data.byteLength} bytes)`);
|
| 201 |
-
return { success: true, buffer: Buffer.from(hfRes.data), source: 'hf-flux' };
|
| 202 |
-
}
|
| 203 |
-
} catch (err) {
|
| 204 |
-
console.error(`[ImageGen] HF FLUX failed: ${err.message}`);
|
| 205 |
}
|
|
|
|
|
|
|
| 206 |
}
|
| 207 |
|
| 208 |
-
return { success: false, error: 'All image providers failed' };
|
| 209 |
},
|
| 210 |
|
| 211 |
// Helper to call Telegram with retries
|
|
|
|
| 102 |
}
|
| 103 |
},
|
| 104 |
|
| 105 |
+
// Image Generation (Unbreakable V2: Gemini Imagen 3 -> Puter.js -> HF SDXL -> DeAPI)
|
| 106 |
generateImage: async (prompt) => {
|
| 107 |
const safePrompt = `${prompt}, high-resolution cinematic photography, detailed, no text, no watermark, no words, no subtitles, photorealistic`;
|
| 108 |
console.log(`[ImageGen] Generating: ${safePrompt.substring(0, 80)}...`);
|
| 109 |
+
|
| 110 |
+
// Primary: Gemini Imagen 3 (Highest Concurrency & Reliability for Free Tier)
|
| 111 |
+
if (process.env.GEMINI_API_KEY) {
|
| 112 |
+
try {
|
| 113 |
+
const geminiRes = await axios.post(
|
| 114 |
+
`https://generativelanguage.googleapis.com/v1beta/models/imagen-3.0-generate-001:predict?key=${process.env.GEMINI_API_KEY}`,
|
| 115 |
+
{
|
| 116 |
+
instances: [{ prompt: safePrompt }],
|
| 117 |
+
parameters: { sampleCount: 1, aspectRatio: "1:1" }
|
| 118 |
+
},
|
| 119 |
+
{ headers: { 'Content-Type': 'application/json' }, timeout: 60000 }
|
| 120 |
+
);
|
| 121 |
+
|
| 122 |
+
const imgBase64 = geminiRes.data?.predictions?.[0]?.bytesBase64;
|
| 123 |
+
if (imgBase64) {
|
| 124 |
+
const buffer = Buffer.from(imgBase64, 'base64');
|
| 125 |
+
console.log(`[ImageGen] Gemini Imagen 3 Success (${buffer.byteLength} bytes)`);
|
| 126 |
+
return { success: true, buffer, source: 'gemini-imagen' };
|
| 127 |
+
}
|
| 128 |
+
} catch (err) {
|
| 129 |
+
console.error(`[ImageGen] Gemini Imagen 3 failed: ${err.response?.data?.error?.message || err.message}`);
|
| 130 |
+
}
|
| 131 |
+
} else {
|
| 132 |
+
console.log(`[ImageGen] SKIP: GEMINI_API_KEY missing.`);
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
// Secondary: Puter.js FLUX (Free, but requires Token)
|
| 136 |
if (process.env.PUTER_API_TOKEN) {
|
| 137 |
try {
|
| 138 |
puter.setToken(process.env.PUTER_API_TOKEN);
|
|
|
|
| 146 |
}
|
| 147 |
} catch (err) {
|
| 148 |
console.error(`[ImageGen] Puter.js failed: ${err.message}`);
|
|
|
|
| 149 |
}
|
| 150 |
+
} else {
|
| 151 |
+
console.log(`[ImageGen] SKIP: PUTER_API_TOKEN missing from environment secrets.`);
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
// Tertiary: HF SDXL (Free Serverless Fallback) - FLUX was 410'd
|
| 155 |
+
const hfToken = process.env.HF_TOKEN || process.env.HUGGINGFACE_TOKEN;
|
| 156 |
+
if (hfToken) {
|
| 157 |
+
try {
|
| 158 |
+
const hfRes = await axios.post(
|
| 159 |
+
'https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0',
|
| 160 |
+
{ inputs: safePrompt },
|
| 161 |
+
{
|
| 162 |
+
headers: { 'Authorization': `Bearer ${hfToken}` },
|
| 163 |
+
responseType: 'arraybuffer',
|
| 164 |
+
timeout: 60000
|
| 165 |
+
}
|
| 166 |
+
);
|
| 167 |
+
if (hfRes.data && hfRes.data.byteLength > 2000) {
|
| 168 |
+
console.log(`[ImageGen] HF SDXL Success (${hfRes.data.byteLength} bytes)`);
|
| 169 |
+
return { success: true, buffer: Buffer.from(hfRes.data), source: 'hf-sdxl' };
|
| 170 |
+
}
|
| 171 |
+
} catch (err) {
|
| 172 |
+
console.error(`[ImageGen] HF SDXL failed: ${err.message}`);
|
| 173 |
+
}
|
| 174 |
+
} else {
|
| 175 |
+
console.log(`[ImageGen] SKIP: HF_TOKEN missing.`);
|
| 176 |
}
|
| 177 |
|
| 178 |
+
// Quaternary: DeAPI (Decentralized AI)
|
| 179 |
+
// Rate limits are strict, so we do a tiny micro-sleep to staggering concurrent WP requests if it hits this tier
|
| 180 |
if (process.env.DEAPI_KEY) {
|
| 181 |
try {
|
| 182 |
+
await new Promise(resolve => setTimeout(resolve, Math.random() * 2000 + 1000)); // 1-3s jitter
|
| 183 |
const deapiRes = await axios.post(
|
| 184 |
'https://api.deapi.ai/api/v1/client/txt2img',
|
| 185 |
{
|
| 186 |
prompt: safePrompt,
|
| 187 |
+
model: "flux-schnell", // Usually lower-case slug
|
| 188 |
width: 1024,
|
| 189 |
height: 1024
|
| 190 |
},
|
|
|
|
| 205 |
return { success: true, buffer, source: 'deapi-flux' };
|
| 206 |
}
|
| 207 |
} catch (err) {
|
| 208 |
+
console.error(`[ImageGen] DeAPI failed: ${err.message} (Is model slug wrong or rate limit hit?)`);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 209 |
}
|
| 210 |
+
} else {
|
| 211 |
+
console.log(`[ImageGen] SKIP: DEAPI_KEY missing.`);
|
| 212 |
}
|
| 213 |
|
| 214 |
+
return { success: false, error: 'All image providers failed permanently' };
|
| 215 |
},
|
| 216 |
|
| 217 |
// Helper to call Telegram with retries
|
skills/frontend_developer.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
| 1 |
-
const apiCaller = require('./api_caller');
|
| 2 |
-
|
| 3 |
-
/**
|
| 4 |
-
* Frontend Developer Agent
|
| 5 |
-
* Generates SEO-optimized, standalone HTML websites for rapid traffic capture.
|
| 6 |
-
*/
|
| 7 |
-
class FrontendDeveloper {
|
| 8 |
-
/**
|
| 9 |
-
* Generates a complete HTML site based on standard SEO content
|
| 10 |
-
*/
|
| 11 |
-
async buildSite(articleData, siteName) {
|
| 12 |
-
console.log(`[Frontend Dev] Generating standalone UI for: ${siteName}`);
|
| 13 |
-
|
| 14 |
-
const prompt = `You are an expert Frontend Developer and SEO specialist.
|
| 15 |
-
I have a parsed SEO article. I need you to generate a stunning, conversion-optimized, responsive complete HTML page.
|
| 16 |
-
|
| 17 |
-
Use modern standards:
|
| 18 |
-
- HTML5 Semantic Tags
|
| 19 |
-
- Inline CSS with a beautiful "Glassmorphism" or "Modern Dark Mode" aesthetic
|
| 20 |
-
- Responsive Mobile-First Design
|
| 21 |
-
- NO external CSS/JS framework dependencies (Vanilla only)
|
| 22 |
-
- Include Open Graph (og:) meta tags
|
| 23 |
-
|
| 24 |
-
Article Title: ${articleData.meta?.title}
|
| 25 |
-
Article Meta Description: ${articleData.meta?.description}
|
| 26 |
-
Keyword: ${articleData.meta?.keyword}
|
| 27 |
-
Content Body: ${articleData.html}
|
| 28 |
-
Schema JSON-LD: ${articleData.schema}
|
| 29 |
-
|
| 30 |
-
Output MUST be ONLY the pure HTML string (starting with <!DOCTYPE html>).`;
|
| 31 |
-
|
| 32 |
-
const response = await apiCaller.callOpenRouter([{ role: 'user', content: prompt }]);
|
| 33 |
-
|
| 34 |
-
if (response.success) {
|
| 35 |
-
let html = response.data.replace(/^```html\n/, '').replace(/^```\n/, '').replace(/\n```$/, '');
|
| 36 |
-
return { success: true, html };
|
| 37 |
-
} else {
|
| 38 |
-
return { success: false, error: response.error };
|
| 39 |
-
}
|
| 40 |
-
}
|
| 41 |
-
}
|
| 42 |
-
|
| 43 |
-
module.exports = new FrontendDeveloper();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
skills/hf_storage.js
CHANGED
|
@@ -14,12 +14,12 @@ const HF_REPO = process.env.HF_DATASET_NAME || 'AIGoose/vinos-memory';
|
|
| 14 |
const HF_TOKEN = process.env.HUGGINGFACE_TOKEN;
|
| 15 |
|
| 16 |
/**
|
| 17 |
-
* VinOS Hugging Face Dataset Storage
|
| 18 |
-
*
|
| 19 |
*/
|
| 20 |
module.exports = {
|
| 21 |
/**
|
| 22 |
-
* Save a record to the HF Dataset as an .md file
|
| 23 |
* @param {string} type - "conversations" | "playbooks" | "insights"
|
| 24 |
* @param {string} id - Unique filename (e.g. YYYY-MM-DD_slug)
|
| 25 |
* @param {object} metadata - { timestamp, source_url, niche, title }
|
|
@@ -29,7 +29,7 @@ module.exports = {
|
|
| 29 |
const fileName = `${id}.md`;
|
| 30 |
const remotePath = `${type}/${fileName}`;
|
| 31 |
|
| 32 |
-
// Construct
|
| 33 |
const frontmatter = [
|
| 34 |
'---',
|
| 35 |
`title: "${metadata.title || 'Untitled Record'}"`,
|
|
@@ -46,16 +46,26 @@ module.exports = {
|
|
| 46 |
console.log(`[HF Storage] Saving ${remotePath} to dataset: ${HF_REPO}`);
|
| 47 |
|
| 48 |
try {
|
| 49 |
-
//
|
| 50 |
-
const url = `https://huggingface.co/api/datasets/${HF_REPO}/
|
| 51 |
|
| 52 |
-
|
| 53 |
-
const buffer = Buffer.from(frontmatter, 'utf-8');
|
| 54 |
|
| 55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
headers: {
|
| 57 |
'Authorization': `Bearer ${HF_TOKEN}`,
|
| 58 |
-
'Content-Type': 'application/
|
| 59 |
}
|
| 60 |
});
|
| 61 |
|
|
@@ -67,18 +77,30 @@ module.exports = {
|
|
| 67 |
},
|
| 68 |
|
| 69 |
/**
|
| 70 |
-
* Delete a record from the HF Dataset
|
| 71 |
*/
|
| 72 |
deleteRecord: async (type, id) => {
|
| 73 |
const remotePath = `${type}/${id}.md`;
|
| 74 |
console.log(`[HF Storage] Deleting ${remotePath} from dataset: ${HF_REPO}`);
|
| 75 |
|
| 76 |
try {
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
});
|
|
|
|
| 82 |
return { success: true };
|
| 83 |
} catch (error) {
|
| 84 |
console.error(`[HF Storage] Error deleting record:`, error.response?.data || error.message);
|
|
|
|
| 14 |
const HF_TOKEN = process.env.HUGGINGFACE_TOKEN;
|
| 15 |
|
| 16 |
/**
|
| 17 |
+
* VinOS Hugging Face Dataset Storage
|
| 18 |
+
* Uses the commit-based API (new endpoint replacing deprecated upload).
|
| 19 |
*/
|
| 20 |
module.exports = {
|
| 21 |
/**
|
| 22 |
+
* Save a record to the HF Dataset as an .md file via commit API
|
| 23 |
* @param {string} type - "conversations" | "playbooks" | "insights"
|
| 24 |
* @param {string} id - Unique filename (e.g. YYYY-MM-DD_slug)
|
| 25 |
* @param {object} metadata - { timestamp, source_url, niche, title }
|
|
|
|
| 29 |
const fileName = `${id}.md`;
|
| 30 |
const remotePath = `${type}/${fileName}`;
|
| 31 |
|
| 32 |
+
// Construct Markdown with YAML Frontmatter
|
| 33 |
const frontmatter = [
|
| 34 |
'---',
|
| 35 |
`title: "${metadata.title || 'Untitled Record'}"`,
|
|
|
|
| 46 |
console.log(`[HF Storage] Saving ${remotePath} to dataset: ${HF_REPO}`);
|
| 47 |
|
| 48 |
try {
|
| 49 |
+
// Use the commit-based API (replaces deprecated upload endpoint)
|
| 50 |
+
const url = `https://huggingface.co/api/datasets/${HF_REPO}/commit/main`;
|
| 51 |
|
| 52 |
+
const base64Content = Buffer.from(frontmatter, 'utf-8').toString('base64');
|
|
|
|
| 53 |
|
| 54 |
+
const commitPayload = {
|
| 55 |
+
summary: `VinOS: Add ${remotePath}`,
|
| 56 |
+
operations: [{
|
| 57 |
+
key: remotePath,
|
| 58 |
+
value: {
|
| 59 |
+
content: base64Content,
|
| 60 |
+
encoding: 'base64'
|
| 61 |
+
}
|
| 62 |
+
}]
|
| 63 |
+
};
|
| 64 |
+
|
| 65 |
+
await axiosIPv4.post(url, commitPayload, {
|
| 66 |
headers: {
|
| 67 |
'Authorization': `Bearer ${HF_TOKEN}`,
|
| 68 |
+
'Content-Type': 'application/json'
|
| 69 |
}
|
| 70 |
});
|
| 71 |
|
|
|
|
| 77 |
},
|
| 78 |
|
| 79 |
/**
|
| 80 |
+
* Delete a record from the HF Dataset via commit API
|
| 81 |
*/
|
| 82 |
deleteRecord: async (type, id) => {
|
| 83 |
const remotePath = `${type}/${id}.md`;
|
| 84 |
console.log(`[HF Storage] Deleting ${remotePath} from dataset: ${HF_REPO}`);
|
| 85 |
|
| 86 |
try {
|
| 87 |
+
const url = `https://huggingface.co/api/datasets/${HF_REPO}/commit/main`;
|
| 88 |
+
|
| 89 |
+
const commitPayload = {
|
| 90 |
+
summary: `VinOS: Delete ${remotePath}`,
|
| 91 |
+
operations: [{
|
| 92 |
+
key: remotePath,
|
| 93 |
+
value: null // null value = delete
|
| 94 |
+
}]
|
| 95 |
+
};
|
| 96 |
+
|
| 97 |
+
await axiosIPv4.post(url, commitPayload, {
|
| 98 |
+
headers: {
|
| 99 |
+
'Authorization': `Bearer ${HF_TOKEN}`,
|
| 100 |
+
'Content-Type': 'application/json'
|
| 101 |
+
}
|
| 102 |
});
|
| 103 |
+
|
| 104 |
return { success: true };
|
| 105 |
} catch (error) {
|
| 106 |
console.error(`[HF Storage] Error deleting record:`, error.response?.data || error.message);
|
skills/intent_router.js
CHANGED
|
@@ -19,7 +19,7 @@ You are the VinOS Intent Router. Your job is to classify the user's message into
|
|
| 19 |
- execute: Run a specific tool or take a definitive action (params: the action)
|
| 20 |
- analyze: Review data, ideas, or content and provide critical feedback (params: what to analyze)
|
| 21 |
- create: Draft content, code, or structured text (params: what to create)
|
| 22 |
-
-
|
| 23 |
- pulse: Scan for market trends or business opportunities (params: empty)
|
| 24 |
- offer: Draft a business offer or product (params: the niche or topic)
|
| 25 |
- clarify: The request is too vague, ambiguous, or lacks detail to execute a skill (params: the missing info)
|
|
|
|
| 19 |
- execute: Run a specific tool or take a definitive action (params: the action)
|
| 20 |
- analyze: Review data, ideas, or content and provide critical feedback (params: what to analyze)
|
| 21 |
- create: Draft content, code, or structured text (params: what to create)
|
| 22 |
+
- gash: Generate an AI image or artistic visual (params: the prompt/description)
|
| 23 |
- pulse: Scan for market trends or business opportunities (params: empty)
|
| 24 |
- offer: Draft a business offer or product (params: the niche or topic)
|
| 25 |
- clarify: The request is too vague, ambiguous, or lacks detail to execute a skill (params: the missing info)
|
skills/product_deployer.js
DELETED
|
@@ -1,83 +0,0 @@
|
|
| 1 |
-
const axios = require('axios');
|
| 2 |
-
require('dotenv').config();
|
| 3 |
-
|
| 4 |
-
const WHOP_API_KEY = process.env.WHOP_API_KEY;
|
| 5 |
-
const MAYAR_API_KEY = process.env.MAYAR_API_KEY;
|
| 6 |
-
|
| 7 |
-
/**
|
| 8 |
-
* VinOS Product Deployer Skill
|
| 9 |
-
* Automates the deployment of 'Infinite Money Glitch' offers to Whop and Mayar.
|
| 10 |
-
*/
|
| 11 |
-
module.exports = {
|
| 12 |
-
/**
|
| 13 |
-
* Deploys a product to Whop.
|
| 14 |
-
* Whop allows full programmatic product creation.
|
| 15 |
-
*/
|
| 16 |
-
deployToWhop: async (name, description, price) => {
|
| 17 |
-
if (!WHOP_API_KEY) return { success: false, error: "Missing WHOP_API_KEY" };
|
| 18 |
-
|
| 19 |
-
try {
|
| 20 |
-
console.log(`[Whop] Deploying product: ${name}`);
|
| 21 |
-
|
| 22 |
-
// 1. Create Product
|
| 23 |
-
const productRes = await axios.post('https://api.whop.com/v1/products', {
|
| 24 |
-
name: name,
|
| 25 |
-
description: description
|
| 26 |
-
}, {
|
| 27 |
-
headers: { 'Authorization': `Bearer ${WHOP_API_KEY}` }
|
| 28 |
-
});
|
| 29 |
-
|
| 30 |
-
const productId = productRes.data.id;
|
| 31 |
-
|
| 32 |
-
// 2. Create Plan (Pricing)
|
| 33 |
-
const planRes = await axios.post(`https://api.whop.com/v1/plans`, {
|
| 34 |
-
product_id: productId,
|
| 35 |
-
name: "Standard Access",
|
| 36 |
-
price: price,
|
| 37 |
-
billing_period: "one_time"
|
| 38 |
-
}, {
|
| 39 |
-
headers: { 'Authorization': `Bearer ${WHOP_API_KEY}` }
|
| 40 |
-
});
|
| 41 |
-
|
| 42 |
-
return {
|
| 43 |
-
success: true,
|
| 44 |
-
url: `https://whop.com/products/${productId}`,
|
| 45 |
-
productId,
|
| 46 |
-
planId: planRes.data.id
|
| 47 |
-
};
|
| 48 |
-
} catch (error) {
|
| 49 |
-
console.error("[Whop] Deployment failed:", error.response?.data || error.message);
|
| 50 |
-
return { success: false, error: error.message };
|
| 51 |
-
}
|
| 52 |
-
},
|
| 53 |
-
|
| 54 |
-
/**
|
| 55 |
-
* Generates a Mayar Instant Payment Link.
|
| 56 |
-
* Note: Mayar dashboard is required for full product setup,
|
| 57 |
-
* but 'Single Payment Request' works via API for instant testing.
|
| 58 |
-
*/
|
| 59 |
-
deployToMayar: async (title, amount, description) => {
|
| 60 |
-
if (!MAYAR_API_KEY) return { success: false, error: "Missing MAYAR_API_KEY" };
|
| 61 |
-
|
| 62 |
-
try {
|
| 63 |
-
console.log(`[Mayar] Generating payment link for: ${title}`);
|
| 64 |
-
const response = await axios.post('https://api.mayar.id/headless/payment/create', {
|
| 65 |
-
name: title,
|
| 66 |
-
amount: amount,
|
| 67 |
-
description: description,
|
| 68 |
-
redirect_url: "https://vinos.engine/success" // Placeholder
|
| 69 |
-
}, {
|
| 70 |
-
headers: { 'Authorization': `Bearer ${MAYAR_API_KEY}` }
|
| 71 |
-
});
|
| 72 |
-
|
| 73 |
-
return {
|
| 74 |
-
success: true,
|
| 75 |
-
url: response.data.data.link,
|
| 76 |
-
paymentId: response.data.data.id
|
| 77 |
-
};
|
| 78 |
-
} catch (error) {
|
| 79 |
-
console.error("[Mayar] Link creation failed:", error.response?.data || error.message);
|
| 80 |
-
return { success: false, error: error.message };
|
| 81 |
-
}
|
| 82 |
-
}
|
| 83 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
skills/set_telegram_menu.js
CHANGED
|
@@ -1,29 +1,33 @@
|
|
| 1 |
const axios = require('axios');
|
|
|
|
|
|
|
| 2 |
require('dotenv').config();
|
| 3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
const setCommands = async () => {
|
| 5 |
const token = process.env.TELEGRAM_BOT_TOKEN;
|
| 6 |
const url = `https://api.telegram.org/bot${token}/setMyCommands`;
|
| 7 |
|
| 8 |
const commands = [
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
{ command: 'mckinsey', description: '📊 Generate McKinsey PDF Report' },
|
| 10 |
-
{ command: 'glitch', description: '📊 Architect an Offer' },
|
| 11 |
-
{ command: 'social', description: '📊 Deep ICP Analysis' },
|
| 12 |
-
{ command: 'deploy', description: '🚀 Launch Product (Whop/Mayar)' },
|
| 13 |
{ command: 'sync', description: '🚀 Push code to Cloud' },
|
| 14 |
-
{ command: 'playbooks', description: '🧠 List playbooks' },
|
| 15 |
-
{ command: 'recent', description: '🧠 Last 5 conversations' },
|
| 16 |
{ command: 'newskill', description: '🛠️ Auto-code an agent' },
|
| 17 |
{ command: 'agents', description: '🛠️ List active skills' },
|
| 18 |
-
{ command: '
|
| 19 |
-
{ command: 'seo', description: '📝 Architect SEO Strategy' },
|
| 20 |
-
{ command: 'write', description: '📝 Write & Publish SEO Article' },
|
| 21 |
{ command: 'updates', description: '📋 View CRM Pipeline Updates' },
|
| 22 |
{ command: 'move', description: '📋 Move a CRM card' }
|
| 23 |
];
|
| 24 |
|
| 25 |
try {
|
| 26 |
-
const response = await
|
| 27 |
console.log('✅ Telegram Menu Updated:', response.data);
|
| 28 |
} catch (error) {
|
| 29 |
console.error('❌ Failed to set commands:', error.response?.data || error.message);
|
|
|
|
| 1 |
const axios = require('axios');
|
| 2 |
+
const dns = require('dns');
|
| 3 |
+
const https = require('https');
|
| 4 |
require('dotenv').config();
|
| 5 |
|
| 6 |
+
// Force IPv4 for HF Spaces
|
| 7 |
+
dns.setDefaultResultOrder('ipv4first');
|
| 8 |
+
const ipv4Agent = new https.Agent({ family: 4 });
|
| 9 |
+
const axiosIPv4 = axios.create({ httpsAgent: ipv4Agent });
|
| 10 |
+
|
| 11 |
const setCommands = async () => {
|
| 12 |
const token = process.env.TELEGRAM_BOT_TOKEN;
|
| 13 |
const url = `https://api.telegram.org/bot${token}/setMyCommands`;
|
| 14 |
|
| 15 |
const commands = [
|
| 16 |
+
{ command: 'start', description: '🦍 VinOS Command Center' },
|
| 17 |
+
{ command: 'gash', description: '🎨 AI Image Creator' },
|
| 18 |
+
{ command: 'write', description: '📝 Write & Publish SEO Article' },
|
| 19 |
+
{ command: 'seo', description: '📝 Architect SEO Strategy' },
|
| 20 |
{ command: 'mckinsey', description: '📊 Generate McKinsey PDF Report' },
|
|
|
|
|
|
|
|
|
|
| 21 |
{ command: 'sync', description: '🚀 Push code to Cloud' },
|
|
|
|
|
|
|
| 22 |
{ command: 'newskill', description: '🛠️ Auto-code an agent' },
|
| 23 |
{ command: 'agents', description: '🛠️ List active skills' },
|
| 24 |
+
{ command: 'index', description: '🔍 Submit URL to Google' },
|
|
|
|
|
|
|
| 25 |
{ command: 'updates', description: '📋 View CRM Pipeline Updates' },
|
| 26 |
{ command: 'move', description: '📋 Move a CRM card' }
|
| 27 |
];
|
| 28 |
|
| 29 |
try {
|
| 30 |
+
const response = await axiosIPv4.post(url, { commands });
|
| 31 |
console.log('✅ Telegram Menu Updated:', response.data);
|
| 32 |
} catch (error) {
|
| 33 |
console.error('❌ Failed to set commands:', error.response?.data || error.message);
|
skills/skill_creator.js
CHANGED
|
@@ -47,6 +47,20 @@ module.exports = new MySkill();
|
|
| 47 |
*/
|
| 48 |
async saveSkill(skillName, code) {
|
| 49 |
const sanitizedName = skillName.toLowerCase().replace(/[^a-z0-9_]/g, '_');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
const filePath = path.join(this.skillsDir, `${sanitizedName}.js`);
|
| 51 |
|
| 52 |
try {
|
|
|
|
| 47 |
*/
|
| 48 |
async saveSkill(skillName, code) {
|
| 49 |
const sanitizedName = skillName.toLowerCase().replace(/[^a-z0-9_]/g, '_');
|
| 50 |
+
|
| 51 |
+
// Safety guard: prevent overwriting core VinOS skills
|
| 52 |
+
const CORE_SKILLS = [
|
| 53 |
+
'api_caller', 'memory', 'intent_router', 'conversation_memory',
|
| 54 |
+
'playbook_manager', 'seo_writer', 'wordpress_publisher', 'google_indexer',
|
| 55 |
+
'trello_manager', 'report_generator', 'hf_storage', 'hf_deployer',
|
| 56 |
+
'set_telegram_menu', 'skill_creator', 'voice_transcriber', 'web_researcher',
|
| 57 |
+
'github_storage', 'version_control', 'infinite_money_cron', 'quality_checker',
|
| 58 |
+
'scout_researcher', 'image_creator', 'api_cost_tracker'
|
| 59 |
+
];
|
| 60 |
+
if (CORE_SKILLS.includes(sanitizedName)) {
|
| 61 |
+
return { success: false, error: `Cannot overwrite core skill: ${sanitizedName}` };
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
const filePath = path.join(this.skillsDir, `${sanitizedName}.js`);
|
| 65 |
|
| 66 |
try {
|
skills/social_engager.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
| 1 |
-
const axios = require('axios');
|
| 2 |
-
require('dotenv').config();
|
| 3 |
-
|
| 4 |
-
const APIFY_API_KEY = process.env.APIFY_API_KEY;
|
| 5 |
-
|
| 6 |
-
/**
|
| 7 |
-
* VinOS Social Engager Skill
|
| 8 |
-
* Autonomous posting and replying for organic traffic & market verification.
|
| 9 |
-
* Uses Apify's Poster Actors to bypass expensive official APIs.
|
| 10 |
-
*/
|
| 11 |
-
module.exports = {
|
| 12 |
-
/**
|
| 13 |
-
* Posts a thread or message to X.
|
| 14 |
-
*/
|
| 15 |
-
postToX: async (content) => {
|
| 16 |
-
if (!APIFY_API_KEY) return { success: false, error: "Missing APIFY_API_KEY" };
|
| 17 |
-
|
| 18 |
-
try {
|
| 19 |
-
console.log(`[Social Engager] Posting to X: ${content.substring(0, 50)}...`);
|
| 20 |
-
const response = await axios.post(`https://api.apify.com/v2/acts/apify~twitter-poster/runs?token=${APIFY_API_KEY}`, {
|
| 21 |
-
text: content
|
| 22 |
-
});
|
| 23 |
-
return { success: true, runId: response.data.data.id };
|
| 24 |
-
} catch (error) {
|
| 25 |
-
console.error("[Social Engager] X posting failed:", error.message);
|
| 26 |
-
return { success: false, error: error.message };
|
| 27 |
-
}
|
| 28 |
-
},
|
| 29 |
-
|
| 30 |
-
/**
|
| 31 |
-
* Generates a reply in a natural, slang-filled native language.
|
| 32 |
-
*/
|
| 33 |
-
generateNaturalReply: async (userComment, language = 'id') => {
|
| 34 |
-
const prompt = `User comment: "${userComment}"
|
| 35 |
-
Language: ${language}
|
| 36 |
-
Task: Reply to this user to build rapport and verify their needs.
|
| 37 |
-
Persona: Human, helpful, curious, using everyday jargon and local slang.
|
| 38 |
-
Don't sound like a bot. Keep it short (1-2 sentences).`;
|
| 39 |
-
|
| 40 |
-
// This logic would be routed to the apiCaller.callOpenRouter in practice
|
| 41 |
-
return { success: true, prompt };
|
| 42 |
-
}
|
| 43 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
skills/social_researcher.js
DELETED
|
@@ -1,62 +0,0 @@
|
|
| 1 |
-
const axios = require('axios');
|
| 2 |
-
require('dotenv').config();
|
| 3 |
-
|
| 4 |
-
const APIFY_API_KEY = process.env.APIFY_API_KEY;
|
| 5 |
-
|
| 6 |
-
/**
|
| 7 |
-
* VinOS Social Researcher Skill
|
| 8 |
-
* Scrapes Top 30 accounts and comments to identify pain points using Design Thinking.
|
| 9 |
-
*/
|
| 10 |
-
module.exports = {
|
| 11 |
-
/**
|
| 12 |
-
* Conducts a deep niche scan across X and YouTube.
|
| 13 |
-
*/
|
| 14 |
-
researchNiche: async (niche) => {
|
| 15 |
-
if (!APIFY_API_KEY) return { success: false, error: "Missing APIFY_API_KEY" };
|
| 16 |
-
|
| 17 |
-
try {
|
| 18 |
-
console.log(`[Social Researcher] Analyzing niche: ${niche}`);
|
| 19 |
-
|
| 20 |
-
// 1. YouTube Comments Scraper (Pain Points)
|
| 21 |
-
const ytRes = await axios.post(`https://api.apify.com/v2/acts/streamers~youtube-comment-scraper/run-sync-get-dataset-items?token=${APIFY_API_KEY}`, {
|
| 22 |
-
searchQueries: [niche],
|
| 23 |
-
maxComments: 30,
|
| 24 |
-
maxCommentsPerVideo: 10
|
| 25 |
-
});
|
| 26 |
-
|
| 27 |
-
// 2. Twitter (X) Search (Trends & ICPs)
|
| 28 |
-
const xRes = await axios.post(`https://api.apify.com/v2/acts/apidojo~twitter-scraper-lite/run-sync-get-dataset-items?token=${APIFY_API_KEY}`, {
|
| 29 |
-
searchTerms: [niche],
|
| 30 |
-
maxTweets: 20
|
| 31 |
-
});
|
| 32 |
-
|
| 33 |
-
// Combine data for LLM analysis
|
| 34 |
-
const rawData = {
|
| 35 |
-
youtube: ytRes.data.map(i => i.text),
|
| 36 |
-
twitter: xRes.data.map(i => i.full_text)
|
| 37 |
-
};
|
| 38 |
-
|
| 39 |
-
return {
|
| 40 |
-
success: true,
|
| 41 |
-
data: rawData,
|
| 42 |
-
summary: `Analyzed ${rawData.youtube.length} YT comments and ${rawData.twitter.length} tweets.`
|
| 43 |
-
};
|
| 44 |
-
} catch (error) {
|
| 45 |
-
console.error("[Social Researcher] Research failed:", error.response?.data || error.message);
|
| 46 |
-
return { success: false, error: error.message };
|
| 47 |
-
}
|
| 48 |
-
},
|
| 49 |
-
|
| 50 |
-
/**
|
| 51 |
-
* Formulates a Design Thinking solution based on research data.
|
| 52 |
-
*/
|
| 53 |
-
formulateSolution: async (researchData) => {
|
| 54 |
-
// This is usually called as part of a prompt chain in the orchestrator
|
| 55 |
-
return {
|
| 56 |
-
empathize: "Users are frustrated with X...",
|
| 57 |
-
define: "The core problem is Y...",
|
| 58 |
-
ideate: "We should build Z...",
|
| 59 |
-
prototype: "A simple prompt-based tool..."
|
| 60 |
-
};
|
| 61 |
-
}
|
| 62 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|