Update .gitignore and remove ignored files
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,8 +0,0 @@
|
||||
2025-05-25 09:22:06 Exception ResponAI: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'nomor_whatsapp' at row 1
|
||||
2025-05-25 09:22:16 Exception ResponAI: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'nomor_whatsapp' at row 1
|
||||
2025-05-25 09:22:26 Exception ResponAI: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'nomor_whatsapp' at row 1
|
||||
2025-05-25 09:22:36 Exception ResponAI: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'nomor_whatsapp' at row 1
|
||||
2025-05-30 22:04:51 Exception ResponAI: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'nomor_whatsapp' at row 1
|
||||
2025-05-30 22:05:01 Exception ResponAI: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'nomor_whatsapp' at row 1
|
||||
2025-05-30 22:05:11 Exception ResponAI: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'nomor_whatsapp' at row 1
|
||||
2025-05-30 22:05:21 Exception ResponAI: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'nomor_whatsapp' at row 1
|
||||
@@ -1,111 +0,0 @@
|
||||
<?php
|
||||
|
||||
include __DIR__ . "/../../config/whatsapp_api.php";
|
||||
include __DIR__ . "/respon_ai.php";
|
||||
|
||||
// Setup error reporting untuk debugging
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
// Simpan log raw input untuk debug paling awal
|
||||
// file_put_contents(__DIR__ . "/debug_raw_input.log", date('Y-m-d H:i:s') . " Input:\n" . print_r(file_get_contents('php://input'), true) . "\n", FILE_APPEND);
|
||||
|
||||
try {
|
||||
// Ambil dan decode input JSON
|
||||
$data = file_get_contents('php://input');
|
||||
$json_data = json_decode($data, true);
|
||||
|
||||
if (!isset($json_data['results']['apiKey'])) {
|
||||
http_response_code(400);
|
||||
echo "apiKey tidak ditemukan.";
|
||||
exit;
|
||||
}
|
||||
|
||||
$apiKey = $json_data['results']['apiKey'];
|
||||
|
||||
// file_put_contents(__DIR__ . "/debug_apikey.log", date('Y-m-d H:i:s') . " apiKey: $apiKey\n", FILE_APPEND);
|
||||
|
||||
if (
|
||||
isset($json_data['type']) && $json_data['type'] === 'message' &&
|
||||
isset($json_data['results']['fromMe']) && $json_data['results']['fromMe'] === false &&
|
||||
isset($json_data['results']['isGroupMsg']) && $json_data['results']['isGroupMsg'] === false
|
||||
) {
|
||||
$sender = $json_data['results']['sender'] ?? 'Tidak diketahui';
|
||||
$sender = str_replace("@s.whatsapp.net", "", $sender);
|
||||
$body = $json_data['results']['body'] ?? '';
|
||||
|
||||
// file_put_contents(__DIR__ . "/debug_sender_body.log", date('Y-m-d H:i:s') . " Sender: $sender, Body: $body\n", FILE_APPEND);
|
||||
|
||||
$filtered = [
|
||||
'sender' => $sender,
|
||||
'body' => $body,
|
||||
'apiKey' => $apiKey
|
||||
];
|
||||
|
||||
$log_file = __DIR__ . "/" . $apiKey . ".log";
|
||||
$log_entry = "[" . date('Y-m-d H:i:s') . "] Masuk: " . print_r($filtered, true);
|
||||
|
||||
// Pastikan kelas ResponAI ada
|
||||
if (!class_exists('ResponAI')) {
|
||||
file_put_contents(__DIR__ . "/error.log", date('Y-m-d H:i:s') . " Class ResponAI tidak ditemukan!\n", FILE_APPEND);
|
||||
http_response_code(500);
|
||||
exit("Server error: ResponAI class missing");
|
||||
}
|
||||
|
||||
$ResAI = new ResponAI();
|
||||
|
||||
// Tangkap exception saat proses respon_chat
|
||||
try {
|
||||
$Respon = $ResAI->respon_chat($body, $sender, $apiKey);
|
||||
} catch (Exception $e) {
|
||||
file_put_contents(__DIR__ . "/error.log", date('Y-m-d H:i:s') . " Exception ResponAI: " . $e->getMessage() . "\n", FILE_APPEND);
|
||||
http_response_code(500);
|
||||
exit("Server error: gagal proses AI");
|
||||
}
|
||||
|
||||
// file_put_contents(__DIR__ . "/step2_respon_ai.log", date('Y-m-d H:i:s') . " " . print_r($Respon, true), FILE_APPEND);
|
||||
|
||||
if (!empty($Respon['id']) && !empty($Respon['nomor'])) {
|
||||
if (!class_exists('PesanWA')) {
|
||||
file_put_contents(__DIR__ . "/error.log", date('Y-m-d H:i:s') . " Class PesanWA tidak ditemukan!\n", FILE_APPEND);
|
||||
http_response_code(500);
|
||||
exit("Server error: PesanWA class missing");
|
||||
}
|
||||
|
||||
$API_WA = new PesanWA();
|
||||
|
||||
try {
|
||||
$send_result = $API_WA->Send_Pesan($Respon['id'], 'sendMessage', array($Respon['nomor']), $Respon['respon']);
|
||||
} catch (Exception $e) {
|
||||
file_put_contents(__DIR__ . "/error.log", date('Y-m-d H:i:s') . " Exception Send_Pesan: " . $e->getMessage() . "\n", FILE_APPEND);
|
||||
http_response_code(500);
|
||||
exit("Server error: gagal kirim pesan");
|
||||
}
|
||||
|
||||
// file_put_contents(__DIR__ . "/step3_send_pesan.log", date('Y-m-d H:i:s') . " Kirim pesan ke: {$Respon['nomor']}\nResponse Send_Pesan: " . print_r($send_result, true), FILE_APPEND);
|
||||
|
||||
$log_entry .= "[" . date('Y-m-d H:i:s') . "] Balasan AI: " . print_r($Respon, true) . PHP_EOL;
|
||||
// file_put_contents($log_file, $log_entry, FILE_APPEND);
|
||||
|
||||
http_response_code(200);
|
||||
exit;
|
||||
|
||||
} else {
|
||||
// file_put_contents(__DIR__ . "/error_send_pesan.log", date('Y-m-d H:i:s') . " Gagal kirim pesan, id atau nomor kosong: " . print_r($Respon, true) . "\n", FILE_APPEND);
|
||||
http_response_code(500);
|
||||
echo "Gagal mengirim pesan: data tidak lengkap.";
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
http_response_code(400);
|
||||
echo "Data tidak valid atau bukan pesan yang diinginkan.";
|
||||
exit;
|
||||
}
|
||||
} catch (Throwable $t) {
|
||||
// Tangkap semua error fatal / throwable
|
||||
file_put_contents(__DIR__ . "/error.log", date('Y-m-d H:i:s') . " Fatal error: " . $t->getMessage() . "\n", FILE_APPEND);
|
||||
http_response_code(500);
|
||||
echo "Server error: " . $t->getMessage();
|
||||
exit;
|
||||
}
|
||||
@@ -1,276 +0,0 @@
|
||||
<?php
|
||||
|
||||
class ResponAI {
|
||||
|
||||
private function connectDB() {
|
||||
include __DIR__ . "/../../config/connect.php"; // Harus mengisi $pdo
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
private function deteksi_topik($message) {
|
||||
$rules = [
|
||||
'gangguan' => ['lambat', 'tidak konek', 'jaringan', 'trouble', 'gangguan', 'internet mati'],
|
||||
'tagihan' => ['tagihan', 'bayar', 'invoice', 'pembayaran', 'rekening'],
|
||||
'pemasangan' => ['pasang', 'berlangganan', 'pemasangan', 'registrasi', 'daftar', 'masang'],
|
||||
'umum' => []
|
||||
];
|
||||
|
||||
$message = strtolower($message);
|
||||
foreach ($rules as $topik => $keywords) {
|
||||
foreach ($keywords as $keyword) {
|
||||
if (strpos($message, $keyword) !== false) {
|
||||
return $topik;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 'umum';
|
||||
}
|
||||
|
||||
private function get_data_pelanggan($sender) {
|
||||
$pdo = $this->connectDB();
|
||||
$stmt = $pdo->prepare("SELECT nama, nama_paket, status, akun, status_koneksi FROM v_pelanggan WHERE nomor_whatsapp = ?");
|
||||
$stmt->execute([$sender]);
|
||||
$pelanggan = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($pelanggan) {
|
||||
return "Pelanggan atas nama {$pelanggan['nama']} (ID: {$pelanggan['akun']}) menggunakan paket {$pelanggan['nama_paket']} dan status koneksi {$pelanggan['status_koneksi']}. Status langganan: {$pelanggan['status']}.";
|
||||
}
|
||||
return "Data pelanggan tidak ditemukan.";
|
||||
}
|
||||
|
||||
private function get_id_server($apikey_wa) {
|
||||
$pdo = $this->connectDB();
|
||||
$stmt = $pdo->prepare("SELECT id FROM data_server WHERE apikey_whatsapp = ?");
|
||||
$stmt->execute([$apikey_wa]);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
return $row['id'] ?? null;
|
||||
}
|
||||
|
||||
private function get_paket_berlangganan($id) {
|
||||
$pdo = $this->connectDB();
|
||||
$stmt = $pdo->prepare("SELECT nama, harga_paket FROM profile_paket WHERE id_data_server = ?");
|
||||
$stmt->execute([$id]);
|
||||
$pakets = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$pakets) return "Paket berlangganan belum tersedia.";
|
||||
$list = "Berikut adalah daftar paket layanan:\n";
|
||||
foreach ($pakets as $p) {
|
||||
$list .= "- {$p['nama']}: Rp " . number_format($p['harga_paket'], 0, ',', '.') . "\n";
|
||||
}
|
||||
return trim($list);
|
||||
}
|
||||
|
||||
private function haversine($lat1, $lon1, $lat2, $lon2) {
|
||||
$earthRadius = 6371;
|
||||
$dLat = deg2rad($lat2 - $lat1);
|
||||
$dLon = deg2rad($lon2 - $lon1);
|
||||
|
||||
$a = sin($dLat / 2) ** 2 + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($dLon / 2) ** 2;
|
||||
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
|
||||
return $earthRadius * $c;
|
||||
}
|
||||
|
||||
private function get_info_pemasangan($id, $lat = null, $lon = null) {
|
||||
$pdo = $this->connectDB();
|
||||
|
||||
$stmt1 = $pdo->prepare("SELECT harga_sewa FROM data_server WHERE id = ?");
|
||||
$stmt1->execute([$id]);
|
||||
$row = $stmt1->fetch(PDO::FETCH_ASSOC);
|
||||
$biaya = isset($row['harga_sewa']) ? "Biaya pemasangan sebesar Rp " . number_format($row['harga_sewa'], 0, ',', '.') . "." : "";
|
||||
|
||||
$stmt2 = $pdo->prepare("SELECT nama FROM master_desa WHERE id_data_server = ?");
|
||||
$stmt2->execute([$id]);
|
||||
$desas = $stmt2->fetchAll(PDO::FETCH_ASSOC);
|
||||
$wilayah = $desas ? implode(", ", array_column($desas, 'nama')) : "Wilayah layanan belum terdaftar.";
|
||||
|
||||
$stmt3 = $pdo->prepare("SELECT titik_koordinat FROM master_topologi WHERE id_data_server = ?");
|
||||
$stmt3->execute([$id]);
|
||||
$koordinats = $stmt3->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($lat !== null && $lon !== null && $koordinats) {
|
||||
foreach ($koordinats as $k) {
|
||||
$raw = $k['titik_koordinat'];
|
||||
|
||||
// Cek apakah tidak kosong dan mengandung koma
|
||||
if (!empty($raw) && strpos($raw, ',') !== false) {
|
||||
$parts = explode(',', $raw);
|
||||
|
||||
// Pastikan hasil explode memiliki dua elemen
|
||||
if (count($parts) === 2) {
|
||||
$latParsed = trim($parts[0]);
|
||||
$lonParsed = trim($parts[1]);
|
||||
|
||||
// Validasi bahwa lat dan lon adalah angka
|
||||
if (is_numeric($latParsed) && is_numeric($lonParsed)) {
|
||||
$distance = $this->haversine($lat, $lon, (float)$latParsed, (float)$lonParsed);
|
||||
if ($distance <= 0.3) {
|
||||
$formulir = "Anda berada dalam jangkauan layanan kami.\n\nSilakan lengkapi data berikut untuk registrasi:\n"
|
||||
. "- Nama lengkap\n"
|
||||
. "- NIK\n"
|
||||
. "- Alamat Lengkap\n"
|
||||
. "- Titik Koordinat\n"
|
||||
. "- Nomor WhatsApp\n"
|
||||
. "- Paket Layanan";
|
||||
return "$biaya\n$formulir";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "Mohon maaf, titik koordinat Anda belum terjangkau jaringan kami.";
|
||||
}
|
||||
|
||||
return "$biaya Wilayah layanan mencakup: $wilayah.\n\nSilakan kirimkan titik koordinat lokasi Anda agar kami bisa melakukan pengecekan jangkauan.";
|
||||
}
|
||||
|
||||
private function get_data_tagihan($sender) {
|
||||
$pdo = $this->connectDB();
|
||||
$stmt = $pdo->prepare("SELECT nama, total_tagihan, limit_pembayaran, tanggal_bayar, status FROM v_tagihan WHERE nomor_whatsapp = ? ORDER BY tanggal_bayar DESC");
|
||||
$stmt->execute([$sender]);
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$rows) return "Tidak ada tagihan yang ditemukan.";
|
||||
$list = "Riwayat tagihan:\n";
|
||||
foreach ($rows as $row) {
|
||||
$list .= "- Tagihan: Rp " . number_format($row['total_tagihan'], 0, ',', '.') . " | Jatuh Tempo: {$row['limit_pembayaran']} | Status: {$row['status']}\n";
|
||||
}
|
||||
return trim($list);
|
||||
}
|
||||
|
||||
private function simpan_sesi($sender, $topik) {
|
||||
$pdo = $this->connectDB();
|
||||
$stmt = $pdo->prepare("INSERT INTO chat_session (nomor_whatsapp, topik_terakhir) VALUES (?, ?) ON DUPLICATE KEY UPDATE topik_terakhir = VALUES(topik_terakhir)");
|
||||
$stmt->execute([$sender, $topik]);
|
||||
}
|
||||
|
||||
private function ambil_sesi($sender) {
|
||||
$pdo = $this->connectDB();
|
||||
$stmt = $pdo->prepare("SELECT topik_terakhir FROM chat_session WHERE nomor_whatsapp = ?");
|
||||
$stmt->execute([$sender]);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
return $row['topik_terakhir'] ?? null;
|
||||
}
|
||||
|
||||
private function simpan_log($sender, $role, $pesan, $id) {
|
||||
$pdo = $this->connectDB();
|
||||
$stmt = $pdo->prepare("INSERT INTO chat_log (nomor_whatsapp, role, pesan, id_data_server) VALUES (?, ?, ?, ?)");
|
||||
$stmt->execute([$sender, $role, $pesan, $id]);
|
||||
}
|
||||
|
||||
public function respon_chat($message, $sender, $apikey_wa) {
|
||||
$OPENAI_API_KEY = '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'; // Ganti dengan API key valid
|
||||
$id = $this->get_id_server($apikey_wa);
|
||||
|
||||
if (empty($message) || empty($sender) || !$id) {
|
||||
return [
|
||||
'id' => $id,
|
||||
'nomor' => $sender,
|
||||
'respon' => 'Input tidak valid atau data server tidak ditemukan.'
|
||||
];
|
||||
}
|
||||
|
||||
$topik = $this->deteksi_topik($message);
|
||||
$topik_sesi = $this->ambil_sesi($sender);
|
||||
if (!$topik && $topik_sesi) {
|
||||
$topik = $topik_sesi;
|
||||
}
|
||||
|
||||
if ($topik) {
|
||||
$this->simpan_sesi($sender, $topik);
|
||||
}
|
||||
|
||||
$this->simpan_log($sender, 'user', $message, $id);
|
||||
|
||||
$pdo = $this->connectDB();
|
||||
$stmt = $pdo->prepare("SELECT role, pesan FROM chat_log WHERE id_data_server = ? AND nomor_whatsapp = ? ORDER BY id DESC LIMIT 10");
|
||||
$stmt->execute([$id, $sender]);
|
||||
$riwayat = array_reverse($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
|
||||
$messages = [];
|
||||
foreach ($riwayat as $log) {
|
||||
$messages[] = ['role' => $log['role'], 'content' => $log['pesan']];
|
||||
}
|
||||
$messages[] = ['role' => 'user', 'content' => $message];
|
||||
|
||||
$data_pelanggan = $this->get_data_pelanggan($sender);
|
||||
$info_paket = $this->get_paket_berlangganan($id);
|
||||
$info_pasang = $this->get_info_pemasangan($id);
|
||||
$data_tagihan = $this->get_data_tagihan($sender);
|
||||
|
||||
$roles = [
|
||||
'gangguan' => 'Kamu adalah customer service penyedia layanan internet untuk masalah teknis.',
|
||||
'tagihan' => 'Kamu adalah customer service penyedia layanan internet untuk urusan tagihan.',
|
||||
'pemasangan' => 'Kamu adalah customer service penyedia layanan internet untuk pemasangan baru.',
|
||||
'umum' => 'Kamu adalah customer service penyedia layanan internet untuk pertanyaan umum.'
|
||||
];
|
||||
|
||||
$topik_final = $topik ?: 'umum';
|
||||
|
||||
switch ($topik_final) {
|
||||
case 'tagihan':
|
||||
$tambahan = $data_tagihan;
|
||||
break;
|
||||
case 'pemasangan':
|
||||
$tambahan = $info_paket . "\n" . $info_pasang;
|
||||
break;
|
||||
default:
|
||||
$tambahan = '';
|
||||
break;
|
||||
}
|
||||
|
||||
$system_message = $roles[$topik_final] . " Data pelanggan: $data_pelanggan\n$tambahan\nJawaban maksimal 3 kalimat, singkat, sopan, dan informatif.";
|
||||
array_unshift($messages, ['role' => 'system', 'content' => $system_message]);
|
||||
|
||||
$payload = [
|
||||
'model' => 'gpt-3.5-turbo',
|
||||
'messages' => $messages,
|
||||
'temperature' => 0.7,
|
||||
'max_tokens' => 100
|
||||
];
|
||||
|
||||
$ch = curl_init('https://api.openai.com/v1/chat/completions');
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
'Content-Type: application/json',
|
||||
'Authorization: Bearer ' . $OPENAI_API_KEY,
|
||||
]);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
|
||||
|
||||
$response = curl_exec($ch);
|
||||
|
||||
if (curl_errno($ch)) {
|
||||
$error = curl_error($ch);
|
||||
curl_close($ch);
|
||||
return [
|
||||
'id' => $id,
|
||||
'nomor' => $sender,
|
||||
'respon' => 'Terjadi kesalahan koneksi ke OpenAI: ' . $error
|
||||
];
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
$data = json_decode($response, true);
|
||||
|
||||
$reply = $data['choices'][0]['message']['content'] ?? 'Maaf, tidak dapat memberikan jawaban saat ini.';
|
||||
$this->simpan_log($sender, 'assistant', $reply, $id);
|
||||
|
||||
$hasil = [
|
||||
'id' => $id,
|
||||
'nomor' => $sender,
|
||||
'respon' => trim($reply)
|
||||
];
|
||||
|
||||
// Debug log
|
||||
// file_put_contents("debug_respon_chat.log",
|
||||
// "====\n[" . date("Y-m-d H:i:s") . "]\n".
|
||||
// "Payload:\n" . print_r($payload, true) .
|
||||
// "Response:\n" . print_r($data, true) .
|
||||
// "Final:\n" . print_r($hasil, true),
|
||||
// FILE_APPEND
|
||||
// );
|
||||
|
||||
return $hasil;
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,39 +0,0 @@
|
||||
<?php
|
||||
// Menangkap data JSON dari webhook
|
||||
$data = file_get_contents('php://input');
|
||||
|
||||
// Decode JSON untuk membaca isinya
|
||||
$json_data = json_decode($data, true);
|
||||
|
||||
// Validasi payload JSON
|
||||
if (isset($json_data['results']['apiKey'])) {
|
||||
$apiKey = $json_data['results']['apiKey'];
|
||||
|
||||
// Periksa jika bukan pesan grup
|
||||
if (isset($json_data['results']['isGroupMsg']) && $json_data['results']['isGroupMsg'] === false) {
|
||||
// Nama file log berdasarkan apiKey
|
||||
$log_file = $apiKey . ".log";
|
||||
|
||||
// Menambahkan data baru dengan waktu (opsional)
|
||||
$log_entry = "[" . date('Y-m-d H:i:s') . "] " . $data . PHP_EOL;
|
||||
|
||||
// Simpan ke file log sesuai apiKey
|
||||
if (file_put_contents($log_file, $log_entry, FILE_APPEND) !== false) {
|
||||
// Tanggapan ke pengirim webhook
|
||||
http_response_code(200);
|
||||
echo "Data webhook diterima dan disimpan di $log_file";
|
||||
} else {
|
||||
// Gagal menyimpan file log
|
||||
http_response_code(500);
|
||||
echo "Gagal menyimpan data ke file log.";
|
||||
}
|
||||
} else {
|
||||
// Pesan grup tidak diproses
|
||||
http_response_code(400);
|
||||
echo "Pesan grup tidak diproses.";
|
||||
}
|
||||
} else {
|
||||
// Jika `apiKey` tidak ditemukan
|
||||
http_response_code(400);
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user