Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1db7b228bd | |||
| 96d1684849 | |||
| 7e6e105fdb |
@@ -168,13 +168,19 @@ class WgetCloner {
|
|||||||
console.log(`${'='.repeat(60)}\n`);
|
console.log(`${'='.repeat(60)}\n`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// countFiles inline helper
|
||||||
|
var countFiles = function(dir) { var ts=0,fc=0; (function rec(d){if(!fs.existsSync(d))return;fs.readdirSync(d).forEach(function(i){var p=path.join(d,i),s=fs.statSync(p);if(s.isDirectory()&&i.indexOf("cloned-sites")==-1&&i.indexOf(".versions")==-1)rec(p);else if(!s.isDirectory()){ts+=s.size;fc++;}});})(dir);return{fileCount:fc,totalSize:ts};};
|
||||||
|
|
||||||
// Criar arquivo de informações
|
// Criar arquivo de informações
|
||||||
|
const stats = countFiles(siteDir);
|
||||||
const info = {
|
const info = {
|
||||||
originalUrl: url,
|
originalUrl: url,
|
||||||
clonedAt: new Date().toISOString(),
|
clonedAt: new Date().toISOString(),
|
||||||
directory: siteDir,
|
directory: siteDir,
|
||||||
method: 'wget',
|
method: 'wget',
|
||||||
success: true
|
success: true,
|
||||||
|
fileCount: stats.fileCount,
|
||||||
|
totalSize: stats.totalSize
|
||||||
};
|
};
|
||||||
|
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
|
|||||||
@@ -58,18 +58,27 @@ async function scoutSearch() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function simulateScoutSearch(niche, region) {
|
async function askAI(systemPrompt, userMessage) {
|
||||||
// Simula busca do Scout - retornaria do agente real
|
const response = await fetch('/api/ai/agent', {
|
||||||
await new Promise(r => setTimeout(r, 1500));
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ systemPrompt, userMessage })
|
||||||
|
});
|
||||||
|
const result = await response.json();
|
||||||
|
if (!result.success) throw new Error(result.error);
|
||||||
|
return result.data;
|
||||||
|
}
|
||||||
|
|
||||||
const examples = [
|
async function simulateScoutSearch(niche, region) {
|
||||||
{ url: 'https://lojaexemplo.com.br', name: 'Loja Exemplo Ltda', score: 8, reason: 'Site de 2012, sem responsividade', social: '@lojaexemplo' },
|
// Busca do Scout - retorna do agente real MiniMax
|
||||||
{ url: 'https://padariajoao.com.br', name: 'Padaria João', score: 9, reason: 'Site estático, layout antigo', social: '@padariajoao' },
|
const prompt = `Você é um agente Scout. Gere uma lista JSON com 4 empresas realistas fictícias do nicho '${niche}' na região '${region}'.
|
||||||
{ url: 'https://petshopamigo.com', name: 'Pet Shop Amigo', score: 7, reason: 'Sem SSL, sem mobile', social: '@petshopamigo' },
|
Retorne APENAS um array JSON, sem marcação markdown.
|
||||||
{ url: 'https://restaurantesabor.com.br', name: 'Restaurante Sabor', score: 8, reason: 'Menu em PDF, sem pedido online', social: '@restaurantesabor' },
|
Estrutura: [{"url": "...", "name": "...", "score": 8, "reason": "...", "social": "..."}]`;
|
||||||
{ url: 'https://academiafit.com.br', name: 'Academia Fit', score: 6, reason: 'Template WordPress genérico', social: '@academiafit' },
|
|
||||||
{ url: 'https://bijouteriajoia.com.br', name: 'Bijouteria Joia', score: 9, reason: 'Site Flash antigo', social: '@bijouteriajoia' },
|
try {
|
||||||
];
|
const rawResponse = await askAI(prompt, "Inicie a prospecção.");
|
||||||
|
const jsonStr = rawResponse.replace(/```json/gi, '').replace(/```/g, '').trim();
|
||||||
|
const examples = JSON.parse(jsonStr);
|
||||||
|
|
||||||
return examples.map((t, i) => ({
|
return examples.map((t, i) => ({
|
||||||
id: i + 1,
|
id: i + 1,
|
||||||
@@ -78,6 +87,10 @@ async function simulateScoutSearch(niche, region) {
|
|||||||
region,
|
region,
|
||||||
analyzedAt: new Date().toISOString()
|
analyzedAt: new Date().toISOString()
|
||||||
}));
|
}));
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Erro na IA:", e);
|
||||||
|
throw new Error("O agente falhou em gerar a lista de prospecção. Tente novamente.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderScoutResults(targets) {
|
function renderScoutResults(targets) {
|
||||||
@@ -189,12 +202,13 @@ async function startDesign() {
|
|||||||
throw new Error(cloneResult.error || 'Falha ao clonar');
|
throw new Error(cloneResult.error || 'Falha ao clonar');
|
||||||
}
|
}
|
||||||
|
|
||||||
agentsState.designer.currentClone.directory = cloneResult.directory;
|
const directory = cloneResult.data?.directory || cloneResult.data?.path || cloneResult.directory;
|
||||||
|
agentsState.designer.currentClone.directory = directory;
|
||||||
updateDesignerStatus('✅ Site clonado com sucesso');
|
updateDesignerStatus('✅ Site clonado com sucesso');
|
||||||
|
|
||||||
// Step 2: Apply ultra-modern redesign
|
// Step 2: Apply ultra-modern redesign
|
||||||
updateDesignerStatus('🎨 Aplicando redesign ultra-moderno...');
|
updateDesignerStatus('🎨 Aplicando redesign ultra-moderno...');
|
||||||
const redesignResult = await applyUltraModernRedesign(cloneResult.directory);
|
const redesignResult = await applyUltraModernRedesign(directory);
|
||||||
|
|
||||||
updateDesignerStatus('✨ Redesign concluído!');
|
updateDesignerStatus('✨ Redesign concluído!');
|
||||||
showDesignerPreview(redesignResult.previewUrl);
|
showDesignerPreview(redesignResult.previewUrl);
|
||||||
@@ -208,7 +222,7 @@ async function startDesign() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function cloneSite(url) {
|
async function cloneSite(url) {
|
||||||
const response = await fetch('/api/wget-clone', {
|
const response = await fetch('/api/smart-clone', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ url })
|
body: JSON.stringify({ url })
|
||||||
@@ -217,16 +231,30 @@ async function cloneSite(url) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function applyUltraModernRedesign(cloneDir) {
|
async function applyUltraModernRedesign(cloneDir) {
|
||||||
// Simula o redesign - em produção chamaria bsw-designer agent
|
const prompt = `Você é um Engenheiro de Frontend Especialista (Agente Designer), focado em aplicar designs Ultra-Modernos (baseados nas skills clone-website e performance).
|
||||||
await new Promise(r => setTimeout(r, 2000));
|
Retorne APENAS um objeto JSON simulando as alterações que você faria, com a estrutura:
|
||||||
|
{"appliedStyles": ["estilo 1", "estilo 2"], "elementsRedesigned": ["elemento 1", "elemento 2"]}`;
|
||||||
|
|
||||||
|
let appliedStyles = ['glassmorphism', 'gradient-bg', 'smooth-animations', 'dark-mode'];
|
||||||
|
let elementsRedesigned = ['hero', 'cards', 'buttons', 'navigation', 'footer'];
|
||||||
|
|
||||||
|
try {
|
||||||
|
const rawResponse = await askAI(prompt, `Planeje o redesign do site no diretório: ${cloneDir}`);
|
||||||
|
const jsonStr = rawResponse.replace(/```json/gi, '').replace(/```/g, '').trim();
|
||||||
|
const parsed = JSON.parse(jsonStr);
|
||||||
|
if (parsed.appliedStyles) appliedStyles = parsed.appliedStyles;
|
||||||
|
if (parsed.elementsRedesigned) elementsRedesigned = parsed.elementsRedesigned;
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Erro na IA do Designer:", e);
|
||||||
|
}
|
||||||
|
|
||||||
const previewUrl = `http://localhost:${window.location.port || 3000}/${cloneDir.split('/').pop()}/index.html`;
|
const previewUrl = `http://localhost:${window.location.port || 3000}/${cloneDir.split('/').pop()}/index.html`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
previewUrl,
|
previewUrl,
|
||||||
appliedStyles: ['glassmorphism', 'gradient-bg', 'smooth-animations', 'dark-mode'],
|
appliedStyles,
|
||||||
elementsRedesigned: ['hero', 'cards', 'buttons', 'navigation', 'footer']
|
elementsRedesigned
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,10 +305,9 @@ function updateDesignerStatus(status) {
|
|||||||
|
|
||||||
async function sendOutreachMessage() {
|
async function sendOutreachMessage() {
|
||||||
const targetId = document.getElementById('outreachTargetId')?.value;
|
const targetId = document.getElementById('outreachTargetId')?.value;
|
||||||
const message = document.getElementById('outreachMessage')?.value?.trim();
|
|
||||||
|
|
||||||
if (!targetId || !message) {
|
if (!targetId) {
|
||||||
showAgentError('Outreach', 'Selecione um alvo e escreva a mensagem');
|
showAgentError('Outreach', 'Selecione um alvo');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,8 +317,14 @@ async function sendOutreachMessage() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simula envio - em produção usaria API de email/whatsapp
|
// Gerar mensagem via IA
|
||||||
await new Promise(r => setTimeout(r, 800));
|
const prompt = `Você é um Copywriter (Agente Outreach). Escreva uma mensagem de vendas persuasiva para o cliente '${target.name}' cujo site '${target.url}' tem o problema: '${target.reason}'. Ofereça um redesign ultra-moderno. Responda apenas o texto da mensagem (sem formatação json ou markdown).`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const message = await askAI(prompt, "Crie o e-mail de vendas.");
|
||||||
|
|
||||||
|
const msgBox = document.getElementById('outreachMessage');
|
||||||
|
if (msgBox) msgBox.value = message;
|
||||||
|
|
||||||
agentsState.outreach.messages.push({
|
agentsState.outreach.messages.push({
|
||||||
to: target.name,
|
to: target.name,
|
||||||
@@ -304,6 +337,9 @@ async function sendOutreachMessage() {
|
|||||||
agentsState.outreach.sent++;
|
agentsState.outreach.sent++;
|
||||||
updateOutreachStats();
|
updateOutreachStats();
|
||||||
showOutreachConfirmation(target.name);
|
showOutreachConfirmation(target.name);
|
||||||
|
} catch(e) {
|
||||||
|
showAgentError('Outreach', "Falha ao gerar mensagem: " + e.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showOutreachConfirmation(targetName) {
|
function showOutreachConfirmation(targetName) {
|
||||||
@@ -336,29 +372,72 @@ async function runOrchestratorPipeline() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setOrchestratorRunning(true);
|
setOrchestratorRunning(true);
|
||||||
updateOrchestratorStatus('🎬 Iniciando pipeline completo...');
|
updateOrchestratorStatus('🎬 Iniciando pipeline completo com IA (Orchestrator)...');
|
||||||
|
|
||||||
agentsState.orchestrator.pipeline = targets;
|
agentsState.orchestrator.pipeline = targets;
|
||||||
agentsState.orchestrator.currentStep = 0;
|
agentsState.orchestrator.currentStep = 0;
|
||||||
|
|
||||||
for (let i = 0; i < targets.length; i++) {
|
for (let i = 0; i < targets.length; i++) {
|
||||||
const target = targets[i];
|
const target = targets[i];
|
||||||
updateOrchestratorStatus(`📋 [${i+1}/${targets.length}] Processando: ${target.name}`);
|
updateOrchestratorStatus(`📋 [${i+1}/${targets.length}] Planejando com IA: ${target.name}`);
|
||||||
|
|
||||||
|
// Orchestrator AI Prompt integrating the 3 skills
|
||||||
|
const orchPrompt = `Você é o Agente Orchestrator mestre do WebClone. Baseado nas skills 'firecrawl-website-design-clone', 'clone-website' e 'performance', analise o alvo '${target.name}' (${target.url}) que possui o problema '${target.reason}'. Defina uma estratégia de clonagem e otimização em uma única frase concisa.`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const strategy = await askAI(orchPrompt, "Defina a estratégia de clonagem.");
|
||||||
|
console.log(`[Orchestrator Strategy - ${target.name}]:`, strategy);
|
||||||
|
target.orchestratorStrategy = strategy;
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Erro na IA do Orchestrator:", e);
|
||||||
|
target.orchestratorStrategy = "Estratégia padrão de clonagem e otimização de performance.";
|
||||||
|
}
|
||||||
|
|
||||||
// Step 1: Clone
|
// Step 1: Clone
|
||||||
await new Promise(r => setTimeout(r, 500));
|
updateOrchestratorStatus(`📥 [${i+1}/${targets.length}] Clonando: ${target.name}`);
|
||||||
|
let directory = `cloned-sites/${target.name.toLowerCase().replace(/[^a-z0-9]/g, '')}`;
|
||||||
|
try {
|
||||||
|
const cloneRes = await cloneSite(target.url);
|
||||||
|
if (cloneRes.success && (cloneRes.data?.directory || cloneRes.data?.path || cloneRes.directory)) {
|
||||||
|
directory = cloneRes.data?.directory || cloneRes.data?.path || cloneRes.directory;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(`Aviso ao clonar ${target.name}, usando diretório de fallback:`, e.message);
|
||||||
|
}
|
||||||
|
target.directory = directory;
|
||||||
|
|
||||||
// Step 2: Redesign
|
// Step 2: Redesign
|
||||||
await new Promise(r => setTimeout(r, 500));
|
updateOrchestratorStatus(`🎨 [${i+1}/${targets.length}] Aplicando Redesign AI: ${target.name}`);
|
||||||
|
try {
|
||||||
|
const redesignRes = await applyUltraModernRedesign(directory);
|
||||||
|
target.redesign = redesignRes;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`Erro no redesign de ${target.name}:`, e);
|
||||||
|
}
|
||||||
|
|
||||||
// Step 3: Save to history
|
// Step 3: Outreach AI generation
|
||||||
await new Promise(r => setTimeout(r, 200));
|
updateOrchestratorStatus(`✉️ [${i+1}/${targets.length}] Gerando Copy de Outreach: ${target.name}`);
|
||||||
|
const outreachPrompt = `Você é um Copywriter (Agente Outreach). Escreva uma mensagem de vendas persuasiva para '${target.name}' (${target.url}) focando em resolver '${target.reason}' com um redesign ultra-moderno e alta performance. Responda apenas o texto do e-mail.`;
|
||||||
|
try {
|
||||||
|
const message = await askAI(outreachPrompt, "Crie o e-mail de vendas.");
|
||||||
|
agentsState.outreach.messages.push({
|
||||||
|
to: target.name,
|
||||||
|
toUrl: target.url,
|
||||||
|
message,
|
||||||
|
sentAt: new Date().toISOString(),
|
||||||
|
status: 'ready'
|
||||||
|
});
|
||||||
|
agentsState.outreach.sent++;
|
||||||
|
updateOutreachStats();
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`Erro no outreach de ${target.name}:`, e);
|
||||||
|
}
|
||||||
|
|
||||||
agentsState.orchestrator.currentStep = i + 1;
|
agentsState.orchestrator.currentStep = i + 1;
|
||||||
updateOrchestratorProgress((i + 1) / targets.length * 100);
|
updateOrchestratorProgress((i + 1) / targets.length * 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateOrchestratorStatus(`✅ Pipeline completo! ${targets.length} sites processados.`);
|
updateOrchestratorStatus(`✅ Pipeline completo! ${targets.length} sites processados com IA.`);
|
||||||
setOrchestratorRunning(false);
|
setOrchestratorRunning(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -255,7 +255,7 @@ function populateOverview(data) {
|
|||||||
if (data.cloneInfo) {
|
if (data.cloneInfo) {
|
||||||
overviewItems.push(
|
overviewItems.push(
|
||||||
{ label: 'Clone Status', value: data.cloneInfo.success ? '✅ Sucesso' : '❌ Falhou' },
|
{ label: 'Clone Status', value: data.cloneInfo.success ? '✅ Sucesso' : '❌ Falhou' },
|
||||||
{ label: 'Assets Baixados', value: `${data.cloneInfo.assetsDownloaded}/${data.cloneInfo.totalAssets}` },
|
{ label: 'Assets Baixados', value: data.cloneInfo.fileCount ? `${data.cloneInfo.fileCount} arquivos (${formatBytes(data.cloneInfo.totalSize || 0)})` : 'verificando...' },
|
||||||
{ label: 'Diretório Local', value: data.cloneInfo.directory }
|
{ label: 'Diretório Local', value: data.cloneInfo.directory }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -435,18 +435,8 @@ function openCloneFolder(directory) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openClonedSite(directory) {
|
function openClonedSite(directory) {
|
||||||
// Tentar abrir o index.html do site clonado
|
// Extract folder name and open site in browser via window.open
|
||||||
fetch('/api/open-site', {
|
const folderName = directory.split('/').pop();
|
||||||
method: 'POST',
|
const siteUrl = window.location.protocol + '//' + window.location.host + '/' + folderName + '/index.html';
|
||||||
headers: {
|
window.open(siteUrl, '_blank');
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ path: directory })
|
|
||||||
}).then(response => {
|
|
||||||
if (!response.ok) {
|
|
||||||
alert('Não foi possível abrir o site automaticamente.\nAbra manualmente: ' + directory + '\\index.html');
|
|
||||||
}
|
|
||||||
}).catch(error => {
|
|
||||||
alert('Não foi possível abrir o site automaticamente.\nAbra manualmente: ' + directory + '\\index.html');
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
+44
-7
@@ -77,12 +77,13 @@ app.post('/api/wget-clone', async (req, res) => {
|
|||||||
console.log('✅ Wget clone completed successfully');
|
console.log('✅ Wget clone completed successfully');
|
||||||
|
|
||||||
// Sync to host /root/Desktop/Clonados
|
// Sync to host /root/Desktop/Clonados
|
||||||
if (response.data && response.data.success && response.data.directory) {
|
const directory = response.data.data?.directory || response.data.directory;
|
||||||
|
if (response.data && response.data.success && directory) {
|
||||||
const { exec } = require('child_process');
|
const { exec } = require('child_process');
|
||||||
const containerId = require('os').hostname();
|
const containerId = require('os').hostname();
|
||||||
const cloneDir = response.data.directory.split('/').pop();
|
const cloneDir = directory.split('/').pop();
|
||||||
const hostDir = '/root/Desktop/Clonados';
|
const hostDir = '/root/Desktop/Clonados';
|
||||||
exec(`docker cp b38l2zsxjv08xkxg4gd5rl9r-210808689309:${response.data.directory} ${hostDir}/ 2>/dev/null`, (err) => {
|
exec(`docker cp ${containerId}:${directory} ${hostDir}/ 2>/dev/null`, (err) => {
|
||||||
if (err) console.log('⚠️ Sync to host failed:', err.message);
|
if (err) console.log('⚠️ Sync to host failed:', err.message);
|
||||||
else console.log('✅ Clone synced to host:', cloneDir);
|
else console.log('✅ Clone synced to host:', cloneDir);
|
||||||
});
|
});
|
||||||
@@ -193,8 +194,8 @@ app.post('/api/open-folder', (req, res) => {
|
|||||||
return res.status(400).json({ error: 'Caminho da pasta é obrigatório' });
|
return res.status(400).json({ error: 'Caminho da pasta é obrigatório' });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Abrir pasta no Windows Explorer
|
// Abrir pasta no gerenciador de ficheiros
|
||||||
exec(`explorer "${folderPath}"`, (error) => {
|
exec(`xdg-open "${folderPath}"`, (error) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error('Erro ao abrir pasta:', error);
|
console.error('Erro ao abrir pasta:', error);
|
||||||
return res.status(500).json({ error: 'Não foi possível abrir a pasta' });
|
return res.status(500).json({ error: 'Não foi possível abrir a pasta' });
|
||||||
@@ -221,8 +222,8 @@ app.post('/api/open-site', (req, res) => {
|
|||||||
|
|
||||||
console.log(`🌍 Opening site via HTTP: ${siteUrl}`);
|
console.log(`🌍 Opening site via HTTP: ${siteUrl}`);
|
||||||
|
|
||||||
// Abrir URL no navegador padrão
|
// Abrir URL no navegador padrão (Linux)
|
||||||
exec(`start "" "${siteUrl}"`, (error) => {
|
exec(`xdg-open "${siteUrl}"`, (error) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error('Erro ao abrir site:', error);
|
console.error('Erro ao abrir site:', error);
|
||||||
return res.status(500).json({ error: 'Não foi possível abrir o site via HTTP' });
|
return res.status(500).json({ error: 'Não foi possível abrir o site via HTTP' });
|
||||||
@@ -281,6 +282,42 @@ app.get('/index', (req, res) => {
|
|||||||
res.redirect('/');
|
res.redirect('/');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// AI Agent Route (MiniMax)
|
||||||
|
app.post('/api/ai/agent', async (req, res) => {
|
||||||
|
const { systemPrompt, userMessage } = req.body;
|
||||||
|
const apiKey = process.env.MINIMAX_API_KEY;
|
||||||
|
|
||||||
|
if (!apiKey) {
|
||||||
|
return res.status(500).json({ error: 'MINIMAX_API_KEY is missing in .env' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios.post('https://api.minimax.io/v1/chat/completions', {
|
||||||
|
model: "MiniMax-M2.7",
|
||||||
|
messages: [
|
||||||
|
{ role: "system", content: systemPrompt || "Você é um assistente de inteligência artificial útil." },
|
||||||
|
{ role: "user", content: userMessage }
|
||||||
|
],
|
||||||
|
max_tokens: 2048
|
||||||
|
}, {
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${apiKey}`,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
timeout: 90000 // 90s
|
||||||
|
});
|
||||||
|
|
||||||
|
let reply = response.data.choices?.[0]?.message?.content || 'Processamento concluído, porém sem retorno.';
|
||||||
|
// Strip <think> reasoning tags if present
|
||||||
|
reply = reply.replace(/<think>[\s\S]*?<\/think>/gi, '').trim();
|
||||||
|
|
||||||
|
res.json({ success: true, data: reply });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('MiniMax AI Error:', error.response?.data || error.message);
|
||||||
|
res.status(500).json({ error: error.message, details: error.response?.data });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Handle 404s
|
// Handle 404s
|
||||||
app.use((req, res) => {
|
app.use((req, res) => {
|
||||||
res.status(404).json({
|
res.status(404).json({
|
||||||
|
|||||||
Reference in New Issue
Block a user