Deploy: 2026-05-24 01:22:55
This commit is contained in:
@@ -639,10 +639,8 @@ class WhatsAppController extends BaseController
|
|||||||
$mimeType = trim(explode(';', $mimeType)[0]);
|
$mimeType = trim(explode(';', $mimeType)[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instruct Gemini to identify payment slips and output a specific command format if found
|
// Prevent blind image processing outside of interactive flows to save OCR/Vision costs.
|
||||||
$imageSystemPrompt = $systemPrompt . "\n\nإرشادات إضافية للصور والوصولات:\nإذا كانت الصورة المرفقة عبارة عن وصل دفع أو إيصال تحويل مالي (مثل زين كاش أو إيداع بنكي)، يرجى استخراج البيانات التالية بدقة بالغة وكتابتها في بداية ردك بصيغة JSON محاطة بـ [PAYMENT_RECEIPT: { ... }] كالتالي:\n[PAYMENT_RECEIPT: {\"transaction_id\": \"رقم المعاملة أو الحوالة هنا\", \"amount\": \"المبلغ المستخرج كأرقام فقط\", \"method\": \"طريقة الدفع مثل Zain Cash أو Bank\"}]\nثم أكمل ردك الطبيعي بالترحيب بالسائق/العميل وإخباره بأنه جاري التحقق من عملية الدفع الآن.";
|
$replyText = "عذراً كابتن، يرجى إرسال الصور والمستندات فقط عندما يطلب منك النظام ذلك (مثلاً أثناء التسجيل عن طريق طباعة 'تسجيل' أو فحص الإيصالات بطباعة 'دفع').";
|
||||||
|
|
||||||
$replyText = \App\Services\GeminiService::generateResponseFromImage($apiKey, $imageSystemPrompt, $msgData['image'], $mimeType);
|
|
||||||
} else {
|
} else {
|
||||||
$replyText = \App\Services\GeminiService::generateResponse($apiKey, $systemPrompt, $incomingText);
|
$replyText = \App\Services\GeminiService::generateResponse($apiKey, $systemPrompt, $incomingText);
|
||||||
}
|
}
|
||||||
@@ -657,7 +655,7 @@ class WhatsAppController extends BaseController
|
|||||||
$replyText = trim(str_replace($matches[0], '', $replyText));
|
$replyText = trim(str_replace($matches[0], '', $replyText));
|
||||||
|
|
||||||
// Call the payment verification API (passing company_id)
|
// 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) {
|
if ($verificationResult) {
|
||||||
$replyText .= "\n\n" . $verificationResult;
|
$replyText .= "\n\n" . $verificationResult;
|
||||||
}
|
}
|
||||||
@@ -745,7 +743,7 @@ class WhatsAppController extends BaseController
|
|||||||
/**
|
/**
|
||||||
* Call external API to verify payment slip
|
* 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 {
|
try {
|
||||||
$data = json_decode($jsonStr, true);
|
$data = json_decode($jsonStr, true);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ class ConversationFlowEngine
|
|||||||
private static array $flows = [
|
private static array $flows = [
|
||||||
'test_flow' => TestFlow::class,
|
'test_flow' => TestFlow::class,
|
||||||
'driver_registration_flow' => DriverRegistrationFlow::class,
|
'driver_registration_flow' => DriverRegistrationFlow::class,
|
||||||
|
'payment_flow' => PaymentFlow::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,6 +29,10 @@ class ConversationFlowEngine
|
|||||||
'سجل' => 'driver_registration_flow',
|
'سجل' => 'driver_registration_flow',
|
||||||
'تسجيل' => 'driver_registration_flow',
|
'تسجيل' => 'driver_registration_flow',
|
||||||
'register' => 'driver_registration_flow',
|
'register' => 'driver_registration_flow',
|
||||||
|
'دفع' => 'payment_flow',
|
||||||
|
'وصل' => 'payment_flow',
|
||||||
|
'تسديد' => 'payment_flow',
|
||||||
|
'رصيد' => 'payment_flow',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
76
backend/app/Core/Flows/PaymentFlow.php
Normal file
76
backend/app/Core/Flows/PaymentFlow.php
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user