diff --git a/.env b/.env new file mode 100644 index 0000000..ef50b5d --- /dev/null +++ b/.env @@ -0,0 +1,5 @@ +OPENROUTER_API_KEY=your_key_here +BOT_API_SECRET=microjob_bot_secret_2024 +BACKEND_URL=http://localhost:3001/api +TRANSACTION_TYPES=SERVICE,JOB +COUNT_PER_TYPE=1 diff --git a/.env.example b/.env.example index 91dbe88..19ef502 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,5 @@ OPENROUTER_API_KEY=your_openrouter_api_key_here BOT_API_SECRET=your_super_secret_bot_key BACKEND_URL=http://localhost:3001/api - +TRANSACTION_TYPES=SERVICE,JOB +COUNT_PER_TYPE=1 \ No newline at end of file diff --git a/README.md b/README.md index 83eaff9..33e6b78 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,10 @@ Bot ini dirancang untuk mensimulasikan aktivitas nyata di platform Microjob (mem ## 🚀 Fitur Utama -- **AI-Driven Data**: Menggunakan OpenRouter (Llama-3) untuk menghasilkan nama orang Indonesia, nama bisnis profesional, deskripsi, hingga ulasan yang realistis. -- **Dynamic Location**: Menghasilkan koordinat (Lat/Lng) dan alamat acak di berbagai kota besar di Indonesia. -- **Smart Simulation**: Meniru perilaku manusia dengan jeda waktu (*delay*) antar tindakan. -- **Automated Transactions**: Melewati gerbang pembayaran (*skip payment*) untuk memudahkan simulasi internal. +- **Dual Flow Simulation**: Mendukung simulasi transaksi **Layanan** (pembelian langsung) dan **Lowongan** (post job -> lamar -> terima). +- **AI-Driven Data**: Menggunakan OpenRouter (Gemini/Llama) untuk menghasilkan persona Indonesia yang realistis. +- **Natural Behavior**: Meniru perilaku manusia dengan jeda waktu acak dan pengacakan urutan transaksi. +- **Automated Transactions**: Melewati gerbang pembayaran untuk memudahkan pengisian data internal. ## 🛠️ Instalasi @@ -29,22 +29,29 @@ Buat file `.env` (salin dari `.env.example`) dan isi variabel berikut: OPENROUTER_API_KEY=your_key_here BOT_API_SECRET=your_backend_bot_secret BACKEND_URL=http://localhost:3001/api +TRANSACTION_TYPES=SERVICE,JOB +COUNT_PER_TYPE=1 ``` -- `OPENROUTER_API_KEY`: Kunci API Anda dari [OpenRouter](https://openrouter.ai/). -- `BOT_API_SECRET`: Kunci rahasia yang harus sama dengan yang ada di `.env` backend Anda (untuk otentikasi API Bot). -- `BACKEND_URL`: URL API backend Microjob Anda. +- `OPENROUTER_API_KEY`: Kunci API dari [OpenRouter](https://openrouter.ai/). +- `BOT_API_SECRET`: Kunci rahasia yang **harus sama** dengan yang ada di `.env` backend Anda. +- `TRANSACTION_TYPES`: Tipe transaksi yang ingin dijalankan (`SERVICE`, `JOB`, atau keduanya dipisah koma). +- `COUNT_PER_TYPE`: Berapa kali setiap tipe transaksi dijalankan dalam satu kali running. ## 🏁 Cara Menjalankan -### Jalankan Simulasi Sekali (On-Demand) -Untuk menjalankan satu siklus simulasi (Buat Akun -> Buat Jasa -> Order -> Selesai) secara instan: +### Jalankan Sekali (On-Demand / Cron Job) +Untuk menjalankan simulasi sesuai jumlah di `.env` lalu berhenti: ```bash python main.py ``` -### Jalankan Sebagai Scheduler (Harian) -Bot ini mendukung penjadwalan otomatis. Anda bisa mengaktifkan bagian `schedule` di dalam `main.py` agar bot berjalan otomatis setiap hari pada jam tertentu. +### Jalankan Sebagai Background Service (VPS) +Anda bisa menggunakan **PM2** agar bot ini berjalan terus dan otomatis restart jika terjadi error: +```bash +pm2 start main.py --name "microjob-bot" --interpreter python3 +``` + ## 📂 Struktur Folder diff --git a/main.py b/main.py index cee76cf..41263ad 100644 --- a/main.py +++ b/main.py @@ -11,6 +11,12 @@ load_dotenv() BACKEND_URL = os.getenv("BACKEND_URL", "http://localhost:3001/api") BOT_SECRET = os.getenv("BOT_API_SECRET", "") +# Ambil list tipe transaksi dari ENV (misal: "SERVICE,JOB") +ALLOWED_TYPES = os.getenv("TRANSACTION_TYPES", "SERVICE,JOB").split(",") +# Ambil jumlah transaksi per tipe +COUNT_PER_TYPE = int(os.getenv("COUNT_PER_TYPE", "1")) + + headers = { "Content-Type": "application/json", "x-bot-api-key": BOT_SECRET @@ -19,75 +25,154 @@ headers = { def log(msg): print(f"[BOT] {time.strftime('%Y-%m-%d %H:%M:%S')} - {msg}") -def run_daily_simulation(): - log("=== Memulai Simulasi Transaksi Harian ===") +def run_service_simulation(): + """Menjalankan 1 siklus transaksi Layanan/Service""" + log("--- Memulai 1 Siklus Transaksi LAYANAN ---") # 1. Generate Data AI log("Generating data using AI...") - ai_data = generate_bot_data() + try: + ai_data = generate_bot_data() + except Exception as e: + log(f"AI Generation failed: {e}") + return False - # 2. Setup Accounts (Akun 1 & Akun 2) + # 2. Setup Accounts log("Step 1: Setup Accounts") - # TODO: Panggil API Backend req1 = requests.post(f"{BACKEND_URL}/bot/setup-account", json={"data": ai_data}, headers=headers) if req1.status_code != 200: log(f"Failed to setup accounts: {req1.text}") - return + return False + res_data1 = req1.json() provider_id = res_data1['data']['user1']['providerProfile']['id'] buyer_id = res_data1['data']['user2']['id'] log(f"Accounts created! ProviderID: {provider_id}, BuyerID: {buyer_id}") - # Delay acak agar terlihat natural (misal: 10 - 30 menit) - delay_minutes = random.randint(10, 30) - log(f"Menunggu {delay_minutes} menit sebelum membuat layanan...") - # time.sleep(delay_minutes * 60) # Uncomment in production + time.sleep(random.randint(60, 180)) # 3. Create Service log("Step 2: Create Service") - # TODO: Panggil API Backend req2 = requests.post(f"{BACKEND_URL}/bot/create-service", json={ "providerId": provider_id, "data": ai_data }, headers=headers) if req2.status_code != 200: log(f"Failed to create service: {req2.text}") - return + return False + res_data2 = req2.json() service_id = res_data2['data']['id'] log(f"Service created! ServiceID: {service_id}") - # Delay tunggu pesanan (misal: 1 - 3 jam) - delay_hours = random.randint(1, 3) - log(f"Menunggu {delay_hours} jam sebelum simulasi order...") - # time.sleep(delay_hours * 3600) # Uncomment in production + time.sleep(random.randint(120, 300)) - # 4. Simulate Transaction & Payment - log("Step 3: Place Order & Skip Payment") - # TODO: Panggil API Backend + # 4. Simulate Transaction + log("Step 3: Place Order (Service)") req3 = requests.post(f"{BACKEND_URL}/bot/simulate-transaction", json={ "buyerId": buyer_id, "providerId": provider_id, "serviceId": service_id, "data": ai_data }, headers=headers) + if req3.status_code != 200: log(f"Failed to simulate transaction: {req3.text}") - return - res_data3 = req3.json() - log(f"Transaction Simulated Successfully! OrderID: {res_data3['data']['orderId']}") + return False + + log(f"Service Transaction Completed! OrderID: {req3.json()['data']['orderId']}") + return True + +def run_job_simulation(): + """Menjalankan 1 siklus transaksi Lowongan/Job""" + log("--- Memulai 1 Siklus Transaksi JOB ---") - log("=== Simulasi Selesai ===") + # 1. Generate Data AI + log("Generating data using AI...") + try: + ai_data = generate_bot_data() + except Exception as e: + log(f"AI Generation failed: {e}") + return False + + # 2. Setup Accounts + log("Step 1: Setup Accounts") + req1 = requests.post(f"{BACKEND_URL}/bot/setup-account", json={"data": ai_data}, headers=headers) + if req1.status_code != 200: + log(f"Failed to setup accounts: {req1.text}") + return False + + res_data1 = req1.json() + provider_id = res_data1['data']['user1']['providerProfile']['id'] + buyer_id = res_data1['data']['user2']['id'] + log(f"Accounts created! ProviderID: {provider_id}, BuyerID: {buyer_id}") + + time.sleep(random.randint(120, 300)) + + # 3. Simulate Job Transaction (Post Job -> Apply -> Accept -> Transact) + log("Step 2: Simulate Job Lifecycle") + req2 = requests.post(f"{BACKEND_URL}/bot/simulate-job", json={ + "buyerId": buyer_id, + "providerId": provider_id, + "data": ai_data + }, headers=headers) + + if req2.status_code != 200: + log(f"Failed to simulate job: {req2.text}") + return False + + res_data2 = req2.json() + log(f"Job Transaction Completed! JobID: {res_data2['data']['job']['id']}, OrderID: {res_data2['data']['transaction']['orderId']}") + return True + +def run_job(): + # Bersihkan whitespace dari list tipe + types = [t.strip().upper() for t in ALLOWED_TYPES if t.strip()] + + log(f"=== Memulai Batch Harian: Tipe={types}, Jumlah/Tipe={COUNT_PER_TYPE} ===") + + # Gabungkan semua tugas dan acak urutannya agar natural + tasks = [] + for t in types: + tasks.extend([t] * COUNT_PER_TYPE) + + random.shuffle(tasks) + + success_count = 0 + for i, task_type in enumerate(tasks): + log(f"Eksekusi ke-{i+1} dari {len(tasks)}: {task_type}") + + success = False + if task_type == 'SERVICE': + success = run_service_simulation() + elif task_type == 'JOB': + success = run_job_simulation() + else: + log(f"Tipe transaksi '{task_type}' tidak dikenali. Melewati...") + continue + + if success: + success_count += 1 + + # Jeda antar simulasi dalam batch (15-45 menit) + if i < len(tasks) - 1: + batch_delay = random.randint(900, 2700) + log(f"Jeda antar simulasi batch: {batch_delay} detik...") + time.sleep(batch_delay) + + log(f"=== Batch Selesai: {success_count}/{len(tasks)} Berhasil ===") if __name__ == "__main__": - log("Bot Juaskill Started!") + types = [t.strip().upper() for t in ALLOWED_TYPES if t.strip()] + total_trx = len(types) * COUNT_PER_TYPE + log(f"Bot Juaskill Started! (Target: {total_trx} trx/hari dari tipe: {types})") - # Jadwalkan bot untuk jalan 1 kali setiap hari di jam random antara 08:00 - 10:00 pagi - # Untuk testing, kita jalankan langsung 1x - run_daily_simulation() + # Mode Langsung + run_job() + - # Uncomment untuk menjalankan scheduler - # schedule.every().day.at("09:00").do(run_daily_simulation) + # Mode Scheduler (Opsional untuk VPS) + # schedule.every().day.at("09:00").do(run_job) # while True: # schedule.run_pending() # time.sleep(60)