| | const { | | | System, | | | getData, | | | setData, | | | makeUrl |
| | } = require("../lib/"); |
| | // ============================================= |
| | // GROQ CONFIGURATION | | | // ============================================= | | | const GROQ_API = | | | "https://api.groq.com/openai/v1/chat/completions"; | | | const GROQ_API_KEY = process.env.GROQ_API_KEY || ""; |
| | const TEXT_MODEL = "openai/gpt-oss-20b"; |
| | const VISION_MODEL = "qwen/qwen3.8-27b"; |
| | const MAX_HISTORY = 10; |
| | const MAX_TOKENS = 700; |
| | const TIMEZONE = "Asia/Kolkata"; |
| | const conversations = new Map(); |
| | // ============================================= |
| | // OWNER SETTINGS |
| | // ============================================= |
| | const OWNER_NAME = "BLIX-XER"; |
| | const OWNER_NUMBER = "918075298454"; | | | // ============================================= | | | // MOTIVATIONAL SPEECH COLLECTION |
| | // ============================================= |
| | const MOTIVATION_SPEECHES = [ |
| | [ | | | "Your current situation is not your final destination.", | | | "Keep moving forward; your future is still yours to create." | | | ], | | | [ | | | "Greatness begins when you stop waiting for the perfect moment.", | | | "Take the first step today, and let your actions build tomorrow." | | | ], | | | [ | | | "Your dreams deserve more than just your imagination.", | | | "Give them your effort, your patience, and your determination." | | | ], | | | [ | | | "Every challenge is an opportunity to discover your strength.", | | | "Rise above the difficulty and prove what you are capable of." | | | ], | | | [ | | | "Do not let one difficult chapter define your entire story.", | | | "You still have countless pages left to write." | | | ], | | | [ | | | "Success is built through small efforts repeated consistently.", | | | "Keep showing up, even when nobody notices your progress." | | | ], | | | [ | | | "The road to greatness is not always easy.", | | | "But every step you take makes you stronger than yesterday." | | | ], | | | [ | | | "Stop measuring your journey against someone else's timeline.", | | | "Build your own path and move at your own pace." | | | ], | | | [ | | | "A powerful future begins with a decision made today.", | | | "Choose courage over excuses and progress over perfection." | | | ], | | | [ | | | "Your mistakes are lessons, not permanent labels.", | | | "Learn from them, stand again, and keep building your future." | | | ], | | | [ | | | "You do not need to have everything figured out today.", | | | "You only need the courage to take your next step." | | | ], | | | [ | | | "Let your determination speak louder than your doubts.", | | | "One day, your hard work will tell a story worth remembering." | | | ], | | | [ | | | "Never underestimate what consistent effort can accomplish.", | | | "Small steps taken every day can lead to extraordinary places." | | | ], | | | [ | | | "The strongest progress often happens when nobody is watching.", | | | "Keep improving yourself, even when the applause is absent." | | | ], | | | [ | | | "Do not surrender your dreams because the journey feels difficult.", | | | "Some of the most meaningful achievements take time." | | | ] |
| | ]; |
| | // ============================================= |
| | // MOTIVATION REQUEST DETECTION |
| | // ============================================= |
| | function isMotivationRequest(text) { |
| | const input = String(text \|\| "") |
| | .toLowerCase() |
| | .trim(); |
| | const patterns = [ |
| | /\bgive me (some )?motivation\b/, | | | /\bmotivate me\b/, | | | /\bi need motivation\b/, | | | /\bneed some motivation\b/, | | | /\bmotivation speech\b/, | | | /\bsay something motivational\b/, | | | /\binspire me\b/, | | | /\bgive me an? motivational\b/, | | | /\bmotivation please\b/, | | | /\bmotivation venam\b/, | | | /\bmotivation tharamo\b/, | | | /\boru motivation\b/, | | | /\benik motivation\b/, | | | /\benikku motivation\b/, | | | /\bkurach motivation\b/, | | | /\bmotivate cheyy\b/, | | | /ą“Ŗąµą“°ą“ąµą“¦ą“Øą“/, | | | /ą“®ąµą“ąµą“ą“æą“µąµą“·ąµ»/, | | | /ą“ą“Øą“æą“ąµą“ąµ ą“®ąµą“ąµą“ą“æą“µąµą“·ąµ»/ |
| | ]; |
| | return patterns.some(pattern => pattern.test(input)); |
| | } | | | // ============================================= | | | // GET A DIFFERENT MOTIVATIONAL SPEECH |
| | // ============================================= |
| | function getMotivationSpeech(history) { |
| | const recentAnswers = (history \|\| []) |
| | .filter(item => item.role === "assistant") |
| | .map(item => item.content); |
| | const unusedSpeeches = MOTIVATION_SPEECHES.filter( | | | speech => { | | | const formatted = |
| | speech.join("\n") + |
| | "\n\n*ā JARVIS (Original)*"; |
| | return !recentAnswers.includes(formatted); |
| | } | | | ); | | | const available = | | | unusedSpeeches.length > 0 | | | ? unusedSpeeches | | | : MOTIVATION_SPEECHES; | | | const selected = | | | available[ |
| | Math.floor(Math.random() * available.length) |
| | ]; |
| | return ( | | | selected[0] + | | | "\n" + | | | selected[1] + | | | "\n\n" + |
| | "*ā JARVIS (Original)*" |
| | ); |
| | } | | | // ============================================= | | | // CURRENT DATE AND TIME |
| | // ============================================= |
| | function getCurrentDateTime() { |
| | const now = new Date(); |
| | const date = new Intl.DateTimeFormat("en-IN", { |
| | timeZone: TIMEZONE, | | | weekday: "long", | | | day: "2-digit", | | | month: "long", | | | year: "numeric" |
| | }).format(now); |
| | const time = new Intl.DateTimeFormat("en-IN", { |
| | timeZone: TIMEZONE, |
| | hour: "2-digit", |
| | minute: "2-digit", |
| | second: "2-digit", |
| | hour12: true | | | }).format(now); | | | return { | | | date, | | | time, |
| | timezone: "Indian Standard Time (IST)" |
| | }; |
| | } | | | // ============================================= | | | // HELPER FUNCTIONS |
| | // ============================================= |
| | function getNumber(jid) { |
| | if (!jid) return ""; |
| | return String(jid) |
| | .split("@")[0] |
| | .split(":")[0] |
| | .replace(/\D/g, ""); |
| | } |
| | function isOwner(jid) { |
| | return getNumber(jid) === getNumber(OWNER_NUMBER); |
| | } |
| | function getQuotedName(quoted) { |
| | if (!quoted) return null; |
| | return ( | | | quoted.pushName || | | | quoted.notify || | | | quoted.name || | | | quoted.senderName || | | | quoted.contact?.name || | | | null | | | ); | | | } |
| | function getQuotedSender(quoted) { |
| | if (!quoted) return ""; |
| | return ( | | | quoted.sender || | | | quoted.participant || | | | quoted.key?.participant || | | | quoted.from || | | | "" | | | ); | | | } | | | // ============================================= | | | // GROQ API FUNCTION |
| | // ============================================= |
| | async function askGroq(model, messages) { |
| | if (!GROQ_API_KEY) { |
| | throw new Error("GROQ_API_KEY is missing."); |
| | } | | | const response = await fetch(GROQ_API, { | | | method: "POST", |
| | headers: { |
| | Authorization: `Bearer ${GROQ_API_KEY}`, |
| | "Content-Type": "application/json" | | | }, | | | body: JSON.stringify({ | | | model, | | | messages, | | | max_completion_tokens: MAX_TOKENS, | | | temperature: 0.7, | | | stream: false |
| | }), |
| | signal: AbortSignal.timeout(60000) |
| | }); |
| | if (!response.ok) { |
| | const errorText = await response.text(); |
| | console.error( | | | "JARVIS Groq Error:", | | | response.status, |
| | errorText.slice(0, 1500) |
| | ); |
| | throw new Error( |
| | Groq API returned ${response.status} |
| | ); |
| | } |
| | const data = await response.json(); |
| | const answer = |
| | data.choices?.[0]?.message?.content?.trim(); |
| | if (!answer) { |
| | throw new Error("Groq returned an empty response."); | | | } | | | return answer; | | | } | | | // ============================================= | | | // JARVIS PERSONALITY |
| | // ============================================= |
| | function createSystemPrompt({ |
| | userName, | | | owner, | | | quoted, | | | quotedName, | | | quotedOwner |
| | }) { |
| | const current = getCurrentDateTime(); |
| | return ` | | | You are JARVIS, an intelligent, friendly, | | | natural and highly capable WhatsApp AI assistant. | | | ======================== | | | OWNER INFORMATION |
| | ======================== |
| | Owner name: ${OWNER_NAME} |
| | Current user: ${userName} |
| | Is current user the owner: ${owner ? "YES" : "NO"} |
| | IDENTITY RULES: | | | 1. The owner's name is always ${OWNER_NAME}. | | | 2. If the owner asks "What is my name?", | | | answer: "Your name is ${OWNER_NAME}." | | | 3. If someone asks who owns you, | | | answer: "My owner is ${OWNER_NAME}." | | | 4. Never call another user your owner. | | | 5. Never invent a person's name. | | | 6. Use the available WhatsApp display name naturally. | | | ======================== | | | QUOTED MESSAGE IDENTITY |
| | ======================== |
| | Quoted message exists: ${quoted ? "YES" : "NO"} |
| | Quoted sender name: ${quotedName || "Unavailable"} | | | Is quoted sender the owner: ${quotedOwner ? "YES" : "NO"} | | | If the user asks who sent the quoted message, | | | use the quoted sender information. | | | Never guess an unavailable identity. | | | ======================== | | | LIVE DATE AND TIME |
| | ======================== |
| | Current date: ${current.date} |
| | Current time: ${current.time} |
| | Timezone: ${current.timezone} |
| | RULES: | | | 1. Use this supplied date and time as the current reference. | | | 2. Always use Asia/Kolkata timezone. | | | 3. Understand questions about today's date. | | | 4. Understand questions about the current time. | | | 5. Understand questions about the current weekday. | | | 6. Calculate tomorrow and yesterday correctly. | | | 7. Understand questions about other dates, months and years. | | | 8. Never invent the current date or time. | | | 9. This information is refreshed for every incoming message. | | | ======================== | | | ADVANCED KERALA LANGUAGE INTELLIGENCE | | | ======================== | | | Understand natural Kerala Malayalam, Manglish and English. | | | SUPPORTED INPUT: | | | 1. Malayalam script. | | | 2. Manglish using English letters. | | | 3. English. | | | 4. Malayalam-English mixed sentences. | | | 5. Casual Kerala slang and colloquial expressions. | | | MANGLISH UNDERSTANDING: | | | Manglish has no single fixed spelling. | | | Examples: | | | - "sugham ano?" | | | - "sukham aano?" | | | - "sugham aano?" | | | - "sukhamano?" | | | These can mean "ą“øąµą“ą“®ą“¾ą“£ąµ?" | | | More examples: | | | - "nee evideya?" = "ą“Øąµ ą“ą“µą“æą“ąµą“Æą“¾?" | | | - "entha parupadi?" = "ą“ą“Øąµą“¤ą“¾ ą“Ŗą“°ą“æą“Ŗą“¾ą“ą“æ?" | | | - "enik ariyilla" = "ą“ą“Øą“æą“ąµą“ąµ ą“ ą“±ą“æą“Æą“æą“²ąµą“²" | | | - "avan entha paranje?" = "ą“ ą“µąµ» ą“ą“Øąµą“¤ą“¾ ą“Ŗą“±ą“ąµą“ą“¤ąµ?" | | | - "njan varam" = "ą“ą“¾ąµ» ą“µą“°ą“¾ą“" | | | - "onnu help cheyyamo?" = "ą“ą“Øąµą“Øąµ ą“¹ąµąµ½ą“Ŗąµą“Ŗąµ ą“ąµą“Æąµą“Æą“¾ą“®ąµ?" | | | IMPORTANT RULES: | | | 1. Never require perfect Manglish spelling. | | | 2. Understand words based on the full sentence. | | | 3. Recognize different spellings of the same word. | | | 4. Understand casual Kerala conversation. | | | 5. Understand common abbreviations and informal typing. | | | 6. Do not interpret every Manglish word literally. | | | 7. Use conversation context to understand unclear words. | | | 8. Never invent a meaning if genuinely unclear. | | | 9. Ask a short clarification question when necessary. | | | RESPONSE LANGUAGE RULES: | | | 1. Malayalam input ā Reply in natural Malayalam. | | | 2. Manglish input ā Reply in natural Manglish using English letters. | | | 3. English input ā Reply in natural English. | | | 4. Mixed input ā Reply in the same natural mixed style. | | | 5. Never convert Manglish into Malayalam script unless requested. | | | 6. Never convert Malayalam into Manglish unless requested. | | | 7. Do not sound like a translation engine. | | | 8. Use natural Kerala conversational expressions. | | | 9. Avoid unnecessarily formal Malayalam. | | | 10. Preserve the user's original meaning and tone. | | | EXAMPLES: | | | User: "eda nee evideya?" | | | Good response: "Njan ivide thanne undu. Enthada vendathu?" | | | User: "enik oru karyam parayan und" | | | Good response: "Parayoo, entha karyam?" | | | Your goal is to understand how real Kerala users | | | communicate, not just textbook Malayalam. | | | ======================== | | | MOTIVATIONAL INTELLIGENCE | | | ======================== | | | Understand requests for motivation in English, | | | Malayalam and Manglish. | | | Examples: | | | - Give me motivation. | | | - Motivate me. | | | - I need motivation. | | | - Give me a motivational speech. | | | - Motivation tharamo? | | | - Enik oru motivation venam. | | | - Kurach motivation parayamo? | | | - ą“ą“Øą“æą“ąµą“ąµ ą“ą“°ąµ ą“®ąµą“ąµą“ą“æą“µąµą“·ąµ» ą“¤ą“°ą“¾ą“®ąµ? | | | When a user requests motivation: | | | 1. Give a powerful and meaningful motivational speech. | | | 2. The speech must contain exactly two motivational lines. | | | 3. Include an author attribution separately. | | | 4. Use the attribution "JARVIS (Original)" for original speeches. | | | 5. Never falsely attribute original writing to famous people. | | | 6. Keep the message inspiring, positive and memorable. | | | 7. Avoid repeating recent motivational speeches. | | | 8. Match the user's language when generating motivation. | | | 9. Do not add unnecessary introductions or explanations. | | | ======================== | | | IMAGE UNDERSTANDING | | | ======================== | | | When an image is provided, analyze it carefully. | | | Capabilities: | | | - Object recognition | | | - Animals and vehicles | | | - Products and devices | | | - Places and scenery | | | - Colors and visual details | | | - Image descriptions | | | - OCR and text extraction | | | - Screenshots and documents | | | - Visual question answering | | | - Visible logos and symbols | | | IMAGE RULES: | | | 1. Answer using visible evidence. | | | 2. Read visible text accurately. | | | 3. If text is unclear, say so. | | | 4. Never invent image details. | | | 5. Distinguish certainty from guesses. | | | 6. Never identify a real person in an image. | | | 7. Do not infer sensitive personal characteristics. | | | 8. Reply in the user's language. | | | ======================== | | | PERSONALITY | | | ======================== | | | - Speak naturally and conversationally. | | | - Be intelligent, friendly and helpful. | | | - Understand follow-up questions. | | | - Use previous conversation context. | | | - Understand jokes and casual language. | | | - Give concise answers unless detail is needed. | | | - Avoid unnecessary repetition. | | | - Never reveal API keys or private configuration. | | | - Never invent facts. | | | - Admit when you do not know something. | | | - Avoid unnecessary emojis. | | | You are JARVIS. Maintain this personality. | | | `; | | | } | | | // ============================================= | | | // CHATBOT COMMAND MENU |
| | // ============================================= |
| | function chatbotMenu() { |
| | return ( | | | "J A R V I S A I\n" + | | | "āāāāāāāāāāāāāāāāāā\n\n" + | | | "AVAILABLE COMMANDS\n\n" + | | | "1. .chatbot on\n" + | | | " Activate JARVIS AI\n\n" + | | | "2. .chatbot off\n" + | | | " Deactivate JARVIS AI\n\n" + | | | "āāāāāāāāāāāāāāāāāā\n" + | | | "ACCESS: OWNER ONLY\n" + | | | "SYSTEM: JARVIS CHATBOT" | | | ); | | | } | | | // ============================================= | | | // CHATBOT ON / OFF COMMAND |
| | // ============================================= |
| | System({ |
| | pattern: "chatbot", | | | fromMe: true, | | | desc: "Turn JARVIS AI on or off", | | | type: "misc" |
| | }, async (message, match) => { |
| | const command = String(match \|\| "") |
| | .trim() |
| | .toLowerCase(); |
| | if (command !== "on" && command !== "off") { |
| | return message.send(chatbotMenu()); |
| | } | | | const enabled = | | | command === "on" ? "true" : "false"; | | | await setData( | | | message.user.id, | | | "status", | | | enabled, | | | "chatBot" | | | ); | | | return message.send( | | | command === "on" | | | ? ( | | | "J A R V I S A I\n" + | | | "āāāāāāāāāāāāāāāāāā\n\n" + | | | "STATUS: ACTIVATED\n\n" + | | | "JARVIS AI is now online and ready.\n" + | | | "āāāāāāāāāāāāāāāāāā" | | | ) | | | : ( | | | "J A R V I S A I\n" + | | | "āāāāāāāāāāāāāāāāāā\n\n" + | | | "STATUS: DEACTIVATED\n\n" + | | | "JARVIS AI has been switched off.\n" + | | | "āāāāāāāāāāāāāāāāāā" | | | ) |
| | ); |
| | }); |
| | // ============================================= |
| | // AUTOMATIC AI CHATBOT |
| | // ============================================= |
| | System({ |
| | on: "text", | | | fromMe: false, | | | dontAddCommandList: true | | | }, async (m) => { | | | try { | | | // ===================================== | | | // MESSAGE CHECKS |
| | // ===================================== |
| | if (m.isBot \|\| !m.body) return; |
| | // In groups, only respond to replies. |
| | if (m.isGroup && !m.reply_message) return; |
| | const { chatBot } = |
| | await getData(m.user.id); |
| | if (!chatBot \|\| chatBot.status !== "true") { |
| | return; | | | } | | | const mode = chatBot.message || "chat"; |
| | if (mode === "pm" && m.isGroup) return; |
| | if (mode === "group" && !m.isGroup) return; |
| | // ===================================== |
| | // GROQ API KEY CHECK |
| | // ===================================== |
| | if (!GROQ_API_KEY) { |
| | console.error( | | | "JARVIS: Missing GROQ_API_KEY." | | | ); | | | return m.reply( | | | "JARVIS AI CONFIGURATION ERROR\n" + | | | "āāāāāāāāāāāāāāāāāā\n\n" + | | | "GROQ API KEY IS MISSING!\n\n" + | | | "Please configure your Groq API key in Render Environment Variables.\n\n" + | | | "GET YOUR GROQ API KEY:\n" + | | | "https://console.groq.com/keys\n\n" + | | | "ENVIRONMENT VARIABLE:\n" + | | | "GROQ_API_KEY\n\n" + | | | "āāāāāāāāāāāāāāāāāā\n" + | | | "JARVIS SYSTEM" | | | ); | | | } | | | // ===================================== | | | // CURRENT USER IDENTITY |
| | // ===================================== |
| | const sender = m.sender; |
| | const owner = isOwner(sender); |
| | const userName = owner | | | ? OWNER_NAME |
| | : (m.pushName \|\| "Unknown"); |
| | // ===================================== |
| | // QUOTED MESSAGE IDENTITY |
| | // ===================================== |
| | const quoted = m.reply_message; |
| | const quotedSender = getQuotedSender(quoted); |
| | const quotedOwner = quotedSender |
| | ? isOwner(quotedSender) |
| | : false; |
| | const quotedName = quoted | | | ? ( | | | quotedOwner | | | ? OWNER_NAME | | | : getQuotedName(quoted) | | | ) |
| | : null; |
| | // ===================================== |
| | // CONVERSATION MEMORY |
| | // ===================================== |
| | const historyKey = |
| | ${m.user.id}:${sender}; |
| | const history = |
| | conversations.get(historyKey) \|\| []; |
| | const userText = String(m.body).trim(); |
| | // ===================================== |
| | // MOTIVATIONAL SPEECH FEATURE |
| | // ===================================== |
| | if (isMotivationRequest(userText)) { |
| | const motivation = |
| | getMotivationSpeech(history); |
| | const updatedHistory = [ |
| | ...history, | | | { | | | role: "user", | | | content: userText | | | }, | | | { | | | role: "assistant", | | | content: motivation | | | } | | | ]; | | | conversations.set( | | | historyKey, |
| | updatedHistory.slice(-MAX_HISTORY) |
| | ); |
| | return await m.reply(motivation); |
| | } | | | // ===================================== | | | // QUOTED IMAGE PROCESSING |
| | // ===================================== |
| | let imageUrl = null; |
| | if (quoted && quoted.image) { |
| | try { | | | console.log( | | | "JARVIS: Quoted image detected." | | | ); | | | const imagePath = |
| | await quoted.downloadAndSave(); |
| | if (!imagePath) { |
| | throw new Error( | | | "Image download returned no file." | | | ); | | | } | | | imageUrl = await makeUrl(imagePath); | | | if ( | | | !imageUrl || |
| | !/^https?:\/\//i.test(imageUrl) |
| | ) { |
| | throw new Error( | | | "Invalid uploaded image URL." | | | ); | | | } | | | console.log( | | | "JARVIS: Image uploaded successfully." |
| | ); |
| | } catch (imageError) { |
| | console.error( | | | "JARVIS Image Error:", | | | imageError | | | ); | | | return m.reply( | | | "I couldn't process that image. Please try again." | | | ); | | | } | | | } | | | // ===================================== | | | // SYSTEM PROMPT |
| | // ===================================== |
| | const systemPrompt = createSystemPrompt({ |
| | userName, | | | owner, | | | quoted, | | | quotedName, | | | quotedOwner |
| | }); |
| | // ===================================== |
| | // PREPARE MESSAGES |
| | // ===================================== |
| | const messages = [ |
| | { | | | role: "system", | | | content: systemPrompt | | | }, |
| | ...history.slice(-MAX_HISTORY) |
| | ]; |
| | // ===================================== |
| | // VISION REQUEST |
| | // ===================================== |
| | if (imageUrl) { |
| | messages.push({ |
| | role: "user", | | | content: [ | | | { | | | type: "text", | | | text: userText || | | | "Describe this image and explain what is visible." | | | }, | | | { | | | type: "image_url", | | | image_url: { | | | url: imageUrl | | | } | | | } | | | ] |
| | }); |
| | } else { |
| | // ================================= |
| | // NORMAL TEXT REQUEST |
| | // ================================= |
| | messages.push({ |
| | role: "user", | | | content: userText | | | }); | | | } | | | // ===================================== | | | // SELECT MODEL | | | // ===================================== | | | const selectedModel = imageUrl | | | ? VISION_MODEL | | | : TEXT_MODEL; | | | console.log( |
| | `JARVIS: Using model ${selectedModel}` |
| | ); |
| | // ===================================== |
| | // GROQ REQUEST |
| | // ===================================== |
| | const answer = await askGroq( |
| | selectedModel, | | | messages |
| | ); |
| | // ===================================== |
| | // SAVE HISTORY |
| | // ===================================== |
| | const updatedHistory = [ |
| | ...history, |
| | { |
| | role: "user", |
| | content: imageUrl |
| | ? ${userText}\n[Image analyzed] |
| | : userText |
| | }, |
| | { |
| | role: "assistant", |
| | content: answer |
| | } |
| | ]; |
| | conversations.set( |
| | historyKey, |
| | updatedHistory.slice(-MAX_HISTORY) |
| | ); |
| | // ===================================== |
| | // SEND RESPONSE |
| | // ===================================== |
| | return await m.reply(answer); |
| | } catch (error) { |
| | console.error( | | | "JARVIS Chatbot Error:", | | | error | | | ); | | | return m.reply( | | | "JARVIS encountered an unexpected error. Please try again." | | | ); | | | } | | | }); |