prepare("SELECT * FROM ride WHERE id = ? AND (status = 'Finished' OR status = 'Begin')"); $stmt->execute([$rideId]); $ride = $stmt->fetch(PDO::FETCH_ASSOC); if (!$ride) { // رسالة خطأ أوضح للمستخدم error_log("WARNING: Complaint filing failed for ride ID: $rideId. Ride not found or status is invalid."); // ⚠️ تسجيل الخطأ jsonError("Complaint cannot be filed for this ride. It may not have been completed or started."); exit; } $passengerId = $ride['passenger_id']; $driverId = $ride['driver_id']; // --- دوال مساعدة لجلب البيانات (تم افتراض أن الدوال تصل إلى $con و $encryptionHelper عبر النطاق global أو تمريرها كـ arguments) --- /** * جلب بيانات ومعلومات تقييم السائق */ function getDriverFullProfile($con, $encryptionHelper, $driverId) { $profile = ['info' => null, 'ratings' => null, 'comments' => []]; // جلب معلومات السائق الأساسية $stmt = $con->prepare("SELECT id, first_name, last_name, created_at FROM driver WHERE id = ?"); $stmt->execute([$driverId]); $driverInfo = $stmt->fetch(PDO::FETCH_ASSOC); // فك تشفير البيانات الحساسة if ($driverInfo) { // التحقق من وجود ودوال فك التشفير قبل الاستخدام if (isset($encryptionHelper) && method_exists($encryptionHelper, 'decryptData')) { $decryptedFirstName = $encryptionHelper->decryptData($driverInfo['first_name']); $decryptedLastName = $encryptionHelper->decryptData($driverInfo['last_name']); $driverInfo['full_name'] = trim($decryptedFirstName . ' ' . $decryptedLastName); } else { $driverInfo['full_name'] = 'Decryption Failed'; } unset($driverInfo['first_name'], $driverInfo['last_name']); // إزالة الحقول المشفرة $profile['info'] = $driverInfo; } // جلب ملخص التقييمات والتعليقات $stmt = $con->prepare("SELECT AVG(rating) as avg_rating, COUNT(id) as total_ratings FROM ratingDriver WHERE driver_id = ?"); $stmt->execute([$driverId]); $profile['ratings'] = $stmt->fetch(PDO::FETCH_ASSOC); $stmt = $con->prepare("SELECT comment FROM ratingDriver WHERE driver_id = ? AND comment IS NOT NULL AND comment != '' ORDER BY created_at DESC LIMIT 5"); $stmt->execute([$driverId]); $profile['comments'] = $stmt->fetchAll(PDO::FETCH_COLUMN); return $profile; } /** * جلب بيانات ومعلومات تقييم الراكب */ function getPassengerFullProfile($con, $encryptionHelper, $passengerId) { $profile = ['info' => null, 'ratings' => null, 'comments' => []]; $stmt = $con->prepare("SELECT id, first_name, last_name, created_at FROM passengers WHERE id = ?"); $stmt->execute([$passengerId]); $passengerInfo = $stmt->fetch(PDO::FETCH_ASSOC); // فك تشفير البيانات الحساسة if ($passengerInfo) { if (isset($encryptionHelper) && method_exists($encryptionHelper, 'decryptData')) { $decryptedFirstName = $encryptionHelper->decryptData($passengerInfo['first_name']); $decryptedLastName = $encryptionHelper->decryptData($passengerInfo['last_name']); $passengerInfo['full_name'] = trim($decryptedFirstName . ' ' . $decryptedLastName); } else { $passengerInfo['full_name'] = 'Decryption Failed'; } unset($passengerInfo['first_name'], $passengerInfo['last_name']); $profile['info'] = $passengerInfo; } $stmt = $con->prepare("SELECT AVG(rating) as avg_rating, COUNT(id) as total_ratings FROM ratingPassenger WHERE passenger_id = ?"); $stmt->execute([$passengerId]); $profile['ratings'] = $stmt->fetch(PDO::FETCH_ASSOC); $stmt = $con->prepare("SELECT comment FROM ratingPassenger WHERE passenger_id = ? AND comment IS NOT NULL AND comment != '' ORDER BY created_at DESC LIMIT 5"); $stmt->execute([$passengerId]); $profile['comments'] = $stmt->fetchAll(PDO::FETCH_COLUMN); return $profile; } /** * جلب بيانات سلوك السائق في الرحلة المحددة */ function getDriverBehavior($con, $rideId, $driverId) { $stmt = $con->prepare("SELECT max_speed, avg_speed, hard_brakes, behavior_score FROM driver_behavior WHERE trip_id = ? AND driver_id = ?"); $stmt->execute([$rideId, $driverId]); return $stmt->fetch(PDO::FETCH_ASSOC) ?: null; } // استدعاء الدوال لجلب البيانات $passengerProfile = getPassengerFullProfile($con, $encryptionHelper, $passengerId); $driverProfile = getDriverFullProfile($con, $encryptionHelper, $driverId); $driverBehavior = getDriverBehavior($con, $rideId, $driverId); // --- 4. بناء الـ Prompt وإرساله إلى Gemini --- $prompt = " أنت خبير في حل النزاعات في خدمات نقل الركاب لتطبيق intaleqapp.com. قم بتحليل الشكوى التالية بين راكب وسائق بناءً على البيانات الشاملة التالية: **1. تفاصيل الرحلة:** " . json_encode($ride, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . " **2. ملف الراكب:** " . json_encode($passengerProfile, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . " **3. ملف السائق:** " . json_encode($driverProfile, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . " **4. بيانات سلوك السائق (في هذه الرحلة):** " . json_encode($driverBehavior, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . " **5. الشكوى نفسها:** - نص الشكوى من الراكب: '" . $complaintText . "' - رابط تسجيل صوتي للشكوى (إن وجد): " . $audioLink . " **مهمتك هي:** 1. تحليل جميع البيانات المتاحة لتحديد الطرف المخطئ على الأرجح. 2. تحديد ما إذا كانت الشكوى كيدية أم حقيقية. 3. **تصنيف الشكوى** (مثال: سلوك السائق، مشكلة في الأجرة، مسار الرحلة، حالة السيارة، أخرى). 4. اقتراح حلين واضحين ومختلفين لفريق خدمة العملاء. 5. كتابة تقرير موجز ومناسب للراكب. 6. كتابة تقرير موجز ومناسب للسائق. **الخرج المطلوب:** أعد الرد بصيغة JSON فقط، بدون أي نصوص إضافية، وباللغة العربية (لهجة مصرية)، بالهيكل التالي: { \"customerServiceSolutions\": [\"الحل المقترح الأول\", \"الحل المقترح الثاني\"], \"passengerReport\": { \"title\": \"بخصوص شكوتك في رحلة Intaleq\", \"body\": \"رسالة واضحة للراكب بنتيجة الشكوى\" }, \"driverReport\": { \"title\": \"بخصوص بلاغ رحلتك الأخيرة في Intaleq\", \"body\": \"رسالة واضحة للسائق بنتيجة الشكوى\" }, \"fault_determination\": \"الطرف المخطئ (الراكب/السائق/كلاهما/غير واضح)\", \"complaint_nature\": \"طبيعة الشكوى (حقيقية/كيدية/نزاع بسيط)\", \"complaint_type\": \"تصنيف الشكوى الذي حددته\" } "; // استخدام نموذج Gemini 1.5 Flash Lite $apiURL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-flash-lite-latest:generateContent?key=$geminiApiKey"; $headers = ["Content-Type: application/json"]; $payload = ['contents' => [['parts' => [['text' => $prompt]]]]]; error_log("INFO: Submitting complaint analysis to Gemini for ride ID: $rideId."); // ℹ️ تسجيل الحدث $ch = curl_init($apiURL); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => $headers, CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_TIMEOUT => 60 ]); $response = curl_exec($ch); if (curl_errno($ch)) { $errorMsg = curl_error($ch); error_log("ERROR: AI Service Curl Error for ride $rideId: $errorMsg"); // ⚠️ تسجيل الخطأ jsonError("AI Service Error: " . $errorMsg); curl_close($ch); exit; } curl_close($ch); $data = json_decode($response, true); $analysisResultText = $data['candidates'][0]['content']['parts'][0]['text'] ?? ''; $analysisResultJson = trim(preg_replace('/```json|```/', '', $analysisResultText)); $analysisResult = json_decode($analysisResultJson, true); if (json_last_error() !== JSON_ERROR_NONE || !isset($analysisResult['passengerReport']) || !isset($analysisResult['driverReport'])) { error_log("ERROR: Failed to parse AI response for ride $rideId. Raw Response: " . substr($response, 0, 500)); // ⚠️ تسجيل الخطأ jsonError("Failed to parse AI response. Please try again later."); exit; } error_log("INFO: Gemini analysis successful for ride $rideId. Type: " . ($analysisResult['complaint_type'] ?? 'N/A')); // ℹ️ تسجيل الحدث // --- 5. تنفيذ الإجراءات بناءً على التحليل --- // تجميع الوصف الكامل للشكوى $fullDescription = $complaintText; if (!empty($audioLink)) { $fullDescription .= "\n\n[رابط صوتي مرفق: " . $audioLink . "]"; } // ** التعديل: تم تحديث جملة الحفظ لتشمل جميع مخرجات التحليل ** $stmt = $con->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 (?, ?, ?, ?, ?, NOW(), ?, ?, ?, ?, ?, ?, ?, NOW()) "); try { $success = $stmt->execute([ $rideId, $passengerId, $driverId, $analysisResult['complaint_type'] ?? 'General', $fullDescription, 'Resolved', // statusComplaint $analysisResultJson, // resolution (الـ JSON الكامل) json_encode($analysisResult['passengerReport'] ?? null, JSON_UNESCAPED_UNICODE), // passenger_report json_encode($analysisResult['driverReport'] ?? null, JSON_UNESCAPED_UNICODE), // driver_report json_encode($analysisResult['customerServiceSolutions'] ?? null, JSON_UNESCAPED_UNICODE), // cs_solutions $analysisResult['fault_determination'] ?? 'N/A', // fault_determination $analysisResult['complaint_nature'] ?? 'N/A' // complaint_nature ]); if (!$success) { // يمكنك تسجيل رسالة الخطأ من PDO إذا كانت متاحة (للتصحيح فقط وليس للإنتاج) error_log("CRITICAL: Failed to save complaint to DB for ride $rideId. PDO Error Info: " . json_encode($stmt->errorInfo())); // ⚠️ تسجيل الخطأ } $complaintId = $con->lastInsertId(); error_log("SUCCESS: Complaint ID $complaintId processed and saved for ride $rideId."); // ✅ تسجيل النجاح } catch (PDOException $e) { error_log("CRITICAL: PDO Exception when saving complaint for ride $rideId: " . $e->getMessage()); // ⚠️ تسجيل خطأ قاعدة البيانات jsonError("A database error occurred while saving the complaint."); exit; } // إرسال رسالة WhatsApp لخدمة العملاء if (function_exists('sendWhatsAppFromServer') && !empty($customerServiceWhatsapp)) { $csMessage = "*شكوى جديدة (رقم $complaintId)*\n" . "*- الرحلة:* $rideId\n" . "*- تصنيف الشكوى:* " . ($analysisResult['complaint_type'] ?? 'غير محدد') . "\n" . "*- المخطئ (تقدير النظام):* " . $analysisResult['fault_determination'] . "\n" . "*- طبيعة الشكوى:* " . $analysisResult['complaint_nature'] . "\n\n" . "*حلول مقترحة:*\n1. " . ($analysisResult['customerServiceSolutions'][0] ?? 'N/A') . "\n" . "2. " . ($analysisResult['customerServiceSolutions'][1] ?? 'N/A'); sendWhatsAppFromServer($customerServiceWhatsapp, $csMessage); error_log("INFO: WhatsApp notification sent to customer service for complaint ID $complaintId."); // ℹ️ تسجيل الحدث } // --- 6. إرسال الرد النهائي للتطبيق --- printSuccess([ 'message' => 'Complaint processed successfully.', 'passenger_response' => $analysisResult['passengerReport'], 'driver_response' => $analysisResult['driverReport'] ]); ?>