'failure', 'message' => 'Method not allowed']); exit; } $apiKey = $_SERVER['HTTP_X_API_KEY'] ?? ''; $expectedKey = getenv('NABEH_API_KEY') ?: ''; if (empty($apiKey) || $apiKey !== $expectedKey) { http_response_code(401); echo json_encode(['status' => 'failure', 'message' => 'Unauthorized']); exit; } $input = json_decode(file_get_contents('php://input'), true); $phone = preg_replace('/\D+/', '', $input['phone'] ?? ''); $rideId = trim($input['ride_id'] ?? ''); $complaintText = trim($input['complaint_text'] ?? ''); $audioLink = trim($input['audio_link'] ?? ''); $userType = trim($input['user_type'] ?? ''); if (empty($phone) || empty($rideId) || empty($complaintText)) { http_response_code(400); echo json_encode(['status' => 'failure', 'message' => 'phone, ride_id, and complaint_text are required']); exit; } $mainDb = Database::get('main'); $rideDb = Database::get('ride'); global $encryptionHelper; // ── Resolve user by phone ──────────────────────────────────── $encryptedPhone = $encryptionHelper->encryptData($phone); $driverRow = $mainDb->prepare("SELECT id, first_name, last_name FROM driver WHERE phone = :p LIMIT 1"); $driverRow->execute([':p' => $encryptedPhone]); $driver = $driverRow->fetch(PDO::FETCH_ASSOC); $passengerRow = null; if (!$driver) { $passengerRow = $mainDb->prepare("SELECT id, first_name, last_name FROM passengers WHERE phone = :p LIMIT 1"); $passengerRow->execute([':p' => $encryptedPhone]); $passenger = $passengerRow->fetch(PDO::FETCH_ASSOC); } if (!$driver && !$passenger) { http_response_code(404); echo json_encode(['status' => 'failure', 'message' => 'User not found']); exit; } $userId = $driver ? $driver['id'] : $passenger['id']; $detectedType = $driver ? 'driver' : 'passenger'; if (empty($userType)) $userType = $detectedType; // ── Validate ride exists ───────────────────────────────────── $stmt = $rideDb->prepare("SELECT * FROM ride WHERE id = :id"); $stmt->execute([':id' => $rideId]); $ride = $stmt->fetch(PDO::FETCH_ASSOC); if (!$ride) { http_response_code(404); echo json_encode(['status' => 'failure', 'message' => 'Ride not found']); exit; } // ── Fetch full context ────────────────────────────────────── $passengerId = $ride['passenger_id']; $driverId = $ride['driver_id']; /** * Fetch user profile + full rating history (received + given) */ function getEnhancedProfile($db, $table, $id, $enc, $ratingReceivedTable, $ratingReceivedCol, $ratingGivenTable, $ratingGivenCol, $ratingsDb) { $profile = ['info' => null, 'ratings_received' => [], 'ratings_given' => [], 'stats' => []]; // Profile info $stmt = $db->prepare("SELECT id, first_name, last_name, created_at FROM $table WHERE id = :id LIMIT 1"); $stmt->execute([':id' => $id]); $info = $stmt->fetch(PDO::FETCH_ASSOC); if ($info) { $fn = $enc->decryptData($info['first_name']); $ln = $enc->decryptData($info['last_name']); $info['full_name'] = trim("$fn $ln"); $info['account_age_days'] = $info['created_at'] ? round((time() - strtotime($info['created_at'])) / 86400) : 0; unset($info['first_name'], $info['last_name']); $profile['info'] = $info; } // Ratings received (others rated this user) $stmt = $ratingsDb->prepare(" SELECT rating, comment, created_at FROM $ratingReceivedTable WHERE $ratingReceivedCol = :id ORDER BY created_at DESC LIMIT 10 "); $stmt->execute([':id' => $id]); $profile['ratings_received'] = $stmt->fetchAll(PDO::FETCH_ASSOC); // Ratings given (this user rated others) $stmt = $ratingsDb->prepare(" SELECT rating, comment, created_at FROM $ratingGivenTable WHERE $ratingGivenCol = :id ORDER BY created_at DESC LIMIT 10 "); $stmt->execute([':id' => $id]); $profile['ratings_given'] = $stmt->fetchAll(PDO::FETCH_ASSOC); // Aggregate stats for received ratings $stmt = $ratingsDb->prepare(" SELECT COUNT(id) AS total, AVG(rating) AS avg_rating, SUM(CASE WHEN rating <= 2 THEN 1 ELSE 0 END) AS low_count, SUM(CASE WHEN rating = 3 THEN 1 ELSE 0 END) AS mid_count, SUM(CASE WHEN rating >= 4 THEN 1 ELSE 0 END) AS high_count FROM $ratingReceivedTable WHERE $ratingReceivedCol = :id "); $stmt->execute([':id' => $id]); $profile['stats'] = $stmt->fetch(PDO::FETCH_ASSOC); return $profile; } // Driver profile: received ratings from ratingDriver (by driver_id), given ratings in ratingPassenger (by driverID) $driverProfile = getEnhancedProfile( $mainDb, 'driver', $driverId, $encryptionHelper, 'ratingDriver', 'driver_id', // received: passengers rate driver 'ratingPassenger', 'driverID', // given: driver rates passenger $mainDb ); // Passenger profile: received ratings from ratingPassenger (by passenger_id), given ratings in ratingDriver (by passenger_id) $passengerProfile = getEnhancedProfile( $mainDb, 'passengers', $passengerId, $encryptionHelper, 'ratingPassenger', 'passenger_id', // received: drivers rate passenger 'ratingDriver', 'passenger_id', // given: passenger rates driver $mainDb ); // Driver behavior data $behavior = null; $bStmt = $rideDb->prepare("SELECT max_speed, avg_speed, hard_brakes, behavior_score FROM driver_behavior WHERE trip_id = :trip AND driver_id = :did LIMIT 1"); $bStmt->execute([':trip' => $rideId, ':did' => $driverId]); $behavior = $bStmt->fetch(PDO::FETCH_ASSOC) ?: null; // ── Gemini AI Analysis ────────────────────────────────────── $geminiKey = getenv('GEMINI_API_KEY'); if (!$geminiKey) { http_response_code(500); echo json_encode(['status' => 'failure', 'message' => 'AI service not configured']); exit; } // Check existing complaints for the same ride $existingStmt = $mainDb->prepare("SELECT id, statusComplaint FROM complaint WHERE ride_id = :rid ORDER BY id DESC LIMIT 1"); $existingStmt->execute([':rid' => $rideId]); $existingComplaint = $existingStmt->fetch(PDO::FETCH_ASSOC); $prompt = " أنت خبير في حل النزاعات في خدمات نقل الركاب لتطبيق Siro. قم بتحليل الشكوى التالية بناءً على البيانات الشاملة: **1. تفاصيل الرحلة:** " . json_encode($ride, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . " **2. ملف الراكب (بيانات الحساب + سجل التقييمات):** " . json_encode($passengerProfile, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . " **3. ملف السائق (بيانات الحساب + سجل التقييمات + سلوك القيادة):** " . json_encode([ 'info' => $driverProfile['info'], 'ratings_received' => $driverProfile['ratings_received'], 'ratings_given' => $driverProfile['ratings_given'], 'stats' => $driverProfile['stats'], 'behavior' => $behavior, ], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . " **4. الشكوى:** - نص الشكوى: '" . $complaintText . "' - رابط تسجيل صوتي: " . ($audioLink ?: 'لا يوجد') . " - مقدم الشكوى: " . $userType . " " . ($existingComplaint ? "- شكوى سابقة موجودة للرحلة: ID={$existingComplaint['id']}, status={$existingComplaint['statusComplaint']}" : '') . " **تعليمات التحليل الذكي (التقييمات):** - حلل سجل تقييمات السائق: هل يتكرر حصوله على تقييمات منخفضة (1-2)؟ ماذا تقول تعليقات الركاب السابقين عنه؟ - حلل سجل تقييمات الراكب: هل يميل لإعطاء تقييمات منخفضة للسائقين؟ - ادرس توزيع التقييمات: average + low/mid/high counts يعطي صورة عن سلوك كل طرف - اربط التعليقات السابقة بمضمون الشكوى الحالية: هل هناك نمط متكرر؟ - استخدم عمر الحساب (account_age_days) لتقييم مصداقية المستخدم **المطلوب:** 1. تحديد الطرف المخطئ على الأرجح بناءً على: تفاصيل الرحلة + تاريخ التقييمات + سلوك القيادة. 2. تحديد ما إذا كانت الشكوى حقيقية أم كيدية. 3. تصنيف الشكوى (سلوك السائق، مشكلة أجرة، مسار، حالة السيارة، غير ذلك). 4. اقتراح حلين واضحين ومحددين لخدمة العملاء. 5. كتابة تقرير مناسب لمقدم الشكوى (دون إحراج). 6. كتابة تقرير مناسب للطرف الآخر (مهذب ومحترم). **الخرج المطلوب (JSON فقط، بالعربية):** { \"customerServiceSolutions\": [\"حل 1\", \"حل 2\"], \"passengerReport\": {\"title\": \"...\", \"body\": \"...\"}, \"driverReport\": {\"title\": \"...\", \"body\": \"...\"}, \"fault_determination\": \"الراكب/السائق/كلاهما/غير واضح\", \"complaint_nature\": \"حقيقية/كيدية/نزاع بسيط\", \"complaint_type\": \"تصنيف الشكوى\" } "; $apiURL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-flash-lite-latest:generateContent?key=$geminiKey"; $ch = curl_init($apiURL); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode(['contents' => [['parts' => [['text' => $prompt]]]]]), CURLOPT_TIMEOUT => 60, ]); $response = curl_exec($ch); $curlErr = curl_error($ch); curl_close($ch); if ($curlErr) { http_response_code(500); echo json_encode(['status' => 'failure', 'message' => 'AI service error: ' . $curlErr]); exit; } $data = json_decode($response, true); $rawText = $data['candidates'][0]['content']['parts'][0]['text'] ?? ''; $cleanJson = trim(preg_replace('/```json|```/', '', $rawText)); $analysis = json_decode($cleanJson, true); if (!$analysis || !isset($analysis['passengerReport']) || !isset($analysis['driverReport'])) { http_response_code(500); echo json_encode(['status' => 'failure', 'message' => 'Failed to parse AI response']); exit; } // ── Save to complaint table ────────────────────────────────── $fullDesc = $complaintText; if ($audioLink) $fullDesc .= "\n\n[audio: $audioLink]"; $stmt = $mainDb->prepare(" INSERT INTO complaint (ride_id, passenger_id, driver_id, complaint_type, description, date_filed, statusComplaint, resolution, passenger_report, driver_report, cs_solutions, fault_determination, complaint_nature, date_resolved) VALUES (:rid, :pid, :did, :ctype, :desc, NOW(), 'Resolved', :res, :preport, :dreport, :cssol, :fault, :nature, NOW()) "); $stmt->execute([ ':rid' => $rideId, ':pid' => $passengerId, ':did' => $driverId, ':ctype' => $analysis['complaint_type'] ?? 'General', ':desc' => $fullDesc, ':res' => $cleanJson, ':preport'=> json_encode($analysis['passengerReport'] ?? null, JSON_UNESCAPED_UNICODE), ':dreport'=> json_encode($analysis['driverReport'] ?? null, JSON_UNESCAPED_UNICODE), ':cssol' => json_encode($analysis['customerServiceSolutions'] ?? null, JSON_UNESCAPED_UNICODE), ':fault' => $analysis['fault_determination'] ?? 'N/A', ':nature' => $analysis['complaint_nature'] ?? 'N/A', ]); $complaintId = $mainDb->lastInsertId(); // ── Notify customer service ────────────────────────────────── $csPhone = getenv('SERVICE_PHONE1'); $sendFn = getenv('SEND_WHATSAPP_FN_PATH'); if (!empty($csPhone) && $sendFn && file_exists($sendFn)) { require_once $sendFn; if (function_exists('sendWhatsAppFromServer')) { $csMsg = "*شكوى جديدة (#$complaintId)*\n" . "*- الرحلة:* $rideId\n" . "*- مقدمها:* $userType\n" . "*- تصنيف:* {$analysis['complaint_type']}\n" . "*- المخطئ:* {$analysis['fault_determination']}\n" . "*- الحلول:* {$analysis['customerServiceSolutions'][0]} / {$analysis['customerServiceSolutions'][1]}"; sendWhatsAppFromServer($csPhone, $csMsg); } } // ── Response ───────────────────────────────────────────────── $report = $userType === 'driver' ? $analysis['driverReport'] : $analysis['passengerReport']; echo json_encode([ 'status' => 'success', 'message' => 'Complaint submitted and analyzed.', 'complaint_id'=> $complaintId, 'report' => $report, 'ai_result' => [ 'fault_determination' => $analysis['fault_determination'], 'complaint_nature' => $analysis['complaint_nature'], 'complaint_type' => $analysis['complaint_type'], ], ], JSON_UNESCAPED_UNICODE);