Donyking1818 commited on
Commit
45cd9df
Β·
verified Β·
1 Parent(s): 27c8fb3

Update index.js

Browse files
Files changed (1) hide show
  1. index.js +126 -320
index.js CHANGED
@@ -4,372 +4,178 @@ const {
4
  useMultiFileAuthState,
5
  fetchLatestBaileysVersion
6
  } = require('@whiskeysockets/baileys');
 
7
  const qrcode = require('qrcode');
8
- const axios = require('axios');
9
  const fs = require('fs');
10
  const path = require('path');
11
- const express = require('express');
12
  const http = require('http');
13
  const pino = require('pino');
14
 
15
- const app = express();
16
- const server = http.createServer(app);
17
-
18
- const PORT = process.env.PORT || 7860;
19
- const HF_TOKEN = process.env.HF_TOKEN || '';
20
- const AUTH_FOLDER = path.join(__dirname, 'auth');
21
 
22
  let sock = null;
23
  let qrCodeData = null;
24
  let connectionStatus = 'disconnected';
25
- let startTime = Date.now();
26
-
27
- // ===== LOGGER YANG BENER =====
28
- const logger = pino({
29
- level: 'silent',
30
- transport: {
31
- target: 'pino-pretty',
32
- options: { colorize: false }
33
- }
34
- }).child({ class: 'baileys' });
35
 
36
- // ===== SIMPLE UI =====
37
- const HTML_UI = `
 
 
 
38
  <!DOCTYPE html>
39
- <html lang="id">
40
  <head>
41
- <meta charset="UTF-8">
42
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
43
- <title>πŸ€– WhatsApp Bot</title>
44
  <style>
45
- * { margin: 0; padding: 0; box-sizing: border-box; }
46
- body {
47
- font-family: 'Segoe UI', sans-serif;
48
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
49
- min-height: 100vh;
50
- color: white;
51
- padding: 20px;
52
- }
53
- .container { max-width: 600px; margin: 0 auto; }
54
- h1 { text-align: center; font-size: 2.5em; margin-bottom: 10px; }
55
- .subtitle { text-align: center; opacity: 0.9; margin-bottom: 30px; }
56
- .card {
57
- background: rgba(255,255,255,0.1);
58
- backdrop-filter: blur(10px);
59
- border-radius: 20px;
60
- padding: 25px;
61
- margin-bottom: 20px;
62
- border: 1px solid rgba(255,255,255,0.2);
63
- }
64
- .status-box {
65
- display: flex;
66
- align-items: center;
67
- gap: 15px;
68
- margin-bottom: 20px;
69
- }
70
- .status-icon {
71
- width: 60px; height: 60px;
72
- border-radius: 50%;
73
- display: flex; align-items: center; justify-content: center;
74
- font-size: 28px;
75
- }
76
- .online { background: #00b894; }
77
- .offline { background: #e17055; }
78
- .waiting { background: #fdcb6e; animation: pulse 2s infinite; }
79
- @keyframes pulse {
80
- 0%, 100% { transform: scale(1); }
81
- 50% { transform: scale(1.05); }
82
  }
83
- .qr-section { text-align: center; padding: 20px; }
84
- .qr-box {
85
- background: white;
86
- padding: 20px;
87
- border-radius: 15px;
88
  display: inline-block;
89
- margin: 15px 0;
90
  }
91
- .qr-box img { width: 280px; height: 280px; }
92
- .btn {
93
- padding: 12px 25px;
94
- border: none;
95
- border-radius: 25px;
96
- font-size: 14px;
97
- font-weight: bold;
98
- cursor: pointer;
99
- margin: 5px;
100
- background: rgba(255,255,255,0.2);
101
- color: white;
102
- border: 1px solid rgba(255,255,255,0.3);
103
- }
104
- .btn:hover { transform: translateY(-2px); }
105
- .logs {
106
- background: rgba(0,0,0,0.4);
107
- border-radius: 10px;
108
  padding: 15px;
109
- margin-top: 20px;
110
- max-height: 200px;
111
- overflow-y: auto;
112
- font-family: monospace;
113
- font-size: 12px;
114
  }
115
- .hidden { display: none !important; }
 
 
116
  </style>
117
  </head>
118
  <body>
119
- <div class="container">
120
- <h1>πŸš€ WhatsApp Bot</h1>
121
- <p class="subtitle">Hugging Face Space</p>
122
-
123
- <div class="card">
124
- <div class="status-box">
125
- <div class="status-icon offline" id="statusIcon">πŸ“΄</div>
126
- <div>
127
- <h2 id="statusTitle">Starting...</h2>
128
- <span id="statusBadge" style="background:#e17055;padding:4px 12px;border-radius:12px;font-size:12px;">Offline</span>
129
- </div>
130
- </div>
131
-
132
- <div id="loadingPanel">
133
- <p>⏳ Menyiapkan koneksi...</p>
134
- <p style="font-size:12px;opacity:0.7;margin-top:10px;">Tunggu 10-30 detik</p>
135
- </div>
136
-
137
- <div id="qrPanel" class="qr-section hidden">
138
- <h3>πŸ“· Scan QR Code</h3>
139
- <div class="qr-box">
140
- <img id="qrImage" src="" alt="QR">
141
- </div>
142
- <p style="font-size:14px;opacity:0.9;">WhatsApp β†’ Menu β†’ Linked Devices β†’ Link</p>
143
- <button class="btn" onclick="location.reload()">πŸ”„ Refresh QR</button>
144
- </div>
145
-
146
- <div id="connectedPanel" class="hidden" style="text-align:center;padding:30px;">
147
- <div style="font-size:4em;margin-bottom:15px;">βœ…</div>
148
- <h3 style="color:#00b894;">Terhubung!</h3>
149
- <p style="margin:15px 0;">Bot siap menerima pesan</p>
150
- <button class="btn" onclick="logout()">πŸšͺ Logout</button>
151
- </div>
152
-
153
- <div class="logs" id="logs"></div>
154
  </div>
 
155
  </div>
156
-
157
  <script>
158
- function addLog(msg) {
159
- const logs = document.getElementById('logs');
160
- const time = new Date().toLocaleTimeString();
161
- logs.innerHTML += '<div>[' + time + '] ' + msg + '</div>';
162
- logs.scrollTop = logs.scrollHeight;
163
- }
164
-
165
- async function checkStatus() {
166
- try {
167
- const res = await fetch('/api/status');
168
- const data = await res.json();
169
-
170
- const icon = document.getElementById('statusIcon');
171
- const title = document.getElementById('statusTitle');
172
- const badge = document.getElementById('statusBadge');
173
-
174
- if (data.status === 'connected') {
175
- icon.className = 'status-icon online';
176
- icon.textContent = 'βœ“';
177
- title.textContent = 'Terhubung';
178
- badge.style.background = '#00b894';
179
- badge.textContent = 'Online';
180
- document.getElementById('loadingPanel').classList.add('hidden');
181
- document.getElementById('qrPanel').classList.add('hidden');
182
- document.getElementById('connectedPanel').classList.remove('hidden');
183
- }
184
- else if (data.status === 'qr_ready') {
185
- icon.className = 'status-icon waiting';
186
- icon.textContent = 'πŸ“·';
187
- title.textContent = 'Scan QR';
188
- badge.style.background = '#fdcb6e';
189
- badge.textContent = 'QR Ready';
190
- document.getElementById('loadingPanel').classList.add('hidden');
191
- document.getElementById('qrPanel').classList.remove('hidden');
192
- document.getElementById('qrImage').src = '/api/qr?' + Date.now();
193
- }
194
- else if (data.status === 'error') {
195
- title.textContent = 'Error: ' + data.error;
196
- addLog('Error: ' + data.error);
197
- }
198
-
199
- } catch (e) {
200
- addLog('Connection error');
201
- }
202
- }
203
-
204
- async function logout() {
205
- if (!confirm('Logout?')) return;
206
- await fetch('/api/logout');
207
- location.reload();
208
- }
209
-
210
- setInterval(checkStatus, 3000);
211
- checkStatus();
212
- addLog('Panel loaded');
213
  </script>
214
  </body>
215
  </html>
216
- `;
217
-
218
- // ===== ROUTES =====
219
- app.get('/', (req, res) => res.send(HTML_UI));
220
-
221
- app.get('/api/status', (req, res) => {
222
- res.json({
223
- status: connectionStatus,
224
- uptime: Math.floor((Date.now() - startTime) / 1000)
225
- });
226
- });
227
-
228
- app.get('/api/qr', async (req, res) => {
229
- if (!qrCodeData) return res.status(404).send('No QR');
230
- try {
231
- const buffer = await qrcode.toBuffer(qrCodeData, { type: 'png', width: 300 });
232
- res.set('Content-Type', 'image/png');
233
- res.send(buffer);
234
- } catch (e) {
235
- res.status(500).send('QR Error');
236
  }
237
- });
238
-
239
- app.get('/api/logout', async (req, res) => {
240
- try {
241
- if (sock) await sock.logout();
242
- if (fs.existsSync(AUTH_FOLDER)) {
243
- fs.rmSync(AUTH_FOLDER, { recursive: true, force: true });
244
  }
245
- res.json({ success: true });
246
- setTimeout(() => process.exit(0), 1000);
247
- } catch (e) {
248
- res.status(500).json({ error: e.message });
 
 
 
 
 
 
 
249
  }
250
  });
251
 
252
- // ===== WHATSAPP BOT =====
253
  async function startBot() {
254
- console.log('πŸš€ Starting...');
 
255
 
256
- try {
257
- const { state, saveCreds } = await useMultiFileAuthState(AUTH_FOLDER);
258
- const { version } = await fetchLatestBaileysVersion();
259
-
260
- sock = makeWASocket({
261
- version,
262
- logger: logger, // Pake logger yang bener
263
- printQRInTerminal: false,
264
- auth: state,
265
- browser: ['Ubuntu', 'Chrome', '20.0.04'],
266
- syncFullHistory: false,
267
- markOnlineOnConnect: true,
268
- keepAliveIntervalMs: 30000,
269
- connectTimeoutMs: 60000,
270
- retryRequestDelayMs: 1000,
271
- maxMsgRetryCount: 5,
272
- // Tambahin agent biar gak kena block
273
- agent: {
274
- keepAlive: true,
275
- maxSockets: 10
276
- }
277
- });
278
 
279
- // Error handler
280
- sock.ev.on('connection.update', async (update) => {
281
- const { connection, lastDisconnect, qr } = update;
282
-
283
- if (qr) {
284
- console.log('πŸ“· QR Ready');
285
- qrCodeData = qr;
286
- connectionStatus = 'qr_ready';
287
- }
288
 
289
- if (connection === 'open') {
290
- connectionStatus = 'connected';
291
- qrCodeData = null;
292
- console.log('βœ… Connected:', sock.user?.id);
293
-
294
- try {
295
- await sock.sendMessage(sock.user.id, {
296
- text: 'πŸ€– Bot aktif!'
297
- });
298
- } catch (e) {}
299
- }
300
 
301
- else if (connection === 'close') {
302
- const statusCode = lastDisconnect?.error?.output?.statusCode;
303
- const shouldReconnect = statusCode !== DisconnectReason.loggedOut;
304
-
305
- console.log('❌ Disconnected:', statusCode);
306
- connectionStatus = 'disconnected';
307
-
308
- if (shouldReconnect) {
309
- console.log('πŸ”„ Reconnecting...');
310
- setTimeout(startBot, 5000);
311
- }
312
- }
313
- });
314
-
315
- // Error handling
316
- sock.ev.on('creds.update', saveCreds);
317
-
318
- sock.ws.on('error', (err) => {
319
- console.log('WebSocket error:', err.message);
320
- });
321
 
322
- // Message handler
323
- sock.ev.on('messages.upsert', async ({ messages, type }) => {
324
- if (type !== 'notify') return;
325
- const msg = messages[0];
326
- if (!msg.message || msg.key.fromMe) return;
327
 
328
- const sender = msg.key.remoteJid;
329
- const text = msg.message.conversation ||
330
- msg.message.extendedTextMessage?.text || '';
 
331
 
332
- if (!text.startsWith('!')) return;
 
333
 
334
- const cmd = text.slice(1).split(' ')[0].toLowerCase();
335
- const args = text.slice(1).split(' ').slice(1).join(' ');
336
 
337
- if (cmd === 'help') {
338
- await sock.sendMessage(sender, {
339
- text: '!ai [tanya] - Tanya AI\n!status - Status'
340
- });
341
- }
342
- else if (cmd === 'status') {
343
- await sock.sendMessage(sender, {
344
- text: 'Status: ' + connectionStatus
345
- });
346
- }
347
- else if (cmd === 'ai' && args) {
348
- await sock.sendMessage(sender, { text: '⏳ AI mikir...' });
349
- try {
350
- const res = await axios.post(
351
- 'https://api-inference.huggingface.co/models/mistralai/Mistral-7B-Instruct-v0.2',
352
- { inputs: `<s>[INST] ${args} [/INST]`, parameters: { max_new_tokens: 300 } },
353
- { headers: { 'Authorization': `Bearer ${HF_TOKEN}` }, timeout: 30000 }
354
- );
355
- let reply = res.data[0]?.generated_text || 'Gagal';
356
- reply = reply.replace(/<s>\[INST\].*?\[\/INST\]\s*/, '');
357
- await sock.sendMessage(sender, { text: reply.substring(0, 1000) });
358
- } catch (e) {
359
- await sock.sendMessage(sender, { text: '❌ AI sibuk' });
360
- }
361
- }
362
- });
363
 
364
- } catch (error) {
365
- console.error('Fatal:', error.message);
366
- connectionStatus = 'error';
367
- setTimeout(startBot, 10000);
368
- }
 
 
 
 
 
 
 
369
  }
370
 
371
- // ===== START =====
372
- server.listen(PORT, () => {
373
- console.log(`🌐 Server: ${PORT}`);
374
  startBot();
375
  });
 
4
  useMultiFileAuthState,
5
  fetchLatestBaileysVersion
6
  } = require('@whiskeysockets/baileys');
7
+ const QRCode = require('qrcode-terminal');
8
  const qrcode = require('qrcode');
 
9
  const fs = require('fs');
10
  const path = require('path');
 
11
  const http = require('http');
12
  const pino = require('pino');
13
 
14
+ const AUTH_FOLDER = './auth';
15
+ const PORT = 8080; // Localhost port
 
 
 
 
16
 
17
  let sock = null;
18
  let qrCodeData = null;
19
  let connectionStatus = 'disconnected';
 
 
 
 
 
 
 
 
 
 
20
 
21
+ // Simple HTTP server buat lihat QR di browser HP
22
+ const server = http.createServer(async (req, res) => {
23
+ if (req.url === '/') {
24
+ res.writeHead(200, {'Content-Type': 'text/html'});
25
+ res.end(`
26
  <!DOCTYPE html>
27
+ <html>
28
  <head>
 
29
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
30
+ <title>WA Bot - Termux</title>
31
  <style>
32
+ body {
33
+ font-family: Arial;
34
+ background: #1a1a2e;
35
+ color: white;
36
+ text-align: center;
37
+ padding: 20px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  }
39
+ .qr {
40
+ background: white;
41
+ padding: 20px;
42
+ border-radius: 10px;
 
43
  display: inline-block;
44
+ margin: 20px 0;
45
  }
46
+ .status {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  padding: 15px;
48
+ border-radius: 10px;
49
+ margin: 20px 0;
 
 
 
50
  }
51
+ .connected { background: #00b894; }
52
+ .disconnected { background: #e17055; }
53
+ .waiting { background: #fdcb6e; color: black; }
54
  </style>
55
  </head>
56
  <body>
57
+ <h1>πŸ€– WhatsApp Bot (Termux)</h1>
58
+ <div class="status ${connectionStatus}" id="status">
59
+ Status: ${connectionStatus}
60
+ </div>
61
+ <div id="qrSection">
62
+ <p>Scan QR Code:</p>
63
+ <div class="qr">
64
+ <img id="qr" src="/qr" width="300" height="300" onerror="this.style.display='none'">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  </div>
66
+ <p>Atau lihat QR di terminal!</p>
67
  </div>
 
68
  <script>
69
+ setInterval(() => {
70
+ document.getElementById('qr').src = '/qr?' + Date.now();
71
+ fetch('/status').then(r => r.text()).then(s => {
72
+ document.getElementById('status').className = 'status ' + s;
73
+ document.getElementById('status').textContent = 'Status: ' + s;
74
+ });
75
+ }, 3000);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  </script>
77
  </body>
78
  </html>
79
+ `);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  }
81
+ else if (req.url === '/qr') {
82
+ if (!qrCodeData) {
83
+ res.writeHead(404);
84
+ res.end('No QR');
85
+ return;
 
 
86
  }
87
+ const buffer = await qrcode.toBuffer(qrCodeData, { type: 'png', width: 300 });
88
+ res.writeHead(200, {'Content-Type': 'image/png'});
89
+ res.end(buffer);
90
+ }
91
+ else if (req.url === '/status') {
92
+ res.writeHead(200);
93
+ res.end(connectionStatus);
94
+ }
95
+ else {
96
+ res.writeHead(404);
97
+ res.end('Not found');
98
  }
99
  });
100
 
101
+ // WhatsApp Bot
102
  async function startBot() {
103
+ console.log('πŸš€ Starting WhatsApp Bot...');
104
+ console.log('πŸ“± Buka http://localhost:8080 di browser HP lu');
105
 
106
+ const { state, saveCreds } = await useMultiFileAuthState(AUTH_FOLDER);
107
+ const { version } = await fetchLatestBaileysVersion();
108
+
109
+ sock = makeWASocket({
110
+ version,
111
+ logger: pino({ level: 'silent' }),
112
+ printQRInTerminal: true, // Tampilkan QR di terminal juga
113
+ auth: state,
114
+ browser: ['Termux', 'Chrome', 'Android'],
115
+ syncFullHistory: false,
116
+ markOnlineOnConnect: true,
117
+ });
 
 
 
 
 
 
 
 
 
 
118
 
119
+ sock.ev.on('connection.update', async (update) => {
120
+ const { connection, lastDisconnect, qr } = update;
121
+
122
+ if (qr) {
123
+ console.log('\nπŸ”₯ QR CODE (Scan ini):');
124
+ QRCode.generate(qr, { small: true });
125
+ qrCodeData = qr;
126
+ connectionStatus = 'waiting';
127
+ }
128
 
129
+ if (connection === 'open') {
130
+ connectionStatus = 'connected';
131
+ qrCodeData = null;
132
+ console.log('\nβœ… BERHASIL! Bot terhubung.');
133
+ console.log('πŸ“± Nomor:', sock.user.id.split(':')[0]);
 
 
 
 
 
 
134
 
135
+ try {
136
+ await sock.sendMessage(sock.user.id, {
137
+ text: 'πŸ€– Bot aktif di Termux!\n\nKetik !help'
138
+ });
139
+ } catch (e) {}
140
+ }
141
+ else if (connection === 'close') {
142
+ const shouldReconnect = lastDisconnect?.error?.output?.statusCode !== DisconnectReason.loggedOut;
143
+ connectionStatus = 'disconnected';
144
+ console.log('\n❌ Terputus, reconnect...');
145
+ if (shouldReconnect) setTimeout(startBot, 5000);
146
+ }
147
+ });
 
 
 
 
 
 
 
148
 
149
+ sock.ev.on('creds.update', saveCreds);
 
 
 
 
150
 
151
+ sock.ev.on('messages.upsert', async ({ messages, type }) => {
152
+ if (type !== 'notify') return;
153
+ const msg = messages[0];
154
+ if (!msg.message || msg.key.fromMe) return;
155
 
156
+ const sender = msg.key.remoteJid;
157
+ const text = msg.message.conversation || msg.message.extendedTextMessage?.text || '';
158
 
159
+ if (!text.startsWith('!')) return;
 
160
 
161
+ const cmd = text.slice(1).split(' ')[0].toLowerCase();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
 
163
+ if (cmd === 'help') {
164
+ await sock.sendMessage(sender, {
165
+ text: '*Command:*\n!ping - Test\n!status - Status'
166
+ });
167
+ }
168
+ else if (cmd === 'ping') {
169
+ await sock.sendMessage(sender, { text: 'πŸ“ Pong!' });
170
+ }
171
+ else if (cmd === 'status') {
172
+ await sock.sendMessage(sender, { text: 'Status: ' + connectionStatus });
173
+ }
174
+ });
175
  }
176
 
177
+ server.listen(PORT, '0.0.0.0', () => {
178
+ console.log(`🌐 Web UI: http://localhost:${PORT}`);
179
+ console.log(`🌐 Atau: http://127.0.0.1:${PORT}`);
180
  startBot();
181
  });