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.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 8.5.6 All 537 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.1, at includes/integration/grok/qcld-bot-grok.php

670 lines 30.3 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, 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
670 }