| @@ -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,33 @@ | ||
| 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, respond with 'Invalid answer found' and ask the exact same question again."; | |
| 267 | + } | |
| 268 | + } | |
| 269 | + | |
| 270 | + if ( !$is_playground && get_option('gemeni_context_awareness_enabled') == '1' ) { | |
| 248 | 271 | $site_name = get_bloginfo('name'); |
| 249 | 272 | $site_desc = get_bloginfo('description'); |
| 250 | 273 | |
| 251 | 274 | // Get current page URL and title more reliably |
| @@ -329,12 +352,21 @@ | ||
| 329 | 352 | if ( $current_url ) { $context_bits[] = 'URL: ' . $current_url; } |
| 330 | 353 | if ( $page_summary ) { $context_bits[] = 'Page summary: ' . $page_summary; } |
| 331 | 354 | |
| 332 | 355 | if ( ! empty( $context_bits ) ) { |
| 333 | - $system_instructions = 'Context Information: ' . implode( '. ', $context_bits ) . '. Please use this context to provide more relevant and accurate responses.'; | |
| 356 | + if (!empty($system_instructions)) { | |
| 357 | + $system_instructions .= "\n\nContext Information: " . implode( '. ', $context_bits ) . '. Please use this context to provide more relevant and accurate responses.'; | |
| 358 | + } else { | |
| 359 | + $system_instructions = 'Context Information: ' . implode( '. ', $context_bits ) . '. Please use this context to provide more relevant and accurate responses.'; | |
| 360 | + } | |
| 334 | 361 | } |
| 335 | 362 | } |
| 336 | 363 | |
| 364 | + $action_prompt = !empty($_POST['action_prompt']) ? wp_unslash($_POST['action_prompt']) : ''; | |
| 365 | + if (!empty($action_prompt)) { | |
| 366 | + $system_instructions .= "\n\nCRITICAL ACTIVE ACTION INSTRUCTION:\n" . $action_prompt; | |
| 367 | + } | |
| 368 | + | |
| 337 | 369 | // RAG Integration |
| 338 | 370 | if (get_option('is_page_rag_enabled') == '1') { |
| 339 | 371 | $rag_context_text = Qcld_Bot_Rag::instance()->run_rag_search($keyword); |
| 340 | 372 | if (!empty($rag_context_text) && $rag_context_text != "No knowledge base found.") { |
| @@ -351,16 +383,14 @@ | ||
| 351 | 383 | } |
| 352 | 384 | |
| 353 | 385 | if ( ( get_option( 'page_suggestion_enabled' ) == '1' ) && count( $relevant_pagelink ) > 0 ) { |
| 354 | 386 | $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 | 387 | $locale = get_locale(); |
| 357 | - if ( is_array( $relevant_post_link ) && isset( $relevant_post_link[ $locale ] ) && is_array( $relevant_post_link[ $locale ] ) ) { | |
| 388 | + if ( !$is_playground && is_array( $relevant_post_link ) && isset( $relevant_post_link[ $locale ] ) && is_array( $relevant_post_link[ $locale ] ) ) { | |
| 358 | 389 | $relevant_pagelinks = '<br><br><p><em>' . implode( '', $relevant_post_link[ $locale ] ) . '</em><p>' . implode( '</br>', $relevant_pagelink ); |
| 359 | 390 | } else { |
| 360 | - // Fallback: try to use $locale, but check if key exists | |
| 361 | 391 | $em_text = ''; |
| 362 | - if ( is_array( $relevant_post_link ) && isset( $relevant_post_link[ $locale ] ) ) { | |
| 392 | + if ( !$is_playground && is_array( $relevant_post_link ) && isset( $relevant_post_link[ $locale ] ) ) { | |
| 363 | 393 | $em_text = is_array( $relevant_post_link[ $locale ] ) ? implode( '', $relevant_post_link[ $locale ] ) : $relevant_post_link[ $locale ]; |
| 364 | 394 | } |
| 365 | 395 | $relevant_pagelinks = '<br><br><p><em>' . $em_text . '</em><p>' . implode( '</br>', $relevant_pagelink ); |
| 366 | 396 | } |
| @@ -368,15 +398,12 @@ | ||
| 368 | 398 | $relevant_pagelinks = ''; |
| 369 | 399 | } |
| 370 | 400 | |
| 371 | 401 | $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 | 402 | $api_url = 'https://generativelanguage.googleapis.com/v1/models/' . $selected_model . ':generateContent'; |
| 374 | 403 | |
| 375 | - // Build formatted messages with system instructions | |
| 376 | 404 | $formatted_messages = []; |
| 377 | 405 | |
| 378 | - // Add system instructions as first user message if context is enabled | |
| 379 | 406 | if ( ! empty( $system_instructions ) ) { |
| 380 | 407 | $formatted_messages[] = [ |
| 381 | 408 | 'role' => 'user', |
| 382 | 409 | 'parts' => [ |
| @@ -383,9 +410,8 @@ | ||
| 383 | 410 | ['text' => "[System Instructions] " . $system_instructions] |
| 384 | 411 | ] |
| 385 | 412 | ]; |
| 386 | 413 | |
| 387 | - // Add model response to acknowledge system instructions | |
| 388 | 414 | $formatted_messages[] = [ |
| 389 | 415 | 'role' => 'model', |
| 390 | 416 | 'parts' => [ |
| 391 | 417 | ['text' => "I understand and will follow these instructions."] |
| @@ -391,22 +417,40 @@ | ||
| 391 | 417 | ['text' => "I understand and will follow these instructions."] |
| 392 | 418 | ] |
| 393 | 419 | ]; |
| 394 | 420 | } |
| 421 | + | |
| 422 | + if (!empty($_POST['ai_history'])) { | |
| 423 | + $parsed_history = json_decode(wp_unslash($_POST['ai_history']), true); | |
| 424 | + if (is_array($parsed_history)) { | |
| 425 | + foreach ($parsed_history as $h) { | |
| 426 | + if (isset($h['role']) && isset($h['content'])) { | |
| 427 | + $role = ($h['role'] === 'assistant') ? 'model' : 'user'; | |
| 428 | + $formatted_messages[] = [ | |
| 429 | + 'role' => $role, | |
| 430 | + 'parts' => [ | |
| 431 | + ['text' => sanitize_text_field($h['content'])] | |
| 432 | + ] | |
| 433 | + ]; | |
| 434 | + } | |
| 435 | + } | |
| 436 | + } | |
| 437 | + } | |
| 395 | 438 | |
| 396 | - // Add the actual user query | |
| 397 | - $formatted_messages[] = [ | |
| 398 | - 'role' => 'user', | |
| 399 | - 'parts' => [ | |
| 400 | - ['text' => $keyword] | |
| 401 | - ] | |
| 402 | - ]; | |
| 439 | + $last_msg = end($formatted_messages); | |
| 440 | + if (!$last_msg || $last_msg['role'] !== 'user' || empty($last_msg['parts'][0]['text']) || $last_msg['parts'][0]['text'] !== $keyword) { | |
| 441 | + $formatted_messages[] = [ | |
| 442 | + 'role' => 'user', | |
| 443 | + 'parts' => [ | |
| 444 | + ['text' => $keyword] | |
| 445 | + ] | |
| 446 | + ]; | |
| 447 | + } | |
| 403 | 448 | |
| 404 | 449 | $data = array( |
| 405 | 450 | 'contents' => $formatted_messages, |
| 406 | 451 | ); |
| 407 | 452 | |
| 408 | - // Use WordPress wp_remote_post for better error handling and consistency | |
| 409 | 453 | $args = array( |
| 410 | 454 | 'body' => json_encode($data), |
| 411 | 455 | 'headers' => array( |
| 412 | 456 | 'Content-Type' => 'application/json', |
| @@ -420,9 +464,8 @@ | ||
| 420 | 464 | ); |
| 421 | 465 | |
| 422 | 466 | $result = wp_remote_post($api_url, $args); |
| 423 | 467 | |
| 424 | - // Check for WordPress errors | |
| 425 | 468 | if (is_wp_error($result)) { |
| 426 | 469 | $response['status'] = 'error'; |
| 427 | 470 | $response['message'] = 'API request failed: ' . $result->get_error_message(); |
| 428 | 471 | } else { |
| @@ -430,15 +473,20 @@ | ||
| 430 | 473 | $response_body = wp_remote_retrieve_body($result); |
| 431 | 474 | |
| 432 | 475 | if ($http_code === 200) { |
| 433 | 476 | $msg = json_decode($response_body); |
| 434 | - // Gemini API returns candidates[0]->content->parts[0]->text | |
| 435 | 477 | if ( |
| 436 | 478 | isset($msg->candidates[0]->content->parts[0]->text) |
| 437 | 479 | && !empty($msg->candidates[0]->content->parts[0]->text) |
| 438 | 480 | ) { |
| 439 | 481 | $response['status'] = 'success'; |
| 440 | - $response['message'] = $Qcld_Parsedown->text( $msg->candidates[0]->content->parts[0]->text ) . $relevant_pagelinks; | |
| 482 | + $reply_text = $Qcld_Parsedown->text( $msg->candidates[0]->content->parts[0]->text ); | |
| 483 | + if (strpos($reply_text, 'AI_FORM_DATA') !== false) { | |
| 484 | + $reply_text = Qcld_WPBot_Common_Functions::format_and_save_ai_form_response($reply_text); | |
| 485 | + $response['message'] = $reply_text; | |
| 486 | + } else { | |
| 487 | + $response['message'] = $reply_text . $relevant_pagelinks; | |
| 488 | + } | |
| 441 | 489 | } else { |
| 442 | 490 | $response['status'] = 'error'; |
| 443 | 491 | $response['message'] = 'Invalid response format from Gemini API'; |
| 444 | 492 | } |