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/openai/qcld-bot-openai.php +52 -20 8.7.2 → 8.8.1 View file →
@@ -448,29 +448,58 @@
448 448 flush();
449 449 wp_die();
450 450 }
451 451
452 - $system_content = get_option( 'qcld_openai_system_content', 'You are a helpful assistant.' );
452 + $is_playground = isset( $_POST['is_ai_actions_playground'] ) && intval( $_POST['is_ai_actions_playground'] ) === 1;
453 + $active_ai_action = isset( $_POST['active_ai_action'] ) ? sanitize_text_field( wp_unslash( $_POST['active_ai_action'] ) ) : '';
454 + $raw_ai_history = isset( $_POST['ai_history'] ) ? json_decode( stripslashes( $_POST['ai_history'] ), true ) : array();
455 + $is_ai_action = $is_playground || ! empty( $active_ai_action ) || ( class_exists( 'Qcld_WPBot_Common_Functions' ) && Qcld_WPBot_Common_Functions::is_ai_action_in_progress( $raw_ai_history, $keyword ) );
456 +
457 + $system_content = $is_playground ? 'You are a helpful AI assistant. You MUST strictly follow the interactive form instructions if the user asks for them.' : get_option( 'qcld_openai_system_content' );
458 + if ( empty( $system_content ) ) {
459 + $system_content = 'You are a helpful assistant.';
460 + }
453 461
454 462 // AI Interactive Form
455 - if (get_option('enable_ai_interactive_form') == '1') {
456 - $saved_ai_forms = get_option('wpbot_ai_forms', array());
457 - if (!empty($saved_ai_forms) && is_array($saved_ai_forms)) {
458 - $system_content .= "\n\nYou must handle the following interactive forms when the user asks for them:\n";
459 - foreach ($saved_ai_forms as $form) {
460 - $system_content .= "\nForm Title: " . $form['title'] . "\nInstructions: " . $form['prompt'] . "\n";
463 + $saved_ai_forms = get_option( 'wpbot_ai_forms', array() );
464 + $active_interactive_forms = array();
465 + if ( get_option( 'enable_ai_interactive_form' ) == '1' && ! empty( $saved_ai_forms ) && is_array( $saved_ai_forms ) ) {
466 + foreach ( $saved_ai_forms as $form ) {
467 + if ( ! isset( $form['interactive'] ) || $form['interactive'] == 1 ) {
468 + $active_interactive_forms[] = $form;
461 469 }
462 - $system_content .= "\n\nCRITICAL INSTRUCTIONS FOR INTERACTIVE FORMS:\n";
463 - $system_content .= "When a user triggers an interactive form, you must act as a step-by-step data collection agent.\n";
464 - $system_content .= "1. DO NOT ask all questions at once. Ask exactly ONE question at a time.\n";
465 - $system_content .= "2. Wait for the user's response before asking the next question.\n";
466 - $system_content .= "3. Once all necessary information is collected for the form, you MUST output a final JSON block summarizing the collected data, wrapped EXACTLY in these delimiters:\n";
467 - $system_content .= "__AI_FORM_DATA__{ \"form_title\": \"<Form Title>\", \"data\": { \"Question 1\": \"Answer 1\", \"Question 2\": \"Answer 2\" } }__AI_FORM_DATA_END__\n";
468 - $system_content .= "Do not include any other text after this JSON block once the form is complete.\n";
469 - $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, respond with 'Invalid answer found' and ask the exact same question again.";
470 470 }
471 471 }
472 472
473 + if ( ! empty( $active_interactive_forms ) ) {
474 + $system_content .= "\n\nYou must handle the following interactive forms when the user asks for them:\n";
475 + foreach ( $active_interactive_forms as $form ) {
476 + $system_content .= "\nForm Title: " . $form['title'] . "\nInstructions: " . $form['prompt'] . "\n";
477 + }
478 + $system_content .= "\n\nCRITICAL INSTRUCTIONS FOR INTERACTIVE FORMS:\n";
479 + $system_content .= "When a user triggers an interactive form, you must act as a step-by-step data collection agent.\n";
480 + $system_content .= "1. DO NOT ask all questions at once. Ask exactly ONE question at a time.\n";
481 + $system_content .= "2. Wait for the user's response before asking the next question.\n";
482 + $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";
483 + $system_content .= "__AI_FORM_DATA__{ \"form_title\": \"<Form Title>\", \"data\": { \"<Generated Key 1>\": \"Answer 1\", \"<Generated Key 2>\": \"Answer 2\" } }__AI_FORM_DATA_END__\n";
484 + $system_content .= "Do not include any other text after this JSON block once the form is complete.\n";
485 + $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";
486 + $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.";
487 + }
488 +
489 + if ( $is_ai_action ) {
490 + $system_content .= "\n\nCRITICAL ACTIVE FORM COLLECTION INSTRUCTION:\n" .
491 + "You are currently conducting an interactive step-by-step form data collection.\n" .
492 + "RULES FOR ACTIVE FORM COLLECTION:\n" .
493 + "1. The user's message is an answer to your last question (e.g. name, email, dates, guests, room type, phone number, etc.).\n" .
494 + "2. Review the conversation history carefully. Notice which questions from the form have ALREADY been asked and answered.\n" .
495 + "3. NEVER repeat questions that have already been answered earlier in the conversation.\n" .
496 + "4. Ask the NEXT missing question in the form sequence, exactly ONE question at a time.\n" .
497 + "5. Once ALL questions for this form have been answered, DO NOT ask any more questions or restart the form. Immediately output the final summary JSON block wrapped in __AI_FORM_DATA__{ \"form_title\": \"...\", \"data\": { ... } }__AI_FORM_DATA_END__.\n" .
498 + "6. DO NOT apologize or state that you lack information in documentation. Just proceed with the form collection.\n" .
499 + "7. LANGUAGE CONSISTENCY: Always respond, ask questions, validate answers, and provide feedback in the user's language (the language the user is speaking, e.g. German, French, Spanish, etc.). Do not switch to English. If an answer cannot be assigned or is invalid, explain this politely in the user's language and re-ask the question in that language. Always accept valid answers in the user's language.";
500 + }
501 +
473 502 // RAG integration
474 503 if ( get_option( 'is_page_rag_enabled' ) == '1' ) {
475 504 if ( class_exists( 'Qcld_Bot_Rag' ) ) {
476 505 $rag_context_text = Qcld_Bot_Rag::instance()->run_rag_search( $keyword );
@@ -541,8 +570,9 @@
541 570 'messages' => $messages,
542 571 'stream' => true,
543 572 ] );
544 573
574 + // phpcs:disable WordPress.WP.AlternativeFunctions.curl_curl_init, WordPress.WP.AlternativeFunctions.curl_curl_setopt, WordPress.WP.AlternativeFunctions.curl_curl_exec, WordPress.WP.AlternativeFunctions.curl_curl_errno, WordPress.WP.AlternativeFunctions.curl_curl_error, WordPress.WP.AlternativeFunctions.curl_curl_close -- SSE streaming requires cURL write callback.
545 575 $ch = curl_init( 'https://api.openai.com/v1/chat/completions' );
546 576 curl_setopt( $ch, CURLOPT_POST, true );
547 577 curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
548 578 curl_setopt( $ch, CURLOPT_POSTFIELDS, $post_data );
@@ -557,8 +587,9 @@
557 587 echo 'data: [ERROR] ' . esc_html( curl_error( $ch ) ) . "\n\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- curl_error is already escaped above
558 588 flush();
559 589 }
560 590 curl_close( $ch );
591 + // phpcs:enable WordPress.WP.AlternativeFunctions.curl_curl_init, WordPress.WP.AlternativeFunctions.curl_curl_setopt, WordPress.WP.AlternativeFunctions.curl_curl_exec, WordPress.WP.AlternativeFunctions.curl_curl_errno, WordPress.WP.AlternativeFunctions.curl_curl_error, WordPress.WP.AlternativeFunctions.curl_curl_close
561 592 do_action( 'qcld_openai_user_rate_cal', 1 );
562 593 exit;
563 594 }
564 595
@@ -613,9 +644,10 @@
613 644 $system_content .= "2. Wait for the user's response before asking the next question.\n";
614 645 $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";
615 646 $system_content .= "__AI_FORM_DATA__{ \"form_title\": \"<Form Title>\", \"data\": { \"<Generated Key 1>\": \"Answer 1\", \"<Generated Key 2>\": \"Answer 2\" } }__AI_FORM_DATA_END__\n";
616 647 $system_content .= "Do not include any other text after this JSON block once the form is complete.\n";
617 - $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, respond with 'Invalid answer found' and ask the exact same question again.";
648 + $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";
649 + $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.";
618 650 }
619 651
620 652 if ($is_ai_action) {
621 653 $system_content .= "\n\nCRITICAL ACTIVE FORM COLLECTION INSTRUCTION:\n" .
@@ -625,9 +657,10 @@
625 657 "2. Review the conversation history carefully. Notice which questions from the form have ALREADY been asked and answered.\n" .
626 658 "3. NEVER repeat questions that have already been answered earlier in the conversation.\n" .
627 659 "4. Ask the NEXT missing question in the form sequence, exactly ONE question at a time.\n" .
628 660 "5. Once ALL questions for this form have been answered, DO NOT ask any more questions or restart the form. Immediately output the final summary JSON block wrapped in __AI_FORM_DATA__{ \"form_title\": \"...\", \"data\": { ... } }__AI_FORM_DATA_END__.\n" .
629 - "6. DO NOT apologize or state that you lack information in documentation. Just proceed with the form collection.";
661 + "6. DO NOT apologize or state that you lack information in documentation. Just proceed with the form collection.\n" .
662 + "7. LANGUAGE CONSISTENCY: Always respond, ask questions, validate answers, and provide feedback in the user's language (the language the user is speaking, e.g. German, French, Spanish, etc.). Do not switch to English. If an answer cannot be assigned or is invalid, explain this politely in the user's language and re-ask the question in that language. Always accept valid answers in the user's language.";
630 663 }
631 664
632 665 // RAG Integration
633 666 if (!$is_playground && !$is_ai_action && get_option('is_page_rag_enabled') == '1') {
@@ -892,8 +925,9 @@
892 925 if( $ai_enabled == 1 ){
893 926 update_option('qcld_openrouter_enabled',0);
894 927 update_option('qcld_grok_enabled',0);
895 928 update_option('qcld_gemini_enabled',0);
929 + update_option('qcld_claude_enabled',0);
896 930 update_option('disable_wp_chatbot_site_search',1);
897 931 }
898 932
899 933 update_option('qcld_openai_relevant_enabled',$is_relevant_enabled);
@@ -1342,9 +1376,9 @@
1342 1376 if (isset($form['email'])) {
1343 1377 $email_enabled = $form['email'] == 1;
1344 1378 }
1345 1379 $per_action_emails = isset($form['email_addresses']) ? trim($form['email_addresses']) : '';
1346 - error_log('[WPBot AI] Matched form: "' . $form['title'] . '" | email_addresses stored: "' . $per_action_emails . '"');
1380 + //error_log('[WPBot AI] Matched form: "' . $form['title'] . '" | email_addresses stored: "' . $per_action_emails . '"');
1347 1381 break;
1348 1382 }
1349 1383 }
1350 1384 }
@@ -1356,10 +1390,8 @@
1356 1390 } else {
1357 1391 $default = get_option('qlcd_wp_chatbot_admin_email', '');
1358 1392 $to = !empty($default) ? array_map('trim', explode(',', $default)) : get_option('admin_email');
1359 1393 }
1360 - error_log('[WPBot AI] Sending email to: ' . print_r($to, true));
1361 - error_log('[WPBot AI] Reply-To email: ' . $reply_to);
1362 1394 $subject = sanitize_text_field($data['form_title']) . " - " . esc_html__('New AI Chat Submission', 'chatbot');
1363 1395 $headers = array('Content-Type: text/html; charset=UTF-8');
1364 1396 if (!empty($reply_to)) {
1365 1397 $headers[] = 'Reply-To: ' . $reply_to;