PluginProbe
WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services / 8.8.1
WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services v8.8.1
8.8.2 8.8.1 8.8.0 8.7.9 8.7.8 8.7.7 8.7.6 8.7.5 8.7.4 8.7.3 8.7.2 8.7.1 8.7.0 8.6.9 8.6.8 8.6.7 8.6.6 8.6.5 8.6.4 8.6.2 8.6.1 8.6.0 8.5.9 8.5.8 8.5.7 All 538 releases
← All changes | includes/integration/gemini/qcld-bot-gemini.php +73 -24 8.6.0 → 8.8.1 View file →
@@ -131,8 +131,9 @@
131 131 if($gemini_enabled == '1') {
132 132 update_option('ai_enabled', 0);
133 133 update_option('qcld_openrouter_enabled', 0);
134 134 update_option('qcld_grok_enabled', 0);
135 + update_option('disable_wp_chatbot_site_search',1);
135 136
136 137 } else {
137 138 update_option('ai_enabled', 1);
138 139 }
@@ -182,11 +183,11 @@
182 183 $api_url = 'https://generativelanguage.googleapis.com/v1/models/' . $selected_model . ':generateContent';
183 184 $result = wp_remote_post($api_url, $args);
184 185 $result = json_decode(wp_remote_retrieve_body($result), true);
185 186 if( $result['error'] ?? false ) {
186 - wp_send_json( array( 'status' => 'error', 'msg' => esc_html__( $result['error']['message'], 'chatbot' ) ) );
187 + wp_send_json( array( 'status' => 'error', 'msg' => esc_html( $result['error']['message'] ) ) );
187 188 } elseif ( $result['candidates'] ?? false ) {
188 - wp_send_json( array( 'status' => 'success', 'msg' => esc_html__( $result['candidates'][0]['content']['parts'][0]['text'], 'chatbot' ) ) );
189 + wp_send_json( array( 'status' => 'success', 'msg' => esc_html( $result['candidates'][0]['content']['parts'][0]['text'] ) ) );
189 190 }
190 191
191 192 wp_die();
192 193
@@ -241,11 +242,34 @@
241 242 }
242 243
243 244 $Qcld_Parsedown = new Qcld_Parsedown();
244 245
246 + $is_playground = isset($_POST['is_ai_actions_playground']) && intval($_POST['is_ai_actions_playground']) === 1;
247 +
245 248 // Build context-aware content with system instructions
246 - $system_instructions = '';
247 - if ( get_option('gemeni_context_awareness_enabled') == '1' ) {
249 + $system_instructions = $is_playground ? 'You are a helpful AI assistant. You MUST strictly follow the interactive form instructions if the user asks for them.' : '';
250 +
251 + // AI Interactive Form
252 + if (get_option('enable_ai_interactive_form') == '1') {
253 + $saved_ai_forms = get_option('wpbot_ai_forms', array());
254 + if (!empty($saved_ai_forms) && is_array($saved_ai_forms)) {
255 + $system_instructions .= "\n\nYou must handle the following interactive forms when the user asks for them:\n";
256 + foreach ($saved_ai_forms as $form) {
257 + $system_instructions .= "\nForm Title: " . $form['title'] . "\nInstructions: " . $form['prompt'] . "\n";
258 + }
259 + $system_instructions .= "\n\nCRITICAL INSTRUCTIONS FOR INTERACTIVE FORMS:\n";
260 + $system_instructions .= "When a user triggers an interactive form, you must act as a step-by-step data collection agent.\n";
261 + $system_instructions .= "1. DO NOT ask all questions at once. Ask exactly ONE question at a time.\n";
262 + $system_instructions .= "2. Wait for the user's response before asking the next question.\n";
263 + $system_instructions .= "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";
264 + $system_instructions .= "__AI_FORM_DATA__{ \"form_title\": \"<Form Title>\", \"data\": { \"Question 1\": \"Answer 1\", \"Question 2\": \"Answer 2\" } }__AI_FORM_DATA_END__\n";
265 + $system_instructions .= "Do not include any other text after this JSON block once the form is complete.\n";
266 + $system_instructions .= "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";
267 + $system_instructions .= "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.";
268 + }
269 + }
270 +
271 + if ( !$is_playground && get_option('gemeni_context_awareness_enabled') == '1' ) {
248 272 $site_name = get_bloginfo('name');
249 273 $site_desc = get_bloginfo('description');
250 274
251 275 // Get current page URL and title more reliably
@@ -329,12 +353,21 @@
329 353 if ( $current_url ) { $context_bits[] = 'URL: ' . $current_url; }
330 354 if ( $page_summary ) { $context_bits[] = 'Page summary: ' . $page_summary; }
331 355
332 356 if ( ! empty( $context_bits ) ) {
333 - $system_instructions = 'Context Information: ' . implode( '. ', $context_bits ) . '. Please use this context to provide more relevant and accurate responses.';
357 + if (!empty($system_instructions)) {
358 + $system_instructions .= "\n\nContext Information: " . implode( '. ', $context_bits ) . '. Please use this context to provide more relevant and accurate responses.';
359 + } else {
360 + $system_instructions = 'Context Information: ' . implode( '. ', $context_bits ) . '. Please use this context to provide more relevant and accurate responses.';
361 + }
334 362 }
335 363 }
336 364
365 + $action_prompt = !empty($_POST['action_prompt']) ? wp_unslash($_POST['action_prompt']) : '';
366 + if (!empty($action_prompt)) {
367 + $system_instructions .= "\n\nCRITICAL ACTIVE ACTION INSTRUCTION:\n" . $action_prompt;
368 + }
369 +
337 370 // RAG Integration
338 371 if (get_option('is_page_rag_enabled') == '1') {
339 372 $rag_context_text = Qcld_Bot_Rag::instance()->run_rag_search($keyword);
340 373 if (!empty($rag_context_text) && $rag_context_text != "No knowledge base found.") {
@@ -351,16 +384,14 @@
351 384 }
352 385
353 386 if ( ( get_option( 'page_suggestion_enabled' ) == '1' ) && count( $relevant_pagelink ) > 0 ) {
354 387 $relevant_post_link = maybe_unserialize( get_option( 'qlcd_wp_chatbot_relevant_post_link_openai' ) );
355 - // Always use get_locale() to avoid undefined function error
356 388 $locale = get_locale();
357 - if ( is_array( $relevant_post_link ) && isset( $relevant_post_link[ $locale ] ) && is_array( $relevant_post_link[ $locale ] ) ) {
389 + if ( !$is_playground && is_array( $relevant_post_link ) && isset( $relevant_post_link[ $locale ] ) && is_array( $relevant_post_link[ $locale ] ) ) {
358 390 $relevant_pagelinks = '<br><br><p><em>' . implode( '', $relevant_post_link[ $locale ] ) . '</em><p>' . implode( '</br>', $relevant_pagelink );
359 391 } else {
360 - // Fallback: try to use $locale, but check if key exists
361 392 $em_text = '';
362 - if ( is_array( $relevant_post_link ) && isset( $relevant_post_link[ $locale ] ) ) {
393 + if ( !$is_playground && is_array( $relevant_post_link ) && isset( $relevant_post_link[ $locale ] ) ) {
363 394 $em_text = is_array( $relevant_post_link[ $locale ] ) ? implode( '', $relevant_post_link[ $locale ] ) : $relevant_post_link[ $locale ];
364 395 }
365 396 $relevant_pagelinks = '<br><br><p><em>' . $em_text . '</em><p>' . implode( '</br>', $relevant_pagelink );
366 397 }
@@ -368,15 +399,12 @@
368 399 $relevant_pagelinks = '';
369 400 }
370 401
371 402 $selected_model = get_option('qcld_gemini_model') ? get_option('qcld_gemini_model') : 'gemini-2.5-flash';
372 - // Gemini API expects a different payload and endpoint
373 403 $api_url = 'https://generativelanguage.googleapis.com/v1/models/' . $selected_model . ':generateContent';
374 404
375 - // Build formatted messages with system instructions
376 405 $formatted_messages = [];
377 406
378 - // Add system instructions as first user message if context is enabled
379 407 if ( ! empty( $system_instructions ) ) {
380 408 $formatted_messages[] = [
381 409 'role' => 'user',
382 410 'parts' => [
@@ -383,9 +411,8 @@
383 411 ['text' => "[System Instructions] " . $system_instructions]
384 412 ]
385 413 ];
386 414
387 - // Add model response to acknowledge system instructions
388 415 $formatted_messages[] = [
389 416 'role' => 'model',
390 417 'parts' => [
391 418 ['text' => "I understand and will follow these instructions."]
@@ -391,22 +418,40 @@
391 418 ['text' => "I understand and will follow these instructions."]
392 419 ]
393 420 ];
394 421 }
422 +
423 + if (!empty($_POST['ai_history'])) {
424 + $parsed_history = json_decode(wp_unslash($_POST['ai_history']), true);
425 + if (is_array($parsed_history)) {
426 + foreach ($parsed_history as $h) {
427 + if (isset($h['role']) && isset($h['content'])) {
428 + $role = ($h['role'] === 'assistant') ? 'model' : 'user';
429 + $formatted_messages[] = [
430 + 'role' => $role,
431 + 'parts' => [
432 + ['text' => sanitize_text_field($h['content'])]
433 + ]
434 + ];
435 + }
436 + }
437 + }
438 + }
395 439
396 - // Add the actual user query
397 - $formatted_messages[] = [
398 - 'role' => 'user',
399 - 'parts' => [
400 - ['text' => $keyword]
401 - ]
402 - ];
440 + $last_msg = end($formatted_messages);
441 + if (!$last_msg || $last_msg['role'] !== 'user' || empty($last_msg['parts'][0]['text']) || $last_msg['parts'][0]['text'] !== $keyword) {
442 + $formatted_messages[] = [
443 + 'role' => 'user',
444 + 'parts' => [
445 + ['text' => $keyword]
446 + ]
447 + ];
448 + }
403 449
404 450 $data = array(
405 451 'contents' => $formatted_messages,
406 452 );
407 453
408 - // Use WordPress wp_remote_post for better error handling and consistency
409 454 $args = array(
410 455 'body' => json_encode($data),
411 456 'headers' => array(
412 457 'Content-Type' => 'application/json',
@@ -420,9 +465,8 @@
420 465 );
421 466
422 467 $result = wp_remote_post($api_url, $args);
423 468
424 - // Check for WordPress errors
425 469 if (is_wp_error($result)) {
426 470 $response['status'] = 'error';
427 471 $response['message'] = 'API request failed: ' . $result->get_error_message();
428 472 } else {
@@ -430,15 +474,20 @@
430 474 $response_body = wp_remote_retrieve_body($result);
431 475
432 476 if ($http_code === 200) {
433 477 $msg = json_decode($response_body);
434 - // Gemini API returns candidates[0]->content->parts[0]->text
435 478 if (
436 479 isset($msg->candidates[0]->content->parts[0]->text)
437 480 && !empty($msg->candidates[0]->content->parts[0]->text)
438 481 ) {
439 482 $response['status'] = 'success';
440 - $response['message'] = $Qcld_Parsedown->text( $msg->candidates[0]->content->parts[0]->text ) . $relevant_pagelinks;
483 + $reply_text = $Qcld_Parsedown->text( $msg->candidates[0]->content->parts[0]->text );
484 + if (strpos($reply_text, 'AI_FORM_DATA') !== false) {
485 + $reply_text = Qcld_WPBot_Common_Functions::format_and_save_ai_form_response($reply_text);
486 + $response['message'] = $reply_text;
487 + } else {
488 + $response['message'] = $reply_text . $relevant_pagelinks;
489 + }
441 490 } else {
442 491 $response['status'] = 'error';
443 492 $response['message'] = 'Invalid response format from Gemini API';
444 493 }