feat: initial bot orchestrator with AI integration
This commit is contained in:
4
.env.example
Normal file
4
.env.example
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
OPENROUTER_API_KEY=your_openrouter_api_key_here
|
||||||
|
BOT_API_SECRET=your_super_secret_bot_key
|
||||||
|
BACKEND_URL=http://localhost:3001/api
|
||||||
|
|
||||||
57
README.md
Normal file
57
README.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# Juaskill Bot - Platform Simulation Orchestrator
|
||||||
|
|
||||||
|
Bot ini dirancang untuk mensimulasikan aktivitas nyata di platform Microjob (membuat akun, membuat layanan, dan melakukan transaksi) menggunakan data cerdas yang dihasilkan oleh AI (OpenRouter).
|
||||||
|
|
||||||
|
## 🚀 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.
|
||||||
|
|
||||||
|
## 🛠️ Instalasi
|
||||||
|
|
||||||
|
1. Pastikan Anda memiliki Python 3.8+ terinstal.
|
||||||
|
2. Masuk ke direktori bot:
|
||||||
|
```bash
|
||||||
|
cd bot
|
||||||
|
```
|
||||||
|
3. Instal semua dependensi:
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
## ⚙️ Konfigurasi (.env)
|
||||||
|
|
||||||
|
Buat file `.env` (salin dari `.env.example`) dan isi variabel berikut:
|
||||||
|
|
||||||
|
```env
|
||||||
|
OPENROUTER_API_KEY=your_key_here
|
||||||
|
BOT_API_SECRET=your_backend_bot_secret
|
||||||
|
BACKEND_URL=http://localhost:3001/api
|
||||||
|
```
|
||||||
|
|
||||||
|
- `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.
|
||||||
|
|
||||||
|
## 🏁 Cara Menjalankan
|
||||||
|
|
||||||
|
### Jalankan Simulasi Sekali (On-Demand)
|
||||||
|
Untuk menjalankan satu siklus simulasi (Buat Akun -> Buat Jasa -> Order -> Selesai) secara instan:
|
||||||
|
```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.
|
||||||
|
|
||||||
|
## 📂 Struktur Folder
|
||||||
|
|
||||||
|
- `main.py`: Orkestrator utama alur bisnis bot.
|
||||||
|
- `ai_generator.py`: Modul untuk berinteraksi dengan OpenRouter AI.
|
||||||
|
- `requirements.txt`: Daftar pustaka Python yang dibutuhkan.
|
||||||
|
- `.env.example`: Contoh file konfigurasi lingkungan.
|
||||||
|
|
||||||
|
## ⚠️ Catatan Keamanan
|
||||||
|
Pastikan endpoint `/api/bot/*` di backend hanya dapat diakses menggunakan `BOT_API_SECRET` yang kuat untuk mencegah penyalahgunaan oleh pihak luar.
|
||||||
99
ai_generator.py
Normal file
99
ai_generator.py
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
import os
|
||||||
|
from openai import OpenAI
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
# Setup OpenRouter Client
|
||||||
|
client = OpenAI(
|
||||||
|
base_url="https://openrouter.ai/api/v1",
|
||||||
|
api_key=os.getenv("OPENROUTER_API_KEY"),
|
||||||
|
)
|
||||||
|
|
||||||
|
def generate_bot_data():
|
||||||
|
"""
|
||||||
|
Generate realistic Indonesian persona and service data using OpenRouter.
|
||||||
|
"""
|
||||||
|
prompt = """
|
||||||
|
Kamu adalah pembuat data realistis untuk platform Microjob/Gig Economy di Indonesia.
|
||||||
|
Buat 1 set data dalam format JSON yang berisi:
|
||||||
|
{
|
||||||
|
"akun1": {
|
||||||
|
"nama_lengkap": "Nama orang Indonesia yang realistis",
|
||||||
|
"email": "Email pribadi realistis berdasarkan nama",
|
||||||
|
"nama_bisnis": "Nama profesional atau brand jasa (contoh: Jasa Desain Grafis Budi, Tukang AC Cepat)",
|
||||||
|
"deskripsi_bisnis": "Deskripsi singkat tentang keahlian atau layanan yang ditawarkan",
|
||||||
|
"lokasi": {
|
||||||
|
"lat": "Latitude acak di area perkotaan Indonesia (misal: Jakarta, Bandung, atau Surabaya)",
|
||||||
|
"lng": "Longitude acak di area perkotaan Indonesia",
|
||||||
|
"alamat": "Alamat lengkap realistis di Indonesia",
|
||||||
|
"radius": "Angka radius layanan dalam KM (antara 10-100)"
|
||||||
|
},
|
||||||
|
"identitas": {
|
||||||
|
"tipe": "KTP",
|
||||||
|
"nomor": "16 digit angka KTP acak yang valid secara format"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"akun2": {
|
||||||
|
"nama_lengkap": "Nama pembeli Indonesia yang realistis",
|
||||||
|
"email": "Email pribadi realistis berdasarkan nama"
|
||||||
|
},
|
||||||
|
"layanan": {
|
||||||
|
"judul": "Judul jasa yang ditawarkan",
|
||||||
|
"deskripsi": "Deskripsi lengkap layanan tersebut",
|
||||||
|
"harga": "Angka saja dalam rupiah, misal 50000"
|
||||||
|
},
|
||||||
|
"review": {
|
||||||
|
"rating": 5,
|
||||||
|
"komentar": "Komentar positif dari pembeli"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Berikan HANYA JSON output tanpa teks lain.
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = client.chat.completions.create(
|
||||||
|
model="meta-llama/llama-3-8b-instruct:free", # Free tier model for testing, can be changed
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": "You output only valid JSON."},
|
||||||
|
{"role": "user", "content": prompt}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
content = response.choices[0].message.content.strip()
|
||||||
|
|
||||||
|
# Strip markdown backticks if present
|
||||||
|
if content.startswith("```"):
|
||||||
|
content = content.split("```")[1]
|
||||||
|
if content.startswith("json"):
|
||||||
|
content = content[4:]
|
||||||
|
content = content.split("```")[0].strip()
|
||||||
|
|
||||||
|
import json
|
||||||
|
return json.loads(content)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error generating AI data: {e}")
|
||||||
|
# Fallback dummy data if AI fails
|
||||||
|
return {
|
||||||
|
"akun1": {
|
||||||
|
"nama_lengkap": "Budi Santoso",
|
||||||
|
"email": "budi.santoso@gmail.com",
|
||||||
|
"nama_bisnis": "Budi Creative Design",
|
||||||
|
"deskripsi_bisnis": "Spesialis desain grafis dan branding logo",
|
||||||
|
"lokasi": {
|
||||||
|
"lat": -6.2088,
|
||||||
|
"lng": 106.8456,
|
||||||
|
"alamat": "Jl. Gajah Mada No. 12, Jakarta Pusat",
|
||||||
|
"radius": 25
|
||||||
|
},
|
||||||
|
"identitas": {
|
||||||
|
"tipe": "KTP",
|
||||||
|
"nomor": "3171234567890001"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"akun2": {"nama_lengkap": "Andi Pratama", "email": "andipratama12@yahoo.com"},
|
||||||
|
"layanan": {"judul": "Jasa Desain Banner", "deskripsi": "Desain banner cepat dan profesional", "harga": 50000},
|
||||||
|
"review": {"rating": 5, "komentar": "Pekerjaannya cepat dan hasilnya bagus sekali!"}
|
||||||
|
}
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(generate_bot_data())
|
||||||
93
main.py
Normal file
93
main.py
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
import os
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
import requests
|
||||||
|
import schedule
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from ai_generator import generate_bot_data
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
BACKEND_URL = os.getenv("BACKEND_URL", "http://localhost:3001/api")
|
||||||
|
BOT_SECRET = os.getenv("BOT_API_SECRET", "")
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"x-bot-api-key": BOT_SECRET
|
||||||
|
}
|
||||||
|
|
||||||
|
def log(msg):
|
||||||
|
print(f"[BOT] {time.strftime('%Y-%m-%d %H:%M:%S')} - {msg}")
|
||||||
|
|
||||||
|
def run_daily_simulation():
|
||||||
|
log("=== Memulai Simulasi Transaksi Harian ===")
|
||||||
|
|
||||||
|
# 1. Generate Data AI
|
||||||
|
log("Generating data using AI...")
|
||||||
|
ai_data = generate_bot_data()
|
||||||
|
|
||||||
|
# 2. Setup Accounts (Akun 1 & Akun 2)
|
||||||
|
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
|
||||||
|
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
|
||||||
|
|
||||||
|
# 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
|
||||||
|
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
|
||||||
|
|
||||||
|
# 4. Simulate Transaction & Payment
|
||||||
|
log("Step 3: Place Order & Skip Payment")
|
||||||
|
# TODO: Panggil API Backend
|
||||||
|
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']}")
|
||||||
|
|
||||||
|
log("=== Simulasi Selesai ===")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
log("Bot Juaskill Started!")
|
||||||
|
|
||||||
|
# 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()
|
||||||
|
|
||||||
|
# Uncomment untuk menjalankan scheduler
|
||||||
|
# schedule.every().day.at("09:00").do(run_daily_simulation)
|
||||||
|
# while True:
|
||||||
|
# schedule.run_pending()
|
||||||
|
# time.sleep(60)
|
||||||
5
requirements.txt
Normal file
5
requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
requests
|
||||||
|
openai
|
||||||
|
schedule
|
||||||
|
python-dotenv
|
||||||
|
faker
|
||||||
Reference in New Issue
Block a user