first commit

This commit is contained in:
Hamza-Ayed
2026-06-09 08:40:31 +03:00
commit d8901e1a87
3161 changed files with 536187 additions and 0 deletions

View File

@@ -0,0 +1,286 @@
<?php
// --- معالجة الشكوى من جهة الخادم (Backend) ---
// 1. تضمين ملف الاتصال والدوال المساعدة
// ! تأكد من أن هذا المسار صحيح بالنسبة لهيكل مشروعك
require_once __DIR__ . '/../../connect.php';
// --- إعدادات النظام ---
$geminiApiKey = getenv("GEMINI_API_KEY");
$customerServiceWhatsapp = getenv("SERVICE_PHONE1"); // يُفترض أن هذا مُعرّف في connect.php أو متغيرات البيئة
// التحقق من وجود مفتاح Gemini API
if (!$geminiApiKey) {
error_log("CRITICAL: Gemini API Key is not configured on the server."); // ⚠️ تسجيل الخطأ
jsonError("Gemini API Key is not configured on the server.");
exit;
}
// --- 2. استقبال البيانات والتحقق منها ---
$rideId = filterRequest("ride_id");
$complaintText = filterRequest("complaint_text");
$audioLink = filterRequest("audio_link");
if (empty($rideId)) {
error_log("WARNING: Complaint request failed. Ride ID is missing."); // ⚠️ تسجيل الخطأ
jsonError("Ride ID is required.");
exit;
}
// --- 3. جلب البيانات المفصلة من قاعدة البيانات ---
global $con, $encryptionHelper; // تم افتراض أن هذه المتغيرات global ومتاحة في هذا النطاق
// جلب تفاصيل الرحلة الأساسية والتحقق من حالتها
$stmt = $con->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']
]);
?>