| @@ -168,12 +168,11 @@ | ||
| 168 | 168 | } |
| 169 | 169 | if ( $grok_enabled == '1' ) { |
| 170 | 170 | update_option( 'ai_enabled', 0 ); |
| 171 | 171 | update_option( 'qcld_ollama_enabled', 0 ); |
| 172 | - update_option('qcld_gemini_enabled', 0); | |
| 172 | + update_option('qcld_gemini_enabled', 0); | |
| 173 | 173 | update_option( 'qcld_openrouter_enabled', 0 ); |
| 174 | - } else { | |
| 175 | - update_option( 'ai_enabled', 1 ); | |
| 174 | + update_option('disable_wp_chatbot_site_search',1); | |
| 176 | 175 | } |
| 177 | 176 | if ( $qcld_grok_system_content != '' ) { |
| 178 | 177 | update_option( 'qcld_grok_system_content', $qcld_grok_system_content ); |
| 179 | 178 | } |
| @@ -205,11 +204,40 @@ | ||
| 205 | 204 | } |
| 206 | 205 | $grok_api_key = get_option( 'qcld_grok_api_key' ); |
| 207 | 206 | $keyword = isset($_POST['keyword']) ? sanitize_text_field( wp_unslash($_POST['keyword']) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing |
| 208 | 207 | $grok_system_content = get_option( 'qcld_grok_system_content' ); |
| 208 | + | |
| 209 | + // AI Interactive Form | |
| 210 | + if (get_option('enable_ai_interactive_form') == '1') { | |
| 211 | + $saved_ai_forms = get_option('wpbot_ai_forms', array()); | |
| 212 | + if (!empty($saved_ai_forms) && is_array($saved_ai_forms)) { | |
| 213 | + $grok_system_content .= "\n\nYou must handle the following interactive forms when the user asks for them:\n"; | |
| 214 | + foreach ($saved_ai_forms as $form) { | |
| 215 | + $grok_system_content .= "\nForm Title: " . $form['title'] . "\nInstructions: " . $form['prompt'] . "\n"; | |
| 216 | + } | |
| 217 | + $grok_system_content .= "\n\nCRITICAL INSTRUCTIONS FOR INTERACTIVE FORMS:\n"; | |
| 218 | + $grok_system_content .= "When a user triggers an interactive form, you must act as a step-by-step data collection agent.\n"; | |
| 219 | + $grok_system_content .= "1. DO NOT ask all questions at once. Ask exactly ONE question at a time.\n"; | |
| 220 | + $grok_system_content .= "2. Wait for the user's response before asking the next question.\n"; | |
| 221 | + $grok_system_content .= "3. Once all necessary information is collected for the form, you MUST output a final JSON block summarizing the collected data. The keys inside the \"data\" object MUST be dynamically named based on the specific questions you asked during the form collection (e.g., \"Full Name\", \"Company Size\", \"Email\", etc.). The final JSON block must be wrapped EXACTLY in these delimiters:\n"; | |
| 222 | + $grok_system_content .= "__AI_FORM_DATA__{ \"form_title\": \"<Form Title>\", \"data\": { \"Question 1\": \"Answer 1\", \"Question 2\": \"Answer 2\" } }__AI_FORM_DATA_END__\n"; | |
| 223 | + $grok_system_content .= "Do not include any other text after this JSON block once the form is complete.\n"; | |
| 224 | + $grok_system_content .= "4. If the user provides an invalid, irrelevant, or nonsensical answer to your question, DO NOT apologize or state that you lack information. Instead, politely inform the user in the language of the conversation (the language the user is speaking in, e.g. German if communicating in German) that their answer is invalid or cannot be assigned, and ask the exact same question again in the user's language. NEVER output the English phrase 'Invalid answer found' unless the user is communicating in English.\n"; | |
| 225 | + $grok_system_content .= "5. MULTI-LANGUAGE SUPPORT: Always communicate, ask questions, validate answers, and reply strictly in the user's language (matching the language used by the user, e.g. German, French, Spanish, etc.). Understand and accept valid answers in the user's language."; | |
| 226 | + } | |
| 227 | + } | |
| 228 | + | |
| 229 | + $action_prompt = !empty($_POST['action_prompt']) ? wp_unslash($_POST['action_prompt']) : ''; | |
| 230 | + if (!empty($action_prompt)) { | |
| 231 | + $grok_system_content .= "\n\nCRITICAL ACTIVE ACTION INSTRUCTION:\n" . $action_prompt; | |
| 232 | + } | |
| 233 | + | |
| 209 | 234 | $rag_context = ""; |
| 210 | 235 | if (get_option('qcld_grok_rag_enabled') == '1') { |
| 211 | 236 | $rag_context = Qcld_Bot_Rag()->run_rag_search($keyword); |
| 237 | + if (!empty($rag_context) && $rag_context != "No knowledge base found.") { | |
| 238 | + $grok_system_content .= "\n\nRelevant Knowledge Base Information:\n" . $rag_context; | |
| 239 | + } | |
| 212 | 240 | } |
| 213 | 241 | $relevant_pagelink = Qcld_WPBot_Common_Functions::qcpd_relevant_pagelink( $keyword ); |
| 214 | 242 | $relevant_pagelink = array_slice( $relevant_pagelink, 0, 5, true ); |
| 215 | 243 | if ( ( get_option( 'page_suggestion_enabled' ) == '1' ) && count( $relevant_pagelink ) > 0 ) { |
| @@ -228,8 +256,32 @@ | ||
| 228 | 256 | $response['status'] = 'success'; |
| 229 | 257 | $response['message'] = $result ; |
| 230 | 258 | wp_send_json( $response ); |
| 231 | 259 | } else { |
| 260 | + $messages = [ | |
| 261 | + ['role' => 'system', 'content' => $grok_system_content ?? 'You are a helpful and intelligent assistant for the website "' . site_url() . '". Use live website data and the provided context to respond accurately and briefly. Stay relevant and do not introduce additional topics.' ] | |
| 262 | + ]; | |
| 263 | + | |
| 264 | + if (!empty($_POST['ai_history'])) { | |
| 265 | + $parsed_history = json_decode(wp_unslash($_POST['ai_history']), true); | |
| 266 | + if (is_array($parsed_history)) { | |
| 267 | + foreach ($parsed_history as $h) { | |
| 268 | + if (isset($h['role']) && isset($h['content'])) { | |
| 269 | + $role = ($h['role'] === 'assistant') ? 'assistant' : 'user'; | |
| 270 | + $messages[] = [ | |
| 271 | + 'role' => $role, | |
| 272 | + 'content' => sanitize_text_field($h['content']) | |
| 273 | + ]; | |
| 274 | + } | |
| 275 | + } | |
| 276 | + } | |
| 277 | + } | |
| 278 | + | |
| 279 | + $last_msg = end($messages); | |
| 280 | + if (!$last_msg || $last_msg['role'] !== 'user' || $last_msg['content'] !== $keyword) { | |
| 281 | + $messages[] = ['role' => 'user', 'content' => $keyword]; | |
| 282 | + } | |
| 283 | + | |
| 232 | 284 | $response_mess = wp_remote_post('https://api.x.ai/v1/chat/completions', [ |
| 233 | 285 | 'headers' => [ |
| 234 | 286 | 'Authorization' => 'Bearer ' . $grok_api_key, |
| 235 | 287 | 'Content-Type' => 'application/json', |
| @@ -234,12 +286,9 @@ | ||
| 234 | 286 | 'Authorization' => 'Bearer ' . $grok_api_key, |
| 235 | 287 | 'Content-Type' => 'application/json', |
| 236 | 288 | ], |
| 237 | 289 | 'body' => wp_json_encode([ |
| 238 | - 'messages' => [ | |
| 239 | - ['role' => 'system', 'content' => $grok_system_content ?? 'You are a helpful and intelligent assistant for the website "' . site_url() . '". Use live website data and the provided context to respond accurately and briefly. Stay relevant and do not introduce additional topics.' ], | |
| 240 | - ['role' => 'user', 'content' => $keyword ] | |
| 241 | - ], | |
| 290 | + 'messages' => $messages, | |
| 242 | 291 | 'model' => 'grok-3-latest', |
| 243 | 292 | 'temperature' => 0, |
| 244 | 293 | 'stream' => false |
| 245 | 294 | ]), |
| @@ -246,14 +295,21 @@ | ||
| 246 | 295 | 'timeout' => 60, |
| 247 | 296 | ]); |
| 248 | 297 | $response['message'] = ''; |
| 249 | 298 | $status_code = wp_remote_retrieve_response_code($response_mess); |
| 250 | - // Step 2: Get the raw body (this is almost always what you want) | |
| 251 | 299 | $data = wp_remote_retrieve_body($response_mess); |
| 252 | - $data = json_decode($data, true); // Decode as associative array | |
| 300 | + $data = json_decode($data, true); | |
| 301 | + do_action('qcld_openai_user_rate_cal', 1); | |
| 253 | 302 | $response['status'] = 'success'; |
| 254 | - $response['message'] = $data['choices'][0]['message']['content'] ?? 'No content received'; // true = assoc array | |
| 255 | - do_action('qcld_openai_user_rate_cal', 1); | |
| 303 | + $reply_raw = $data['choices'][0]['message']['content'] ?? 'No content received'; | |
| 304 | + $Parsedown = new Parsedown(); | |
| 305 | + $reply_text = $Parsedown->text($reply_raw); | |
| 306 | + if (strpos($reply_text, 'AI_FORM_DATA') !== false) { | |
| 307 | + $reply_text = Qcld_WPBot_Common_Functions::format_and_save_ai_form_response($reply_text); | |
| 308 | + $response['message'] = $reply_text; | |
| 309 | + } else { | |
| 310 | + $response['message'] = $reply_text . $relevant_pagelinks; | |
| 311 | + } | |
| 256 | 312 | wp_send_json( $response ); |
| 257 | 313 | } |
| 258 | 314 | } |
| 259 | 315 | public function qcld_stream_grok_callback() |
| @@ -289,9 +345,31 @@ | ||
| 289 | 345 | $headers = [ |
| 290 | 346 | 'Content-Type: application/json', |
| 291 | 347 | 'Authorization: Bearer ' . $api_key, |
| 292 | 348 | ]; |
| 293 | - $system_content = 'You are a helpful and intelligent assistant for the website "' . site_url() . '". Use live website data and the provided context to respond accurately and briefly. Stay relevant and do not introduce additional topics.'; | |
| 349 | + $system_content = get_option( 'qcld_grok_system_content' ); | |
| 350 | + if (empty($system_content)) { | |
| 351 | + $system_content = 'You are a helpful and intelligent assistant for the website "' . site_url() . '". Use live website data and the provided context to respond accurately and briefly. Stay relevant and do not introduce additional topics.'; | |
| 352 | + } | |
| 353 | + // AI Interactive Form | |
| 354 | + if (get_option('enable_ai_interactive_form') == '1') { | |
| 355 | + $saved_ai_forms = get_option('wpbot_ai_forms', array()); | |
| 356 | + if (!empty($saved_ai_forms) && is_array($saved_ai_forms)) { | |
| 357 | + $system_content .= "\n\nYou must handle the following interactive forms when the user asks for them:\n"; | |
| 358 | + foreach ($saved_ai_forms as $form) { | |
| 359 | + $system_content .= "\nForm Title: " . $form['title'] . "\nInstructions: " . $form['prompt'] . "\n"; | |
| 360 | + } | |
| 361 | + $system_content .= "\n\nCRITICAL INSTRUCTIONS FOR INTERACTIVE FORMS:\n"; | |
| 362 | + $system_content .= "When a user triggers an interactive form, you must act as a step-by-step data collection agent.\n"; | |
| 363 | + $system_content .= "1. DO NOT ask all questions at once. Ask exactly ONE question at a time.\n"; | |
| 364 | + $system_content .= "2. Wait for the user's response before asking the next question.\n"; | |
| 365 | + $system_content .= "3. Once all necessary information is collected for the form, you MUST output a final JSON block summarizing the collected data. The keys inside the \"data\" object MUST be dynamically named based on the specific questions you asked during the form collection (e.g., \"Full Name\", \"Company Size\", \"Email\", etc.). The final JSON block must be wrapped EXACTLY in these delimiters:\n"; | |
| 366 | + $system_content .= "__AI_FORM_DATA__{ \"form_title\": \"<Form Title>\", \"data\": { \"Question 1\": \"Answer 1\", \"Question 2\": \"Answer 2\" } }__AI_FORM_DATA_END__\n"; | |
| 367 | + $system_content .= "Do not include any other text after this JSON block once the form is complete.\n"; | |
| 368 | + $system_content .= "4. If the user provides an invalid, irrelevant, or nonsensical answer to your question, DO NOT apologize or state that you lack information. Instead, politely inform the user in the language of the conversation (the language the user is speaking in, e.g. German if communicating in German) that their answer is invalid or cannot be assigned, and ask the exact same question again in the user's language. NEVER output the English phrase 'Invalid answer found' unless the user is communicating in English.\n"; | |
| 369 | + $system_content .= "5. MULTI-LANGUAGE SUPPORT: Always communicate, ask questions, validate answers, and reply strictly in the user's language (matching the language used by the user, e.g. German, French, Spanish, etc.). Understand and accept valid answers in the user's language."; | |
| 370 | + } | |
| 371 | + } | |
| 294 | 372 | $messages = []; |
| 295 | 373 | // Load previous conversation from cookie if continuity is enabled |
| 296 | 374 | if ($conversation_continuity == 1 && !empty($_COOKIE['last_five_prompt'])) { |
| 297 | 375 | $decoded_cookie = json_decode(stripslashes($_COOKIE['last_five_prompt']), true); |