getMessage() . "\n"); } echo "Starting Siro AI Engine v2 (Powered by Pricing Engine)...\n"; // ========================================== // 1. التسعير الديناميكي بناءً على المعادلات الإحصائية // ========================================== echo "1. Reading competitor formulas from Pricing Engine...\n"; try { // قراءة آخر المعادلات من التحليل الإحصائي $sql = "SELECT * FROM competitor_secret_formulas WHERE last_updated >= DATE_SUB(NOW(), INTERVAL 24 HOUR) ORDER BY last_updated DESC"; $stmt = $con->query($sql); $formulas = $stmt->fetchAll(PDO::FETCH_ASSOC); if (empty($formulas)) { echo " ⚠️ No recent formulas found. Run pricing-engine first.\n"; } else { // تجميع المعادلات حسب الدولة $byCountry = []; foreach ($formulas as $f) { $country = $f['country_code']; if (!isset($byCountry[$country])) $byCountry[$country] = []; $byCountry[$country][] = $f; } foreach ($byCountry as $country => $countryFormulas) { $countryNameMap = ['JO' => 'Jordan', 'SY' => 'Syria', 'EG' => 'Egypt', 'IQ' => 'Iraq']; $countryName = $countryNameMap[$country] ?? $country; // اختيار أفضل معادلة للتسعير حسب الأولوية: // 1. Economy tier (الأكثر تنافسية) // 2. Standard tier (إذا ما في Economy) // 3. أي tier ثاني بأعلى R² $tierPriority = ['standard', 'economy', 'premium']; $bestFormula = null; $bestTierIdx = 999; foreach ($countryFormulas as $f) { $tier = $f['tier'] ?? 'standard'; $tierIdx = array_search($tier, $tierPriority); if ($tierIdx === false) $tierIdx = 999; $currentRSq = (float)($f['r_squared'] ?? 0); $currentKm = (float)($f['price_per_km'] ?? 0); // أفضلية: Tier أعلى أولوية، ثم R² أعلى if ($currentKm > 0 && ( $bestFormula === null || $tierIdx < $bestTierIdx || ($tierIdx === $bestTierIdx && $currentRSq > (float)($bestFormula['r_squared'] ?? 0)) )) { $bestTierIdx = $tierIdx; $bestFormula = $f; } } if ($bestFormula) { $bestKmRate = (float)$bestFormula['price_per_km']; $bestMinRate = (float)$bestFormula['price_per_min']; $bestBaseFare = (float)$bestFormula['base_fare']; $bestMinFare = (float)$bestFormula['min_fare']; $bestRSq = (float)($bestFormula['r_squared'] ?? 0); } if ($bestKmRate === null) { echo " ⚠️ No valid formula for $countryName. Skipping.\n"; continue; } // تسعير Siro: أرخص بنسبة 6.5% من المنافس مع الحفاظ على هيكل التسعير $discountFactor = 1 - 0.065; $ourKmRate = round($bestKmRate * $discountFactor, 3); $ourMinRate = round($bestMinRate * $discountFactor, 3); $ourBase = round($bestBaseFare * $discountFactor, 3); echo " 📊 $countryName: Using formula (R²=$bestRSq)\n"; echo " Competitor: KM=$bestKmRate, MIN=$bestMinRate, Base=$bestBaseFare, MinFare=$bestMinFare\n"; echo " Siro (6.5% less): KM=$ourKmRate, MIN=$ourMinRate, Base=$ourBase\n"; // تحديث جدول kazan $speedPrice = $ourKmRate; $comfortPrice = round($ourKmRate * 1.30, 3); $ladyPrice = round($ourKmRate * 1.10, 3); $electricPrice = round($ourKmRate * 1.20, 3); $vanPrice = round($ourKmRate * 1.50, 3); $deliveryPrice = round($ourKmRate * 0.90, 3); $mishwarVipPrice = round($ourKmRate * 1.40, 3); $fixedPrice = $speedPrice; $awfarPrice = round($ourKmRate * 0.85, 3); // أسعار الدقائق if ($country === 'JO') { $normalMin = $ourMinRate > 0 ? $ourMinRate : 0.05; $peakMin = round($normalMin * 1.15, 3); $lateMin = $normalMin; } else { $normalMin = $ourMinRate > 0 ? $ourMinRate : round($speedPrice / 4, 3); $peakMin = round($normalMin * 1.15, 3); $lateMin = round($normalMin * 1.25, 3); } $updateSql = "UPDATE kazan SET speedPrice = :speedPrice, comfortPrice = :comfortPrice, ladyPrice = :ladyPrice, electricPrice = :electricPrice, vanPrice = :vanPrice, deliveryPrice = :deliveryPrice, mishwarVipPrice = :mishwarVipPrice, fixedPrice = :fixedPrice, awfarPrice = :awfarPrice, normalMinPrice = :normalMin, peakMinPrice = :peakMin, lateMinPrice = :lateMin, startPrice = :startPrice WHERE country = :countryName"; $upStmt = $con->prepare($updateSql); $upStmt->execute([ ':speedPrice' => $speedPrice, ':comfortPrice' => $comfortPrice, ':ladyPrice' => $ladyPrice, ':electricPrice' => $electricPrice, ':vanPrice' => $vanPrice, ':deliveryPrice' => $deliveryPrice, ':mishwarVipPrice' => $mishwarVipPrice, ':fixedPrice' => $fixedPrice, ':awfarPrice' => $awfarPrice, ':normalMin' => $normalMin, ':peakMin' => $peakMin, ':lateMin' => $lateMin, ':startPrice' => $ourBase, ':countryName' => $countryName ]); echo " ✅ Updated $countryName pricing in kazan table.\n"; } } } catch (Exception $e) { echo " ❌ Error in Pricing Module: " . $e->getMessage() . "\n"; } // ========================================== // 2. قراءة Surge Insights من الـ Pricing Engine // ========================================== echo "2. Reading surge insights from Pricing Engine...\n"; try { $sql = "SELECT * FROM competitor_surge_insights WHERE detected_at >= DATE_SUB(NOW(), INTERVAL 12 HOUR) ORDER BY surge_multiplier DESC LIMIT 20"; $stmt = $con->query($sql); $surgeRecords = $stmt->fetchAll(PDO::FETCH_ASSOC); if (!empty($surgeRecords)) { $surgeByCountry = []; foreach ($surgeRecords as $sr) { $country = $sr['country_code']; if (!isset($surgeByCountry[$country])) { $surgeByCountry[$country] = [ 'avg_multiplier' => 0, 'count' => 0, 'peak_hours' => [] ]; } $surgeByCountry[$country]['avg_multiplier'] += $sr['surge_multiplier']; $surgeByCountry[$country]['count']++; $surgeByCountry[$country]['peak_hours'][] = "{$sr['peak_start_hour']}:00-{$sr['peak_end_hour']}:00"; } foreach ($surgeByCountry as $country => $data) { $avgMult = round($data['avg_multiplier'] / $data['count'], 3); $peakHoursStr = implode(', ', array_unique($data['peak_hours'])); // تخزين معلومات الـ Surge في Redis — مفتاحين: // 1. surge:opportunities (متوافق مع get.php الحالي) // 2. surge:opportunities:{country} (متوافق مع cron_kazan_adjuster.php) $surgeData = [ 'avg_competitor_surge' => $avgMult, 'suggested_multiplier' => round(1.0 + ($avgMult - 1.0) * 0.6, 3), 'peak_hours' => $data['peak_hours'], 'updated_at' => date('Y-m-d H:i:s') ]; $redis->setex("surge:opportunities", 7200, json_encode($surgeData)); $redis->setex("surge:opportunities:{$country}", 7200, json_encode($surgeData)); echo " ⚡ $country: Avg competitor surge = {$avgMult}x, peak hours: {$peakHoursStr}\n"; } } else { echo " ℹ️ No recent surge insights found.\n"; } } catch (Exception $e) { echo " ❌ Error in Surge Module: " . $e->getMessage() . "\n"; } // ========================================== // 3. وحدة استهداف الركاب الخاملين (Smart Retention) - كما هي // ========================================== echo "3. Running Smart Retention Module...\n"; try { $sql = "SELECT source, COUNT(*) as opens FROM passenger_opening_locations WHERE created_at >= DATE_SUB(NOW(), INTERVAL 3 HOUR) GROUP BY source HAVING opens >= 3"; $stmt = $con->query($sql); $idleRiders = $stmt->fetchAll(PDO::FETCH_ASSOC); $notifiedCount = count($idleRiders); echo " 📱 Identified $notifiedCount idle riders requiring push notifications.\n"; } catch (Exception $e) { echo " ❌ Error in Smart Retention: " . $e->getMessage() . "\n"; } // ========================================== // 4. Export AI Hotzones to Redis for Captains // ========================================== echo "4. Exporting AI Hotzones to Redis...\n"; try { $sql = "SELECT latitude, longitude, competitor_name AS top_competitor, avg_ppk AS avg_price FROM competitor_surge_zones WHERE detected_at >= DATE_SUB(NOW(), INTERVAL 6 HOUR) AND surge_multiplier > 1.1"; $stmt = $con->query($sql); $zones = $stmt->fetchAll(PDO::FETCH_ASSOC); if (!empty($zones)) { $redisData = [ 'status' => 'success', 'data' => $zones ]; $redis->setex('siro:cache:ai:hotzones', 3600, json_encode($redisData)); echo " 🗺️ Exported " . count($zones) . " hot zones to Redis (siro:cache:ai:hotzones).\n"; } else { // Clear if no surge to avoid stale data $redis->del('siro:cache:ai:hotzones'); echo " ℹ️ No active hot zones to export.\n"; } } catch (Exception $e) { echo " ❌ Error in Hotzones Export: " . $e->getMessage() . "\n"; } echo "AI Engine v2 finished successfully.\n";