bot-mwsm 3.0.4 → 3.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/mwsm.js CHANGED
@@ -1219,331 +1219,367 @@ async function WwjsVersion(GET) {
1219
1219
  // ==================================================
1220
1220
 
1221
1221
  async function getEmbedding(text) {
1222
- try {
1223
- if (!text) return null;
1224
- const mwsmHost = Debug('OPTIONS').mwsmhost;
1225
- const mwsmPort = Debug('OPTIONS').mwsmport;
1226
-
1227
- const localResp = await axios.post(
1228
- `http://${mwsmHost}:${mwsmPort}/embed`,
1229
- { text },
1230
- { timeout: 10000 }
1231
- );
1232
-
1233
- if (localResp.data?.embedding) return localResp.data.embedding;
1234
- throw new Error('No embedding returned');
1235
- } catch {
1236
- // 🔹 fallback determinístico (garante vetor estável)
1237
- return Array.from(text)
1238
- .map((ch, i) => ((ch.charCodeAt(0) + i * 13) % 255) / 255)
1239
- .slice(0, 256);
1240
- }
1222
+ try {
1223
+ if (!text) return null;
1224
+ const mwsmHost = Debug('OPTIONS').mwsmhost;
1225
+ const mwsmPort = Debug('OPTIONS').mwsmport;
1226
+
1227
+ const localResp = await axios.post(
1228
+ `http://${mwsmHost}:${mwsmPort}/embed`, {
1229
+ text
1230
+ }, {
1231
+ timeout: 10000
1232
+ }
1233
+ );
1234
+
1235
+ if (localResp.data?.embedding) return localResp.data.embedding;
1236
+ throw new Error('No embedding returned');
1237
+ } catch {
1238
+ // 🔹 fallback determinístico (garante vetor estável)
1239
+ return Array.from(text)
1240
+ .map((ch, i) => ((ch.charCodeAt(0) + i * 13) % 255) / 255)
1241
+ .slice(0, 256);
1242
+ }
1241
1243
  }
1242
1244
 
1243
1245
  // ==================================================
1244
1246
  // 🕒 Timezone e Cumprimentos Dinâmicos
1245
1247
  // ==================================================
1246
1248
  async function getTimezoneByUF(uf) {
1247
- return new Promise((resolve) => {
1248
- db.get("SELECT timezone FROM localzone WHERE uf = ?", [uf], (err, row) => {
1249
- if (err || !row) return resolve("America/Sao_Paulo"); // padrão SP
1250
- resolve(row.timezone);
1251
- });
1252
- });
1249
+ return new Promise((resolve) => {
1250
+ db.get("SELECT timezone FROM localzone WHERE uf = ?", [uf], (err, row) => {
1251
+ if (err || !row) return resolve("America/Sao_Paulo"); // padrão SP
1252
+ resolve(row.timezone);
1253
+ });
1254
+ });
1253
1255
  }
1254
1256
 
1255
1257
  function getGreetingPeriod(timezone) {
1256
- try {
1257
- const now = new Date();
1258
- const localTime = new Date(now.toLocaleString("pt-BR", { timeZone: timezone }));
1259
- const hour = localTime.getHours();
1260
-
1261
- if (hour >= 5 && hour < 12) return "bom dia";
1262
- if (hour >= 12 && hour < 18) return "boa tarde";
1263
- return "boa noite";
1264
- } catch {
1265
- return "";
1266
- }
1258
+ try {
1259
+ // Captura a hora local correta sem dupla conversão
1260
+ const now = new Date();
1261
+ const localHour = new Intl.DateTimeFormat("pt-BR", {
1262
+ timeZone: timezone,
1263
+ hour: "numeric",
1264
+ hour12: false
1265
+ }).format(now);
1266
+
1267
+ const hour = parseInt(localHour, 10);
1268
+
1269
+ if (hour >= 5 && hour < 12) return "bom dia";
1270
+ if (hour >= 12 && hour < 18) return "boa tarde";
1271
+ if (hour >= 18 && hour < 24) return "boa noite";
1272
+ if (hour >= 0 && hour < 5) return "boa madrugada";
1273
+ } catch (err) {
1274
+ console.error("[ERRO] Falha ao determinar saudação:", err);
1275
+ return "";
1276
+ }
1267
1277
  }
1268
1278
 
1279
+
1269
1280
  // ==================================================
1270
1281
  // 🔒 Filtro Temático (Palavras-chave no BD)
1271
1282
  // ==================================================
1272
1283
  async function isRelevantQuestion(text) {
1273
- return new Promise((resolve) => {
1274
- db.all("SELECT filter FROM keywords", [], (err, rows) => {
1275
- if (err) {
1276
- console.error("Keyword filter error:", err.message);
1277
- return resolve(true); // não bloqueia em erro
1278
- }
1279
- if (!rows || rows.length === 0) return resolve(true);
1280
-
1281
- const keywords = rows.map(r => (r.filter || "").toLowerCase().trim());
1282
- text = (text || "").toLowerCase().trim();
1283
- const found = keywords.some(k => text.includes(k));
1284
- resolve(found);
1285
- });
1286
- });
1284
+ return new Promise((resolve) => {
1285
+ db.all("SELECT filter FROM keywords", [], (err, rows) => {
1286
+ if (err) {
1287
+ console.error("Keyword filter error:", err.message);
1288
+ return resolve(true); // não bloqueia em erro
1289
+ }
1290
+ if (!rows || rows.length === 0) return resolve(true);
1291
+
1292
+ const keywords = rows.map(r => (r.filter || "").toLowerCase().trim());
1293
+ text = (text || "").toLowerCase().trim();
1294
+ const found = keywords.some(k => text.includes(k));
1295
+ resolve(found);
1296
+ });
1297
+ });
1287
1298
  }
1288
1299
 
1289
1300
  // ==================================================
1290
1301
  // 🎯 Lógica Principal da IA
1291
1302
  // ==================================================
1292
1303
  async function askAI(question) {
1293
- return new Promise(async (resolve) => {
1294
- try {
1295
- const text = (question || "").toLowerCase().trim();
1296
-
1297
- // 🔹 1️⃣ Verifica se é um cumprimento antes do filtro
1298
- const isGreeting = await new Promise((resolveGreet) => {
1299
- db.all("SELECT word FROM greetings", [], (err, rows) => {
1300
- if (err || !rows?.length) return resolveGreet(false);
1301
- const greetings = rows.map(r => (r.word || "").toLowerCase());
1302
- resolveGreet(greetings.some(g => text.includes(g)));
1303
- });
1304
- });
1305
-
1306
- if (isGreeting) {
1307
- const uf = Debug('OPTIONS').timezone || 'SP';
1308
- const tz = await getTimezoneByUF(uf);
1309
- const turno = getGreetingPeriod(tz);
1310
-
1311
- if (turno) {
1312
- return resolve(`👋 Olá, ${turno}! Como posso te ajudar com sua conexão de internet?`);
1313
- } else {
1314
- return resolve(`👋 Olá! Como posso te ajudar com sua conexão de internet?`);
1315
- }
1316
- }
1317
-
1318
- // 🔹 2️⃣ Se não for cumprimento, aplica o filtro temático
1319
- const isRelevant = await isRelevantQuestion(text);
1320
- if (!isRelevant) {
1321
- console.log(`> ${Debug('OPTIONS').appname} : Brain: Filter → Ignored.`);
1322
- return resolve("⚠️ Posso ajudar apenas com dúvidas sobre sua conexão de internet e suporte técnico.");
1323
- }
1324
-
1325
- // 🔹 3️⃣ A partir daqui segue o fluxo normal da IA
1326
- const aiMode = parseInt(Debug('OPTIONS').aimode);
1327
- const apiKey = Debug('OPTIONS').keygen;
1328
- const Engine = Debug('OPTIONS').engine;
1329
- const threshold = parseFloat(Debug('OPTIONS').threshold);
1330
- const systemPrompt = Debug('OPTIONS').prompt;
1331
- const aiTimeout = parseInt(Debug('OPTIONS').aitimeout);
1332
- const appName = Debug('OPTIONS').appname;
1333
-
1334
- if (!apiKey) return resolve("⚠️ IA não configurada.");
1335
-
1336
- const engineRow = await Debug("ENGINE", "*", "DIRECT", Engine);
1337
- const Module = engineRow?.module || null;
1338
- const Level = parseInt(engineRow?.level || 0);
1339
-
1340
- if (!Module) return resolve("⚠️ Indisponível no momento.");
1341
-
1342
- const qEmbedding = await getEmbedding(question);
1343
- let bestMatch = null;
1344
- let bestScore = 0;
1345
-
1346
- if (aiMode === 0) {
1347
- console.log(`> ${appName} : Brain: Cloud | Relevance: 0.00`);
1348
- const aiAnswer = await fetchCloudAnswer(question, apiKey, Engine, Module, systemPrompt, aiTimeout, Level);
1349
- return resolve(aiAnswer);
1350
- }
1351
-
1352
- // 🔸 Busca local
1353
- const rows = await Debug('INTELIGENCE', '*', 'ALL');
1354
- for (const r of rows) {
1355
- if (!r.embedding) continue;
1356
- try {
1357
- const emb = JSON.parse(r.embedding);
1358
- const score = cosineSimilarity(emb, qEmbedding);
1359
- if (score > bestScore) {
1360
- bestScore = score;
1361
- bestMatch = r;
1362
- }
1363
- } catch {}
1364
- }
1365
-
1366
- // 🔹 Resposta local encontrada
1367
- if (bestMatch && bestScore >= threshold) {
1368
- console.log(`> ${appName} : Brain: Local | Relevance: ${bestScore.toFixed(2)}`);
1369
- db.run("UPDATE inteligence SET usage_count = usage_count + 1 WHERE id = ?", [bestMatch.id]);
1370
- return resolve(bestMatch.answer);
1371
- }
1372
-
1373
- // 🔹 Caso não tenha resposta local — vai para nuvem
1374
- console.log(`> ${appName} : Brain: Cloud | Relevance: ${bestScore.toFixed(2)}`);
1375
- const aiAnswer = await fetchCloudAnswer(question, apiKey, Engine, Module, systemPrompt, aiTimeout, Level);
1376
-
1377
- // 🔸 Aprendizado local (modo 2)
1378
- if (aiMode === 2 && aiAnswer && !aiAnswer.startsWith("⚠")) {
1379
- try {
1380
- await enforceKnowledgeLimit();
1381
- const _embedding = await getEmbedding(question);
1382
- const embeddingStr = _embedding ? JSON.stringify(_embedding) : null;
1383
-
1384
- db.serialize(() => {
1385
- db.get("SELECT id FROM inteligence WHERE question = ?", [question], (err, row) => {
1386
- if (err) return console.error("DB check error:", err.message);
1387
-
1388
- const sql = row
1389
- ? "UPDATE inteligence SET answer=?, embedding=?, source=?, usage_count=usage_count+1 WHERE id=?"
1390
- : "INSERT INTO inteligence (question, answer, embedding, source, usage_count) VALUES (?, ?, ?, ?, 1)";
1391
-
1392
- const params = row
1393
- ? [aiAnswer, embeddingStr, "local", row.id]
1394
- : [question, aiAnswer, embeddingStr, "local"];
1395
-
1396
- db.run(sql, params, (e) => e && console.error("DB write error:", e.message));
1397
- });
1398
- });
1399
- } catch (e) {
1400
- console.error("Embedding generation failed:", e?.message || e);
1401
- }
1402
- }
1403
-
1404
- return resolve(aiAnswer);
1405
- } catch (err) {
1406
- console.error("IA error:", err.message || err);
1407
- return resolve("⚠️ Não consegui acessar a inteligência artificial no momento.");
1408
- }
1409
- });
1304
+ return new Promise(async (resolve) => {
1305
+ try {
1306
+ const text = (question || "").toLowerCase().trim();
1307
+
1308
+ // 🔹 1️⃣ Verifica se é um cumprimento antes do filtro
1309
+ const isGreeting = await new Promise((resolveGreet) => {
1310
+ db.all("SELECT word FROM greetings", [], (err, rows) => {
1311
+ if (err || !rows?.length) return resolveGreet(false);
1312
+ const greetings = rows.map(r => (r.word || "").toLowerCase());
1313
+ resolveGreet(greetings.some(g => text.includes(g)));
1314
+ });
1315
+ });
1316
+
1317
+ if (isGreeting) {
1318
+ const uf = Debug('OPTIONS').timezone || 'SP';
1319
+ const tz = await getTimezoneByUF(uf);
1320
+ const turno = getGreetingPeriod(tz);
1321
+
1322
+ if (turno) {
1323
+ return resolve(`👋 Olá, ${turno}! Como posso te ajudar com sua conexão de internet?`);
1324
+ } else {
1325
+ return resolve(`👋 Olá! Como posso te ajudar com sua conexão de internet?`);
1326
+ }
1327
+ }
1328
+
1329
+ // 🔹 2️⃣ Se não for cumprimento, aplica o filtro temático
1330
+ const isRelevant = await isRelevantQuestion(text);
1331
+ if (!isRelevant) {
1332
+ console.log(`> ${Debug('OPTIONS').appname} : Brain: Filter → Ignored.`);
1333
+ return resolve("⚠️ Posso ajudar apenas com dúvidas sobre sua conexão de internet e suporte técnico.");
1334
+ }
1335
+
1336
+ // 🔹 3️⃣ A partir daqui segue o fluxo normal da IA
1337
+ const aiMode = parseInt(Debug('OPTIONS').aimode);
1338
+ const apiKey = Debug('OPTIONS').keygen;
1339
+ var Engine = Debug('OPTIONS').engine;
1340
+ const threshold = parseFloat(Debug('OPTIONS').threshold);
1341
+ const systemPrompt = Debug('OPTIONS').prompt;
1342
+ const aiTimeout = parseInt(Debug('OPTIONS').aitimeout);
1343
+ const appName = Debug('OPTIONS').appname;
1344
+
1345
+ if (!apiKey) return resolve("⚠️ IA não configurada.");
1346
+
1347
+ if (Engine.toLowerCase() === 'freerouter') {
1348
+ const Levels = Debug('ENGINE', '*', 'ALL').filter(item => item.level === 0);
1349
+ const ActiveModel = Levels.find(item => item.active === 1);
1350
+
1351
+ if (ActiveModel) {
1352
+ Regedit = ActiveModel;
1353
+ } else if (Levels.length > 0) {
1354
+ const randomIndex = Math.floor(Math.random() * Levels.length);
1355
+ Regedit = Levels[randomIndex];
1356
+ }
1357
+
1358
+ if (Regedit) {
1359
+ Engine = Regedit.title;
1360
+ Module = Regedit.module;
1361
+ Level = parseInt(Regedit.level);
1362
+ }
1363
+ } else {
1364
+ Regedit = await Debug("ENGINE", "*", "DIRECT", Engine);
1365
+ if (Regedit) {
1366
+ Engine = Regedit.title;
1367
+ Module = Regedit.module;
1368
+ Level = parseInt(Regedit.level);
1369
+ }
1370
+ }
1371
+ if (!Module) return resolve("⚠️ Indisponível no momento.");
1372
+
1373
+ const qEmbedding = await getEmbedding(question);
1374
+ let bestMatch = null;
1375
+ let bestScore = 0;
1376
+
1377
+ if (aiMode === 0) {
1378
+ console.log(`> ${appName} : Brain: Cloud | Relevance: 0%`);
1379
+ const aiAnswer = await fetchCloudAnswer(question, apiKey, Engine, Module, systemPrompt, aiTimeout, Level);
1380
+ return resolve(aiAnswer);
1381
+ }
1382
+
1383
+ // 🔸 Busca local
1384
+ const rows = await Debug('INTELIGENCE', '*', 'ALL');
1385
+ for (const r of rows) {
1386
+ if (!r.embedding) continue;
1387
+ try {
1388
+ const emb = JSON.parse(r.embedding);
1389
+ const score = cosineSimilarity(emb, qEmbedding);
1390
+ if (score > bestScore) {
1391
+ bestScore = score;
1392
+ bestMatch = r;
1393
+ }
1394
+ } catch {}
1395
+ }
1396
+
1397
+ // 🔹 Resposta local encontrada
1398
+ if (bestMatch && bestScore >= threshold) {
1399
+ console.log(`> ${appName} : Brain: Local | Relevance: ${(bestScore * 100).toFixed(0)}%`);
1400
+ db.run("UPDATE inteligence SET usage_count = usage_count + 1 WHERE id = ?", [bestMatch.id]);
1401
+ return resolve(bestMatch.answer);
1402
+ }
1403
+
1404
+ // 🔹 Caso não tenha resposta local — vai para nuvem
1405
+ console.log(`> ${appName} : Brain: Cloud | Relevance: ${(bestScore * 100).toFixed(0)}%`);
1406
+ const aiAnswer = await fetchCloudAnswer(question, apiKey, Engine, Module, systemPrompt, aiTimeout, Level);
1407
+
1408
+ // 🔸 Aprendizado local (modo 2)
1409
+ if (aiMode === 2 && aiAnswer && !aiAnswer.startsWith("⚠")) {
1410
+ try {
1411
+ await enforceKnowledgeLimit();
1412
+ const _embedding = await getEmbedding(question);
1413
+ const embeddingStr = _embedding ? JSON.stringify(_embedding) : null;
1414
+
1415
+ db.serialize(() => {
1416
+ db.get("SELECT id FROM inteligence WHERE question = ?", [question], (err, row) => {
1417
+ if (err) return console.error("DB check error:", err.message);
1418
+
1419
+ const sql = row ?
1420
+ "UPDATE inteligence SET answer=?, embedding=?, source=?, usage_count=usage_count+1 WHERE id=?" :
1421
+ "INSERT INTO inteligence (question, answer, embedding, source, usage_count) VALUES (?, ?, ?, ?, 1)";
1422
+
1423
+ const params = row ?
1424
+ [aiAnswer, embeddingStr, "local", row.id] :
1425
+ [question, aiAnswer, embeddingStr, "local"];
1426
+
1427
+ db.run(sql, params, (e) => e && console.error("DB write error:", e.message));
1428
+ });
1429
+ });
1430
+ } catch (e) {
1431
+ console.error("Embedding generation failed:", e?.message || e);
1432
+ }
1433
+ }
1434
+
1435
+ return resolve(aiAnswer);
1436
+ } catch (err) {
1437
+ console.error("IA error:", err.message || err);
1438
+ return resolve("⚠️ Não consegui acessar a inteligência artificial no momento.");
1439
+ }
1440
+ });
1410
1441
  }
1411
1442
 
1412
1443
  // ==================================================
1413
1444
  // 🌐 Comunicação com API (OpenRouter) + Limite de Tentativas
1414
1445
  // ==================================================
1415
1446
  async function fetchCloudAnswer(question, apiKey, Engine, Module, systemPrompt, aiTimeout, Level = 0) {
1416
- const tried = [];
1417
- try {
1418
- let variants = [];
1419
-
1420
- if (Engine.toLowerCase() === "freerouter") {
1421
- variants = await new Promise((resolve) => {
1422
- db.all("SELECT * FROM engine WHERE level = 0 ORDER BY active DESC, id ASC", [], (err, rows) => {
1423
- if (err) return resolve([]);
1424
- resolve(rows);
1425
- });
1426
- });
1427
- } else {
1428
- variants = await new Promise((resolve) => {
1429
- db.all("SELECT * FROM engine WHERE title = ? AND level = ? ORDER BY active DESC, id ASC", [Engine, Level], (err, rows) => {
1430
- if (err) return resolve([]);
1431
- resolve(rows);
1432
- });
1433
- });
1434
- }
1435
-
1436
- if (!variants.length) throw new Error("⚠️ Erro ao buscar resposta da IA online.");
1437
-
1438
- const activeVariant = variants.find(v => v.active === 1);
1439
- const orderedVariants = activeVariant
1440
- ? [activeVariant, ...variants.filter(v => v.id !== activeVariant.id)]
1441
- : variants;
1442
-
1443
- const maxAttempts = parseInt(Debug('OPTIONS').aimaxattempts) || 0;
1444
- let attempts = 0;
1445
-
1446
- for (const variant of orderedVariants) {
1447
- if (maxAttempts && attempts >= maxAttempts) {
1448
- console.log(`> ${Debug('OPTIONS').appname} : Brain: Max Attempts (${maxAttempts}) reached.`);
1449
- break;
1450
- }
1451
- attempts++;
1452
-
1453
- tried.push(variant.module);
1454
- try {
1455
- const response = await axios.post(
1456
- "https://openrouter.ai/api/v1/chat/completions",
1457
- {
1458
- model: variant.module,
1459
- messages: [
1460
- { role: "system", content: systemPrompt },
1461
- { role: "user", content: question }
1462
- ]
1463
- },
1464
- {
1465
- headers: {
1466
- Authorization: `Bearer ${apiKey}`,
1467
- "Content-Type": "application/json"
1468
- },
1469
- timeout: aiTimeout
1470
- }
1471
- );
1472
-
1473
- const aiAnswer =
1474
- response.data?.choices?.[0]?.message?.content?.trim() ||
1475
- "Desculpe, não consegui entender sua solicitação.";
1476
-
1477
- db.run("UPDATE engine SET active = 0 WHERE title = ?", [variant.title]);
1478
- db.run("UPDATE engine SET active = 1 WHERE id = ?", [variant.id]);
1479
-
1480
- console.log(`> ${Debug('OPTIONS').appname} : AskAI: ${variant.title} ${variant.variant} → ATIVA`);
1481
- return aiAnswer.replace(/\s+/g, " ").trim();
1482
- } catch (err) {
1483
- console.log(`> ${Debug('OPTIONS').appname} : AskAI: ${variant.title} ${variant.variant} → INATIVA`);
1484
- db.run("UPDATE engine SET active = 0 WHERE id = ?", [variant.id]);
1485
- continue;
1486
- }
1487
- }
1488
-
1489
- return "⚠️ Erro ao buscar resposta da IA online.";
1490
- } catch {
1491
- return "⚠️ Erro ao buscar resposta da IA online.";
1492
- }
1447
+ const tried = [];
1448
+ try {
1449
+ let variants = [];
1450
+
1451
+ if (Engine.toLowerCase() === "freerouter") {
1452
+ variants = await new Promise((resolve) => {
1453
+ db.all("SELECT * FROM engine WHERE level = 0 ORDER BY active DESC, id ASC", [], (err, rows) => {
1454
+ if (err) return resolve([]);
1455
+ resolve(rows);
1456
+ });
1457
+ });
1458
+ } else {
1459
+ variants = await new Promise((resolve) => {
1460
+ db.all("SELECT * FROM engine WHERE title = ? AND level = ? ORDER BY active DESC, id ASC", [Engine, Level], (err, rows) => {
1461
+ if (err) return resolve([]);
1462
+ resolve(rows);
1463
+ });
1464
+ });
1465
+ }
1466
+
1467
+ if (!variants.length) throw new Error("⚠️ Erro ao buscar resposta da IA online.");
1468
+
1469
+ const activeVariant = variants.find(v => v.active === 1);
1470
+ const orderedVariants = activeVariant ?
1471
+ [activeVariant, ...variants.filter(v => v.id !== activeVariant.id)] :
1472
+ variants;
1473
+
1474
+ const maxAttempts = parseInt(Debug('OPTIONS').aimaxattempts) || 0;
1475
+ let attempts = 0;
1476
+
1477
+ for (const variant of orderedVariants) {
1478
+ if (maxAttempts && attempts >= maxAttempts) {
1479
+ console.log(`> ${Debug('OPTIONS').appname} : Brain: Max Attempts (${maxAttempts}) reached.`);
1480
+ break;
1481
+ }
1482
+ attempts++;
1483
+
1484
+ tried.push(variant.module);
1485
+ try {
1486
+ const response = await axios.post(
1487
+ "https://openrouter.ai/api/v1/chat/completions", {
1488
+ model: variant.module,
1489
+ messages: [{
1490
+ role: "system",
1491
+ content: systemPrompt
1492
+ },
1493
+ {
1494
+ role: "user",
1495
+ content: question
1496
+ }
1497
+ ]
1498
+ }, {
1499
+ headers: {
1500
+ Authorization: `Bearer ${apiKey}`,
1501
+ "Content-Type": "application/json"
1502
+ },
1503
+ timeout: aiTimeout
1504
+ }
1505
+ );
1506
+
1507
+ const aiAnswer =
1508
+ response.data?.choices?.[0]?.message?.content?.trim() ||
1509
+ "Desculpe, não consegui entender sua solicitação.";
1510
+ aiAnswer = aiAnswer.replace(/◁think▷[\s\S]*?◁\/think▷/g, "").trim();
1511
+ db.run("UPDATE engine SET active = 0 WHERE title = ?", [variant.title]);
1512
+ db.run("UPDATE engine SET active = 1 WHERE id = ?", [variant.id]);
1513
+
1514
+ console.log(`> ${Debug('OPTIONS').appname} : AskAI: ${variant.title} ${variant.variant} → ATIVA`);
1515
+ return aiAnswer.replace(/\s+/g, " ").trim();
1516
+ } catch (err) {
1517
+ console.log(`> ${Debug('OPTIONS').appname} : AskAI: ${variant.title} ${variant.variant} → INATIVA`);
1518
+ db.run("UPDATE engine SET active = 0 WHERE id = ?", [variant.id]);
1519
+ continue;
1520
+ }
1521
+ }
1522
+
1523
+ return "⚠️ Erro ao buscar resposta da IA online.";
1524
+ } catch {
1525
+ return "⚠️ Erro ao buscar resposta da IA online.";
1526
+ }
1493
1527
  }
1494
1528
 
1495
1529
  // ==================================================
1496
1530
  // 📊 Similaridade Vetorial
1497
1531
  // ==================================================
1498
1532
  function cosineSimilarity(vecA, vecB) {
1499
- if (!vecA || !vecB || vecA.length !== vecB.length) return 0;
1500
- let dot = 0, normA = 0, normB = 0;
1501
- for (let i = 0; i < vecA.length; i++) {
1502
- dot += vecA[i] * vecB[i];
1503
- normA += vecA[i] * vecA[i];
1504
- normB += vecB[i] * vecB[i];
1505
- }
1506
- return normA && normB ? dot / (Math.sqrt(normA) * Math.sqrt(normB)) : 0;
1533
+ if (!vecA || !vecB || vecA.length !== vecB.length) return 0;
1534
+ let dot = 0,
1535
+ normA = 0,
1536
+ normB = 0;
1537
+ for (let i = 0; i < vecA.length; i++) {
1538
+ dot += vecA[i] * vecB[i];
1539
+ normA += vecA[i] * vecA[i];
1540
+ normB += vecB[i] * vecB[i];
1541
+ }
1542
+ return normA && normB ? dot / (Math.sqrt(normA) * Math.sqrt(normB)) : 0;
1507
1543
  }
1508
1544
 
1509
1545
  // ==================================================
1510
1546
  // 🧹 Limpeza Dinâmica e Inteligente do Conhecimento
1511
1547
  // ==================================================
1512
1548
  async function enforceKnowledgeLimit() {
1513
- try {
1514
- const maxKnowledge = parseInt(Debug("OPTIONS").maxknowledge) || 1000;
1515
- if (!maxKnowledge || maxKnowledge < 100) return;
1516
-
1517
- db.all("SELECT COUNT(*) as total FROM inteligence", async (err, rows) => {
1518
- if (err) return console.error("DB count error:", err.message);
1519
- const total = rows[0]?.total || 0;
1520
- if (total <= maxKnowledge) return;
1521
-
1522
- const excess = total - maxKnowledge;
1523
- db.run(
1524
- `DELETE FROM inteligence
1549
+ try {
1550
+ const maxKnowledge = parseInt(Debug("OPTIONS").maxknowledge) || 1000;
1551
+ if (!maxKnowledge || maxKnowledge < 100) return;
1552
+
1553
+ db.all("SELECT COUNT(*) as total FROM inteligence", async (err, rows) => {
1554
+ if (err) return console.error("DB count error:", err.message);
1555
+ const total = rows[0]?.total || 0;
1556
+ if (total <= maxKnowledge) return;
1557
+
1558
+ const excess = total - maxKnowledge;
1559
+ db.run(
1560
+ `DELETE FROM inteligence
1525
1561
  WHERE id IN (
1526
1562
  SELECT id FROM inteligence
1527
1563
  ORDER BY usage_count ASC, id ASC
1528
1564
  LIMIT ?
1529
1565
  )`,
1530
- [excess],
1531
- function (delErr) {
1532
- if (delErr) console.error("Cleanup error:", delErr.message);
1533
- else console.log(`✅ ${this.changes} registros antigos removidos.`);
1534
- }
1535
- );
1536
- });
1537
- } catch (err) {
1538
- console.error("Erro no enforceKnowledgeLimit:", err.message);
1539
- }
1566
+ [excess],
1567
+ function(delErr) {
1568
+ if (delErr) console.error("Cleanup error:", delErr.message);
1569
+ else console.log(`✅ ${this.changes} registros antigos removidos.`);
1570
+ }
1571
+ );
1572
+ });
1573
+ } catch (err) {
1574
+ console.error("Erro no enforceKnowledgeLimit:", err.message);
1575
+ }
1540
1576
  }
1541
1577
 
1542
1578
  // ==================================================
1543
1579
  // 🔹 Embedding Local (Backup Seguro)
1544
1580
  // ==================================================
1545
1581
  async function getLocalEmbedding(text) {
1546
- return Array.from(text).map((c, i) => ((c.charCodeAt(0) + i * 7) % 255) / 255);
1582
+ return Array.from(text).map((c, i) => ((c.charCodeAt(0) + i * 7) % 255) / 255);
1547
1583
  }
1548
1584
 
1549
1585
  //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -4642,154 +4678,158 @@ const Build = async (SET) => {
4642
4678
  // WhatsApp Bot
4643
4679
  client.on('message', async msg => {
4644
4680
 
4645
- // ==================================================
4646
- // 🤖 Bot Menu e Controle Inteligente de IA
4647
- // ==================================================
4648
- const lastRequestTimes = new Map();
4649
- let lastGlobalRequest = 0;
4650
- let globalQueue = Promise.resolve();
4651
-
4652
- if (activeMenus.has(msg.from)) {
4653
- if (activeSupportIA.has(msg.from)) {
4654
- try {
4655
- const _iaExit = (msg.body || '').toString().trim().toLowerCase();
4656
-
4657
- // 🔹 Encerrar atendimento
4658
- if (["0", "sair", "tchau", "tchal"].includes(_iaExit)) {
4659
- activeSupportIA.delete(msg.from);
4660
- activeMenus.delete(msg.from);
4661
- await client.sendMessage(msg.from, "✅ Atendimento encerrado. Obrigado pelo contato!");
4662
- return;
4663
- }
4664
-
4665
- // 🔹 Voltar ao menu principal
4666
- if (_iaExit === "menu") {
4667
- activeSupportIA.delete(msg.from);
4668
- activeMenus.set(msg.from, true);
4669
- await client.sendMessage(
4670
- msg.from,
4671
- '📋 *Menu Principal*\n\n' +
4672
- '1️⃣ Boleto\n' +
4673
- '2️⃣ Suporte\n' +
4674
- '0️⃣ Encerrar\n\n' +
4675
- '👉 Responda com o número da opção desejada.'
4676
- );
4677
- return;
4678
- }
4679
- } catch (e) {
4680
- console.error('IA exit handler error:', e?.message || e);
4681
- }
4682
-
4683
- try {
4684
- const chat = await msg.getChat();
4685
- const Engine = Debug('OPTIONS').engine;
4686
- const Level = parseInt(Debug("ENGINE", "*", "DIRECT", Engine).level || 0);
4687
- const perUserDelay = parseInt(Debug('OPTIONS').airequestdelay) || 3000;
4688
- const globalDelay = parseInt(Debug('OPTIONS').aiglobaldelay) || 1000;
4689
-
4690
- const now = Date.now();
4691
- const lastUser = lastRequestTimes.get(msg.from) || 0;
4692
- const sinceUser = now - lastUser;
4693
- const sinceGlobal = now - lastGlobalRequest;
4694
- const waitUser = Math.max(0, perUserDelay - sinceUser);
4695
- const waitGlobal = Math.max(0, globalDelay - sinceGlobal);
4696
- const totalWait = Math.max(waitUser, waitGlobal);
4697
-
4698
- // ==================================================
4699
- // 🔹 Modo Free — com fila e controle global
4700
- // ==================================================
4701
- if (Level === 0) {
4702
- globalQueue = globalQueue.then(async () => {
4703
- try {
4704
- if (totalWait > 0) {
4705
- const typingInterval = setInterval(async () => {
4706
- try { await chat.sendStateTyping(); } catch {}
4707
- }, 4000);
4708
-
4709
- await new Promise(r => setTimeout(r, totalWait));
4710
- clearInterval(typingInterval);
4711
- try { await chat.clearState(); } catch {}
4712
- }
4713
-
4714
- lastRequestTimes.set(msg.from, Date.now());
4715
- lastGlobalRequest = Date.now();
4716
-
4717
- const tLevel = parseInt(Debug('OPTIONS').typingspeed);
4718
- const multiplier = 1 + (5 - tLevel) * 0.25;
4719
- const baseTime = 800 * multiplier;
4720
- const extraPerChar = 25 * multiplier;
4721
- const maxTime = 4000 * multiplier;
4722
- const estimatedDelay = Math.min(baseTime + msg.body.length * extraPerChar, maxTime);
4723
-
4724
- await chat.sendStateTyping();
4725
- await new Promise(resolve => setTimeout(resolve, estimatedDelay));
4726
- await chat.clearState();
4727
-
4728
- const reply = await askAI(msg.body);
4729
- await client.sendMessage(msg.from, reply);
4730
- } catch (err) {
4731
- console.error("Erro ao processar IA (free):", err.message);
4732
- try {
4733
- const reply = await askAI(msg.body);
4734
- await client.sendMessage(msg.from, reply);
4735
- } catch (e2) {
4736
- console.error("Erro secundário:", e2.message);
4737
- }
4738
- }
4739
- }).catch(e => console.error("Erro na fila global:", e.message));
4740
- }
4741
-
4742
- // ==================================================
4743
- // 🔹 Modo Premium Resposta direta (sem fila)
4744
- // ==================================================
4745
- else {
4746
- const tLevel = parseInt(Debug('OPTIONS').typingspeed);
4747
- const multiplier = 1 + (5 - tLevel) * 0.25;
4748
- const baseTime = 800 * multiplier;
4749
- const extraPerChar = 25 * multiplier;
4750
- const maxTime = 4000 * multiplier;
4751
- const estimatedDelay = Math.min(baseTime + msg.body.length * extraPerChar, maxTime);
4752
-
4753
- await chat.sendStateTyping();
4754
- await new Promise(r => setTimeout(r, estimatedDelay));
4755
- await chat.clearState();
4756
-
4757
- const reply = await askAI(msg.body);
4758
- await client.sendMessage(msg.from, reply);
4759
- }
4760
-
4761
- } catch (err) {
4762
- console.error("Erro ao simular digitando:", err.message);
4763
- try {
4764
- const reply = await askAI(msg.body);
4765
- await client.sendMessage(msg.from, reply);
4766
- } catch (e2) {
4767
- console.error("Erro no fallback de IA:", e2.message);
4768
- }
4769
- }
4770
- return;
4771
- }
4772
-
4773
- // ==================================================
4774
- // 📋 Menu principal
4775
- // ==================================================
4776
- if (msg.body.startsWith('1')) {
4777
- await client.sendMessage(msg.from, '🔗 Aqui está o link do seu boleto: https://seudominio.com/boleto');
4778
- return;
4779
- }
4780
-
4781
- if (msg.body.startsWith('2')) {
4782
- await client.sendMessage(msg.from, '🤖 Você está agora em atendimento de suporte com IA. Envie sua dúvida.');
4783
- activeSupportIA.set(msg.from, true);
4784
- return;
4785
- }
4786
-
4787
- if (msg.body.startsWith('0')) {
4788
- await client.sendMessage(msg.from, '✅ Atendimento encerrado. Obrigado pelo contato!');
4789
- activeMenus.delete(msg.from);
4790
- return;
4791
- }
4792
- }
4681
+ // ==================================================
4682
+ // 🤖 Bot Menu e Controle Inteligente de IA
4683
+ // ==================================================
4684
+ const lastRequestTimes = new Map();
4685
+ let lastGlobalRequest = 0;
4686
+ let globalQueue = Promise.resolve();
4687
+
4688
+ if (activeMenus.has(msg.from)) {
4689
+ if (activeSupportIA.has(msg.from)) {
4690
+ try {
4691
+ const _iaExit = (msg.body || '').toString().trim().toLowerCase();
4692
+
4693
+ // 🔹 Encerrar atendimento
4694
+ if (["0", "sair", "tchau", "tchal"].includes(_iaExit)) {
4695
+ activeSupportIA.delete(msg.from);
4696
+ activeMenus.delete(msg.from);
4697
+ await client.sendMessage(msg.from, "✅ Atendimento encerrado. Obrigado pelo contato!");
4698
+ return;
4699
+ }
4700
+
4701
+ // 🔹 Voltar ao menu principal
4702
+ if (_iaExit === "menu") {
4703
+ activeSupportIA.delete(msg.from);
4704
+ activeMenus.set(msg.from, true);
4705
+ await client.sendMessage(
4706
+ msg.from,
4707
+ '📋 *Menu Principal*\n\n' +
4708
+ '1️⃣ Boleto\n' +
4709
+ '2️⃣ Suporte\n' +
4710
+ '0️⃣ Encerrar\n\n' +
4711
+ '👉 Responda com o número da opção desejada.'
4712
+ );
4713
+ return;
4714
+ }
4715
+ } catch (e) {
4716
+ console.error('IA exit handler error:', e?.message || e);
4717
+ }
4718
+
4719
+ try {
4720
+ const chat = await msg.getChat();
4721
+ const Engine = Debug('OPTIONS').engine;
4722
+ const Level = parseInt(Debug("ENGINE", "*", "DIRECT", Engine).level || 0);
4723
+ const perUserDelay = parseInt(Debug('OPTIONS').airequestdelay) || 3000;
4724
+ const globalDelay = parseInt(Debug('OPTIONS').aiglobaldelay) || 1000;
4725
+
4726
+ const now = Date.now();
4727
+ const lastUser = lastRequestTimes.get(msg.from) || 0;
4728
+ const sinceUser = now - lastUser;
4729
+ const sinceGlobal = now - lastGlobalRequest;
4730
+ const waitUser = Math.max(0, perUserDelay - sinceUser);
4731
+ const waitGlobal = Math.max(0, globalDelay - sinceGlobal);
4732
+ const totalWait = Math.max(waitUser, waitGlobal);
4733
+
4734
+ // ==================================================
4735
+ // 🔹 Modo Free — com fila e controle global
4736
+ // ==================================================
4737
+ if (Level === 0) {
4738
+ globalQueue = globalQueue.then(async () => {
4739
+ try {
4740
+ if (totalWait > 0) {
4741
+ const typingInterval = setInterval(async () => {
4742
+ try {
4743
+ await chat.sendStateTyping();
4744
+ } catch {}
4745
+ }, 4000);
4746
+
4747
+ await new Promise(r => setTimeout(r, totalWait));
4748
+ clearInterval(typingInterval);
4749
+ try {
4750
+ await chat.clearState();
4751
+ } catch {}
4752
+ }
4753
+
4754
+ lastRequestTimes.set(msg.from, Date.now());
4755
+ lastGlobalRequest = Date.now();
4756
+
4757
+ const tLevel = parseInt(Debug('OPTIONS').typingspeed);
4758
+ const multiplier = 1 + (5 - tLevel) * 0.25;
4759
+ const baseTime = 800 * multiplier;
4760
+ const extraPerChar = 25 * multiplier;
4761
+ const maxTime = 4000 * multiplier;
4762
+ const estimatedDelay = Math.min(baseTime + msg.body.length * extraPerChar, maxTime);
4763
+
4764
+ await chat.sendStateTyping();
4765
+ await new Promise(resolve => setTimeout(resolve, estimatedDelay));
4766
+ await chat.clearState();
4767
+
4768
+ const reply = await askAI(msg.body);
4769
+ await client.sendMessage(msg.from, reply);
4770
+ } catch (err) {
4771
+ console.error("Erro ao processar IA (free):", err.message);
4772
+ try {
4773
+ const reply = await askAI(msg.body);
4774
+ await client.sendMessage(msg.from, reply);
4775
+ } catch (e2) {
4776
+ console.error("Erro secundário:", e2.message);
4777
+ }
4778
+ }
4779
+ }).catch(e => console.error("Erro na fila global:", e.message));
4780
+ }
4781
+
4782
+ // ==================================================
4783
+ // 🔹 Modo Premium Resposta direta (sem fila)
4784
+ // ==================================================
4785
+ else {
4786
+ const tLevel = parseInt(Debug('OPTIONS').typingspeed);
4787
+ const multiplier = 1 + (5 - tLevel) * 0.25;
4788
+ const baseTime = 800 * multiplier;
4789
+ const extraPerChar = 25 * multiplier;
4790
+ const maxTime = 4000 * multiplier;
4791
+ const estimatedDelay = Math.min(baseTime + msg.body.length * extraPerChar, maxTime);
4792
+
4793
+ await chat.sendStateTyping();
4794
+ await new Promise(r => setTimeout(r, estimatedDelay));
4795
+ await chat.clearState();
4796
+
4797
+ const reply = await askAI(msg.body);
4798
+ await client.sendMessage(msg.from, reply);
4799
+ }
4800
+
4801
+ } catch (err) {
4802
+ console.error("Erro ao simular digitando:", err.message);
4803
+ try {
4804
+ const reply = await askAI(msg.body);
4805
+ await client.sendMessage(msg.from, reply);
4806
+ } catch (e2) {
4807
+ console.error("Erro no fallback de IA:", e2.message);
4808
+ }
4809
+ }
4810
+ return;
4811
+ }
4812
+
4813
+ // ==================================================
4814
+ // 📋 Menu principal
4815
+ // ==================================================
4816
+ if (msg.body.startsWith('1')) {
4817
+ await client.sendMessage(msg.from, '🔗 Aqui está o link do seu boleto: https://seudominio.com/boleto');
4818
+ return;
4819
+ }
4820
+
4821
+ if (msg.body.startsWith('2')) {
4822
+ await client.sendMessage(msg.from, '🤖 Você está agora em atendimento de suporte com IA. Envie sua dúvida.');
4823
+ activeSupportIA.set(msg.from, true);
4824
+ return;
4825
+ }
4826
+
4827
+ if (msg.body.startsWith('0')) {
4828
+ await client.sendMessage(msg.from, '✅ Atendimento encerrado. Obrigado pelo contato!');
4829
+ activeMenus.delete(msg.from);
4830
+ return;
4831
+ }
4832
+ }
4793
4833
 
4794
4834
  if (msg.body.toLowerCase() === 'menu') {
4795
4835
  activeMenus.set(msg.from, true);
@@ -4976,4 +5016,4 @@ function hideElement(sel) {
4976
5016
 
4977
5017
  function setText(sel, txt) {
4978
5018
  if (typeof sel === "string") $(sel).text(txt);
4979
- }
5019
+ }