PluginProbe
WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services / 8.8.0
WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services v8.8.0
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 8.5.6 8.5.5 All 536 releases
chatbot / includes / integration / grok / qcld-bot-grok.php

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

668 lines 29.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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, respond with 'Invalid answer found' and ask the exact same question again.";
225 }
226 }
227
228 $action_prompt = !empty($_POST['action_prompt']) ? wp_unslash($_POST['action_prompt']) : '';
229 if (!empty($action_prompt)) {
230 $grok_system_content .= "\n\nCRITICAL ACTIVE ACTION INSTRUCTION:\n" . $action_prompt;
231 }
232
233 $rag_context = "";
234 if (get_option('qcld_grok_rag_enabled') == '1') {
235 $rag_context = Qcld_Bot_Rag()->run_rag_search($keyword);
236 if (!empty($rag_context) && $rag_context != "No knowledge base found.") {
237 $grok_system_content .= "\n\nRelevant Knowledge Base Information:\n" . $rag_context;
238 }
239 }
240 $relevant_pagelink = Qcld_WPBot_Common_Functions::qcpd_relevant_pagelink( $keyword );
241 $relevant_pagelink = array_slice( $relevant_pagelink, 0, 5, true );
242 if ( ( get_option( 'page_suggestion_enabled' ) == '1' ) && count( $relevant_pagelink ) > 0 ) {
243 $relevant_post_link = maybe_unserialize( get_option( 'qlcd_wp_chatbot_relevant_post_link_openai' ) );
244 if ( is_array( $relevant_post_link[ get_wpbot_locale() ] ) ) {
245 $relevant_pagelinks = '<br><br><p><em>' . implode( '', $relevant_post_link[ get_wpbot_locale() ] ) . '</em><p>' . implode( '</br>', $relevant_pagelink );
246 } else {
247 $relevant_pagelinks = '<br><br><p><em>' . $relevant_post_link[ get_wpbot_locale() ] . '</em><p>' . implode( '</br>', $relevant_pagelink );
248 }
249 } else {
250 $relevant_pagelinks = '';
251 }
252 $collection_id = get_option( 'qcld_grok_collection_id' ) ?? '';
253 if( $collection_id != '' ) {
254 $result = $this->direct_search_collection( $keyword );
255 $response['status'] = 'success';
256 $response['message'] = $result ;
257 wp_send_json( $response );
258 } else {
259 $messages = [
260 ['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.' ]
261 ];
262
263 if (!empty($_POST['ai_history'])) {
264 $parsed_history = json_decode(wp_unslash($_POST['ai_history']), true);
265 if (is_array($parsed_history)) {
266 foreach ($parsed_history as $h) {
267 if (isset($h['role']) && isset($h['content'])) {
268 $role = ($h['role'] === 'assistant') ? 'assistant' : 'user';
269 $messages[] = [
270 'role' => $role,
271 'content' => sanitize_text_field($h['content'])
272 ];
273 }
274 }
275 }
276 }
277
278 $last_msg = end($messages);
279 if (!$last_msg || $last_msg['role'] !== 'user' || $last_msg['content'] !== $keyword) {
280 $messages[] = ['role' => 'user', 'content' => $keyword];
281 }
282
283 $response_mess = wp_remote_post('https://api.x.ai/v1/chat/completions', [
284 'headers' => [
285 'Authorization' => 'Bearer ' . $grok_api_key,
286 'Content-Type' => 'application/json',
287 ],
288 'body' => wp_json_encode([
289 'messages' => $messages,
290 'model' => 'grok-3-latest',
291 'temperature' => 0,
292 'stream' => false
293 ]),
294 'timeout' => 60,
295 ]);
296 $response['message'] = '';
297 $status_code = wp_remote_retrieve_response_code($response_mess);
298 $data = wp_remote_retrieve_body($response_mess);
299 $data = json_decode($data, true);
300 do_action('qcld_openai_user_rate_cal', 1);
301 $response['status'] = 'success';
302 $reply_raw = $data['choices'][0]['message']['content'] ?? 'No content received';
303 $Parsedown = new Parsedown();
304 $reply_text = $Parsedown->text($reply_raw);
305 if (strpos($reply_text, 'AI_FORM_DATA') !== false) {
306 $reply_text = Qcld_WPBot_Common_Functions::format_and_save_ai_form_response($reply_text);
307 $response['message'] = $reply_text;
308 } else {
309 $response['message'] = $reply_text . $relevant_pagelinks;
310 }
311 wp_send_json( $response );
312 }
313 }
314 public function qcld_stream_grok_callback()
315 {
316
317 if (!defined('ABSPATH')) {
318 // Optional: protect direct access or require wp-load.php
319 // For security → better to use admin-ajax or custom rewrite rule in production
320 http_response_code(403);
321 exit;
322 }
323
324 if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'wp_chatbot' ) ) {
325 echo "data: [ERROR] Security check failed.\n\n";
326 flush();
327 wp_die();
328 }
329
330 if (get_option('is_rate_limiting_enabled') == '1') {
331 do_action('rate_limit_checker');
332 }
333 $api_key = get_option('qcld_grok_api_key'); // ← Use get_option() or env in real code!
334
335 // Disable compression (critical for streaming)
336 if (function_exists('apache_setenv')) {
337 @apache_setenv('no-gzip', 1);
338 }
339 @ini_set('zlib.output_compression', 0);
340 while (ob_get_level() > 0) { ob_end_clean(); }
341
342 set_time_limit(180); // Allow long-running requests
343
344 $headers = [
345 'Content-Type: application/json',
346 'Authorization: Bearer ' . $api_key,
347 ];
348 $system_content = get_option( 'qcld_grok_system_content' );
349 if (empty($system_content)) {
350 $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.';
351 }
352 // AI Interactive Form
353 if (get_option('enable_ai_interactive_form') == '1') {
354 $saved_ai_forms = get_option('wpbot_ai_forms', array());
355 if (!empty($saved_ai_forms) && is_array($saved_ai_forms)) {
356 $system_content .= "\n\nYou must handle the following interactive forms when the user asks for them:\n";
357 foreach ($saved_ai_forms as $form) {
358 $system_content .= "\nForm Title: " . $form['title'] . "\nInstructions: " . $form['prompt'] . "\n";
359 }
360 $system_content .= "\n\nCRITICAL INSTRUCTIONS FOR INTERACTIVE FORMS:\n";
361 $system_content .= "When a user triggers an interactive form, you must act as a step-by-step data collection agent.\n";
362 $system_content .= "1. DO NOT ask all questions at once. Ask exactly ONE question at a time.\n";
363 $system_content .= "2. Wait for the user's response before asking the next question.\n";
364 $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";
365 $system_content .= "__AI_FORM_DATA__{ \"form_title\": \"<Form Title>\", \"data\": { \"Question 1\": \"Answer 1\", \"Question 2\": \"Answer 2\" } }__AI_FORM_DATA_END__\n";
366 $system_content .= "Do not include any other text after this JSON block once the form is complete.\n";
367 $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.";
368 }
369 }
370 $messages = [];
371 // Load previous conversation from cookie if continuity is enabled
372 if ($conversation_continuity == 1 && !empty($_COOKIE['last_five_prompt'])) {
373 $decoded_cookie = json_decode(stripslashes($_COOKIE['last_five_prompt']), true);
374 if (is_array($decoded_cookie)) {
375 $messages = $decoded_cookie;
376 }
377 }
378 // Ensure system message is the first message.
379 if (empty($messages) || (isset($messages[0]) && $messages[0]['role'] !== 'system')) {
380 array_unshift($messages, ['role' => 'system', 'content' => $system_content]);
381 } elseif (isset($messages[0]) && $messages[0]['role'] === 'system' && $messages[0]['content'] !== $system_content) {
382 $messages[0]['content'] = $system_content;
383 }
384
385 array_push($messages, ['role' => 'user', 'content' => sanitize_text_field( wp_unslash( $_POST['message'] ) )]);
386 $postData = json_encode([
387 'model' => 'grok-3-latest',
388 'messages' => $messages,
389 'stream' => true
390 ]);
391
392 // phpcs:ignore WordPress.WP.AlternativeFunctions -- streaming requires native cURL
393 $ch = curl_init('https://api.x.ai/v1/chat/completions');
394 curl_setopt($ch, CURLOPT_POST, true); // phpcs:ignore WordPress.WP.AlternativeFunctions
395 curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // phpcs:ignore WordPress.WP.AlternativeFunctions
396 curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); // phpcs:ignore WordPress.WP.AlternativeFunctions
397 curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, $chunk) use (&$full_assistant_response) { // phpcs:ignore WordPress.WP.AlternativeFunctions
398 echo $chunk; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- SSE streaming raw output
399 echo str_repeat(' ', 1024); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- SSE streaming padding
400 flush();
401 ob_flush();
402
403 // Parse the chunk to extract assistant's content for continuity.
404 $lines = explode("\n", $chunk);
405 foreach ($lines as $line) {
406 if (strpos($line, 'data: ') === 0) {
407 $json_data = substr($line, 6);
408 if ($json_data === '[DONE]') {
409 continue;
410 }
411 $data = json_decode($json_data, true);
412 if (isset($data['choices'][0]['delta']['content'])) {
413 $full_assistant_response .= $data['choices'][0]['delta']['content'];
414 }
415 }
416 }
417 return strlen($chunk);
418 });
419 curl_exec($ch); // phpcs:ignore WordPress.WP.AlternativeFunctions
420 curl_close($ch); // phpcs:ignore WordPress.WP.AlternativeFunctions
421 // phpcs:ignore WordPress.WP.AlternativeFunctions -- streaming requires native cURL
422 $ch = curl_init('https://api.x.ai/v1/chat/completions');
423
424 // phpcs:ignore WordPress.WP.AlternativeFunctions
425 curl_setopt_array($ch, [
426 CURLOPT_POST => true,
427 CURLOPT_HTTPHEADER => $headers,
428 CURLOPT_POSTFIELDS => $postData,
429 CURLOPT_RETURNTRANSFER => false, // We echo ourselves
430 CURLOPT_WRITEFUNCTION => function ($curl, $chunk) {
431 echo $chunk; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- SSE streaming raw output
432 flush(); // Push to browser immediately
433 return strlen($chunk);
434 },
435 CURLOPT_TIMEOUT => 150,
436 CURLOPT_CONNECTTIMEOUT => 30,
437 CURLOPT_SSL_VERIFYPEER => true,
438 CURLOPT_FOLLOWLOCATION => true,
439 CURLOPT_ENCODING => '', // Let server decide
440 ]);
441
442 $success = curl_exec($ch); // phpcs:ignore WordPress.WP.AlternativeFunctions
443 do_action('qcld_openai_user_rate_cal', 1);
444 if (curl_errno($ch)) { // phpcs:ignore WordPress.WP.AlternativeFunctions
445 $err = curl_error($ch); // phpcs:ignore WordPress.WP.AlternativeFunctions
446 echo "data: " . wp_json_encode( array( 'error' => 'cURL error: ' . $err ) ) . "\n\n";
447 flush();
448 }
449
450 curl_close($ch); // phpcs:ignore WordPress.WP.AlternativeFunctions
451
452 // Final done signal (optional but nice)
453 echo "data: [DONE]\n\n";
454 flush();
455 }
456 public function qcld_grok_collectionlist_callback() {
457 $nonce = sanitize_text_field( wp_unslash($_POST['nonce']) ?? '' );
458 if ( ! wp_verify_nonce( $nonce, 'wp_chatbot' ) || ! current_user_can( 'manage_options' ) ) {
459 wp_send_json(
460 array(
461 'success' => false,
462 'msg' => esc_html__( 'Failed in Security check', 'chatbot'),
463 )
464 );
465 wp_die();
466 }
467 $grok_api_key = get_option( 'qcld_grok_api_key' );
468 $response_raw = wp_remote_get(
469 'https://api.x.ai/v1/collections',
470 array(
471 'headers' => array(
472 'Authorization' => 'Bearer ' . $grok_api_key,
473 'Content-Type' => 'application/json',
474 ),
475 'timeout' => 60,
476 )
477 );
478 $response = json_decode( wp_remote_retrieve_body( $response_raw ), true );
479 wp_send_json( $response );
480 }
481 public function qcld_grok_file_upload_callback()
482 {
483
484 $nonce = sanitize_text_field(wp_unslash($_POST['nonce']));
485 if (! wp_verify_nonce($nonce, 'wp_chatbot') || ! current_user_can( 'manage_options' ) ) {
486 wp_send_json(
487 array(
488 'success' => false,
489 'msg' => esc_html__('Failed in Security check', 'chatbot'),
490 )
491 );
492 wp_die();
493 } else {
494 // $uploadedfile = $_FILES['file'];
495 // $collection_id = sanitize_text_field(wp_unslash($_POST['collection_id']));
496 // $api_key = get_option( 'qcld_grok_api_key' );
497
498 // $ch = curl_init();
499
500 // $file = new CURLFile(
501 // $uploadedfile['tmp_name'],
502 // $uploadedfile['type'] ?: 'application/octet-stream',
503 // $uploadedfile['name']
504 // );
505
506 // $post_data = ['file' => $file];
507
508 // curl_setopt_array($ch, [
509 // CURLOPT_URL => 'https://api.x.ai/v1/files',
510 // CURLOPT_POST => true,
511 // CURLOPT_POSTFIELDS => $post_data,
512 // CURLOPT_RETURNTRANSFER => true,
513 // CURLOPT_HTTPHEADER => [
514 // 'Authorization: Bearer ' . $api_key,
515 // // Do NOT add Content-Type here!!
516 // ],
517 // CURLOPT_TIMEOUT => 180,
518 // CURLOPT_CONNECTTIMEOUT => 30,
519 // ]);
520
521 // $result = json_decode(curl_exec($ch));
522 // $error = curl_error($ch);
523 // curl_close($ch);
524 // $file_id = $result->id
525 $collection_id = "collection_22aa88f1-80e8-4e1a-8e13-c119afb0481c";
526 $file_id = "file_06208083-0e27-44ff-af29-5faa211f4892";
527 $this->add_file_to_collection($collection_id, $file_id, []);
528 if (! empty($res->error)) {
529 $response['status'] = 'error';
530 $response['message'] = $res->error->message;
531 }
532
533 if (! empty($res->status)) {
534 $response['status'] = 'success';
535 $response['message'] = 'Successfully Created file' . $res->id;
536 }
537 // echo wp_send_json(array($response));
538 // wp_die();
539 }
540 }
541 public function add_file_to_collection($collection_id, $file_id, $metadata = []) {
542 $url = "https://management-api.x.ai/v1/collections/{$collection_id}/documents/{$file_id}";
543 $grok_management_api_key = get_option( 'qcld_grok_management_api_key' );
544
545 $args = [
546 'method' => 'POST',
547 'timeout' => 30,
548 'redirection' => 5,
549 'httpversion' => '1.1',
550 'blocking' => true,
551 'headers' => [
552 'Authorization' => 'Bearer ' . $grok_management_api_key, // Management API key required
553 'Content-Type' => 'application/json',
554 ],
555 // 'body' => json_encode([
556 // 'fields' => $metadata // Optional: matches your field_definitions
557 // ]),
558 ];
559 // return ['success' => false, 'error' => $response->get_error_message()];
560 $response = wp_remote_post( $url, $args );
561 $body = wp_remote_retrieve_body( $response );
562 $status_code = wp_remote_retrieve_response_code( $response );
563 if ($status_code >= 200 && $status_code < 300) {
564 return ['success' => true, 'message' => 'File added to collection', 'body' => $body];
565 } else {
566 return ['success' => false, 'status' => $status_code, 'error' => $body];
567 }
568 }
569 public function qcld_grok_remove_collection_callback() {
570 $nonce = sanitize_text_field( wp_unslash($_POST['nonce']) ?? '' );
571 if ( ! wp_verify_nonce( $nonce, 'wp_chatbot' ) || ! current_user_can( 'manage_options' ) ) {
572 wp_send_json(
573 array(
574 'success' => false,
575 'msg' => esc_html__( 'Failed in Security check', 'chatbot'),
576 )
577 );
578 wp_die();
579 }
580 $grok_api_key = get_option( 'qcld_grok_api_key' );
581 $collection_id = sanitize_text_field( wp_unslash($_POST['collection_id']) ?? '' ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
582 $url = 'https://api.x.ai/v1/collections/' . $collection_id; // Check exact endpoint in docs.x.ai
583 $args = [
584 'method' => 'DELETE',
585 'headers' => [
586 'Authorization' => 'Bearer ' . $grok_api_key,
587 'Content-Type' => 'application/json'
588 ],
589 'timeout' => 60,
590 ];
591 $response = wp_remote_request( $url, $args );
592 $response_data = json_decode( wp_remote_retrieve_body( $response ), true );
593 wp_send_json( $response_data );
594 }
595 public function qcld_grok_add_collection_callback() {
596 $nonce = sanitize_text_field( wp_unslash($_POST['nonce']) ?? '' );
597 if ( ! wp_verify_nonce( $nonce, 'wp_chatbot' ) || ! current_user_can( 'manage_options' ) ) {
598 wp_send_json(
599 array(
600 'success' => false,
601 'msg' => esc_html__( 'Failed in Security check', 'chatbot'),
602 )
603 );
604 wp_die();
605 }
606 $grok_api_key = get_option( 'qcld_grok_api_key' );
607 $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
608 $response_raw = wp_remote_post(
609 'https://api.x.ai/v1/collections',
610 array(
611 'headers' => array(
612 'Authorization' => 'Bearer ' . $grok_api_key,
613 'Content-Type' => 'application/json',
614 ),
615 'body' => wp_json_encode( array( 'collection_name' => $collection_name, 'field_definitions' => array() ) ),
616 'timeout' => 60,
617 )
618 );
619 $response = json_decode( wp_remote_retrieve_body( $response_raw ), true );
620 wp_send_json( $response );
621 }
622 public function direct_search_collection( $query ) {
623
624 $collection_id = get_option( 'qcld_grok_collection_id' );
625 $grok_api_key = get_option( 'qcld_grok_api_key' );
626 $url = 'https://api.x.ai/v1/documents/search';
627 $payload = [
628 'query' => $query,
629 'source' => ['collection_ids' => [$collection_id]],
630 'retrieval_mode' => ['type' => 'hybrid'] // or 'semantic', 'keyword'
631 ];
632 $args = [
633 'method' => 'POST',
634 'headers' => [
635 'Authorization' => 'Bearer ' . $grok_api_key,
636 'Content-Type' => 'application/json',
637 ],
638 'body' => wp_json_encode($payload),
639 'timeout' => 30,
640 ];
641 $response = wp_remote_post($url, $args);
642 $result = json_decode(wp_remote_retrieve_body($response), true);
643 if (is_wp_error($response)) {
644 return ['error' => $response->get_error_message()];
645 }
646 foreach ($result['matches'] as $key => $match) {
647 if ($key >= 1) break;
648 $responses = $match ["chunk_content"];
649 }
650 return $responses;
651 }
652 }
653
654 /**
655 * @return qcld_wpopenai_addon
656 */
657 if ( ! function_exists( 'qcld_wpgrok_addons' ) ) {
658
659 function qcld_wpgrok_addons() {
660 $qcld_wpgrok_addon = new qcld_wpgrok_addons();
661 return $qcld_wpgrok_addon->instance();
662 }
663 }
664
665 // fire off the plugin.
666 qcld_wpgrok_addons();
667
668 }