diff --git a/README.md b/README.md index bf8a0c4..1e22863 100644 --- a/README.md +++ b/README.md @@ -2,30 +2,25 @@ * Tutorial with VIDEO : https://youtu.be/B6IkggY6ct8 -# Get your discord token, different ways: - -First method: - -Open your browser and activate developer mode - -Login your discord account - -Go to developer mode and click on XHR tab - -Find login request and click - -Go to Responses tab and find token value +## Prerequisites +Pastikan kamu sudah menginstal: +- [Python](https://www.python.org/downloads/) (Centang **"Add Python to PATH"** saat instalasi!) +- Git Bash (jika belum punya, unduh dari [Git for Windows](https://git-scm.com/downloads)) -Copy that token - -Second method: - -Make sure that you already login into your discord account - -Go to Developers tool in your browser +# Get your discord token, different ways: -Find javascript console, and paste code below: +### First method: +1. Open your browser and activate developer mode +2. Login your discord account +3. Go to developer mode and click on XHR tab +4. Find login request and click +5. Go to Responses tab and find token value +6. Copy that token +### Second method: +1. Make sure that you already login into your discord account +2. Go to Developers tool in your browser +3. Find javascript console, and paste code below: ``` ( @@ -46,7 +41,6 @@ Find javascript console, and paste code below: ).exports.default.getToken() ``` - # HOW TO GET GEMINI API : go to : https://aistudio.google.com/apikey @@ -55,7 +49,54 @@ go to : https://aistudio.google.com/apikey * Create API Key * Copy API Key -# PASTE YOUR DISCORD TOKEN & GEMINI API IN FILE .ENV +## PASTE YOUR DISCORD TOKEN & GEMINI API IN FILE .ENV + +### 1. Buka Git Bash dan Masuk ke Direktori Proyek +Jika belum ada, clone repository proyek terlebih dahulu: +```bash + git clone https://github.com/Madleyym/discord-gemini/tree/main +``` +Lalu masuk ke folder proyek: +```bash + cd discord-gemini +``` + +### 2. Buat Virtual Environment +Jalankan perintah berikut untuk membuat virtual environment: +```bash + python -m venv discord +``` +Jika `python` tidak dikenali, coba: +```bash + python3 -m venv discord +``` + +### 3. Aktifkan Virtual Environment +Karena di **Windows**, jalankan perintah berikut: +```bash + source discord/Scripts/activate +``` +Jika berhasil, prompt akan berubah menjadi `(discord)`, menandakan virtual environment aktif. + +### 4. Install Dependencies +Jalankan: +```bash + pip install -r requirements.txt +``` + +### 5. Menjalankan Proyek +Setelah instalasi selesai, kamu bisa menjalankan proyek sesuai dengan instruksi yang ada di repository ini. + +### 6. (Opsional) Menonaktifkan Virtual Environment +Jika ingin keluar dari virtual environment, jalankan: +```bash + deactivate +``` + +## Troubleshooting +Jika ada error seperti **"python not found"**, pastikan: +- Python sudah ditambahkan ke PATH +- Coba jalankan dengan `python3` daripada `python` # Youtube Channel : * https://www.youtube.com/@SHAREITHUB_COM @@ -65,3 +106,7 @@ go to : https://aistudio.google.com/apikey # Group Telegram : * https://t.me/DISS_SHAREITHUB + +--- +Semoga berhasil! 🚀 Jika ada kendala, silakan cek dokumentasi atau tanyakan di forum komunitas. 😃 + diff --git a/chinesse.txt b/chinesse.txt new file mode 100644 index 0000000..e69de29 diff --git a/discord.py b/discord.py index ba92195..cde136a 100644 --- a/discord.py +++ b/discord.py @@ -1,14 +1,11 @@ import json import time -import shareithub import os import random import requests -from dotenv import load_dotenv from datetime import datetime -from shareithub import shareithub +from dotenv import load_dotenv -shareithub() load_dotenv() discord_token = os.getenv('DISCORD_TOKEN') @@ -16,167 +13,238 @@ last_message_id = None bot_user_id = None -last_ai_response = None # Menyimpan respons AI terakhir + +# Rate limiting parameters +GEMINI_RETRY_DELAY = 60 # Delay in seconds before retrying Gemini API +DISCORD_RETRY_DELAY = 5 # Delay in seconds before retrying Discord API +MAX_RETRIES = 3 def log_message(message): print(f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} - {message}") -def generate_reply(prompt, use_google_ai=True, use_file_reply=False, language="id"): - """Membuat balasan, menghindari duplikasi jika menggunakan Google Gemini AI""" - - global last_ai_response # Gunakan variabel global agar dapat diakses di seluruh sesi - - if use_file_reply: - log_message("💬 Menggunakan pesan dari file sebagai balasan.") - return {"candidates": [{"content": {"parts": [{"text": get_random_message()}]}}]} +def get_random_message(): + try: + with open('pesan.txt', 'r', encoding='utf-8') as file: + lines = [line.strip() for line in file.readlines() if line.strip()] + if lines: + return random.choice(lines) + else: + log_message("⚠️ pesan.txt is empty") + return "No messages available" + except FileNotFoundError: + log_message("⚠️ pesan.txt not found") + return "pesan.txt not found" + except Exception as e: + log_message(f"⚠️ Error reading pesan.txt: {str(e)}") + return "Error reading messages" + +def generate_gemini_reply(prompt, language="id", retry_count=0): + """Generate reply using Google Gemini AI with retry logic""" + if retry_count >= MAX_RETRIES: + log_message("❌ Max retries reached for Gemini API") + return None - if use_google_ai: - # Pilihan bahasa + try: if language == "en": ai_prompt = f"{prompt}\n\nRespond with only one sentence in casual urban English, like a natural conversation, and do not use symbols." else: ai_prompt = f"{prompt}\n\nBerikan 1 kalimat saja dalam bahasa gaul daerah Jakarta seperti obrolan dan jangan gunakan simbol apapun." - + url = f'https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent?key={google_api_key}' headers = {'Content-Type': 'application/json'} data = {'contents': [{'parts': [{'text': ai_prompt}]}]} - - for attempt in range(3): # Coba sampai 3 kali jika AI mengulang pesan yang sama - try: - response = requests.post(url, headers=headers, json=data) - response.raise_for_status() - ai_response = response.json() - - # Ambil teks dari respons AI - response_text = ai_response['candidates'][0]['content']['parts'][0]['text'] - - # Cek apakah respons AI sama dengan yang terakhir - if response_text == last_ai_response: - log_message("⚠️ AI memberikan balasan yang sama, mencoba ulang...") - continue # Coba lagi dengan permintaan baru - - last_ai_response = response_text # Simpan respons terbaru - return ai_response - - except requests.exceptions.RequestException as e: - log_message(f"⚠️ Request failed: {e}") - return None - - log_message("⚠️ AI terus memberikan balasan yang sama, menggunakan respons terakhir yang tersedia.") - return {"candidates": [{"content": {"parts": [{"text": last_ai_response or 'Maaf, tidak dapat membalas pesan.'}]}}]} - - else: - return {"candidates": [{"content": {"parts": [{"text": get_random_message()}]}}]} - -def get_random_message(): - """Mengambil pesan acak dari file pesan.txt""" - try: - with open('pesan.txt', 'r') as file: - lines = file.readlines() - if lines: - return random.choice(lines).strip() - else: - log_message("File pesan.txt kosong.") - return "Tidak ada pesan yang tersedia." - except FileNotFoundError: - log_message("File pesan.txt tidak ditemukan.") - return "File pesan.txt tidak ditemukan." + + response = requests.post(url, headers=headers, json=data) + + if response.status_code == 429: + log_message(f"⏳ Rate limited by Gemini API, waiting {GEMINI_RETRY_DELAY} seconds...") + time.sleep(GEMINI_RETRY_DELAY) + return generate_gemini_reply(prompt, language, retry_count + 1) + + response.raise_for_status() + result = response.json() + + if 'candidates' in result and len(result['candidates']) > 0: + text = result['candidates'][0]['content']['parts'][0]['text'] + log_message(f"✅ Gemini response: {text}") + return text + + return None + + except Exception as e: + log_message(f"⚠️ Gemini API error: {str(e)}") + if retry_count < MAX_RETRIES: + log_message(f"⏳ Retrying in {GEMINI_RETRY_DELAY} seconds...") + time.sleep(GEMINI_RETRY_DELAY) + return generate_gemini_reply(prompt, language, retry_count + 1) + return None def send_message(channel_id, message_text, reply_to=None, reply_mode=True): - """Mengirim pesan ke Discord, bisa dengan atau tanpa reply""" + """Send message to Discord with improved rate limit handling""" headers = { 'Authorization': f'{discord_token}', 'Content-Type': 'application/json' } payload = {'content': message_text} - - # Hanya tambahkan reply jika reply_mode diaktifkan if reply_mode and reply_to: payload['message_reference'] = {'message_id': reply_to} - try: - response = requests.post(f"https://discord.com/api/v9/channels/{channel_id}/messages", json=payload, headers=headers) - response.raise_for_status() - - if response.status_code == 201: - log_message(f"✅ Sent message: {message_text}") - else: - log_message(f"⚠️ Failed to send message: {response.status_code}") - except requests.exceptions.RequestException as e: - log_message(f"⚠️ Request error: {e}") - -def auto_reply(channel_id, read_delay, reply_delay, use_google_ai, use_file_reply, language, reply_mode): - """Fungsi untuk auto-reply di Discord dengan menghindari duplikasi AI""" + while True: + try: + response = requests.post( + f"https://discord.com/api/v9/channels/{channel_id}/messages", + json=payload, + headers=headers + ) + + if response.status_code == 429: + retry_after = float(response.json().get('retry_after', DISCORD_RETRY_DELAY)) + log_message(f"⏳ Rate limited by Discord, waiting {retry_after} seconds...") + time.sleep(retry_after) + continue # Retry immediately after timeout + + response.raise_for_status() + log_message(f"✅ Sent: {message_text}") + return True + + except Exception as e: + log_message(f"⚠️ Discord API error: {str(e)}") + return False + +def auto_reply(channel_id, read_delay, reply_delay, use_gemini, language, reply_mode): global last_message_id, bot_user_id headers = {'Authorization': f'{discord_token}'} - + try: - bot_info_response = requests.get('https://discord.com/api/v9/users/@me', headers=headers) - bot_info_response.raise_for_status() - bot_user_id = bot_info_response.json().get('id') - except requests.exceptions.RequestException as e: - log_message(f"⚠️ Failed to retrieve bot information: {e}") + bot_info = requests.get('https://discord.com/api/v9/users/@me', headers=headers) + bot_info.raise_for_status() + bot_user_id = bot_info.json().get('id') + log_message(f"✅ Bot started with ID: {bot_user_id}") + except Exception as e: + log_message(f"⚠️ Failed to get bot info: {str(e)}") return + # Set initial last_message_id + try: + response = requests.get( + f'https://discord.com/api/v9/channels/{channel_id}/messages?limit=1', + headers=headers + ) + response.raise_for_status() + messages = response.json() + if messages and isinstance(messages, list) and len(messages) > 0: + last_message_id = messages[0].get('id') + log_message(f"✅ Initial message ID set to: {last_message_id}") + except Exception as e: + log_message(f"⚠️ Failed to get initial message ID: {str(e)}") + while True: try: - response = requests.get(f'https://discord.com/api/v9/channels/{channel_id}/messages', headers=headers) + # Get latest messages, limit to 5 to catch any missed messages + response = requests.get( + f'https://discord.com/api/v9/channels/{channel_id}/messages?limit=5', + headers=headers + ) + + if response.status_code == 429: + retry_after = float(response.json().get('retry_after', read_delay)) + log_message(f"⏳ Rate limited, waiting {retry_after} seconds...") + time.sleep(retry_after) + continue + response.raise_for_status() - - if response.status_code == 200: - messages = response.json() - if len(messages) > 0: - most_recent_message = messages[0] - message_id = most_recent_message.get('id') - author_id = most_recent_message.get('author', {}).get('id') - message_type = most_recent_message.get('type', '') - - if (last_message_id is None or int(message_id) > int(last_message_id)) and author_id != bot_user_id and message_type != 8: - user_message = most_recent_message.get('content', '') - log_message(f"💬 Received message: {user_message}") - - result = generate_reply(user_message, use_google_ai, use_file_reply, language) - response_text = result['candidates'][0]['content']['parts'][0]['text'] if result else "Maaf, tidak dapat membalas pesan." - - log_message(f"⏳ Waiting {reply_delay} seconds before replying...") - time.sleep(reply_delay) - send_message(channel_id, response_text, reply_to=message_id if reply_mode else None, reply_mode=reply_mode) - last_message_id = message_id - - log_message(f"⏳ Waiting {read_delay} seconds before checking for new messages...") - time.sleep(read_delay) - except requests.exceptions.RequestException as e: - log_message(f"⚠️ Request error: {e}") + messages = response.json() + + if messages and isinstance(messages, list): + # Sort messages by ID to process them in order + messages.sort(key=lambda x: int(x.get('id', 0))) + + for message in messages: + message_id = message.get('id') + author_id = message.get('author', {}).get('id') + + # Check if this is a new message from someone else + if (last_message_id is None or int(message_id) > int(last_message_id)) and author_id != bot_user_id: + user_message = message.get('content', '') + log_message(f"📥 Received new message: {user_message}") + + response_text = None + if use_gemini: + response_text = generate_gemini_reply(user_message, language) + + if response_text is None: + if use_gemini: + log_message("⚠️ Falling back to pesan.txt") + response_text = get_random_message() + + # Wait before replying + if reply_delay > 0: + time.sleep(reply_delay) + + # Send the reply + if send_message(channel_id, response_text, message_id if reply_mode else None, reply_mode): + last_message_id = message_id + log_message(f"✅ Updated last message ID to: {last_message_id}") + + # Wait before checking for new messages + if read_delay > 0: + time.sleep(read_delay) + + except Exception as e: + log_message(f"⚠️ Error in main loop: {str(e)}") time.sleep(read_delay) -if __name__ == "__main__": - use_reply = input("Ingin menggunakan fitur auto-reply? (y/n): ").lower() == 'y' - channel_id = input("Masukkan ID channel: ") - - if use_reply: - use_google_ai = input("Gunakan Google Gemini AI untuk balasan? (y/n): ").lower() == 'y' - use_file_reply = input("Gunakan pesan dari file pesan.txt? (y/n): ").lower() == 'y' - reply_mode = input("Ingin membalas pesan (reply) atau hanya mengirim pesan? (reply/send): ").lower() == 'reply' - language_choice = input("Pilih bahasa untuk balasan (id/en): ").lower() - - if language_choice not in ["id", "en"]: - log_message("⚠️ Bahasa tidak valid, default ke bahasa Indonesia.") - language_choice = "id" - - read_delay = int(input("Set Delay Membaca Pesan Terbaru (dalam detik): ")) - reply_delay = int(input("Set Delay Balas Pesan (dalam detik): ")) - - log_message(f"✅ Mode reply {'aktif' if reply_mode else 'non-reply'} dalam bahasa {'Indonesia' if language_choice == 'id' else 'Inggris'}...") - auto_reply(channel_id, read_delay, reply_delay, use_google_ai, use_file_reply, language_choice, reply_mode) - - else: - send_interval = int(input("Set Interval Pengiriman Pesan (dalam detik): ")) - log_message("✅ Mode kirim pesan acak aktif...") - - while True: +def random_message_mode(channel_id, interval): + log_message("✅ Random message mode started") + + while True: + try: message_text = get_random_message() send_message(channel_id, message_text, reply_mode=False) - log_message(f"⏳ Waiting {send_interval} seconds before sending the next message...") - time.sleep(send_interval) + time.sleep(interval) + + except Exception as e: + log_message(f"⚠️ Error in random message mode: {str(e)}") + time.sleep(interval) + +if __name__ == "__main__": + try: + print("\n=== Discord Auto Reply Bot ===\n") + + mode = input("Pilih mode (1: Auto Reply, 2: Random Message): ").strip() + channel_id = input("Masukkan ID channel: ").strip() + + if mode == "1": + use_gemini = input("Gunakan Google Gemini AI? (y/n): ").lower() == 'y' + reply_mode = input("Mode balas pesan? (y/n): ").lower() == 'y' + language = input("Pilih bahasa (id/en): ").lower() + + if language not in ["id", "en"]: + language = "id" + log_message("⚠️ Invalid language, using Indonesian") + + read_delay = int(input("Delay membaca pesan (detik): ")) + reply_delay = int(input("Delay balas pesan (detik): ")) + + print("\nKonfigurasi Bot:") + print(f"- Menggunakan Gemini AI: {'Ya' if use_gemini else 'Tidak (menggunakan pesan.txt)'}") + print(f"- Mode Reply: {'Ya' if reply_mode else 'Tidak'}") + print(f"- Bahasa: {'Indonesia' if language == 'id' else 'Inggris'}") + print(f"- Delay Membaca: {read_delay}s") + print(f"- Delay Membalas: {reply_delay}s\n") + + auto_reply(channel_id, read_delay, reply_delay, use_gemini, language, reply_mode) + + elif mode == "2": + interval = int(input("Interval kirim pesan (detik): ")) + random_message_mode(channel_id, interval) + + else: + print("⚠️ Mode tidak valid") + + except KeyboardInterrupt: + print("\n\n✅ Bot dihentikan oleh user") + except Exception as e: + print(f"\n⚠️ Error fatal: {str(e)}") \ No newline at end of file diff --git a/english.txt b/english.txt new file mode 100644 index 0000000..e69de29 diff --git a/indonesian.txt b/indonesian.txt new file mode 100644 index 0000000..e69de29 diff --git a/pesan.txt b/pesan.txt index 7026912..33c003a 100644 --- a/pesan.txt +++ b/pesan.txt @@ -1,4 +1,20 @@ -pesan 1 -pesan 2 -pesan 3 -seterusnya +lol yeah that's so true +just take it easy, no need to rush +gaming all night long, let's go +just send it, don't overthink it +that's hilarious fr fr +you're absolutely right +wow your skills are insane +still learning, got a long way to go +anyone up for some games? +come on guys, join the fun +noted, I'll give it a try later +chill gaming is the best gaming +you're too funny lmao +haven't played in ages, missing it +been too busy, rarely online +aight bet, let's grind some rank +gaming till dawn, let's go +you're cracked at this fr +pro player alert! +hop in vc let's go \ No newline at end of file diff --git a/russian.txt b/russian.txt new file mode 100644 index 0000000..e69de29