From 2ea36c98cde0655c35f9e4f730afb67121701dd2 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Fri, 22 May 2026 00:54:36 +0300 Subject: [PATCH] Deploy: 2026-05-22 00:54:36 --- backend/app/Controllers/ChatbotController.php | 61 ++++++ .../app/Controllers/WhatsAppController.php | 3 + backend/app/Services/GeminiService.php | 48 +++++ backend/public/index.html | 176 +++++++++++++++++- backend/public/index.php | 1 + 5 files changed, 287 insertions(+), 2 deletions(-) diff --git a/backend/app/Controllers/ChatbotController.php b/backend/app/Controllers/ChatbotController.php index 6ad08e9..c796df5 100644 --- a/backend/app/Controllers/ChatbotController.php +++ b/backend/app/Controllers/ChatbotController.php @@ -72,4 +72,65 @@ class ChatbotController extends BaseController 'id' => $id ]); } + + /** + * Generate prompt from voice recording using Gemini audio input + */ + public function generatePromptFromAudio(Request $request, Response $response) + { + // 1. Get the uploaded audio file + $files = $_FILES; + if (empty($files['audio']) || $files['audio']['error'] !== UPLOAD_ERR_OK) { + $response->status(400)->json(['status' => 'error', 'message' => 'Missing or invalid audio file upload']); + return; + } + + $audioFile = $files['audio']; + + // 2. Validate file size (max 10MB) + if ($audioFile['size'] > 10 * 1024 * 1024) { + $response->status(400)->json(['status' => 'error', 'message' => 'Audio file size exceeds limit (10MB)']); + return; + } + + // 3. Read the audio content and base64 encode + $audioContent = file_get_contents($audioFile['tmp_name']); + if ($audioContent === false) { + $response->status(500)->json(['status' => 'error', 'message' => 'Failed to read uploaded audio file']); + return; + } + $audioBase64 = base64_encode($audioContent); + $mimeType = $audioFile['type'] ?: 'audio/webm'; // fallback + // Normalize mime type (e.g. "audio/webm;codecs=opus" -> "audio/webm") for Gemini API compatibility + if (strpos($mimeType, ';') !== false) { + $mimeType = trim(explode(';', $mimeType)[0]); + } + + // 4. Retrieve the Gemini API key (custom or system default) + $rules = ChatbotRule::findAllByCompany($request->company_id); + $apiKey = null; + if (!empty($rules) && !empty($rules[0]['gemini_api_key'])) { + $apiKey = $rules[0]['gemini_api_key']; + } + + $apiKey = $apiKey ?: getenv('GEMINI_API_KEY'); + + if (empty($apiKey)) { + $response->status(500)->json(['status' => 'error', 'message' => 'Gemini API Key is not configured in the system']); + return; + } + + // 5. Call Gemini Service + $generatedPrompt = \App\Services\GeminiService::generatePromptFromAudio($apiKey, $audioBase64, $mimeType); + + if (empty($generatedPrompt)) { + $response->status(500)->json(['status' => 'error', 'message' => 'Failed to generate prompt from audio. Please check Gemini logs.']); + return; + } + + $response->json([ + 'status' => 'success', + 'prompt' => trim($generatedPrompt) + ]); + } } diff --git a/backend/app/Controllers/WhatsAppController.php b/backend/app/Controllers/WhatsAppController.php index 2202d01..008bf8e 100644 --- a/backend/app/Controllers/WhatsAppController.php +++ b/backend/app/Controllers/WhatsAppController.php @@ -314,6 +314,9 @@ class WhatsAppController extends BaseController } $systemPrompt = $rule['ai_prompt'] ?: 'You are a helpful customer support assistant.'; + // Enforce language matching rule dynamically + $systemPrompt .= "\n\nIMPORTANT LANGUAGE RULE: Detect the language of the incoming message. If the incoming message is in English, you MUST reply in English. If the incoming message is in Arabic, you MUST reply in Arabic. Override any default language instruction to match the user's language."; + $replyText = \App\Services\GeminiService::generateResponse($apiKey, $systemPrompt, $incomingText); } diff --git a/backend/app/Services/GeminiService.php b/backend/app/Services/GeminiService.php index b6bbe1a..8d7086f 100644 --- a/backend/app/Services/GeminiService.php +++ b/backend/app/Services/GeminiService.php @@ -48,4 +48,52 @@ class GeminiService $data = json_decode($response, true); return $data['candidates'][0]['content']['parts'][0]['text'] ?? null; } + + /** + * Call Gemini API with audio inline data to generate a chatbot prompt + */ + public static function generatePromptFromAudio(string $apiKey, string $audioBase64, string $mimeType): ?string + { + $url = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-flash-lite-latest:generateContent?key=' . $apiKey; + + $payload = json_encode([ + 'contents' => [ + [ + 'role' => 'user', + 'parts' => [ + [ + 'inlineData' => [ + 'mimeType' => $mimeType, + 'data' => $audioBase64 + ] + ], + [ + 'text' => "أنت خبير محترف في هندسة التعليمات (Prompt Engineering). استمع جيداً للتسجيل الصوتي المرفق الذي يصف متجراً أو مشروعاً تجارياً ومتطلبات خدمة العملاء، واستخرج التفاصيل المهمة (اسم المتجر، الخدمات، اللهجة المطلوبة، ساعات العمل، سياسات الشحن والاستبدال، والأسئلة الشائعة). ثم قم بصياغة تعليمة نظام (System Instruction Prompt) مفصلة ومنظمة وعالية الجودة باللغة العربية لروبوت خدمة العملاء المعتمد على الذكاء الاصطناعي. يجب أن ترشد التعليمة الروبوت بكيفية التصرف والرد بنبرة مناسبة. أرجع فقط تعليمة النظام الناتجة مباشرة بدون أي نصوص تمهيدية أو تنسيقات markdown أو علامات اقتباس برمجية." + ] + ] + ] + ] + ]); + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Content-Type: application/json' + ]); + curl_setopt($ch, CURLOPT_TIMEOUT, 35); // 35 seconds timeout for audio analysis + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($httpCode !== 200) { + error_log("[Gemini Audio API Error] HTTP " . $httpCode . " | Response: " . $response); + return null; + } + + $data = json_decode($response, true); + return $data['candidates'][0]['content']['parts'][0]['text'] ?? null; + } } diff --git a/backend/public/index.html b/backend/public/index.html index e26e56f..27a30b4 100644 --- a/backend/public/index.html +++ b/backend/public/index.html @@ -618,6 +618,14 @@ } .font-semibold { font-weight: 600; } .text-muted { color: var(--text-secondary); } + @keyframes pulse-red { + 0% { transform: scale(0.85); opacity: 0.5; } + 50% { transform: scale(1.15); opacity: 1; } + 100% { transform: scale(0.85); opacity: 0.5; } + } + .recording-pulse { + animation: pulse-red 1.2s infinite; + } @@ -1005,8 +1013,41 @@
- - +
+ +
+ + + + + + +
+
+ + + +
+ + جاري صياغة التوجيهات من صوتك باستخدام الذكاء الاصطناعي... يرجى الانتظار +
+ + +
+ + 💡 نصائح وتوجيهات لكتابة تعليمات ممتازة: + +
    +
  • الهوية والاسم: حدد اسم الروبوت بوضوح (مثال: "أنا سارة من فريق تطبيق نبيه").
  • +
  • اللهجة والأسلوب: اطلب من الذكاء الاصطناعي الرد بلهجة معينة (مثال: اللهجة السورية أو الفصحى المبسطة).
  • +
  • البيانات الأساسية: اكتب ساعات عمل المتجر، طرق الدفع والتوصيل، وسياسة الاستبدال لكي يجيب الروبوت بدقة.
  • +
  • التعليمات اللغوية: قمنا بتضمين ميزة مطابقة اللغة تلقائياً (الرد بالإنجليزية على الرسائل الإنجليزية، وبالعربية على العربية).
  • +
+