diff --git a/backend/bot/cron_auto_marketing_pusher.php b/backend/bot/cron_auto_marketing_pusher.php new file mode 100644 index 00000000..cbab5b3b --- /dev/null +++ b/backend/bot/cron_auto_marketing_pusher.php @@ -0,0 +1,124 @@ +getMessage() . "\n"); +} + +echo "Starting Auto Marketing Pusher Engine...\n"; + +// 1. استخراج الركاب الخاملين في آخر ساعتين (الذين لم يقموا بأي طلب اليوم) +// نبحث في جدول locations أو tokens للركاب الذين لديهم نشاط قريب دون رحلات +$sqlIdle = " + SELECT p.id as passenger_id, t.token, p.country_code + FROM passengers p + JOIN tokens t ON p.id = t.passengerID + WHERE p.id NOT IN ( + SELECT passenger_id FROM rides WHERE DATE(created_at) = CURDATE() + ) + LIMIT 1000 +"; +// ملاحظة: في بيئة الإنتاج، استخدم جدول فتح التطبيق (App Opens) للحصول على دقة أعلى للركاب الذين فتحوا التطبيق مؤخراً. + +$stmtIdle = $con->query($sqlIdle); +$idlePassengers = $stmtIdle->fetchAll(PDO::FETCH_ASSOC); + +if (empty($idlePassengers)) { + echo "No idle passengers found at this moment.\n"; + exit; +} + +// تجميع الركاب حسب الدولة لتقليل استدعاءات Gemini +$passengersByCountry = []; +foreach ($idlePassengers as $p) { + $country = strtoupper($p['country_code'] ?? 'SY'); + $passengersByCountry[$country][] = $p; +} + +$geminiService = new SiroGeminiService(); +$encryptionHelper = new EncryptionHelper(); + +$totalPushes = 0; + +foreach ($passengersByCountry as $countryCode => $passengers) { + echo "Processing country: $countryCode (" . count($passengers) . " idle passengers)\n"; + + // 2. سحب أحدث أسعار المنافسين كمرجع لجيميناي + $sqlPrices = "SELECT competitor_name, base_fare, price_per_km, price_per_min + FROM competitor_secret_formulas + WHERE country_code = :country + ORDER BY last_updated DESC LIMIT 3"; + $stmtPrices = $con->prepare($sqlPrices); + $stmtPrices->execute([':country' => $countryCode]); + $competitorFormulas = $stmtPrices->fetchAll(PDO::FETCH_ASSOC); + + if (empty($competitorFormulas)) { + // Fallback + $competitorFormulas = [['competitor_name' => 'Market Average', 'base_fare' => 1]]; + } + + // 3. طلب رسالة تسويقية من Gemini + $siroBasePrice = 1.0; // يمكن استخراج السعر الافتراضي لسيرو من جدول kazan + $regionName = ($countryCode === 'JO') ? 'Amman' : 'Damascus'; + + $aiCampaign = $geminiService->analyzeMarketAndDraftCampaign( + $competitorFormulas, + $siroBasePrice, + $regionName, + $countryCode + ); + + if (!$aiCampaign || $aiCampaign['opportunity_detected'] !== true) { + echo " -> Gemini found no compelling marketing opportunity for $countryCode right now. Skipping push.\n"; + continue; + } + + $title = $aiCampaign['push_title'] ?? 'خصم حصري من سيرو!'; + $body = $aiCampaign['push_body'] ?? 'سيارتك جاهزة وبأرخص سعر في السوق. اطلب الآن.'; + $promoCode = $aiCampaign['promo_code'] ?? ''; + + echo " -> Gemini generated campaign: [$title] $body\n"; + + // 4. إرسال الـ Push Notification لكل راكب + foreach ($passengers as $p) { + $encryptedToken = $p['token']; + $decryptedToken = $encryptionHelper->decryptData($encryptedToken); + + if ($decryptedToken) { + $dataPayload = [ + 'type' => 'marketing_promo', + 'promo_code' => $promoCode + ]; + + // استدعاء دالة الإرسال (يفترض وجودها في نظام FCM الخاص بك، مثل sendFCM) + // sendFCM($decryptedToken, $title, $body, $dataPayload); + // سنطبع للـ Log فقط في هذا السكربت لتجنب إرسال رسائل حقيقية دون تفعيل FCM الفعلي + + error_log("Sending Push to passenger {$p['passenger_id']}: $title"); + $totalPushes++; + } + } +} + +echo "Done. Sent $totalPushes automated marketing pushes via Gemini AI.\n"; +?> diff --git a/backend/bot/cron_gemini_advisor.php b/backend/bot/cron_gemini_advisor.php new file mode 100644 index 00000000..672ec062 --- /dev/null +++ b/backend/bot/cron_gemini_advisor.php @@ -0,0 +1,57 @@ +getMessage() . "\n"); +} + +echo "Starting Gemini Market Advisor Engine...\n"; + +// 1. إنشاء جدول الإحصائيات الذكية إذا لم يكن موجوداً +$sqlInit = " +CREATE TABLE IF NOT EXISTS `gemini_market_insights` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `insight_html` TEXT NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +"; +$con->exec($sqlInit); + +// 2. سحب آخر المعادلات المكتشفة +$stmt = $con->query("SELECT * FROM competitor_secret_formulas"); +$formulas = $stmt->fetchAll(PDO::FETCH_ASSOC); + +if (empty($formulas)) { + echo "No formulas found to analyze. Run ai_formula_solver.php first.\n"; + exit; +} + +// 3. تمرير البيانات إلى Gemini +$geminiService = new SiroGeminiService(); +echo "Sending data to Gemini AI for strategic analysis...\n"; + +$result = $geminiService->analyzeCompetitorFormulas($formulas); + +if ($result && $result['status'] === 'success') { + $htmlReport = $result['html_report']; + + // 4. حفظ التقرير في قاعدة البيانات + $stmtInsert = $con->prepare("INSERT INTO gemini_market_insights (insight_html) VALUES (:html)"); + $stmtInsert->execute([':html' => $htmlReport]); + + echo "Gemini analysis saved successfully! Admin can now view the strategic report.\n"; +} else { + echo "Failed to get analysis from Gemini. Check API keys and logs.\n"; +} +?> diff --git a/backend/core/Services/SiroGeminiService.php b/backend/core/Services/SiroGeminiService.php index afff87f1..3f2fdd76 100644 --- a/backend/core/Services/SiroGeminiService.php +++ b/backend/core/Services/SiroGeminiService.php @@ -66,9 +66,9 @@ class SiroGeminiService { \"recommended_price\": 12000, \"discount_percentage\": 15, \"promo_code\": \"SIROGO15\", - \"push_title\": \"عنوان الإشعار\", - \"push_body\": \"محتوى الإشعار القصير والمثير للاهتمام\", - \"sms_body\": \"محتوى رسالة الاستعادة القصير والمقنع للـ SMS أو الواتساب\" + \"push_title\": \"عنوان الإشعار (بحد أقصى 5 كلمات)\", + \"push_body\": \"محتوى الإشعار القصير والمثير للاهتمام (بحد أقصى 15 كلمة)\", + \"sms_body\": \"محتوى رسالة الاستعادة (بحد أقصى 20 كلمة)\" } "; @@ -124,6 +124,74 @@ class SiroGeminiService { return $this->callGemini($prompt, $model); } + /** + * تقرأ معادلات المنافسين المكتشفة أسبوعياً وتقدم استراتيجية تسويق (Weekly Advisor). + * + * @param array $formulas المصفوفة المستخرجة من competitor_secret_formulas + * @param string $model + * @return array|null + */ + public function analyzeCompetitorFormulas( + array $formulas, + string $model = 'gemini-1.5-flash' + ): ?array { + if (!$this->apiKey) return null; + + $formulasJson = json_encode($formulas, JSON_UNESCAPED_UNICODE); + + $prompt = " + أنت المستشار التسويقي المالي لتطبيق 'سيرو' لنقل الركاب. + لقد قمنا بعمل هندسة عكسية لرحلات منافسينا واكتشفنا معادلات التسعير السرية الخاصة بهم لهذا الأسبوع. + + البيانات المكتشفة: + $formulasJson + + المطلوب منك (كمستشار أعمال خبير): + 1. تحليل هذه الأرقام، وتوضيح أين تكمن نقاط قوة المنافسين وأين نقاط ضعفهم في التسعير (مثلاً من يركز على المسافات القصيرة برفع فتح العداد؟). + 2. اقتراح 3 استراتيجيات تسويقية أو رسائل إعلانية (Push Notifications/Social Media) موجهة للركاب، تستغل نقاط ضعف المنافسين المكتشفة. + + قم بصياغة تقريرك بتنسيق HTML مرتب وجاهز للعرض في لوحة الإدارة (بدون علامات ```html)، واستخدم ألوان خفيفة في العناوين