company_id); $response->json([ 'status' => 'success', 'data' => $rules ]); } /** * Store or update a chatbot rule */ public function store(Request $request, Response $response) { $errors = $this->validate($request, [ 'trigger_type' => 'required', 'is_active' => 'required' ]); if (!empty($errors)) { $response->status(400)->json(['status' => 'error', 'errors' => $errors]); return; } $body = $request->getBody(); // Find existing rule or create one $rules = ChatbotRule::findAllByCompany($request->company_id); $ruleId = null; if (!empty($rules)) { $ruleId = $rules[0]['id']; } $saveData = [ 'company_id' => $request->company_id, 'session_id' => !empty($body['session_id']) ? (int)$body['session_id'] : null, 'trigger_type' => $body['trigger_type'], 'keyword' => $body['keyword'] ?? null, 'ai_prompt' => $body['ai_prompt'] ?? null, 'is_active' => $body['is_active'] ? 1 : 0 ]; if ($ruleId) { $saveData['id'] = $ruleId; } // If gemini_api_key is provided, update it. If not, and we have an existing rule, retain it. // If it's a password placeholder like '••••••••' or similar, don't overwrite the existing one. if (isset($body['gemini_api_key']) && $body['gemini_api_key'] !== '••••••••' && $body['gemini_api_key'] !== '') { $saveData['gemini_api_key'] = $body['gemini_api_key']; } $id = ChatbotRule::saveSecure($saveData); $response->json([ 'status' => 'success', 'message' => 'Chatbot rule saved successfully', '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) ]); } }