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 +72 -24 8.6.6 → 8.8.1 View file →
@@ -183,11 +183,11 @@
183 183 $api_url = 'https://generativelanguage.googleapis.com/v1/models/' . $selected_model . ':generateContent';
184 184 $result = wp_remote_post($api_url, $args);
185 185 $result = json_decode(wp_remote_retrieve_body($result), true);
186 186 if( $result['error'] ?? false ) {
187 - 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'] ) ) );
188 188 } elseif ( $result['candidates'] ?? false ) {
189 - 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'] ) ) );
190 190 }
191 191
192 192 wp_die();
193 193
@@ -242,11 +242,34 @@
242 242 }
243 243
244 244 $Qcld_Parsedown = new Qcld_Parsedown();
245 245
246 + $is_playground = isset($_POST['is_ai_actions_playground']) && intval($_POST['is_ai_actions_playground']) === 1;
247 +
246 248 // Build context-aware content with system instructions
247 - $system_instructions = '';
248 - 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' ) {
249 272 $site_name = get_bloginfo('name');
250 273 $site_desc = get_bloginfo('description');
251 274
252 275 // Get current page URL and title more reliably
@@ -330,12 +353,21 @@
330 353 if ( $current_url ) { $context_bits[] = 'URL: ' . $current_url; }
331 354 if ( $page_summary ) { $context_bits[] = 'Page summary: ' . $page_summary; }
332 355
333 356 if ( ! empty( $context_bits ) ) {
334 - $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 + }
335 362 }
336 363 }
337 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 +
338 370 // RAG Integration
339 371 if (get_option('is_page_rag_enabled') == '1') {
340 372 $rag_context_text = Qcld_Bot_Rag::instance()->run_rag_search($keyword);
341 373 if (!empty($rag_context_text) && $rag_context_text != "No knowledge base found.") {
@@ -352,16 +384,14 @@
352 384 }
353 385
354 386 if ( ( get_option( 'page_suggestion_enabled' ) == '1' ) && count( $relevant_pagelink ) > 0 ) {
355 387 $relevant_post_link = maybe_unserialize( get_option( 'qlcd_wp_chatbot_relevant_post_link_openai' ) );
356 - // Always use get_locale() to avoid undefined function error
357 388 $locale = get_locale();
358 - 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 ] ) ) {
359 390 $relevant_pagelinks = '<br><br><p><em>' . implode( '', $relevant_post_link[ $locale ] ) . '</em><p>' . implode( '</br>', $relevant_pagelink );
360 391 } else {
361 - // Fallback: try to use $locale, but check if key exists
362 392 $em_text = '';
363 - 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 ] ) ) {
364 394 $em_text = is_array( $relevant_post_link[ $locale ] ) ? implode( '', $relevant_post_link[ $locale ] ) : $relevant_post_link[ $locale ];
365 395 }
366 396 $relevant_pagelinks = '<br><br><p><em>' . $em_text . '</em><p>' . implode( '</br>', $relevant_pagelink );
367 397 }
@@ -369,15 +399,12 @@
369 399 $relevant_pagelinks = '';
370 400 }
371 401
372 402 $selected_model = get_option('qcld_gemini_model') ? get_option('qcld_gemini_model') : 'gemini-2.5-flash';
373 - // Gemini API expects a different payload and endpoint
374 403 $api_url = 'https://generativelanguage.googleapis.com/v1/models/' . $selected_model . ':generateContent';
375 404
376 - // Build formatted messages with system instructions
377 405 $formatted_messages = [];
378 406
379 - // Add system instructions as first user message if context is enabled
380 407 if ( ! empty( $system_instructions ) ) {
381 408 $formatted_messages[] = [
382 409 'role' => 'user',
383 410 'parts' => [
@@ -384,9 +411,8 @@
384 411 ['text' => "[System Instructions] " . $system_instructions]
385 412 ]
386 413 ];
387 414
388 - // Add model response to acknowledge system instructions
389 415 $formatted_messages[] = [
390 416 'role' => 'model',
391 417 'parts' => [
392 418 ['text' => "I understand and will follow these instructions."]
@@ -392,22 +418,40 @@
392 418 ['text' => "I understand and will follow these instructions."]
393 419 ]
394 420 ];
395 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 + }
396 439
397 - // Add the actual user query
398 - $formatted_messages[] = [
399 - 'role' => 'user',
400 - 'parts' => [
401 - ['text' => $keyword]
402 - ]
403 - ];
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 + }
404 449
405 450 $data = array(
406 451 'contents' => $formatted_messages,
407 452 );
408 453
409 - // Use WordPress wp_remote_post for better error handling and consistency
410 454 $args = array(
411 455 'body' => json_encode($data),
412 456 'headers' => array(
413 457 'Content-Type' => 'application/json',
@@ -421,9 +465,8 @@
421 465 );
422 466
423 467 $result = wp_remote_post($api_url, $args);
424 468
425 - // Check for WordPress errors
426 469 if (is_wp_error($result)) {
427 470 $response['status'] = 'error';
428 471 $response['message'] = 'API request failed: ' . $result->get_error_message();
429 472 } else {
@@ -431,15 +474,20 @@
431 474 $response_body = wp_remote_retrieve_body($result);
432 475
433 476 if ($http_code === 200) {
434 477 $msg = json_decode($response_body);
435 - // Gemini API returns candidates[0]->content->parts[0]->text
436 478 if (
437 479 isset($msg->candidates[0]->content->parts[0]->text)
438 480 && !empty($msg->candidates[0]->content->parts[0]->text)
439 481 ) {
440 482 $response['status'] = 'success';
441 - $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 + }
442 490 } else {
443 491 $response['status'] = 'error';
444 492 $response['message'] = 'Invalid response format from Gemini API';
445 493 }