Deploy: 2026-05-24 01:22:55

This commit is contained in:
Hamza-Ayed
2026-05-24 01:22:56 +03:00
parent 42725f0529
commit 42afad393c
4 changed files with 16803 additions and 286 deletions

View File

@@ -639,10 +639,8 @@ class WhatsAppController extends BaseController
$mimeType = trim(explode(';', $mimeType)[0]);
}
// Instruct Gemini to identify payment slips and output a specific command format if found
$imageSystemPrompt = $systemPrompt . "\n\nإرشادات إضافية للصور والوصولات:\nإذا كانت الصورة المرفقة عبارة عن وصل دفع أو إيصال تحويل مالي (مثل زين كاش أو إيداع بنكي)، يرجى استخراج البيانات التالية بدقة بالغة وكتابتها في بداية ردك بصيغة JSON محاطة بـ [PAYMENT_RECEIPT: { ... }] كالتالي:\n[PAYMENT_RECEIPT: {\"transaction_id\": \"رقم المعاملة أو الحوالة هنا\", \"amount\": \"المبلغ المستخرج كأرقام فقط\", \"method\": \"طريقة الدفع مثل Zain Cash أو Bank\"}]\nثم أكمل ردك الطبيعي بالترحيب بالسائق/العميل وإخباره بأنه جاري التحقق من عملية الدفع الآن.";
$replyText = \App\Services\GeminiService::generateResponseFromImage($apiKey, $imageSystemPrompt, $msgData['image'], $mimeType);
// Prevent blind image processing outside of interactive flows to save OCR/Vision costs.
$replyText = "عذراً كابتن، يرجى إرسال الصور والمستندات فقط عندما يطلب منك النظام ذلك (مثلاً أثناء التسجيل عن طريق طباعة 'تسجيل' أو فحص الإيصالات بطباعة 'دفع').";
} else {
$replyText = \App\Services\GeminiService::generateResponse($apiKey, $systemPrompt, $incomingText);
}
@@ -657,7 +655,7 @@ class WhatsAppController extends BaseController
$replyText = trim(str_replace($matches[0], '', $replyText));
// Call the payment verification API (passing company_id)
$verificationResult = $this->verifyPaymentSlip($session['company_id'], $msgData['phone'], $jsonStr);
$verificationResult = self::verifyPaymentSlipStatic($session['company_id'], $msgData['phone'], $jsonStr);
if ($verificationResult) {
$replyText .= "\n\n" . $verificationResult;
}
@@ -745,7 +743,7 @@ class WhatsAppController extends BaseController
/**
* Call external API to verify payment slip
*/
private function verifyPaymentSlip(int $companyId, string $phone, string $jsonStr): ?string
public static function verifyPaymentSlipStatic(int $companyId, string $phone, string $jsonStr): ?string
{
try {
$data = json_decode($jsonStr, true);

View File

@@ -17,6 +17,7 @@ class ConversationFlowEngine
private static array $flows = [
'test_flow' => TestFlow::class,
'driver_registration_flow' => DriverRegistrationFlow::class,
'payment_flow' => PaymentFlow::class,
];
/**
@@ -28,6 +29,10 @@ class ConversationFlowEngine
'سجل' => 'driver_registration_flow',
'تسجيل' => 'driver_registration_flow',
'register' => 'driver_registration_flow',
'دفع' => 'payment_flow',
'وصل' => 'payment_flow',
'تسديد' => 'payment_flow',
'رصيد' => 'payment_flow',
];
/**

View File

@@ -0,0 +1,76 @@
<?php
namespace App\Core\Flows;
use App\Services\GeminiService;
use App\Models\ChatbotRule;
/**
* PaymentFlow
* Handles payment receipt uploads and verification.
*/
class PaymentFlow extends BaseFlow
{
public function handleStep(string $step, array $messageData, array &$context): FlowResult
{
$companyId = $context['company_id'] ?? 1;
$phone = $messageData['phone'] ?? '';
switch ($step) {
case 'start':
return new FlowResult(
"أهلاً بك كابتن. يرجى إرسال صورة **إيصال التحويل المالي أو وصل الدفع** لكي نقوم بمراجعته وإضافته لحسابك:",
"awaiting_receipt"
);
case 'awaiting_receipt':
if (empty($messageData['image']) || empty($messageData['imageMimeType'])) {
return new FlowResult("الرجاء إرسال صورة وصل الدفع بوضوح للاستمرار، أو اكتب 'إلغاء' للخروج:", "awaiting_receipt");
}
if ($companyId !== 1) {
if (!\App\Models\CompanySubscriptionUsage::hasRemainingLimit($companyId, 'ocr')) {
return new FlowResult("⚠️ عذراً، تجاوز المتجر الحد المسموح لمعالجة الصور لهذا الشهر.", "finished", true);
}
}
$rule = ChatbotRule::findActiveForRule($companyId);
$configuredGeminiKey = ($rule && !empty($rule['gemini_api_key'])) ? $rule['gemini_api_key'] : null;
$apiKey = GeminiService::getGeminiApiKey($configuredGeminiKey);
if (empty($apiKey)) {
return new FlowResult("عذراً، عطل فني في خادم معالجة الصور بالذكاء الاصطناعي. يرجى المحاولة لاحقاً.", "finished", true);
}
$imageSystemPrompt = "أنت خبير في مراجعة إيصالات الدفع. استخرج البيانات التالية بدقة بالغة واكتبها بصيغة JSON محاطة بـ [PAYMENT_RECEIPT: { ... }] كالتالي:\n[PAYMENT_RECEIPT: {\"transaction_id\": \"رقم المعاملة أو الحوالة هنا\", \"amount\": \"المبلغ المستخرج كأرقام فقط\", \"method\": \"طريقة الدفع مثل Syriatel Cash أو Bemo Bank\"}]\nفي حال عدم وضوح الإيصال، أرجع JSON فارغًا.";
$mimeType = $messageData['imageMimeType'];
if (strpos($mimeType, ';') !== false) {
$mimeType = trim(explode(';', $mimeType)[0]);
}
$replyText = GeminiService::generateResponseFromImage($apiKey, $imageSystemPrompt, $messageData['image'], $mimeType);
if ($companyId !== 1) {
\App\Models\CompanySubscriptionUsage::incrementUsage($companyId, 'ocr');
\App\Models\CompanySubscriptionUsage::incrementUsage($companyId, 'request');
}
if (!empty($replyText) && preg_match('/\[PAYMENT_RECEIPT:\s*(\{.*?\})\]/s', $replyText, $matches)) {
$jsonStr = $matches[1];
$verificationResult = \App\Controllers\WhatsAppController::verifyPaymentSlipStatic($companyId, $phone, $jsonStr);
if ($verificationResult) {
return new FlowResult("تم فحص الإيصال:\n" . $verificationResult, "finished", true);
} else {
return new FlowResult("لم نتمكن من التأكد من بيانات الإيصال. يرجى إرسال صورة أوضح أو التواصل مع الدعم الفني.", "finished", true);
}
}
return new FlowResult("لم أتمكن من التعرف على بيانات الإيصال المرفق. يرجى التأكد من وضوح الصورة وإعادة المحاولة.", "awaiting_receipt");
default:
return new FlowResult("حدث خطأ في المسار.", "finished", true);
}
}
}