PluginProbe
WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services / 8.2.5
WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services v8.2.5
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 8.5.6 8.5.5 8.5.4 8.5.3 8.5.2 All 533 releases
chatbot / includes / integration / gemini / qcld-bot-gemini.php

qcld-bot-gemini.php in WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services 8.2.5, at includes/integration/gemini/qcld-bot-gemini.php

518 lines 20.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) exit; // Exit if accessed directly
3
4 if(!class_exists('qcld_wpgemini_addons')){
5
6
7 /**
8 * Main Class.
9 */
10 final class qcld_wpgemini_addons
11 {
12 private $id = 'Open AI';
13
14 /**
15 * WPBot Pro version.
16 *
17 * @var string
18 */
19 public $version = '1.0.6';
20
21 /**
22 * WPBot Pro helper.
23 *
24 * @var object
25 */
26 public $helper;
27
28 /**
29 * The single instance of the class.
30 *
31 * @var qcld_wb_Chatbot
32 * @since 1.0.0
33 */
34 protected static $_instance = null;
35
36 /**
37 * Main wpbot Instance.
38 *
39 * Ensures only one instance of wpbot is loaded or can be loaded.
40 *
41 * @return qcld_wb_Chatbot - Main instance.
42 * @since 1.0.0
43 * @static
44 */
45 public static function instance() {
46 if ( is_null( self::$_instance ) ) {
47 self::$_instance = new self();
48 }
49
50 return self::$_instance;
51 }
52
53 public $response_list;
54
55 /**
56 * Constructor
57 */
58 public function __construct()
59 {
60
61 $this->includes();
62 add_action('wp_ajax_qcld_gemini_response',[$this,'qcld_gemini_response_callback']);
63 add_action('wp_ajax_nopriv_qcld_gemini_response', [$this, 'qcld_gemini_response_callback']);
64 add_action('wp_ajax_update_settings_option', [$this, 'qcld_update_settings_option_callback']);
65 add_action('wp_ajax_qcld_gemini_settings_option', [$this, 'qcld_gemini_settings_option_callback']);
66 add_action('wp_ajax_qcld_gemini_get_model_list', [$this, 'qcld_gemini_get_model_list_callback']);
67
68 if (is_admin() && !empty($_GET["page"]) && (($_GET["page"] == "openai-panel_dashboard") || ($_GET["page"] == "openai-panel_file") || ($_GET["page"] == "openai-panel_help"))) {
69 add_action('admin_enqueue_scripts', array($this, 'qcld_wb_chatbot_admin_scripts'));
70 }
71 //add_action('wp_enqueue_scripts', array($this, 'qcld_wb_chatbot_gemini_scripts'));
72 add_action('admin_enqueue_scripts', array($this, 'qcld_wb_chatbot_gemini_admin_scripts'));
73 }
74
75
76
77 public function qcld_wb_chatbot_gemini_admin_scripts() {
78 if ( ! current_user_can( 'manage_options' ) ) {
79 return ;
80 }
81 wp_register_script(
82 'qcld-wp-chatbot-gemini-admin-js',
83 QCLD_wpCHATBOT_PLUGIN_URL . 'includes/integration/gemini/assets/js/qcld-wp-gemini-admin.js',
84 array('jquery'),
85 QCLD_wpCHATBOT_VERSION,
86 true
87 );
88
89 // Localize the script with necessary data
90 wp_localize_script('qcld-wp-chatbot-gemini-admin-js', 'qcld_gemini_admin_data', array(
91 'ajax_url' => admin_url('admin-ajax.php'),
92 'ajax_nonce' => wp_create_nonce('wp_chatbot'),
93 'gemini_api_key' => get_option('qcld_gemini_api_key'),
94 'gemini_enabled' => get_option('qcld_gemini_enabled'),
95 'qcld_gemini_append_content' => get_option('qcld_gemini_append_content'),
96 'qcld_gemini_prepend_content' => get_option('qcld_gemini_prepend_content')
97 ));
98
99 wp_enqueue_script('qcld-wp-chatbot-gemini-admin-js');
100 }
101
102 /**
103 * Define wpbot Constants.
104 *
105 * @return void
106 * @since 1.0.0
107 */
108 public function includes() {
109 require_once( QCLD_wpCHATBOT_PLUGIN_DIR_PATH . "includes/Parsedown.php" );
110 require_once( QCLD_wpCHATBOT_PLUGIN_DIR_PATH . "includes/class-common-function.php" );
111 }
112 public function qcld_gemini_settings_option_callback() {
113 $nonce = sanitize_text_field(wp_unslash($_POST['nonce']));
114 if (!wp_verify_nonce($nonce, 'wp_chatbot')) {
115 wp_send_json(array('success' => false, 'msg' => esc_html__('Failed in Security check', 'chatbot')));
116 wp_die();
117 } elseif ( ! current_user_can( 'manage_options' ) ) {
118 wp_send_json( array( 'success' => false, 'msg' => esc_html__( 'Unauthorized user', 'chatbot' ) ) );
119 wp_die();
120 } else {
121 $gemini_api_key = sanitize_text_field(wp_unslash($_POST['gemini_api_key']));
122 $gemini_enabled = sanitize_text_field(wp_unslash($_POST['gemini_enabled']));
123 $gemini_model = sanitize_text_field(wp_unslash($_POST['gemini_model']));
124 $qcld_gemini_page_suggestion_enabled = sanitize_text_field(wp_unslash($_POST['qcld_gemini_page_suggestion_enabled']));
125 $gemini_is_context_awareness_enabled = sanitize_text_field(wp_unslash($_POST['gemini_is_context_awareness_enabled']));
126 $qcld_gemini_append_content = sanitize_text_field(wp_unslash($_POST['qcld_gemini_append_content'])) ?? '';
127 $qcld_gemini_prepend_content = sanitize_text_field(wp_unslash($_POST['qcld_gemini_prepend_content'])) ?? '';
128 update_option('qcld_gemini_api_key', $gemini_api_key);
129 update_option('qcld_gemini_enabled', $gemini_enabled);
130 update_option('qcld_gemini_model', $gemini_model);
131 if($gemini_enabled == '1') {
132 update_option('ai_enabled', 0);
133 update_option('qcld_openrouter_enabled', 0);
134
135 } else {
136 update_option('ai_enabled', 1);
137 }
138 update_option('qcld_gemini_page_suggestion_enabled', $qcld_gemini_page_suggestion_enabled);
139 update_option('gemeni_context_awareness_enabled', $gemini_is_context_awareness_enabled);
140 $openai_post_types = array();
141 if (isset($_POST['openai_post_type'])) {
142 $raw_post_types = wp_unslash($_POST['openai_post_type']);
143 if (is_array($raw_post_types)) {
144 $openai_post_types = array_map('sanitize_text_field', $raw_post_types);
145 } else {
146 $openai_post_types = sanitize_text_field($raw_post_types);
147 }
148 }
149 $is_page_rag_enabled = sanitize_text_field(wp_unslash($_POST['is_page_rag_enabled']));
150 update_option('qcld_openai_relevant_post', $openai_post_types);
151 update_option('is_page_rag_enabled', $is_page_rag_enabled);
152 update_option('qcld_gemini_append_content', $qcld_gemini_append_content);
153 update_option('qcld_gemini_prepend_content', $qcld_gemini_prepend_content);
154
155 // Add the check query
156 $gemini_api_key = get_option( 'qcld_gemini_api_key' );
157 $formatted_messages[] = [
158 'role' => 'user',
159 'parts' => [
160 ['text' => 'give a confirmation that you are Gemini AI ( i a samll response)?']
161 ]
162 ];
163 $data = array(
164 'contents' => $formatted_messages,
165 );
166
167 // Use WordPress wp_remote_post for better error handling and consistency
168 $args = array(
169 'body' => json_encode($data),
170 'headers' => array(
171 'Content-Type' => 'application/json',
172 'X-goog-api-key' => $gemini_api_key,
173 ),
174 'timeout' => 60,
175 'redirection' => 5,
176 'blocking' => true,
177 'httpversion' => '1.0',
178 'sslverify' => true,
179 );
180 $selected_model = get_option('qcld_gemini_model') ? get_option('qcld_gemini_model') : 'gemini-2.5-flash';
181 $api_url = 'https://generativelanguage.googleapis.com/v1/models/' . $selected_model . ':generateContent';
182 $result = wp_remote_post($api_url, $args);
183 $result = json_decode(wp_remote_retrieve_body($result), true);
184 if( $result['error'] ?? false ) {
185 wp_send_json( array( 'status' => 'error', 'msg' => esc_html__( $result['error']['message'], 'chatbot' ) ) );
186 } elseif ( $result['candidates'] ?? false ) {
187 wp_send_json( array( 'status' => 'success', 'msg' => esc_html__( $result['candidates'][0]['content']['parts'][0]['text'], 'chatbot' ) ) );
188 }
189
190 wp_die();
191
192 }
193 // echo wp_json_encode($gemini_enabled);
194 wp_die();
195 }
196 public function qcld_gemini_response_callback() {
197 if (get_option('is_rate_limiting_enabled') == '1') {
198 do_action('rate_limit_checker');
199 }
200 $gemini_api_key = get_option( 'qcld_gemini_api_key' );
201 $keyword = isset($_POST['keyword']) ? sanitize_text_field( wp_unslash($_POST['keyword']) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
202
203 $relevant_pagelink = Qcld_WPBot_Common_Functions::qcpd_relevant_pagelink( $keyword );
204 $relevant_pagelink = array_slice( $relevant_pagelink, 0, 5, true );
205
206 if ( ( get_option( 'page_suggestion_enabled' ) == '1' ) && count( $relevant_pagelink ) > 0 ) {
207 $relevant_post_link = maybe_unserialize( get_option( 'qlcd_wp_chatbot_relevant_post_link_openai' ) );
208 // Always use get_locale() to avoid undefined function error
209 $locale = get_locale();
210 if ( is_array( $relevant_post_link ) && isset( $relevant_post_link[ $locale ] ) && is_array( $relevant_post_link[ $locale ] ) ) {
211 $relevant_pagelinks = '<br><br><p><em>' . implode( '', $relevant_post_link[ $locale ] ) . '</em><p>' . implode( '</br>', $relevant_pagelink );
212 } else {
213 // Fallback: try to use $locale, but check if key exists
214 $em_text = '';
215 if ( is_array( $relevant_post_link ) && isset( $relevant_post_link[ $locale ] ) ) {
216 $em_text = is_array( $relevant_post_link[ $locale ] ) ? implode( '', $relevant_post_link[ $locale ] ) : $relevant_post_link[ $locale ];
217 }
218 $relevant_pagelinks = '<br><br><p><em>' . $em_text . '</em><p>' . implode( '</br>', $relevant_pagelink );
219 }
220 } else {
221 $relevant_pagelinks = '';
222 }
223
224 $Qcld_Parsedown = new Qcld_Parsedown();
225
226 // Build context-aware content with system instructions
227 $system_instructions = '';
228 if ( get_option('gemeni_context_awareness_enabled') == '1' ) {
229 $site_name = get_bloginfo('name');
230 $site_desc = get_bloginfo('description');
231
232 // Get current page URL and title more reliably
233 $current_url = '';
234 $page_title = '';
235 $page_summary = '';
236
237 // Try to get from referrer first
238 $ref = wp_get_referer();
239 if ( ! $ref && isset($_SERVER['HTTP_REFERER']) ) {
240 $ref = esc_url_raw( $_SERVER['HTTP_REFERER'] );
241 }
242
243 if ( $ref ) {
244 $current_url = $ref;
245
246 // Try to get post/page by URL, fallback to query param if needed.
247 $post_id = url_to_postid( $ref );
248 if ( ! $post_id && isset( $_GET['p'] ) ) {
249 $post_id = intval( wp_unslash($_GET['p']) );
250 }
251 if ( $post_id ) {
252 $page_title = get_the_title( $post_id );
253 $raw_content = get_post_field( 'post_content', $post_id );
254 $text_content = wp_strip_all_tags( $raw_content );
255 $page_summary = wp_trim_words( $text_content, 120, '' );
256 } else {
257 // If not a post/page, try to extract title from URL or use current page
258 $parsed_url = wp_parse_url( $ref );
259 if ( isset($parsed_url['path']) ) {
260 $path = trim($parsed_url['path'], '/');
261 if ( ! empty($path) ) {
262 // Try to get title from current page if we're on it
263 if ( is_singular() ) {
264 $page_title = get_the_title();
265 $raw_content = get_the_content();
266 $text_content = wp_strip_all_tags( $raw_content );
267 $page_summary = wp_trim_words( $text_content, 120, '' );
268 } elseif ( is_archive() ) {
269 $page_title = get_the_archive_title();
270 } elseif ( is_search() ) {
271 $page_title = 'Search Results';
272 } elseif ( is_404() ) {
273 $page_title = 'Page Not Found';
274 }
275 }
276 }
277 }
278 } else {
279 // Fallback to current page info.
280 $scheme = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http");
281
282 // Sanitize HTTP_HOST and REQUEST_URI from $_SERVER.
283 $sanitized_host = isset($_SERVER['HTTP_HOST']) ? sanitize_text_field($_SERVER['HTTP_HOST']) : '';
284 $sanitized_request_uri = isset($_SERVER['REQUEST_URI']) ? esc_url_raw($_SERVER['REQUEST_URI']) : '';
285
286 // Construct the URL with sanitized components.
287 $current_url_temp = $scheme . '://' . $sanitized_host . $sanitized_request_uri;
288
289 // Final sanitization of the entire URL string.
290 $current_url = esc_url_raw($current_url_temp);
291
292 if ( is_singular() ) {
293 $page_title = get_the_title();
294 $raw_content = get_the_content();
295 $text_content = wp_strip_all_tags( $raw_content );
296 $page_summary = wp_trim_words( $text_content, 120, '' );
297 } elseif ( is_archive() ) {
298 $page_title = get_the_archive_title();
299 } elseif ( is_search() ) {
300 $page_title = 'Search Results';
301 } elseif ( is_404() ) {
302 $page_title = 'Page Not Found';
303 }
304 }
305
306 $context_bits = array();
307 if ( $site_name ) { $context_bits[] = 'Site: ' . $site_name; }
308 if ( $site_desc ) { $context_bits[] = 'Tagline: ' . $site_desc; }
309 if ( $page_title ) { $context_bits[] = 'Page title: ' . $page_title; }
310 if ( $current_url ) { $context_bits[] = 'URL: ' . $current_url; }
311 if ( $page_summary ) { $context_bits[] = 'Page summary: ' . $page_summary; }
312
313 if ( ! empty( $context_bits ) ) {
314 $system_instructions = 'Context Information: ' . implode( '. ', $context_bits ) . '. Please use this context to provide more relevant and accurate responses.';
315 }
316 }
317
318 // RAG Integration
319 if (get_option('is_page_rag_enabled') == '1') {
320 $rag_context_text = Qcld_Bot_Rag::instance()->run_rag_search($keyword);
321 if (!empty($rag_context_text) && $rag_context_text != "No knowledge base found.") {
322 $rag_context = "Relevant Knowledge Base Information:\n";
323 $rag_context .= $rag_context_text;
324 $rag_context .= "\n\nUse the above information to answer the user's question. If the answer is not in the Knowledge Base, rely on your general knowledge but mention that this information is not in the local knowledge base.";
325
326 if (!empty($system_instructions)) {
327 $system_instructions .= "\n\n" . $rag_context;
328 } else {
329 $system_instructions = $rag_context;
330 }
331 }
332 }
333
334 if ( ( get_option( 'page_suggestion_enabled' ) == '1' ) && count( $relevant_pagelink ) > 0 ) {
335 $relevant_post_link = maybe_unserialize( get_option( 'qlcd_wp_chatbot_relevant_post_link_openai' ) );
336 // Always use get_locale() to avoid undefined function error
337 $locale = get_locale();
338 if ( is_array( $relevant_post_link ) && isset( $relevant_post_link[ $locale ] ) && is_array( $relevant_post_link[ $locale ] ) ) {
339 $relevant_pagelinks = '<br><br><p><em>' . implode( '', $relevant_post_link[ $locale ] ) . '</em><p>' . implode( '</br>', $relevant_pagelink );
340 } else {
341 // Fallback: try to use $locale, but check if key exists
342 $em_text = '';
343 if ( is_array( $relevant_post_link ) && isset( $relevant_post_link[ $locale ] ) ) {
344 $em_text = is_array( $relevant_post_link[ $locale ] ) ? implode( '', $relevant_post_link[ $locale ] ) : $relevant_post_link[ $locale ];
345 }
346 $relevant_pagelinks = '<br><br><p><em>' . $em_text . '</em><p>' . implode( '</br>', $relevant_pagelink );
347 }
348 } else {
349 $relevant_pagelinks = '';
350 }
351
352 $selected_model = get_option('qcld_gemini_model') ? get_option('qcld_gemini_model') : 'gemini-2.5-flash';
353 // Gemini API expects a different payload and endpoint
354 $api_url = 'https://generativelanguage.googleapis.com/v1/models/' . $selected_model . ':generateContent';
355
356 // Build formatted messages with system instructions
357 $formatted_messages = [];
358
359 // Add system instructions as first user message if context is enabled
360 if ( ! empty( $system_instructions ) ) {
361 $formatted_messages[] = [
362 'role' => 'user',
363 'parts' => [
364 ['text' => "[System Instructions] " . $system_instructions]
365 ]
366 ];
367
368 // Add model response to acknowledge system instructions
369 $formatted_messages[] = [
370 'role' => 'model',
371 'parts' => [
372 ['text' => "I understand and will follow these instructions."]
373 ]
374 ];
375 }
376
377 // Add the actual user query
378 $formatted_messages[] = [
379 'role' => 'user',
380 'parts' => [
381 ['text' => $keyword]
382 ]
383 ];
384
385 $data = array(
386 'contents' => $formatted_messages,
387 );
388
389 // Use WordPress wp_remote_post for better error handling and consistency
390 $args = array(
391 'body' => json_encode($data),
392 'headers' => array(
393 'Content-Type' => 'application/json',
394 'X-goog-api-key' => $gemini_api_key,
395 ),
396 'timeout' => 60,
397 'redirection' => 5,
398 'blocking' => true,
399 'httpversion' => '1.0',
400 'sslverify' => true,
401 );
402
403 $result = wp_remote_post($api_url, $args);
404
405 // Check for WordPress errors
406 if (is_wp_error($result)) {
407 $response['status'] = 'error';
408 $response['message'] = 'API request failed: ' . $result->get_error_message();
409 } else {
410 $http_code = wp_remote_retrieve_response_code($result);
411 $response_body = wp_remote_retrieve_body($result);
412
413 if ($http_code === 200) {
414 $msg = json_decode($response_body);
415 // Gemini API returns candidates[0]->content->parts[0]->text
416 if (
417 isset($msg->candidates[0]->content->parts[0]->text)
418 && !empty($msg->candidates[0]->content->parts[0]->text)
419 ) {
420 $response['status'] = 'success';
421 $response['message'] = $Qcld_Parsedown->text( $msg->candidates[0]->content->parts[0]->text ) . $relevant_pagelinks;
422 } else {
423 $response['status'] = 'error';
424 $response['message'] = 'Invalid response format from Gemini API';
425 }
426 } else {
427 $response['status'] = 'error';
428 $response['message'] = 'API request failed with HTTP code: ' . $http_code;
429 }
430 }
431 do_action('qcld_openai_user_rate_cal', 1);
432 //echo wp_send_json( $response );
433 wp_send_json( $response );
434 }
435
436 public function qcld_gemini_get_model_list_callback() {
437 $nonce = sanitize_text_field(wp_unslash($_POST['nonce']));
438 if ( ! wp_verify_nonce( $nonce, 'wp_chatbot' ) ) {
439 wp_send_json_error( array( 'msg' => esc_html__( 'Failed in Security check', 'chatbot') ) );
440 }
441
442 $api_key = sanitize_text_field(wp_unslash($_POST['api_key']));
443 if ( empty( $api_key ) ) {
444 wp_send_json_error( array( 'msg' => esc_html__( 'API Key is required', 'chatbot') ) );
445 }
446
447 $url = "https://generativelanguage.googleapis.com/v1beta/models?key=" . $api_key;
448 $response_raw = wp_remote_get( $url, array( 'timeout' => 30 ) );
449 if ( is_wp_error( $response_raw ) ) {
450 $http_code = 500;
451 $response = wp_json_encode( array( 'error' => array( 'message' => $response_raw->get_error_message() ) ) );
452 } else {
453 $http_code = wp_remote_retrieve_response_code( $response_raw );
454 $response = wp_remote_retrieve_body( $response_raw );
455 }
456
457 if ( $http_code !== 200 ) {
458 $error_data = json_decode( $response, true );
459 $error_msg = isset( $error_data['error']['message'] ) ? $error_data['error']['message'] : 'Failed to fetch models';
460 wp_send_json_error( array( 'msg' => $error_msg ) );
461 }
462
463 $data = json_decode( $response, true );
464 $models = array();
465 if ( isset( $data['models'] ) ) {
466 foreach ( $data['models'] as $model ) {
467 if ( in_array( 'generateContent', $model['supportedGenerationMethods'] ) ) {
468 // Clean model name (models/gemini-pro -> gemini-pro)
469 $name = str_replace( 'models/', '', $model['name'] );
470 $models[] = array(
471 'id' => $name,
472 'name' => $model['displayName']
473 );
474 }
475 }
476 }
477
478 wp_send_json_success( array( 'models' => $models ) );
479 }
480 public function qcld_update_settings_option_callback(){
481 // Verify nonce for CSRF protection
482 $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
483 if (!wp_verify_nonce($nonce, 'wp_chatbot')) {
484 wp_send_json_error(array('message' => esc_html__('Security check failed', 'chatbot')));
485 wp_die();
486 }
487
488 // Check user capability - only administrators can modify settings
489 if (!current_user_can('manage_options')) {
490 wp_send_json_error(array('message' => esc_html__('Unauthorized access', 'chatbot')));
491 wp_die();
492 }
493
494 // Proceed with option updates
495 update_option('disable_wp_chatbot_site_search', 1);
496 update_option('enable_wp_chatbot_post_content', '');
497
498 // Send success response
499 wp_send_json_success(array('message' => esc_html__('Settings updated successfully', 'chatbot')));
500 wp_die();
501 }
502 }
503
504 /**
505 * @return qcld_wpopenai_addon
506 */
507 if(!function_exists('qcld_wpgemini_addons')){
508 function qcld_wpgemini_addons() {
509 $qcld_wpgemini_addon = new qcld_wpgemini_addons();
510 return $qcld_wpgemini_addon->instance();
511
512 }
513 }
514
515 //fire off the plugin
516 qcld_wpgemini_addons();
517
518 }