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/grok/qcld-bot-grok.php +669 -591 8.6.1 → 8.8.1 View file →
@@ -1,592 +1,670 @@
1 -<?php
2 -/**
3 - * grok AI
4 - *
5 - * @package Botmaster
6 - * @since 1.0.0
7 - */
8 -
9 -if ( ! defined( 'ABSPATH' ) ) {
10 - exit; // Exit if accessed directly.
11 -}
12 -
13 -if ( ! class_exists( 'qcld_wpgrok_addons' ) ) {
14 -
15 -
16 - /**
17 - * Main Class.
18 - */
19 - final class qcld_wpgrok_addons {
20 -
21 - private $id = 'Open AI';
22 -
23 - /**
24 - * WPBot Pro version.
25 - *
26 - * @var string
27 - */
28 - public $version = '1.0.6';
29 -
30 - /**
31 - * WPBot Pro helper.
32 - *
33 - * @var object
34 - */
35 - public $helper;
36 -
37 - /**
38 - * The single instance of the class.
39 - *
40 - * @var qcld_wb_Chatbot
41 - * @since 1.0.0
42 - */
43 - protected static $_instance = null;
44 -
45 - /**
46 - * Main wpbot Instance.
47 - *
48 - * Ensures only one instance of wpbot is loaded or can be loaded.
49 - *
50 - * @return qcld_wb_Chatbot - Main instance.
51 - * @since 1.0.0
52 - * @static
53 - */
54 - public static function instance() {
55 -
56 - if ( is_null( self::$_instance ) ) {
57 - self::$_instance = new self();
58 - }
59 -
60 - return self::$_instance;
61 - }
62 -
63 - public $response_list;
64 -
65 - /**
66 - * Constructor
67 - */
68 - public function __construct() {
69 - $this->includes();
70 - add_action( 'wp_ajax_qcld_grok_response', array( $this, 'grok_response_callback' ) );
71 - add_action( 'wp_ajax_nopriv_qcld_grok_response', array( $this, 'grok_response_callback' ) );
72 - add_action('wp_ajax_qcld_stream_grokai', array($this, 'qcld_stream_grok_callback'));
73 - add_action( 'wp_ajax_qcld_grok_add_collection', array( $this, 'qcld_grok_add_collection_callback' ) );
74 - add_action('wp_ajax_qcld_grok_collectionlist', array($this, 'qcld_grok_collectionlist_callback'));
75 - add_action('wp_ajax_nopriv_qcld_stream_grokai', array($this, 'qcld_stream_grok_callback'));
76 - add_action('wp_ajax_qcld_grok_remove_collection', array($this, 'qcld_grok_remove_collection_callback'));
77 - add_action( 'wp_ajax_qcld_grok_settings_option', array( $this, 'qcld_grok_settings_option_callback' ) );
78 - add_action( 'wp_ajax_qcld_grok_file_upload', array( $this, 'qcld_grok_file_upload_callback' ) );
79 - if ( is_admin() && ! empty( $_GET['page'] ) && ( ( $_GET['page'] == 'openai-panel_dashboard' ) || ( $_GET['page'] == 'openai-panel_file' ) || ( $_GET['page'] == 'wpbot_openAi' ) || ( $_GET['page'] == 'openai-panel_help' ) ) ) {// phpcs:ignore WordPress.Security.NonceVerification.Missing
80 - add_action( 'admin_enqueue_scripts', array( $this, 'qcld_wb_chatbot_grok_admin_scripts' ) );
81 - }
82 - // add_action('wp_enqueue_scripts', array($this, 'qcld_wb_chatbot_grok_scripts'));
83 -
84 - }
85 -
86 - public function qcld_wb_chatbot_grok_admin_scripts() {
87 - wp_register_script(
88 - 'qcld-wp-chatbot-grok-admin',
89 - QCLD_wpCHATBOT_PLUGIN_URL . 'includes/integration/grok/js/qcld-wp-grok-admin.js',
90 - array( 'jquery' ),
91 - QCLD_wpCHATBOT_VERSION,
92 - true
93 - );
94 -
95 - // Localize the script with necessary data.
96 - wp_localize_script(
97 - 'qcld-wp-chatbot-grok-admin',
98 - 'ajax_object',
99 - array(
100 - 'ajax_url' => admin_url( 'admin-ajax.php' ),
101 - 'ajax_nonce' => wp_create_nonce( 'wp_chatbot' ),
102 - 'grok_api_key' => get_option( 'qcld_grok_api_key' ),
103 - 'grok_model' => get_option( 'qcld_grok_model' ),
104 - 'grok_enabled' => get_option( 'qcld_grok_enabled' ),
105 - 'qcld_grok_rag_enabled' => get_option( 'qcld_grok_rag_enabled' ),
106 - 'qcld_grok_append_content' => get_option( 'qcld_grok_append_content' ),
107 - 'qcld_grok_prepend_content' => get_option( 'qcld_grok_prepend_content' ),
108 - )
109 - );
110 -
111 - wp_enqueue_script( 'qcld-wp-chatbot-grok-admin' );
112 - }
113 -
114 - /**
115 - * Define wpbot Constants.
116 - *
117 - * @return void
118 - * @since 1.0.0
119 - */
120 - public function includes() {
121 - require_once QCLD_wpCHATBOT_PLUGIN_DIR_PATH . 'includes/Parsedown.php';
122 - require_once QCLD_wpCHATBOT_PLUGIN_DIR_PATH . 'includes/class-common-function.php';
123 - }
124 -
125 - public function qcld_grok_settings_option_callback() {
126 - $nonce = sanitize_text_field(wp_unslash($_POST['nonce']));
127 - if ( ! wp_verify_nonce( $nonce, 'wp_chatbot' ) || ! current_user_can( 'manage_options' ) ) {
128 - wp_send_json(
129 - array(
130 - 'success' => false,
131 - 'msg' => esc_html__( 'Failed in Security check', 'chatbot'),
132 - )
133 - );
134 - wp_die();
135 - } else {
136 - $grok_api_key = sanitize_text_field( wp_unslash($_POST['grok_api_key']) ?? '' );
137 - $grok_model = sanitize_text_field( wp_unslash($_POST['grok_model']) ?? '' );
138 - $grok_enabled = sanitize_text_field(wp_unslash($_POST['grok_enabled']));
139 - $qcld_grok_page_suggestion_enabled = sanitize_text_field(wp_unslash($_POST['qcld_grok_page_suggestion_enabled']));
140 - $qcld_grok_append_content = sanitize_text_field(wp_unslash($_POST['qcld_grok_append_content'])) ?? '';
141 - $qcld_grok_prepend_content = sanitize_text_field(wp_unslash($_POST['qcld_grok_prepend_content'])) ?? '';
142 - $grok_rag_enabled = sanitize_text_field(wp_unslash($_POST['grok_rag_enabled'])) ?? '';
143 - $qcld_grok_system_content = sanitize_text_field(wp_unslash($_POST['qcld_grok_system_content'])) ?? '';
144 - $grok_stream_enabled = sanitize_text_field(wp_unslash($_POST['grok_stream_enabled'])) ?? '';
145 - $grok_management_api_key = sanitize_text_field( wp_unslash($_POST['grok_management_api_key']) ?? '' );
146 - $grok_collection_id = sanitize_text_field( wp_unslash($_POST['grok_collection_id']) ?? '' );
147 -
148 - if ( $grok_management_api_key != '' ) {
149 - update_option( 'qcld_grok_management_api_key', $grok_management_api_key );
150 - }
151 - if ( $grok_rag_enabled != '' ) {
152 - update_option( 'qcld_grok_rag_enabled', $grok_rag_enabled );
153 - }
154 - if ( $grok_stream_enabled != '' ) {
155 - update_option( 'qcld_grok_stream_enabled', $grok_stream_enabled );
156 - }
157 - if ( $grok_api_key != '' ) {
158 - update_option( 'qcld_grok_api_key', $grok_api_key );
159 - }
160 - if ( $grok_model != '' ) {
161 - update_option( 'qcld_grok_model', $grok_model );
162 - }
163 - if ( $grok_enabled != '' ) {
164 - update_option( 'qcld_grok_enabled', $grok_enabled );
165 - }
166 - if ( $grok_collection_id != '' ) {
167 - update_option( 'qcld_grok_collection_id', $grok_collection_id );
168 - }
169 - if ( $grok_enabled == '1' ) {
170 - update_option( 'ai_enabled', 0 );
171 - update_option( 'qcld_ollama_enabled', 0 );
172 - update_option('qcld_gemini_enabled', 0);
173 - update_option( 'qcld_openrouter_enabled', 0 );
174 - } else {
175 - update_option( 'ai_enabled', 1 );
176 - }
177 - if ( $qcld_grok_system_content != '' ) {
178 - update_option( 'qcld_grok_system_content', $qcld_grok_system_content );
179 - }
180 - update_option( 'qcld_grok_page_suggestion_enabled', $qcld_grok_page_suggestion_enabled );
181 - if ( isset( $_POST['openai_post_type'] ) ) {
182 - $openai_post_types = is_array( $_POST['openai_post_type'] )
183 - ? array_map( 'sanitize_text_field', wp_unslash( $_POST['openai_post_type'] ) )
184 - : sanitize_text_field( wp_unslash( $_POST['openai_post_type'] ) );
185 - update_option( 'qcld_openai_relevant_post', $openai_post_types );
186 - }
187 -
188 - update_option( 'qcld_grok_append_content', $qcld_grok_append_content );
189 - update_option( 'qcld_grok_prepend_content', $qcld_grok_prepend_content );
190 - }
191 - wp_send_json( $grok_enabled );
192 - }
193 -
194 - public function grok_response_callback() {
195 - if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'wp_chatbot' ) ) {
196 - wp_send_json_error([
197 - 'status' => 'error',
198 - 'message' => esc_html__( 'Security check failed. Unauthorized request.', 'chatbot' )
199 - ]);
200 - wp_die();
201 - }
202 -
203 - if (get_option('is_rate_limiting_enabled') == '1') {
204 - do_action('rate_limit_checker');
205 - }
206 - $grok_api_key = get_option( 'qcld_grok_api_key' );
207 - $keyword = isset($_POST['keyword']) ? sanitize_text_field( wp_unslash($_POST['keyword']) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
208 - $grok_system_content = get_option( 'qcld_grok_system_content' );
209 - $rag_context = "";
210 - if (get_option('qcld_grok_rag_enabled') == '1') {
211 - $rag_context = Qcld_Bot_Rag()->run_rag_search($keyword);
212 - }
213 - $relevant_pagelink = Qcld_WPBot_Common_Functions::qcpd_relevant_pagelink( $keyword );
214 - $relevant_pagelink = array_slice( $relevant_pagelink, 0, 5, true );
215 - if ( ( get_option( 'page_suggestion_enabled' ) == '1' ) && count( $relevant_pagelink ) > 0 ) {
216 - $relevant_post_link = maybe_unserialize( get_option( 'qlcd_wp_chatbot_relevant_post_link_openai' ) );
217 - if ( is_array( $relevant_post_link[ get_wpbot_locale() ] ) ) {
218 - $relevant_pagelinks = '<br><br><p><em>' . implode( '', $relevant_post_link[ get_wpbot_locale() ] ) . '</em><p>' . implode( '</br>', $relevant_pagelink );
219 - } else {
220 - $relevant_pagelinks = '<br><br><p><em>' . $relevant_post_link[ get_wpbot_locale() ] . '</em><p>' . implode( '</br>', $relevant_pagelink );
221 - }
222 - } else {
223 - $relevant_pagelinks = '';
224 - }
225 - $collection_id = get_option( 'qcld_grok_collection_id' ) ?? '';
226 - if( $collection_id != '' ) {
227 - $result = $this->direct_search_collection( $keyword );
228 - $response['status'] = 'success';
229 - $response['message'] = $result ;
230 - wp_send_json( $response );
231 - } else {
232 - $response_mess = wp_remote_post('https://api.x.ai/v1/chat/completions', [
233 - 'headers' => [
234 - 'Authorization' => 'Bearer ' . $grok_api_key,
235 - 'Content-Type' => 'application/json',
236 - ],
237 - 'body' => wp_json_encode([
238 - 'messages' => [
239 - ['role' => 'system', 'content' => $grok_system_content ?? 'You are a helpful and intelligent assistant for the website "' . site_url() . '". Use live website data and the provided context to respond accurately and briefly. Stay relevant and do not introduce additional topics.' ],
240 - ['role' => 'user', 'content' => $keyword ]
241 - ],
242 - 'model' => 'grok-3-latest',
243 - 'temperature' => 0,
244 - 'stream' => false
245 - ]),
246 - 'timeout' => 60,
247 - ]);
248 - $response['message'] = '';
249 - $status_code = wp_remote_retrieve_response_code($response_mess);
250 - // Step 2: Get the raw body (this is almost always what you want)
251 - $data = wp_remote_retrieve_body($response_mess);
252 - $data = json_decode($data, true); // Decode as associative array
253 - $response['status'] = 'success';
254 - $response['message'] = $data['choices'][0]['message']['content'] ?? 'No content received'; // true = assoc array
255 - do_action('qcld_openai_user_rate_cal', 1);
256 - wp_send_json( $response );
257 - }
258 - }
259 - public function qcld_stream_grok_callback()
260 - {
261 -
262 - if (!defined('ABSPATH')) {
263 - // Optional: protect direct access or require wp-load.php
264 - // For security → better to use admin-ajax or custom rewrite rule in production
265 - http_response_code(403);
266 - exit;
267 - }
268 -
269 - if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'wp_chatbot' ) ) {
270 - echo "data: [ERROR] Security check failed.\n\n";
271 - flush();
272 - wp_die();
273 - }
274 -
275 - if (get_option('is_rate_limiting_enabled') == '1') {
276 - do_action('rate_limit_checker');
277 - }
278 - $api_key = get_option('qcld_grok_api_key'); // ← Use get_option() or env in real code!
279 -
280 - // Disable compression (critical for streaming)
281 - if (function_exists('apache_setenv')) {
282 - @apache_setenv('no-gzip', 1);
283 - }
284 - @ini_set('zlib.output_compression', 0);
285 - while (ob_get_level() > 0) { ob_end_clean(); }
286 -
287 - set_time_limit(180); // Allow long-running requests
288 -
289 - $headers = [
290 - 'Content-Type: application/json',
291 - 'Authorization: Bearer ' . $api_key,
292 - ];
293 - $system_content = 'You are a helpful and intelligent assistant for the website "' . site_url() . '". Use live website data and the provided context to respond accurately and briefly. Stay relevant and do not introduce additional topics.';
294 - $messages = [];
295 - // Load previous conversation from cookie if continuity is enabled
296 - if ($conversation_continuity == 1 && !empty($_COOKIE['last_five_prompt'])) {
297 - $decoded_cookie = json_decode(stripslashes($_COOKIE['last_five_prompt']), true);
298 - if (is_array($decoded_cookie)) {
299 - $messages = $decoded_cookie;
300 - }
301 - }
302 - // Ensure system message is the first message.
303 - if (empty($messages) || (isset($messages[0]) && $messages[0]['role'] !== 'system')) {
304 - array_unshift($messages, ['role' => 'system', 'content' => $system_content]);
305 - } elseif (isset($messages[0]) && $messages[0]['role'] === 'system' && $messages[0]['content'] !== $system_content) {
306 - $messages[0]['content'] = $system_content;
307 - }
308 -
309 - array_push($messages, ['role' => 'user', 'content' => sanitize_text_field( wp_unslash( $_POST['message'] ) )]);
310 - $postData = json_encode([
311 - 'model' => 'grok-3-latest',
312 - 'messages' => $messages,
313 - 'stream' => true
314 - ]);
315 -
316 - // phpcs:ignore WordPress.WP.AlternativeFunctions -- streaming requires native cURL
317 - $ch = curl_init('https://api.x.ai/v1/chat/completions');
318 - curl_setopt($ch, CURLOPT_POST, true); // phpcs:ignore WordPress.WP.AlternativeFunctions
319 - curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // phpcs:ignore WordPress.WP.AlternativeFunctions
320 - curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); // phpcs:ignore WordPress.WP.AlternativeFunctions
321 - curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, $chunk) use (&$full_assistant_response) { // phpcs:ignore WordPress.WP.AlternativeFunctions
322 - echo $chunk; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- SSE streaming raw output
323 - echo str_repeat(' ', 1024); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- SSE streaming padding
324 - flush();
325 - ob_flush();
326 -
327 - // Parse the chunk to extract assistant's content for continuity.
328 - $lines = explode("\n", $chunk);
329 - foreach ($lines as $line) {
330 - if (strpos($line, 'data: ') === 0) {
331 - $json_data = substr($line, 6);
332 - if ($json_data === '[DONE]') {
333 - continue;
334 - }
335 - $data = json_decode($json_data, true);
336 - if (isset($data['choices'][0]['delta']['content'])) {
337 - $full_assistant_response .= $data['choices'][0]['delta']['content'];
338 - }
339 - }
340 - }
341 - return strlen($chunk);
342 - });
343 - curl_exec($ch); // phpcs:ignore WordPress.WP.AlternativeFunctions
344 - curl_close($ch); // phpcs:ignore WordPress.WP.AlternativeFunctions
345 - // phpcs:ignore WordPress.WP.AlternativeFunctions -- streaming requires native cURL
346 - $ch = curl_init('https://api.x.ai/v1/chat/completions');
347 -
348 - // phpcs:ignore WordPress.WP.AlternativeFunctions
349 - curl_setopt_array($ch, [
350 - CURLOPT_POST => true,
351 - CURLOPT_HTTPHEADER => $headers,
352 - CURLOPT_POSTFIELDS => $postData,
353 - CURLOPT_RETURNTRANSFER => false, // We echo ourselves
354 - CURLOPT_WRITEFUNCTION => function ($curl, $chunk) {
355 - echo $chunk; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- SSE streaming raw output
356 - flush(); // Push to browser immediately
357 - return strlen($chunk);
358 - },
359 - CURLOPT_TIMEOUT => 150,
360 - CURLOPT_CONNECTTIMEOUT => 30,
361 - CURLOPT_SSL_VERIFYPEER => true,
362 - CURLOPT_FOLLOWLOCATION => true,
363 - CURLOPT_ENCODING => '', // Let server decide
364 - ]);
365 -
366 - $success = curl_exec($ch); // phpcs:ignore WordPress.WP.AlternativeFunctions
367 - do_action('qcld_openai_user_rate_cal', 1);
368 - if (curl_errno($ch)) { // phpcs:ignore WordPress.WP.AlternativeFunctions
369 - $err = curl_error($ch); // phpcs:ignore WordPress.WP.AlternativeFunctions
370 - echo "data: " . wp_json_encode( array( 'error' => 'cURL error: ' . $err ) ) . "\n\n";
371 - flush();
372 - }
373 -
374 - curl_close($ch); // phpcs:ignore WordPress.WP.AlternativeFunctions
375 -
376 - // Final done signal (optional but nice)
377 - echo "data: [DONE]\n\n";
378 - flush();
379 - }
380 - public function qcld_grok_collectionlist_callback() {
381 - $nonce = sanitize_text_field( wp_unslash($_POST['nonce']) ?? '' );
382 - if ( ! wp_verify_nonce( $nonce, 'wp_chatbot' ) || ! current_user_can( 'manage_options' ) ) {
383 - wp_send_json(
384 - array(
385 - 'success' => false,
386 - 'msg' => esc_html__( 'Failed in Security check', 'chatbot'),
387 - )
388 - );
389 - wp_die();
390 - }
391 - $grok_api_key = get_option( 'qcld_grok_api_key' );
392 - $response_raw = wp_remote_get(
393 - 'https://api.x.ai/v1/collections',
394 - array(
395 - 'headers' => array(
396 - 'Authorization' => 'Bearer ' . $grok_api_key,
397 - 'Content-Type' => 'application/json',
398 - ),
399 - 'timeout' => 60,
400 - )
401 - );
402 - $response = json_decode( wp_remote_retrieve_body( $response_raw ), true );
403 - wp_send_json( $response );
404 - }
405 - public function qcld_grok_file_upload_callback()
406 - {
407 -
408 - $nonce = sanitize_text_field(wp_unslash($_POST['nonce']));
409 - if (! wp_verify_nonce($nonce, 'wp_chatbot') || ! current_user_can( 'manage_options' ) ) {
410 - wp_send_json(
411 - array(
412 - 'success' => false,
413 - 'msg' => esc_html__('Failed in Security check', 'chatbot'),
414 - )
415 - );
416 - wp_die();
417 - } else {
418 - // $uploadedfile = $_FILES['file'];
419 - // $collection_id = sanitize_text_field(wp_unslash($_POST['collection_id']));
420 - // $api_key = get_option( 'qcld_grok_api_key' );
421 -
422 - // $ch = curl_init();
423 -
424 - // $file = new CURLFile(
425 - // $uploadedfile['tmp_name'],
426 - // $uploadedfile['type'] ?: 'application/octet-stream',
427 - // $uploadedfile['name']
428 - // );
429 -
430 - // $post_data = ['file' => $file];
431 -
432 - // curl_setopt_array($ch, [
433 - // CURLOPT_URL => 'https://api.x.ai/v1/files',
434 - // CURLOPT_POST => true,
435 - // CURLOPT_POSTFIELDS => $post_data,
436 - // CURLOPT_RETURNTRANSFER => true,
437 - // CURLOPT_HTTPHEADER => [
438 - // 'Authorization: Bearer ' . $api_key,
439 - // // Do NOT add Content-Type here!!
440 - // ],
441 - // CURLOPT_TIMEOUT => 180,
442 - // CURLOPT_CONNECTTIMEOUT => 30,
443 - // ]);
444 -
445 - // $result = json_decode(curl_exec($ch));
446 - // $error = curl_error($ch);
447 - // curl_close($ch);
448 - // $file_id = $result->id
449 - $collection_id = "collection_22aa88f1-80e8-4e1a-8e13-c119afb0481c";
450 - $file_id = "file_06208083-0e27-44ff-af29-5faa211f4892";
451 - $this->add_file_to_collection($collection_id, $file_id, []);
452 - if (! empty($res->error)) {
453 - $response['status'] = 'error';
454 - $response['message'] = $res->error->message;
455 - }
456 -
457 - if (! empty($res->status)) {
458 - $response['status'] = 'success';
459 - $response['message'] = 'Successfully Created file' . $res->id;
460 - }
461 - // echo wp_send_json(array($response));
462 - // wp_die();
463 - }
464 - }
465 - public function add_file_to_collection($collection_id, $file_id, $metadata = []) {
466 - $url = "https://management-api.x.ai/v1/collections/{$collection_id}/documents/{$file_id}";
467 - $grok_management_api_key = get_option( 'qcld_grok_management_api_key' );
468 -
469 - $args = [
470 - 'method' => 'POST',
471 - 'timeout' => 30,
472 - 'redirection' => 5,
473 - 'httpversion' => '1.1',
474 - 'blocking' => true,
475 - 'headers' => [
476 - 'Authorization' => 'Bearer ' . $grok_management_api_key, // Management API key required
477 - 'Content-Type' => 'application/json',
478 - ],
479 - // 'body' => json_encode([
480 - // 'fields' => $metadata // Optional: matches your field_definitions
481 - // ]),
482 - ];
483 - // return ['success' => false, 'error' => $response->get_error_message()];
484 - $response = wp_remote_post( $url, $args );
485 - $body = wp_remote_retrieve_body( $response );
486 - $status_code = wp_remote_retrieve_response_code( $response );
487 - if ($status_code >= 200 && $status_code < 300) {
488 - return ['success' => true, 'message' => 'File added to collection', 'body' => $body];
489 - } else {
490 - return ['success' => false, 'status' => $status_code, 'error' => $body];
491 - }
492 - }
493 - public function qcld_grok_remove_collection_callback() {
494 - $nonce = sanitize_text_field( wp_unslash($_POST['nonce']) ?? '' );
495 - if ( ! wp_verify_nonce( $nonce, 'wp_chatbot' ) || ! current_user_can( 'manage_options' ) ) {
496 - wp_send_json(
497 - array(
498 - 'success' => false,
499 - 'msg' => esc_html__( 'Failed in Security check', 'chatbot'),
500 - )
501 - );
502 - wp_die();
503 - }
504 - $grok_api_key = get_option( 'qcld_grok_api_key' );
505 - $collection_id = sanitize_text_field( wp_unslash($_POST['collection_id']) ?? '' ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
506 - $url = 'https://api.x.ai/v1/collections/' . $collection_id; // Check exact endpoint in docs.x.ai
507 - $args = [
508 - 'method' => 'DELETE',
509 - 'headers' => [
510 - 'Authorization' => 'Bearer ' . $grok_api_key,
511 - 'Content-Type' => 'application/json'
512 - ],
513 - 'timeout' => 60,
514 - ];
515 - $response = wp_remote_request( $url, $args );
516 - $response_data = json_decode( wp_remote_retrieve_body( $response ), true );
517 - wp_send_json( $response_data );
518 - }
519 - public function qcld_grok_add_collection_callback() {
520 - $nonce = sanitize_text_field( wp_unslash($_POST['nonce']) ?? '' );
521 - if ( ! wp_verify_nonce( $nonce, 'wp_chatbot' ) || ! current_user_can( 'manage_options' ) ) {
522 - wp_send_json(
523 - array(
524 - 'success' => false,
525 - 'msg' => esc_html__( 'Failed in Security check', 'chatbot'),
526 - )
527 - );
528 - wp_die();
529 - }
530 - $grok_api_key = get_option( 'qcld_grok_api_key' );
531 - $collection_name = isset( $_POST['collection_name'] ) ? sanitize_text_field( wp_unslash( $_POST['collection_name'] ) ) : ( site_url() . wp_rand( 1, 999 ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
532 - $response_raw = wp_remote_post(
533 - 'https://api.x.ai/v1/collections',
534 - array(
535 - 'headers' => array(
536 - 'Authorization' => 'Bearer ' . $grok_api_key,
537 - 'Content-Type' => 'application/json',
538 - ),
539 - 'body' => wp_json_encode( array( 'collection_name' => $collection_name, 'field_definitions' => array() ) ),
540 - 'timeout' => 60,
541 - )
542 - );
543 - $response = json_decode( wp_remote_retrieve_body( $response_raw ), true );
544 - wp_send_json( $response );
545 - }
546 - public function direct_search_collection( $query ) {
547 -
548 - $collection_id = get_option( 'qcld_grok_collection_id' );
549 - $grok_api_key = get_option( 'qcld_grok_api_key' );
550 - $url = 'https://api.x.ai/v1/documents/search';
551 - $payload = [
552 - 'query' => $query,
553 - 'source' => ['collection_ids' => [$collection_id]],
554 - 'retrieval_mode' => ['type' => 'hybrid'] // or 'semantic', 'keyword'
555 - ];
556 - $args = [
557 - 'method' => 'POST',
558 - 'headers' => [
559 - 'Authorization' => 'Bearer ' . $grok_api_key,
560 - 'Content-Type' => 'application/json',
561 - ],
562 - 'body' => wp_json_encode($payload),
563 - 'timeout' => 30,
564 - ];
565 - $response = wp_remote_post($url, $args);
566 - $result = json_decode(wp_remote_retrieve_body($response), true);
567 - if (is_wp_error($response)) {
568 - return ['error' => $response->get_error_message()];
569 - }
570 - foreach ($result['matches'] as $key => $match) {
571 - if ($key >= 1) break;
572 - $responses = $match ["chunk_content"];
573 - }
574 - return $responses;
575 - }
576 - }
577 -
578 - /**
579 - * @return qcld_wpopenai_addon
580 - */
581 - if ( ! function_exists( 'qcld_wpgrok_addons' ) ) {
582 -
583 - function qcld_wpgrok_addons() {
584 - $qcld_wpgrok_addon = new qcld_wpgrok_addons();
585 - return $qcld_wpgrok_addon->instance();
586 - }
587 - }
588 -
589 - // fire off the plugin.
590 - qcld_wpgrok_addons();
591 -
1 +<?php
2 +/**
3 + * grok AI
4 + *
5 + * @package Botmaster
6 + * @since 1.0.0
7 + */
8 +
9 +if ( ! defined( 'ABSPATH' ) ) {
10 + exit; // Exit if accessed directly.
11 +}
12 +
13 +if ( ! class_exists( 'qcld_wpgrok_addons' ) ) {
14 +
15 +
16 + /**
17 + * Main Class.
18 + */
19 + final class qcld_wpgrok_addons {
20 +
21 + private $id = 'Open AI';
22 +
23 + /**
24 + * WPBot Pro version.
25 + *
26 + * @var string
27 + */
28 + public $version = '1.0.6';
29 +
30 + /**
31 + * WPBot Pro helper.
32 + *
33 + * @var object
34 + */
35 + public $helper;
36 +
37 + /**
38 + * The single instance of the class.
39 + *
40 + * @var qcld_wb_Chatbot
41 + * @since 1.0.0
42 + */
43 + protected static $_instance = null;
44 +
45 + /**
46 + * Main wpbot Instance.
47 + *
48 + * Ensures only one instance of wpbot is loaded or can be loaded.
49 + *
50 + * @return qcld_wb_Chatbot - Main instance.
51 + * @since 1.0.0
52 + * @static
53 + */
54 + public static function instance() {
55 +
56 + if ( is_null( self::$_instance ) ) {
57 + self::$_instance = new self();
58 + }
59 +
60 + return self::$_instance;
61 + }
62 +
63 + public $response_list;
64 +
65 + /**
66 + * Constructor
67 + */
68 + public function __construct() {
69 + $this->includes();
70 + add_action( 'wp_ajax_qcld_grok_response', array( $this, 'grok_response_callback' ) );
71 + add_action( 'wp_ajax_nopriv_qcld_grok_response', array( $this, 'grok_response_callback' ) );
72 + add_action('wp_ajax_qcld_stream_grokai', array($this, 'qcld_stream_grok_callback'));
73 + add_action( 'wp_ajax_qcld_grok_add_collection', array( $this, 'qcld_grok_add_collection_callback' ) );
74 + add_action('wp_ajax_qcld_grok_collectionlist', array($this, 'qcld_grok_collectionlist_callback'));
75 + add_action('wp_ajax_nopriv_qcld_stream_grokai', array($this, 'qcld_stream_grok_callback'));
76 + add_action('wp_ajax_qcld_grok_remove_collection', array($this, 'qcld_grok_remove_collection_callback'));
77 + add_action( 'wp_ajax_qcld_grok_settings_option', array( $this, 'qcld_grok_settings_option_callback' ) );
78 + add_action( 'wp_ajax_qcld_grok_file_upload', array( $this, 'qcld_grok_file_upload_callback' ) );
79 + if ( is_admin() && ! empty( $_GET['page'] ) && ( ( $_GET['page'] == 'openai-panel_dashboard' ) || ( $_GET['page'] == 'openai-panel_file' ) || ( $_GET['page'] == 'wpbot_openAi' ) || ( $_GET['page'] == 'openai-panel_help' ) ) ) {// phpcs:ignore WordPress.Security.NonceVerification.Missing
80 + add_action( 'admin_enqueue_scripts', array( $this, 'qcld_wb_chatbot_grok_admin_scripts' ) );
81 + }
82 + // add_action('wp_enqueue_scripts', array($this, 'qcld_wb_chatbot_grok_scripts'));
83 +
84 + }
85 +
86 + public function qcld_wb_chatbot_grok_admin_scripts() {
87 + wp_register_script(
88 + 'qcld-wp-chatbot-grok-admin',
89 + QCLD_wpCHATBOT_PLUGIN_URL . 'includes/integration/grok/js/qcld-wp-grok-admin.js',
90 + array( 'jquery' ),
91 + QCLD_wpCHATBOT_VERSION,
92 + true
93 + );
94 +
95 + // Localize the script with necessary data.
96 + wp_localize_script(
97 + 'qcld-wp-chatbot-grok-admin',
98 + 'ajax_object',
99 + array(
100 + 'ajax_url' => admin_url( 'admin-ajax.php' ),
101 + 'ajax_nonce' => wp_create_nonce( 'wp_chatbot' ),
102 + 'grok_api_key' => get_option( 'qcld_grok_api_key' ),
103 + 'grok_model' => get_option( 'qcld_grok_model' ),
104 + 'grok_enabled' => get_option( 'qcld_grok_enabled' ),
105 + 'qcld_grok_rag_enabled' => get_option( 'qcld_grok_rag_enabled' ),
106 + 'qcld_grok_append_content' => get_option( 'qcld_grok_append_content' ),
107 + 'qcld_grok_prepend_content' => get_option( 'qcld_grok_prepend_content' ),
108 + )
109 + );
110 +
111 + wp_enqueue_script( 'qcld-wp-chatbot-grok-admin' );
112 + }
113 +
114 + /**
115 + * Define wpbot Constants.
116 + *
117 + * @return void
118 + * @since 1.0.0
119 + */
120 + public function includes() {
121 + require_once QCLD_wpCHATBOT_PLUGIN_DIR_PATH . 'includes/Parsedown.php';
122 + require_once QCLD_wpCHATBOT_PLUGIN_DIR_PATH . 'includes/class-common-function.php';
123 + }
124 +
125 + public function qcld_grok_settings_option_callback() {
126 + $nonce = sanitize_text_field(wp_unslash($_POST['nonce']));
127 + if ( ! wp_verify_nonce( $nonce, 'wp_chatbot' ) || ! current_user_can( 'manage_options' ) ) {
128 + wp_send_json(
129 + array(
130 + 'success' => false,
131 + 'msg' => esc_html__( 'Failed in Security check', 'chatbot'),
132 + )
133 + );
134 + wp_die();
135 + } else {
136 + $grok_api_key = sanitize_text_field( wp_unslash($_POST['grok_api_key']) ?? '' );
137 + $grok_model = sanitize_text_field( wp_unslash($_POST['grok_model']) ?? '' );
138 + $grok_enabled = sanitize_text_field(wp_unslash($_POST['grok_enabled']));
139 + $qcld_grok_page_suggestion_enabled = sanitize_text_field(wp_unslash($_POST['qcld_grok_page_suggestion_enabled']));
140 + $qcld_grok_append_content = sanitize_text_field(wp_unslash($_POST['qcld_grok_append_content'])) ?? '';
141 + $qcld_grok_prepend_content = sanitize_text_field(wp_unslash($_POST['qcld_grok_prepend_content'])) ?? '';
142 + $grok_rag_enabled = sanitize_text_field(wp_unslash($_POST['grok_rag_enabled'])) ?? '';
143 + $qcld_grok_system_content = sanitize_text_field(wp_unslash($_POST['qcld_grok_system_content'])) ?? '';
144 + $grok_stream_enabled = sanitize_text_field(wp_unslash($_POST['grok_stream_enabled'])) ?? '';
145 + $grok_management_api_key = sanitize_text_field( wp_unslash($_POST['grok_management_api_key']) ?? '' );
146 + $grok_collection_id = sanitize_text_field( wp_unslash($_POST['grok_collection_id']) ?? '' );
147 +
148 + if ( $grok_management_api_key != '' ) {
149 + update_option( 'qcld_grok_management_api_key', $grok_management_api_key );
150 + }
151 + if ( $grok_rag_enabled != '' ) {
152 + update_option( 'qcld_grok_rag_enabled', $grok_rag_enabled );
153 + }
154 + if ( $grok_stream_enabled != '' ) {
155 + update_option( 'qcld_grok_stream_enabled', $grok_stream_enabled );
156 + }
157 + if ( $grok_api_key != '' ) {
158 + update_option( 'qcld_grok_api_key', $grok_api_key );
159 + }
160 + if ( $grok_model != '' ) {
161 + update_option( 'qcld_grok_model', $grok_model );
162 + }
163 + if ( $grok_enabled != '' ) {
164 + update_option( 'qcld_grok_enabled', $grok_enabled );
165 + }
166 + if ( $grok_collection_id != '' ) {
167 + update_option( 'qcld_grok_collection_id', $grok_collection_id );
168 + }
169 + if ( $grok_enabled == '1' ) {
170 + update_option( 'ai_enabled', 0 );
171 + update_option( 'qcld_ollama_enabled', 0 );
172 + update_option('qcld_gemini_enabled', 0);
173 + update_option( 'qcld_openrouter_enabled', 0 );
174 + update_option('disable_wp_chatbot_site_search',1);
175 + }
176 + if ( $qcld_grok_system_content != '' ) {
177 + update_option( 'qcld_grok_system_content', $qcld_grok_system_content );
178 + }
179 + update_option( 'qcld_grok_page_suggestion_enabled', $qcld_grok_page_suggestion_enabled );
180 + if ( isset( $_POST['openai_post_type'] ) ) {
181 + $openai_post_types = is_array( $_POST['openai_post_type'] )
182 + ? array_map( 'sanitize_text_field', wp_unslash( $_POST['openai_post_type'] ) )
183 + : sanitize_text_field( wp_unslash( $_POST['openai_post_type'] ) );
184 + update_option( 'qcld_openai_relevant_post', $openai_post_types );
185 + }
186 +
187 + update_option( 'qcld_grok_append_content', $qcld_grok_append_content );
188 + update_option( 'qcld_grok_prepend_content', $qcld_grok_prepend_content );
189 + }
190 + wp_send_json( $grok_enabled );
191 + }
192 +
193 + public function grok_response_callback() {
194 + if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'wp_chatbot' ) ) {
195 + wp_send_json_error([
196 + 'status' => 'error',
197 + 'message' => esc_html__( 'Security check failed. Unauthorized request.', 'chatbot' )
198 + ]);
199 + wp_die();
200 + }
201 +
202 + if (get_option('is_rate_limiting_enabled') == '1') {
203 + do_action('rate_limit_checker');
204 + }
205 + $grok_api_key = get_option( 'qcld_grok_api_key' );
206 + $keyword = isset($_POST['keyword']) ? sanitize_text_field( wp_unslash($_POST['keyword']) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
207 + $grok_system_content = get_option( 'qcld_grok_system_content' );
208 +
209 + // AI Interactive Form
210 + if (get_option('enable_ai_interactive_form') == '1') {
211 + $saved_ai_forms = get_option('wpbot_ai_forms', array());
212 + if (!empty($saved_ai_forms) && is_array($saved_ai_forms)) {
213 + $grok_system_content .= "\n\nYou must handle the following interactive forms when the user asks for them:\n";
214 + foreach ($saved_ai_forms as $form) {
215 + $grok_system_content .= "\nForm Title: " . $form['title'] . "\nInstructions: " . $form['prompt'] . "\n";
216 + }
217 + $grok_system_content .= "\n\nCRITICAL INSTRUCTIONS FOR INTERACTIVE FORMS:\n";
218 + $grok_system_content .= "When a user triggers an interactive form, you must act as a step-by-step data collection agent.\n";
219 + $grok_system_content .= "1. DO NOT ask all questions at once. Ask exactly ONE question at a time.\n";
220 + $grok_system_content .= "2. Wait for the user's response before asking the next question.\n";
221 + $grok_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";
222 + $grok_system_content .= "__AI_FORM_DATA__{ \"form_title\": \"<Form Title>\", \"data\": { \"Question 1\": \"Answer 1\", \"Question 2\": \"Answer 2\" } }__AI_FORM_DATA_END__\n";
223 + $grok_system_content .= "Do not include any other text after this JSON block once the form is complete.\n";
224 + $grok_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";
225 + $grok_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.";
226 + }
227 + }
228 +
229 + $action_prompt = !empty($_POST['action_prompt']) ? wp_unslash($_POST['action_prompt']) : '';
230 + if (!empty($action_prompt)) {
231 + $grok_system_content .= "\n\nCRITICAL ACTIVE ACTION INSTRUCTION:\n" . $action_prompt;
232 + }
233 +
234 + $rag_context = "";
235 + if (get_option('qcld_grok_rag_enabled') == '1') {
236 + $rag_context = Qcld_Bot_Rag()->run_rag_search($keyword);
237 + if (!empty($rag_context) && $rag_context != "No knowledge base found.") {
238 + $grok_system_content .= "\n\nRelevant Knowledge Base Information:\n" . $rag_context;
239 + }
240 + }
241 + $relevant_pagelink = Qcld_WPBot_Common_Functions::qcpd_relevant_pagelink( $keyword );
242 + $relevant_pagelink = array_slice( $relevant_pagelink, 0, 5, true );
243 + if ( ( get_option( 'page_suggestion_enabled' ) == '1' ) && count( $relevant_pagelink ) > 0 ) {
244 + $relevant_post_link = maybe_unserialize( get_option( 'qlcd_wp_chatbot_relevant_post_link_openai' ) );
245 + if ( is_array( $relevant_post_link[ get_wpbot_locale() ] ) ) {
246 + $relevant_pagelinks = '<br><br><p><em>' . implode( '', $relevant_post_link[ get_wpbot_locale() ] ) . '</em><p>' . implode( '</br>', $relevant_pagelink );
247 + } else {
248 + $relevant_pagelinks = '<br><br><p><em>' . $relevant_post_link[ get_wpbot_locale() ] . '</em><p>' . implode( '</br>', $relevant_pagelink );
249 + }
250 + } else {
251 + $relevant_pagelinks = '';
252 + }
253 + $collection_id = get_option( 'qcld_grok_collection_id' ) ?? '';
254 + if( $collection_id != '' ) {
255 + $result = $this->direct_search_collection( $keyword );
256 + $response['status'] = 'success';
257 + $response['message'] = $result ;
258 + wp_send_json( $response );
259 + } else {
260 + $messages = [
261 + ['role' => 'system', 'content' => $grok_system_content ?? 'You are a helpful and intelligent assistant for the website "' . site_url() . '". Use live website data and the provided context to respond accurately and briefly. Stay relevant and do not introduce additional topics.' ]
262 + ];
263 +
264 + if (!empty($_POST['ai_history'])) {
265 + $parsed_history = json_decode(wp_unslash($_POST['ai_history']), true);
266 + if (is_array($parsed_history)) {
267 + foreach ($parsed_history as $h) {
268 + if (isset($h['role']) && isset($h['content'])) {
269 + $role = ($h['role'] === 'assistant') ? 'assistant' : 'user';
270 + $messages[] = [
271 + 'role' => $role,
272 + 'content' => sanitize_text_field($h['content'])
273 + ];
274 + }
275 + }
276 + }
277 + }
278 +
279 + $last_msg = end($messages);
280 + if (!$last_msg || $last_msg['role'] !== 'user' || $last_msg['content'] !== $keyword) {
281 + $messages[] = ['role' => 'user', 'content' => $keyword];
282 + }
283 +
284 + $response_mess = wp_remote_post('https://api.x.ai/v1/chat/completions', [
285 + 'headers' => [
286 + 'Authorization' => 'Bearer ' . $grok_api_key,
287 + 'Content-Type' => 'application/json',
288 + ],
289 + 'body' => wp_json_encode([
290 + 'messages' => $messages,
291 + 'model' => 'grok-3-latest',
292 + 'temperature' => 0,
293 + 'stream' => false
294 + ]),
295 + 'timeout' => 60,
296 + ]);
297 + $response['message'] = '';
298 + $status_code = wp_remote_retrieve_response_code($response_mess);
299 + $data = wp_remote_retrieve_body($response_mess);
300 + $data = json_decode($data, true);
301 + do_action('qcld_openai_user_rate_cal', 1);
302 + $response['status'] = 'success';
303 + $reply_raw = $data['choices'][0]['message']['content'] ?? 'No content received';
304 + $Parsedown = new Parsedown();
305 + $reply_text = $Parsedown->text($reply_raw);
306 + if (strpos($reply_text, 'AI_FORM_DATA') !== false) {
307 + $reply_text = Qcld_WPBot_Common_Functions::format_and_save_ai_form_response($reply_text);
308 + $response['message'] = $reply_text;
309 + } else {
310 + $response['message'] = $reply_text . $relevant_pagelinks;
311 + }
312 + wp_send_json( $response );
313 + }
314 + }
315 + public function qcld_stream_grok_callback()
316 + {
317 +
318 + if (!defined('ABSPATH')) {
319 + // Optional: protect direct access or require wp-load.php
320 + // For security → better to use admin-ajax or custom rewrite rule in production
321 + http_response_code(403);
322 + exit;
323 + }
324 +
325 + if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'wp_chatbot' ) ) {
326 + echo "data: [ERROR] Security check failed.\n\n";
327 + flush();
328 + wp_die();
329 + }
330 +
331 + if (get_option('is_rate_limiting_enabled') == '1') {
332 + do_action('rate_limit_checker');
333 + }
334 + $api_key = get_option('qcld_grok_api_key'); // ← Use get_option() or env in real code!
335 +
336 + // Disable compression (critical for streaming)
337 + if (function_exists('apache_setenv')) {
338 + @apache_setenv('no-gzip', 1);
339 + }
340 + @ini_set('zlib.output_compression', 0);
341 + while (ob_get_level() > 0) { ob_end_clean(); }
342 +
343 + set_time_limit(180); // Allow long-running requests
344 +
345 + $headers = [
346 + 'Content-Type: application/json',
347 + 'Authorization: Bearer ' . $api_key,
348 + ];
349 + $system_content = get_option( 'qcld_grok_system_content' );
350 + if (empty($system_content)) {
351 + $system_content = 'You are a helpful and intelligent assistant for the website "' . site_url() . '". Use live website data and the provided context to respond accurately and briefly. Stay relevant and do not introduce additional topics.';
352 + }
353 + // AI Interactive Form
354 + if (get_option('enable_ai_interactive_form') == '1') {
355 + $saved_ai_forms = get_option('wpbot_ai_forms', array());
356 + if (!empty($saved_ai_forms) && is_array($saved_ai_forms)) {
357 + $system_content .= "\n\nYou must handle the following interactive forms when the user asks for them:\n";
358 + foreach ($saved_ai_forms as $form) {
359 + $system_content .= "\nForm Title: " . $form['title'] . "\nInstructions: " . $form['prompt'] . "\n";
360 + }
361 + $system_content .= "\n\nCRITICAL INSTRUCTIONS FOR INTERACTIVE FORMS:\n";
362 + $system_content .= "When a user triggers an interactive form, you must act as a step-by-step data collection agent.\n";
363 + $system_content .= "1. DO NOT ask all questions at once. Ask exactly ONE question at a time.\n";
364 + $system_content .= "2. Wait for the user's response before asking the next question.\n";
365 + $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";
366 + $system_content .= "__AI_FORM_DATA__{ \"form_title\": \"<Form Title>\", \"data\": { \"Question 1\": \"Answer 1\", \"Question 2\": \"Answer 2\" } }__AI_FORM_DATA_END__\n";
367 + $system_content .= "Do not include any other text after this JSON block once the form is complete.\n";
368 + $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";
369 + $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.";
370 + }
371 + }
372 + $messages = [];
373 + // Load previous conversation from cookie if continuity is enabled
374 + if ($conversation_continuity == 1 && !empty($_COOKIE['last_five_prompt'])) {
375 + $decoded_cookie = json_decode(stripslashes($_COOKIE['last_five_prompt']), true);
376 + if (is_array($decoded_cookie)) {
377 + $messages = $decoded_cookie;
378 + }
379 + }
380 + // Ensure system message is the first message.
381 + if (empty($messages) || (isset($messages[0]) && $messages[0]['role'] !== 'system')) {
382 + array_unshift($messages, ['role' => 'system', 'content' => $system_content]);
383 + } elseif (isset($messages[0]) && $messages[0]['role'] === 'system' && $messages[0]['content'] !== $system_content) {
384 + $messages[0]['content'] = $system_content;
385 + }
386 +
387 + array_push($messages, ['role' => 'user', 'content' => sanitize_text_field( wp_unslash( $_POST['message'] ) )]);
388 + $postData = json_encode([
389 + 'model' => 'grok-3-latest',
390 + 'messages' => $messages,
391 + 'stream' => true
392 + ]);
393 +
394 + // phpcs:ignore WordPress.WP.AlternativeFunctions -- streaming requires native cURL
395 + $ch = curl_init('https://api.x.ai/v1/chat/completions');
396 + curl_setopt($ch, CURLOPT_POST, true); // phpcs:ignore WordPress.WP.AlternativeFunctions
397 + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // phpcs:ignore WordPress.WP.AlternativeFunctions
398 + curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); // phpcs:ignore WordPress.WP.AlternativeFunctions
399 + curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, $chunk) use (&$full_assistant_response) { // phpcs:ignore WordPress.WP.AlternativeFunctions
400 + echo $chunk; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- SSE streaming raw output
401 + echo str_repeat(' ', 1024); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- SSE streaming padding
402 + flush();
403 + ob_flush();
404 +
405 + // Parse the chunk to extract assistant's content for continuity.
406 + $lines = explode("\n", $chunk);
407 + foreach ($lines as $line) {
408 + if (strpos($line, 'data: ') === 0) {
409 + $json_data = substr($line, 6);
410 + if ($json_data === '[DONE]') {
411 + continue;
412 + }
413 + $data = json_decode($json_data, true);
414 + if (isset($data['choices'][0]['delta']['content'])) {
415 + $full_assistant_response .= $data['choices'][0]['delta']['content'];
416 + }
417 + }
418 + }
419 + return strlen($chunk);
420 + });
421 + curl_exec($ch); // phpcs:ignore WordPress.WP.AlternativeFunctions
422 + curl_close($ch); // phpcs:ignore WordPress.WP.AlternativeFunctions
423 + // phpcs:ignore WordPress.WP.AlternativeFunctions -- streaming requires native cURL
424 + $ch = curl_init('https://api.x.ai/v1/chat/completions');
425 +
426 + // phpcs:ignore WordPress.WP.AlternativeFunctions
427 + curl_setopt_array($ch, [
428 + CURLOPT_POST => true,
429 + CURLOPT_HTTPHEADER => $headers,
430 + CURLOPT_POSTFIELDS => $postData,
431 + CURLOPT_RETURNTRANSFER => false, // We echo ourselves
432 + CURLOPT_WRITEFUNCTION => function ($curl, $chunk) {
433 + echo $chunk; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- SSE streaming raw output
434 + flush(); // Push to browser immediately
435 + return strlen($chunk);
436 + },
437 + CURLOPT_TIMEOUT => 150,
438 + CURLOPT_CONNECTTIMEOUT => 30,
439 + CURLOPT_SSL_VERIFYPEER => true,
440 + CURLOPT_FOLLOWLOCATION => true,
441 + CURLOPT_ENCODING => '', // Let server decide
442 + ]);
443 +
444 + $success = curl_exec($ch); // phpcs:ignore WordPress.WP.AlternativeFunctions
445 + do_action('qcld_openai_user_rate_cal', 1);
446 + if (curl_errno($ch)) { // phpcs:ignore WordPress.WP.AlternativeFunctions
447 + $err = curl_error($ch); // phpcs:ignore WordPress.WP.AlternativeFunctions
448 + echo "data: " . wp_json_encode( array( 'error' => 'cURL error: ' . $err ) ) . "\n\n";
449 + flush();
450 + }
451 +
452 + curl_close($ch); // phpcs:ignore WordPress.WP.AlternativeFunctions
453 +
454 + // Final done signal (optional but nice)
455 + echo "data: [DONE]\n\n";
456 + flush();
457 + }
458 + public function qcld_grok_collectionlist_callback() {
459 + $nonce = sanitize_text_field( wp_unslash($_POST['nonce']) ?? '' );
460 + if ( ! wp_verify_nonce( $nonce, 'wp_chatbot' ) || ! current_user_can( 'manage_options' ) ) {
461 + wp_send_json(
462 + array(
463 + 'success' => false,
464 + 'msg' => esc_html__( 'Failed in Security check', 'chatbot'),
465 + )
466 + );
467 + wp_die();
468 + }
469 + $grok_api_key = get_option( 'qcld_grok_api_key' );
470 + $response_raw = wp_remote_get(
471 + 'https://api.x.ai/v1/collections',
472 + array(
473 + 'headers' => array(
474 + 'Authorization' => 'Bearer ' . $grok_api_key,
475 + 'Content-Type' => 'application/json',
476 + ),
477 + 'timeout' => 60,
478 + )
479 + );
480 + $response = json_decode( wp_remote_retrieve_body( $response_raw ), true );
481 + wp_send_json( $response );
482 + }
483 + public function qcld_grok_file_upload_callback()
484 + {
485 +
486 + $nonce = sanitize_text_field(wp_unslash($_POST['nonce']));
487 + if (! wp_verify_nonce($nonce, 'wp_chatbot') || ! current_user_can( 'manage_options' ) ) {
488 + wp_send_json(
489 + array(
490 + 'success' => false,
491 + 'msg' => esc_html__('Failed in Security check', 'chatbot'),
492 + )
493 + );
494 + wp_die();
495 + } else {
496 + // $uploadedfile = $_FILES['file'];
497 + // $collection_id = sanitize_text_field(wp_unslash($_POST['collection_id']));
498 + // $api_key = get_option( 'qcld_grok_api_key' );
499 +
500 + // $ch = curl_init();
501 +
502 + // $file = new CURLFile(
503 + // $uploadedfile['tmp_name'],
504 + // $uploadedfile['type'] ?: 'application/octet-stream',
505 + // $uploadedfile['name']
506 + // );
507 +
508 + // $post_data = ['file' => $file];
509 +
510 + // curl_setopt_array($ch, [
511 + // CURLOPT_URL => 'https://api.x.ai/v1/files',
512 + // CURLOPT_POST => true,
513 + // CURLOPT_POSTFIELDS => $post_data,
514 + // CURLOPT_RETURNTRANSFER => true,
515 + // CURLOPT_HTTPHEADER => [
516 + // 'Authorization: Bearer ' . $api_key,
517 + // // Do NOT add Content-Type here!!
518 + // ],
519 + // CURLOPT_TIMEOUT => 180,
520 + // CURLOPT_CONNECTTIMEOUT => 30,
521 + // ]);
522 +
523 + // $result = json_decode(curl_exec($ch));
524 + // $error = curl_error($ch);
525 + // curl_close($ch);
526 + // $file_id = $result->id
527 + $collection_id = "collection_22aa88f1-80e8-4e1a-8e13-c119afb0481c";
528 + $file_id = "file_06208083-0e27-44ff-af29-5faa211f4892";
529 + $this->add_file_to_collection($collection_id, $file_id, []);
530 + if (! empty($res->error)) {
531 + $response['status'] = 'error';
532 + $response['message'] = $res->error->message;
533 + }
534 +
535 + if (! empty($res->status)) {
536 + $response['status'] = 'success';
537 + $response['message'] = 'Successfully Created file' . $res->id;
538 + }
539 + // echo wp_send_json(array($response));
540 + // wp_die();
541 + }
542 + }
543 + public function add_file_to_collection($collection_id, $file_id, $metadata = []) {
544 + $url = "https://management-api.x.ai/v1/collections/{$collection_id}/documents/{$file_id}";
545 + $grok_management_api_key = get_option( 'qcld_grok_management_api_key' );
546 +
547 + $args = [
548 + 'method' => 'POST',
549 + 'timeout' => 30,
550 + 'redirection' => 5,
551 + 'httpversion' => '1.1',
552 + 'blocking' => true,
553 + 'headers' => [
554 + 'Authorization' => 'Bearer ' . $grok_management_api_key, // Management API key required
555 + 'Content-Type' => 'application/json',
556 + ],
557 + // 'body' => json_encode([
558 + // 'fields' => $metadata // Optional: matches your field_definitions
559 + // ]),
560 + ];
561 + // return ['success' => false, 'error' => $response->get_error_message()];
562 + $response = wp_remote_post( $url, $args );
563 + $body = wp_remote_retrieve_body( $response );
564 + $status_code = wp_remote_retrieve_response_code( $response );
565 + if ($status_code >= 200 && $status_code < 300) {
566 + return ['success' => true, 'message' => 'File added to collection', 'body' => $body];
567 + } else {
568 + return ['success' => false, 'status' => $status_code, 'error' => $body];
569 + }
570 + }
571 + public function qcld_grok_remove_collection_callback() {
572 + $nonce = sanitize_text_field( wp_unslash($_POST['nonce']) ?? '' );
573 + if ( ! wp_verify_nonce( $nonce, 'wp_chatbot' ) || ! current_user_can( 'manage_options' ) ) {
574 + wp_send_json(
575 + array(
576 + 'success' => false,
577 + 'msg' => esc_html__( 'Failed in Security check', 'chatbot'),
578 + )
579 + );
580 + wp_die();
581 + }
582 + $grok_api_key = get_option( 'qcld_grok_api_key' );
583 + $collection_id = sanitize_text_field( wp_unslash($_POST['collection_id']) ?? '' ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
584 + $url = 'https://api.x.ai/v1/collections/' . $collection_id; // Check exact endpoint in docs.x.ai
585 + $args = [
586 + 'method' => 'DELETE',
587 + 'headers' => [
588 + 'Authorization' => 'Bearer ' . $grok_api_key,
589 + 'Content-Type' => 'application/json'
590 + ],
591 + 'timeout' => 60,
592 + ];
593 + $response = wp_remote_request( $url, $args );
594 + $response_data = json_decode( wp_remote_retrieve_body( $response ), true );
595 + wp_send_json( $response_data );
596 + }
597 + public function qcld_grok_add_collection_callback() {
598 + $nonce = sanitize_text_field( wp_unslash($_POST['nonce']) ?? '' );
599 + if ( ! wp_verify_nonce( $nonce, 'wp_chatbot' ) || ! current_user_can( 'manage_options' ) ) {
600 + wp_send_json(
601 + array(
602 + 'success' => false,
603 + 'msg' => esc_html__( 'Failed in Security check', 'chatbot'),
604 + )
605 + );
606 + wp_die();
607 + }
608 + $grok_api_key = get_option( 'qcld_grok_api_key' );
609 + $collection_name = isset( $_POST['collection_name'] ) ? sanitize_text_field( wp_unslash( $_POST['collection_name'] ) ) : ( site_url() . wp_rand( 1, 999 ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
610 + $response_raw = wp_remote_post(
611 + 'https://api.x.ai/v1/collections',
612 + array(
613 + 'headers' => array(
614 + 'Authorization' => 'Bearer ' . $grok_api_key,
615 + 'Content-Type' => 'application/json',
616 + ),
617 + 'body' => wp_json_encode( array( 'collection_name' => $collection_name, 'field_definitions' => array() ) ),
618 + 'timeout' => 60,
619 + )
620 + );
621 + $response = json_decode( wp_remote_retrieve_body( $response_raw ), true );
622 + wp_send_json( $response );
623 + }
624 + public function direct_search_collection( $query ) {
625 +
626 + $collection_id = get_option( 'qcld_grok_collection_id' );
627 + $grok_api_key = get_option( 'qcld_grok_api_key' );
628 + $url = 'https://api.x.ai/v1/documents/search';
629 + $payload = [
630 + 'query' => $query,
631 + 'source' => ['collection_ids' => [$collection_id]],
632 + 'retrieval_mode' => ['type' => 'hybrid'] // or 'semantic', 'keyword'
633 + ];
634 + $args = [
635 + 'method' => 'POST',
636 + 'headers' => [
637 + 'Authorization' => 'Bearer ' . $grok_api_key,
638 + 'Content-Type' => 'application/json',
639 + ],
640 + 'body' => wp_json_encode($payload),
641 + 'timeout' => 30,
642 + ];
643 + $response = wp_remote_post($url, $args);
644 + $result = json_decode(wp_remote_retrieve_body($response), true);
645 + if (is_wp_error($response)) {
646 + return ['error' => $response->get_error_message()];
647 + }
648 + foreach ($result['matches'] as $key => $match) {
649 + if ($key >= 1) break;
650 + $responses = $match ["chunk_content"];
651 + }
652 + return $responses;
653 + }
654 + }
655 +
656 + /**
657 + * @return qcld_wpopenai_addon
658 + */
659 + if ( ! function_exists( 'qcld_wpgrok_addons' ) ) {
660 +
661 + function qcld_wpgrok_addons() {
662 + $qcld_wpgrok_addon = new qcld_wpgrok_addons();
663 + return $qcld_wpgrok_addon->instance();
664 + }
665 + }
666 +
667 + // fire off the plugin.
668 + qcld_wpgrok_addons();
669 +
592 670 }