← back to browse
goat command

baby

Unified Baby AI with fallback APIs, teaching, media replies and continuous chat

0
views
0
likes
0
installs

Aliases: bby, babu, bbu, jan, janu, bot, hinata, hina, wifey, bbz

raw source
const axios = require("axios");

const COMMAND_NAME = "baby";
const SESSION_TTL = 30 * 60 * 1000;
const SAHU_API_LIST = "https://gitlab.com/shahadat-sahu/sahu-api/-/raw/main/API.json";
const NOOBS_API = "https://noobs-api.top/dipto";
const SECONDARY_API = "https://baby-apisx.vercel.app";
const SIMSIM_API = "https://simsimi-api-tjb1.onrender.com";
const TRIGGERS = ["baby", "bby", "babu", "bbu", "bot", "jan", "janu", "জান", "জানু", "বেবি", "wifey", "hinata", "hina", "suna", "sara", "mikasa", "alya"];
const LOCAL_FALLBACK_REPLIES = [
  "এই মুহূর্তে baby API-গুলো busy, তবুও আমি তোমার কথা শুনছি 😌",
  "API একটু ঘুমাচ্ছে জানু, আবার বলো তো 🥺",
  "সব online reply service ব্যস্ত—local baby reply চালু আছে 💖",
  "আমি আছি, API না থাকলেও তোমাকে ignore করছি না 😚"
];

const sessions = new Map();
const autoTeachUsers = new Set();
let sahuBaseCache = null;
let sahuBaseCheckedAt = 0;

function sessionKey(event) {
  return String(event.threadID) + ":" + String(event.senderID || event.userID);
}

function activateSession(event) {
  sessions.set(sessionKey(event), Date.now() + SESSION_TTL);
}

function isSessionActive(event) {
  const key = sessionKey(event);
  const expiresAt = sessions.get(key);
  if (!expiresAt) return false;
  if (expiresAt <= Date.now()) {
    sessions.delete(key);
    return false;
  }
  return true;
}

function clearSession(event) {
  sessions.delete(sessionKey(event));
  autoTeachUsers.delete(sessionKey(event));
}

function isStopText(text) {
  return /^(stop|off|বন্ধ|থাম|থামো)$/i.test(String(text || "").trim());
}

function getTriggerText(text) {
  const normalized = String(text || "").trim();
  const lower = normalized.toLowerCase();
  for (const trigger of TRIGGERS) {
    const name = trigger.toLowerCase();
    if (lower === name) return "";
    if (lower.startsWith(name + " ")) return normalized.slice(trigger.length).trim();
  }
  return null;
}

function cleanBase(url) {
  return String(url || "").replace(/\/+$/, "");
}

async function getSahuBase() {
  const now = Date.now();
  if (sahuBaseCache && now - sahuBaseCheckedAt < 5 * 60 * 1000) return sahuBaseCache;
  const response = await axios.get(SAHU_API_LIST, { timeout: 10000 });
  const base = response.data && response.data.simsimi;
  if (!base) throw new Error("Sahu API base URL is unavailable");
  sahuBaseCache = cleanBase(base);
  sahuBaseCheckedAt = now;
  return sahuBaseCache;
}

function extractReplies(payload) {
  if (!payload || typeof payload !== "object") return [];
  const raw = payload.response ?? payload.reply ?? payload.text ?? payload.data?.reply ?? payload.data?.response;
  const list = Array.isArray(raw) ? raw : [raw];
  return list.map(value => String(value || "").trim()).filter(value => value && !/undefined|internal server error|cannot read propert/i.test(value));
}

function isBadPayload(payload) {
  if (!payload || typeof payload !== "object") return true;
  if (payload.error) return true;
  return extractReplies(payload).length === 0;
}

async function getChatReplies(text, event, senderName) {
  const encoded = encodeURIComponent(text);
  const sender = encodeURIComponent(String(event.senderID || ""));
  const thread = encodeURIComponent(String(event.threadID || ""));
  const name = encodeURIComponent(String(senderName || "User"));
  const requests = [
    async () => {
      const base = await getSahuBase();
      return (await axios.get(base + "/simsimi?text=" + encoded + "&senderName=" + name + "&senderID=" + sender + "&threadID=" + thread, { timeout: 15000 })).data;
    },
    async () => (await axios.get(NOOBS_API + "/baby?text=" + encoded + "&senderID=" + sender + "&threadID=" + thread + "&font=1", { timeout: 12000 })).data,
    async () => (await axios.get(SECONDARY_API + "/baby?text=" + encoded + "&senderID=" + sender + "&threadID=" + thread + "&font=1", { timeout: 12000 })).data,
    async () => (await axios.get(SIMSIM_API + "/simsimi?text=" + encoded + "&senderName=" + name, { timeout: 12000 })).data
  ];
  let lastError = null;
  for (const request of requests) {
    try {
      const payload = await request();
      if (!isBadPayload(payload)) return extractReplies(payload);
      lastError = new Error("The API returned an empty response");
    } catch (error) {
      lastError = error;
    }
  }
  console.error("baby API fallback exhausted:", lastError?.message || "unknown error");
  return [LOCAL_FALLBACK_REPLIES[Math.floor(Math.random() * LOCAL_FALLBACK_REPLIES.length)]];
}

async function getAttachmentReply(event) {
  const type = event.attachments?.[0]?.type;
  let endpoint = null;
  if (type === "sticker") endpoint = "sticker";
  if (type === "photo" || type === "animated_image") endpoint = "picture";
  if (!endpoint) return null;
  try {
    const response = await axios.get(SECONDARY_API + "/baby/" + endpoint + "?senderID=" + encodeURIComponent(event.senderID), { timeout: 10000 });
    const replies = extractReplies(response.data);
    if (replies.length) return replies;
  } catch {}
  const fallback = {
    photo: ["ছবিটা দেখলাম 😌", "এই ছবির জন্য আলাদা reply লাগবে নাকি? 🥰"],
    animated_image: ["GIF-টা মজার হয়েছে 😂", "এটা দেখে হাসি থামছে না 😄"],
    sticker: ["Cute sticker 😌", "Sticker দিয়ে কথা বলা শিখে গেছো দেখি 🤭"]
  };
  return [fallback[type]?.[Math.floor(Math.random() * fallback[type].length)] || "দেখলাম জানু 😌"];
}

function registerReply(info, event) {
  if (!info?.messageID || !global.GoatBot?.onReply) return;
  global.GoatBot.onReply.set(info.messageID, {
    commandName: COMMAND_NAME,
    type: "reply",
    messageID: info.messageID,
    author: event.senderID
  });
}

function sendMessage(api, event, payload) {
  return new Promise((resolve, reject) => {
    let settled = false;
    const finish = (error, info) => {
      if (settled) return;
      settled = true;
      if (error) return reject(error);
      registerReply(info, event);
      resolve(info);
    };
    try {
      const result = api.sendMessage(payload, event.threadID, finish, event.messageID);
      if (result && typeof result.then === "function") result.then(info => finish(null, info)).catch(finish);
    } catch (error) {
      finish(error);
    }
  });
}

async function sendReplies(api, event, replies) {
  for (const reply of replies.filter(Boolean)) await sendMessage(api, event, reply);
}

async function setTyping(api, threadID, enabled) {
  try {
    if (typeof api.sendTypingIndicator === "function") await api.sendTypingIndicator(threadID, enabled);
  } catch {}
}

async function getUserName(usersData, userID) {
  try { return await usersData.getName(userID) || "User"; } catch { return "User"; }
}

function mention(name, userID, text) {
  return { body: "『 " + name + " 』\n\n" + text, mentions: [{ tag: name, id: userID }] };
}

async function teachSahu(trigger, reply, event) {
  const base = await getSahuBase();
  return (await axios.get(base + "?teach=" + encodeURIComponent(trigger) + "&reply=" + encodeURIComponent(reply) + "&senderID=" + encodeURIComponent(event.senderID) + "&threadID=" + encodeURIComponent(event.threadID), { timeout: 12000 })).data;
}

async function runCommandAction({ api, event, args, usersData }) {
  const raw = args.join(" ").trim();
  const lower = raw.toLowerCase();
  const first = String(args[0] || "").toLowerCase();
  const uid = event.senderID;
  const name = await getUserName(usersData, uid);

  if (isStopText(raw)) {
    clearSession(event);
    return sendMessage(api, event, "✅ bby conversation বন্ধ করা হয়েছে। আবার bby লিখলে চালু হবে।");
  }

  activateSession(event);

  if (first === "autoteach") {
    const mode = String(args[1] || "").toLowerCase();
    if (!["on", "off"].includes(mode)) return sendMessage(api, event, "ব্যবহার: baby autoteach on অথবা baby autoteach off");
    if (mode === "on") autoTeachUsers.add(sessionKey(event));
    else autoTeachUsers.delete(sessionKey(event));
    return sendMessage(api, event, "✅ Auto-teach " + (mode === "on" ? "ON 🟢" : "OFF 🔴") + " করা হয়েছে।");
  }

  if (!raw) {
    return sendMessage(api, event, mention(name, uid, ["Bolo baby 💖", "Hea baby 😚", "Yes, I'm here 😘", "Ki khobor janu? 🥰"][Math.floor(Math.random() * 4)]));
  }

  try {
    const base = await getSahuBase();
    if (first === "remove" && args.length > 1) {
      const key = raw.replace(/^remove\s+/i, "");
      const data = (await axios.get(base + "?remove=" + encodeURIComponent(key) + "&senderID=" + encodeURIComponent(uid), { timeout: 12000 })).data;
      return sendMessage(api, event, data.message || "✅ Removed.");
    }

    if (first === "rm" && lower.includes("-")) {
      const parts = lower.replace(/^rm\s+/i, "").split(/\s*-\s*/);
      const data = (await axios.get(base + "?remove=" + encodeURIComponent(parts[0]) + "&index=" + encodeURIComponent(parts[1] || ""), { timeout: 12000 })).data;
      return sendMessage(api, event, data.message || "✅ Removed.");
    }

    if (first === "list") {
      const data = (await axios.get(base + "?list=all", { timeout: 12000 })).data || {};
      if (String(args[1] || "").toLowerCase() === "all") {
        const list = data.teacher?.teacherList || [];
        const limit = Math.min(parseInt(args[2], 10) || 100, 100);
        const teachers = await Promise.all(list.slice(0, limit).map(async item => {
          const id = Object.keys(item)[0];
          return { name: await getUserName(usersData, id), value: item[id] };
        }));
        teachers.sort((a, b) => b.value - a.value);
        const output = teachers.map((teacher, i) => (i + 1) + ". " + teacher.name + ": " + teacher.value).join("\n");
        return sendMessage(api, event, "👑 Baby teachers\n\n" + (output || "No teachers found."));
      }
      return sendMessage(api, event, "❇️ Total Teach = " + (data.length || data.total || "API unavailable") + "\n♻️ Total Response = " + (data.responseLength || data.totalReplies || "API unavailable"));
    }

    if (first === "msg") {
      const key = raw.replace(/^msg\s+/i, "");
      const data = (await axios.get(base + "?list=" + encodeURIComponent(key), { timeout: 12000 })).data || {};
      return sendMessage(api, event, "Message " + key + " = " + (data.data || data.message || "No reply found."));
    }

    if (first === "edit") {
      const parts = raw.replace(/^edit\s+/i, "").split(/\s*-\s*/);
      if (parts.length < 2) return sendMessage(api, event, "❌ ব্যবহার: baby edit question - new reply");
      const data = (await axios.get(base + "?edit=" + encodeURIComponent(parts[0]) + "&replace=" + encodeURIComponent(parts.slice(1).join(" - ")) + "&senderID=" + encodeURIComponent(uid), { timeout: 12000 })).data;
      return sendMessage(api, event, data.message || "✅ Edited successfully.");
    }

    if (first === "teach" && ["sticker", "picture"].includes(String(args[1] || "").toLowerCase())) {
      const mediaType = String(args[1]).toLowerCase();
      const reply = raw.replace(/^teach\s+(sticker|picture)\s*/i, "").replace(/^-\s*/, "").trim();
      if (!reply) return sendMessage(api, event, "❌ ব্যবহার: baby teach " + mediaType + " - reply");
      const data = (await axios.get(SECONDARY_API + "/baby/" + mediaType + "?teach=1&reply=" + encodeURIComponent(reply) + "&senderID=" + encodeURIComponent(uid), { timeout: 12000 })).data || {};
      return sendMessage(api, event, "✅ " + (data.message || "Media reply added."));
    }

    if (first === "teach" && String(args[1] || "").toLowerCase() === "react") {
      const parts = raw.replace(/^teach\s+react\s+/i, "").split(/\s*-\s*/);
      if (parts.length < 2) return sendMessage(api, event, "❌ ব্যবহার: baby teach react question - ❤️, 😀");
      const data = (await axios.get(base + "?teach=" + encodeURIComponent(parts[0]) + "&react=" + encodeURIComponent(parts.slice(1).join(" - ")), { timeout: 12000 })).data;
      return sendMessage(api, event, "✅ Reacts added: " + (data.message || "Done"));
    }

    if (first === "teach" && String(args[1] || "").toLowerCase() === "amar") {
      const parts = raw.replace(/^teach\s+amar\s+/i, "").split(/\s*-\s*/);
      if (parts.length < 2) return sendMessage(api, event, "❌ ব্যবহার: baby teach amar question - reply");
      const data = (await axios.get(base + "?teach=" + encodeURIComponent(parts[0]) + "&senderID=" + encodeURIComponent(uid) + "&reply=" + encodeURIComponent(parts.slice(1).join(" - ")) + "&key=intro", { timeout: 12000 })).data;
      return sendMessage(api, event, "✅ Intro reply added: " + (data.message || "Done"));
    }

    if (first === "teach") {
      const parts = raw.replace(/^teach\s+/i, "").split(/\s*-\s*/);
      if (parts.length < 2) return sendMessage(api, event, "❌ ব্যবহার: baby teach question - reply1, reply2");
      const data = await teachSahu(parts[0], parts.slice(1).join(" - "), event);
      return sendMessage(api, event, "✅ Replies added: " + (data.message || "Done") + "\n👤 Teacher: " + name + "\n📚 Total: " + (data.teachs || data.total || "N/A"));
    }

    if (["amar name ki", "amr nam ki", "amar nam ki", "amr name ki", "whats my name"].some(value => lower.includes(value))) {
      const data = (await axios.get(base + "?text=amar%20name%20ki&senderID=" + encodeURIComponent(uid) + "&key=intro", { timeout: 12000 })).data;
      return sendMessage(api, event, data.reply || "তোমার নাম আমি এখনো শিখিনি।");
    }
  } catch (error) {
    if (["teach", "edit", "remove", "rm", "list", "msg"].includes(first)) throw error;
  }

  await setTyping(api, event.threadID, true);
  try {
    const replies = event.attachments?.length ? await getAttachmentReply(event) : await getChatReplies(raw, event, name);
    return sendReplies(api, event, replies);
  } finally {
    await setTyping(api, event.threadID, false);
  }
}

module.exports.config = {
  name: "baby",
  aliases: ["bby", "babu", "bbu", "jan", "janu", "bot", "hinata", "hina", "wifey", "bbz"],
  version: "12.0.0",
  author: "Unified community merge",
  countDown: 0,
  role: 0,
  description: "Unified Baby AI with fallback APIs, teaching, media replies and continuous chat",
  category: "chat",
  guide: {
    en: "{pn} [message] | {pn} teach [question] - [reply] | {pn} list [all] | {pn} msg [question] | {pn} edit [question] - [reply] | {pn} remove [question] | {pn} autoteach on/off"
  }
};

module.exports.onStart = async function ({ api, event, args, usersData }) {
  try {
    return await runCommandAction({ api, event, args, usersData });
  } catch (error) {
    console.error("baby onStart error:", error);
    return sendMessage(api, event, "❌ Baby API error: " + (error.message || "Unknown error"));
  }
};

module.exports.onReply = async function ({ api, event, Reply, usersData }) {
  if (Reply?.author && String(Reply.author) !== String(event.senderID)) return;
  const text = String(event.body || "").trim();
  if (!text && !event.attachments?.length) return;
  if (isStopText(text)) {
    clearSession(event);
    return sendMessage(api, event, "✅ bby conversation বন্ধ করা হয়েছে। আবার bby লিখলে চালু হবে।");
  }
  activateSession(event);
  const key = sessionKey(event);
  const name = await getUserName(usersData, event.senderID);
  if (autoTeachUsers.has(key) && event.messageReply?.body && event.messageReply.body !== text) {
    try { await teachSahu(event.messageReply.body, text, event); } catch (error) { console.error("baby auto-teach error:", error.message); }
  }
  try {
    await setTyping(api, event.threadID, true);
    const replies = event.attachments?.length ? await getAttachmentReply(event) : await getChatReplies(text, event, name);
    return await sendReplies(api, event, replies || []);
  } catch (error) {
    return sendMessage(api, event, "❌ Baby API error: " + (error.message || "Unknown error"));
  } finally {
    await setTyping(api, event.threadID, false);
  }
};

module.exports.onChat = async function ({ api, event, usersData, prefix }) {
  if (event.type === "message_reply") return;
  const raw = String(event.body || "").trim();
  if (!raw || (prefix && raw.startsWith(prefix))) return;
  const triggerText = getTriggerText(raw);
  if (triggerText === null) return;
  const text = triggerText;
  if (isStopText(text)) {
    clearSession(event);
    return sendMessage(api, event, "✅ bby conversation বন্ধ করা হয়েছে। আবার bby লিখলে চালু হবে।");
  }
  activateSession(event);
  if (!text && !event.attachments?.length) {
    const name = await getUserName(usersData, event.senderID);
    return sendMessage(api, event, mention(name, event.senderID, ["হুম বলো জানু 🥰", "আমি শুনতেছি 😚", "কি বলবা baby? 💖", "ডাকছো কেন? 😌"][Math.floor(Math.random() * 4)]));
  }
  try {
    await setTyping(api, event.threadID, true);
    const name = await getUserName(usersData, event.senderID);
    const replies = event.attachments?.length ? await getAttachmentReply(event) : await getChatReplies(text, event, name);
    return await sendReplies(api, event, replies || []);
  } catch (error) {
    console.error("baby onChat error:", error);
    return sendMessage(api, event, "❌ Baby API error: " + (error.message || "Unknown error"));
  } finally {
    await setTyping(api, event.threadID, false);
  }
};

View raw file