Files
intaleq_v3_pure_php/ride/feedBack/add_solve_all.php
2026-04-28 13:04:27 +03:00

286 lines
14 KiB
PHP
Executable File
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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']
]);
?>