PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 2.2.51
AI Engine – The Chatbot, AI Framework & MCP for WordPress v2.2.51
3.5.7 3.5.6 3.5.5 3.5.4 3.5.3 3.5.2 3.5.1 3.5.0 3.4.9 3.4.8 3.4.7 0.2.1 1.6.91 0.2.2 1.6.92 0.2.3 1.6.93 0.2.4 1.6.94 0.2.5 1.6.95 0.2.6 1.6.96 0.2.7 1.6.97 0.2.8 1.6.98 0.2.9 1.6.99 0.3.0 1.7.0 0.3.1 1.7.1 0.3.2 1.7.2 0.3.3 1.7.3 0.3.4 1.7.4 0.3.5 1.7.5 0.3.6 1.7.6 0.4.0 1.7.7 0.4.1 1.7.8 0.4.2 1.7.9 0.4.3 1.8.0 0.4.4 1.8.1 0.4.5 1.8.2 0.4.6 1.8.3 0.4.7 1.8.4 0.4.8 1.8.5 0.4.9 1.8.6 0.5.0 1.8.7 0.5.1 1.8.8 0.5.2 1.8.9 0.5.3 1.9.0 0.5.4 1.9.1 0.5.5 1.9.2 0.5.6 1.9.3 0.5.7 1.9.4 0.5.8 1.9.5 0.5.9 1.9.6 0.6.0 1.9.7 0.6.1 1.9.8 0.6.2 1.9.81 0.6.3 1.9.82 0.6.4 1.9.83 0.6.5 1.9.84 0.6.6 1.9.85 0.6.7 1.9.86 0.6.8 1.9.87 0.6.9 1.9.88 0.7.0 1.9.89 0.7.1 1.9.90 0.7.2 1.9.91 0.7.3 1.9.92 0.7.4 1.9.93 0.7.5 1.9.94 0.7.6 1.9.95 0.7.7 1.9.96 0.7.8 1.9.97 0.7.9 1.9.98 0.8.0 1.9.99 0.8.1 2.0.0 0.8.2 2.0.1 0.8.3 2.0.2 0.8.4 2.0.3 0.8.5 2.0.4 0.8.6 2.0.5 0.8.7 2.0.6 0.8.8 2.0.7 0.8.9 2.0.8 0.9.0 2.0.9 0.9.2 2.1.0 0.9.3 2.1.1 0.9.4 2.1.2 0.9.5 2.1.3 0.9.6 2.1.4 0.9.7 2.1.5 0.9.8 2.1.6 0.9.81 2.1.7 0.9.82 2.1.8 0.9.83 2.1.9 0.9.84 2.2.0 0.9.85 2.2.1 0.9.86 2.2.2 0.9.87 2.2.3 0.9.88 2.2.4 0.9.89 2.2.5 0.9.9 2.2.51 0.9.91 2.2.52 0.9.92 2.2.53 0.9.93 2.2.54 0.9.94 2.2.56 0.9.95 2.2.57 0.9.96 2.2.6 0.9.97 2.2.60 0.9.98 2.2.61 0.9.99 2.2.62 1.0.0 2.2.63 1.0.01 2.2.70 1.0.1 2.2.80 1.0.2 2.2.81 1.0.3 2.2.90 1.0.4 2.2.91 1.0.5 2.2.92 1.0.6 2.2.93 1.0.7 2.2.94 1.0.8 2.2.95 1.0.9 2.3.0 1.1.0 2.3.1 1.1.1 2.3.2 1.1.2 2.3.3 1.1.3 2.3.4 1.1.4 2.3.5 1.1.5 2.3.6 1.1.6 2.3.7 1.1.7 2.3.8 1.1.8 2.3.9 1.1.9 2.4.0 1.2.0 2.4.1 1.2.1 2.4.2 1.2.2 2.4.3 1.2.21 2.4.4 1.2.3 2.4.5 1.2.30 2.4.6 1.3.0 2.4.7 1.3.1 2.4.8 1.3.2 2.4.9 1.3.3 2.5.0 1.3.31 2.5.1 1.3.32 2.5.2 1.3.33 2.5.3 1.3.34 2.5.4 1.3.35 2.5.5 1.3.36 2.5.6 1.3.37 2.5.7 1.3.38 2.5.8 1.3.39 2.5.9 1.3.40 2.6.0 1.3.41 2.6.1 1.3.42 2.6.2 1.3.43 2.6.3 1.3.44 2.6.5 1.3.45 2.6.6 1.3.46 2.6.7 1.3.47 2.6.8 1.3.48 2.6.9 1.3.49 2.7.0 1.3.50 2.7.1 1.3.51 2.7.2 1.3.52 2.7.3 1.3.53 2.7.4 1.3.54 2.7.5 1.3.56 2.7.6 1.3.57 2.7.7 1.3.58 2.7.8 1.3.59 2.7.9 1.3.60 2.8.0 1.3.61 2.8.1 1.3.62 2.8.2 1.3.63 2.8.3 1.3.64 2.8.4 1.3.65 2.8.5 1.3.66 2.8.6 1.3.67 2.8.7 1.3.68 2.8.8 1.3.69 2.8.9 1.3.70 2.9.0 1.3.71 2.9.1 1.3.72 2.9.2 1.3.73 2.9.3 1.3.74 2.9.4 1.3.75 2.9.5 1.3.76 2.9.6 1.3.77 2.9.7 1.3.78 2.9.8 1.3.79 2.9.9 1.3.80 3.0.0 1.3.81 3.0.1 1.3.82 3.0.2 1.3.83 3.0.3 1.3.84 3.0.4 1.3.85 3.0.5 1.3.86 3.0.6 1.3.87 3.0.7 1.3.88 3.0.8 1.3.89 3.0.9 1.3.90 3.1.0 1.3.91 3.1.1 1.3.92 3.1.2 1.3.93 3.1.3 1.3.94 3.1.4 1.3.95 3.1.5 1.3.96 3.1.6 1.3.97 3.1.7 1.3.98 3.1.8 1.3.99 3.1.9 1.4.0 3.2.0 1.4.1 3.2.1 1.4.2 3.2.2 1.4.3 3.2.3 1.4.4 3.2.4 1.4.5 3.2.5 1.4.6 3.2.6 1.4.7 3.2.7 1.4.8 3.2.8 1.4.9 3.2.9 1.5.0 3.3.0 1.5.1 3.3.1 1.5.2 3.3.2 1.5.3 3.3.3 1.5.4 3.3.4 1.5.5 3.3.5 1.5.6 3.3.6 1.5.7 3.3.7 1.5.8 3.3.8 1.5.9 3.3.9 1.6.0 3.4.0 1.6.1 3.4.1 1.6.2 3.4.2 1.6.3 3.4.3 1.6.5 3.4.4 1.6.51 3.4.5 1.6.52 3.4.6 1.6.53 1.6.54 1.6.55 1.6.56 1.6.57 1.6.58 1.6.59 1.6.60 1.6.61 1.6.62 1.6.63 1.6.64 1.6.65 1.6.66 1.6.67 1.6.68 trunk 1.6.69 0.0.1 1.6.70 0.0.2 1.6.71 0.0.3 1.6.72 0.0.4 1.6.73 0.0.5 1.6.74 0.0.6 1.6.75 0.0.7 1.6.76 0.0.8 1.6.77 0.0.9 1.6.78 0.1.0 1.6.79 0.1.1 1.6.81 0.1.2 1.6.82 0.1.3 1.6.83 0.1.4 1.6.84 0.1.5 1.6.85 0.1.6 1.6.86 0.1.7 1.6.87 0.1.8 1.6.88 0.1.9 1.6.89 0.2.0 1.6.90
ai-engine / classes / modules / chatbot.php
ai-engine / classes / modules Last commit date
chatbot.php 2 years ago discussions.php 2 years ago files.php 2 years ago security.php 2 years ago tasks.php 2 years ago utilities.php 2 years ago
chatbot.php
533 lines
1 <?php
2
3 // Params for the chatbot (front and server)
4
5 define( 'MWAI_CHATBOT_FRONT_PARAMS', [ 'id', 'customId', 'aiName', 'userName', 'guestName',
6 'textSend', 'textClear', 'imageUpload', 'fileUpload',
7 'textInputPlaceholder', 'textInputMaxLength', 'textCompliance', 'startSentence', 'localMemory',
8 'themeId', 'window', 'icon', 'iconText', 'iconAlt', 'iconPosition', 'fullscreen', 'copyButton'
9 ] );
10 // TODO: Actually, 'env' is being replaced by 'scope', so we need to really remove it from here
11 // after, February 2024.
12 define( 'MWAI_CHATBOT_SERVER_PARAMS', [ 'id', 'envId', 'env', 'scope', 'mode', 'contentAware', 'context',
13 'embeddingsEnvId', 'embeddingsIndex', 'embeddingsNamespace', 'assistantId',
14 'model', 'temperature', 'maxTokens', 'contextMaxLength', 'maxResults', 'apiKey'
15 ] );
16
17 // Params for the discussions (front and server)
18
19 define( 'MWAI_DISCUSSIONS_FRONT_PARAMS', [ 'themeId', 'textNewChat' ] );
20 define( 'MWAI_DISCUSSIONS_SERVER_PARAMS', [ 'customId' ] );
21
22 class Meow_MWAI_Modules_Chatbot {
23 private $core = null;
24 private $namespace = 'mwai-ui/v1';
25 private $siteWideChatId = null;
26
27 public function __construct() {
28 global $mwai_core;
29 $this->core = $mwai_core;
30 add_shortcode( 'mwai_chatbot', array( $this, 'chat_shortcode' ) );
31 add_shortcode( 'mwai_chatbot_v2', array( $this, 'chat_shortcode' ) );
32 add_action( 'rest_api_init', array( $this, 'rest_api_init' ) );
33 $this->siteWideChatId = $this->core->get_option( 'botId' );
34 add_action( 'wp_enqueue_scripts', array( $this, 'register_scripts' ) );
35
36 if ( $this->core->get_option( 'shortcode_chat_discussions' ) ) {
37 add_shortcode( 'mwai_discussions', [ $this, 'shortcode_chat_discussions' ] );
38 }
39 }
40
41 public function register_scripts() {
42 $physical_file = trailingslashit( MWAI_PATH ) . 'app/chatbot.js';
43 $cache_buster = file_exists( $physical_file ) ? filemtime( $physical_file ) : MWAI_VERSION;
44 wp_register_script( 'mwai_chatbot', trailingslashit( MWAI_URL ) . 'app/chatbot.js',
45 [ 'wp-element' ], $cache_buster, false );
46 if ( !empty( $this->siteWideChatId ) && $this->siteWideChatId !== 'none' ) {
47 $this->enqueue_scripts();
48 add_action( 'wp_footer', array( $this, 'inject_chat' ) );
49 }
50 }
51
52 public function enqueue_scripts() {
53 wp_enqueue_script( "mwai_chatbot" );
54 if ( $this->core->get_option( 'shortcode_chat_syntax_highlighting' ) ) {
55 wp_enqueue_script( "mwai_highlight" );
56 }
57 }
58
59 public function rest_api_init() {
60 register_rest_route( $this->namespace, '/chats/submit', array(
61 'methods' => 'POST',
62 'callback' => [ $this, 'rest_chat' ],
63 'permission_callback' => array( $this->core, 'check_rest_nonce' )
64 ) );
65 }
66
67 public function basics_security_check( $botId, $customId, $newMessage ) {
68 if ( empty( $newMessage ) ) {
69 error_log("AI Engine: The query was rejected - message was empty.");
70 return false;
71 }
72 if ( !$botId && !$customId ) {
73 error_log("AI Engine: The query was rejected - no botId nor id was specified.");
74 return false;
75 }
76
77 $length = strlen( $newMessage );
78 if ( $length < 1 || $length > ( 4096 * 16 ) ) {
79 error_log("AI Engine: The query was rejected - message was too short or too long.");
80 return false;
81 }
82 return true;
83 }
84
85 public function rest_chat( $request ) {
86 $params = $request->get_json_params();
87 $botId = $params['botId'] ?? null;
88 $customId = $params['customId'] ?? null;
89 $stream = $params['stream'] ?? false;
90 $newMessage = trim( $params['newMessage'] ?? '' );
91 $newFileId = $params['newFileId'] ?? null;
92
93 if ( !$this->basics_security_check( $botId, $customId, $newMessage )) {
94 return new WP_REST_Response( [
95 'success' => false,
96 'message' => apply_filters( 'mwai_ai_exception', 'Sorry, your query has been rejected.' )
97 ], 403 );
98 }
99
100 try {
101 $data = $this->chat_submit( $botId, $newMessage, $newFileId, $params, $stream );
102 return new WP_REST_Response( [
103 'success' => true,
104 'reply' => $data['reply'],
105 'images' => $data['images'],
106 'usage' => $data['usage']
107 ], 200 );
108 }
109 catch ( Exception $e ) {
110 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
111 return new WP_REST_Response( [
112 'success' => false,
113 'message' => $message
114 ], 500 );
115 }
116 }
117
118 public function chat_submit( $botId, $newMessage, $newFileId, $params = [], $stream = false ) {
119 try {
120 $chatbot = null;
121 $customId = $params['customId'] ?? null;
122
123 // Custom Chatbot
124 if ( $customId ) {
125 $chatbot = get_transient( 'mwai_custom_chatbot_' . $customId );
126 }
127 // Registered Chatbot
128 if ( !$chatbot && $botId ) {
129 $chatbot = $this->core->get_chatbot( $botId );
130 }
131
132 if ( !$chatbot ) {
133 error_log("AI Engine: No chatbot was found for this query.");
134 throw new Exception( 'Sorry, your query has been rejected.' );
135 }
136
137 $textInputMaxLength = $chatbot['textInputMaxLength'] ?? null;
138 if ( $textInputMaxLength && strlen( $newMessage ) > (int)$textInputMaxLength ) {
139 throw new Exception( 'Sorry, your query has been rejected.' );
140 }
141
142 // Create QueryText
143 $context = null;
144 $mode = $chatbot['mode'] ?? 'chat';
145
146 if ( $mode === 'images' ) {
147 $query = new Meow_MWAI_Query_Image( $newMessage );
148
149 // Handle Params
150 $newParams = [];
151 foreach ( $chatbot as $key => $value ) {
152 $newParams[$key] = $value;
153 }
154 foreach ( $params as $key => $value ) {
155 $newParams[$key] = $value;
156 }
157 $params = apply_filters( 'mwai_chatbot_params', $newParams );
158 $params['scope'] = empty( $params['scope'] ) ? 'chatbot' : $params['scope'];
159 $query->inject_params( $params );
160 }
161 else {
162 $query = $mode === 'assistant' ? new Meow_MWAI_Query_Assistant( $newMessage ) :
163 new Meow_MWAI_Query_Text( $newMessage, 1024 );
164 $streamCallback = null;
165
166 // Handle Params
167 $newParams = [];
168 foreach ( $chatbot as $key => $value ) {
169 $newParams[$key] = $value;
170 }
171 foreach ( $params as $key => $value ) {
172 $newParams[$key] = $value;
173 }
174 $params = apply_filters( 'mwai_chatbot_params', $newParams );
175 $params['scope'] = empty( $params['scope'] ) ? 'chatbot' : $params['scope'];
176 $query->inject_params( $params );
177
178 // Support for Uploaded Image
179 if ( !empty( $newFileId ) ) {
180
181 if ( $mode === 'assistant' ) {
182 // This is for Assistant
183 $url = $this->core->files->get_path( $newFileId );
184 $data = $this->core->files->get_data( $newFileId );
185 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $query->envId );
186 $filename = basename( $url );
187 $file = $openai->upload_file( $filename, $data, 'assistants' );
188 $openAiRefId = $file['id'];
189 $internalFileId = $this->core->files->get_id_from_refId( $newFileId );
190 $this->core->files->update_refId( $internalFileId, $openAiRefId );
191 $this->core->files->update_envId( $internalFileId, $query->envId );
192 $newFileId = $openAiRefId;
193 $scope = $params['fileUpload'];
194 if ( $scope === 'discussion' || $scope === 'user' || $scope === 'assistant' ) {
195 $id = $this->core->files->get_id_from_refId( $newFileId );
196 $this->core->files->add_metadata( $id, 'assistant_scope', $scope );
197 }
198 $query->set_file( $openAiRefId, 'refId', 'assistant-in' );
199 }
200 else {
201 // This is for Vision AI
202 $remote_upload = $this->core->get_option( 'image_remote_upload' );
203 if ( $remote_upload === 'data' ) {
204 $data = $this->core->files->get_base64_data( $newFileId );
205 $query->set_file( $data, 'data', 'vision' );
206 }
207 else {
208 $url = $this->core->files->get_url( $newFileId );
209 $query->set_file( $url, 'url', 'vision' );
210 }
211 $fileId = $this->core->files->get_id_from_refId( $newFileId );
212 $this->core->files->update_envId( $fileId, $query->envId );
213 $this->core->files->add_metadata( $fileId, 'query_envId', $query->envId );
214 $this->core->files->add_metadata( $fileId, 'query_session', $query->session );
215 }
216 }
217
218 // Takeover
219 $takeoverAnswer = apply_filters( 'mwai_chatbot_takeover', null, $query, $params );
220 if ( !empty( $takeoverAnswer ) ) {
221 return [
222 'reply' => $takeoverAnswer,
223 'images' => null,
224 'usage' => null
225 ];
226 }
227
228 // Moderation
229 if ( $this->core->get_option( 'shortcode_chat_moderation' ) ) {
230 global $mwai;
231 $isFlagged = $mwai->moderationCheck( $query->get_message() );
232 if ( $isFlagged ) {
233 throw new Exception( 'Sorry, your message has been rejected by moderation.' );
234 }
235 }
236
237 // Awareness & Embeddings
238 $context = $this->core->retrieve_context( $params, $query );
239 if ( !empty( $context ) ) {
240 $query->set_context( $context['content'] );
241 }
242 }
243
244 // Process Query
245 if ( $stream ) {
246 $streamCallback = function( $reply ) {
247 $raw = $reply;
248 $this->stream_push( [ 'type' => 'live', 'data' => $raw ] );
249 if ( ob_get_level() > 0 ) {
250 ob_flush();
251 }
252 flush();
253 };
254 header( 'Cache-Control: no-cache' );
255 header( 'Content-Type: text/event-stream' );
256 // This is useful to disable buffering in nginx through headers.
257 header( 'X-Accel-Buffering: no' );
258 ob_implicit_flush( true );
259 ob_end_flush();
260 }
261
262 $reply = $this->core->run_query( $query, $streamCallback, true );
263 $rawText = $reply->result;
264 $extra = [];
265 if ( $context ) {
266 $extra = [ 'embeddings' => $context['embeddings'] ];
267 }
268 $rawText = apply_filters( 'mwai_chatbot_reply', $rawText, $query, $params, $extra );
269
270 $restRes = [
271 'reply' => $rawText,
272 'images' => $reply->get_type() === 'images' ? $reply->results : null,
273 'usage' => $reply->usage
274 ];
275
276 // Process Reply
277 if ( $stream ) {
278 $this->stream_push( [
279 'type' => 'end',
280 'data' => json_encode([
281 'success' => true,
282 'reply' => $restRes['reply'],
283 'images' => $restRes['images'],
284 'usage' => $restRes['usage']
285 ])
286 ] );
287 die();
288 }
289 else {
290 return $restRes;
291 }
292
293 }
294 catch ( Exception $e ) {
295 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
296 if ( $stream ) {
297 $this->stream_push( [ 'type' => 'error', 'data' => $message ] );
298 die();
299 }
300 else {
301 throw $e;
302 }
303 }
304 }
305
306 public function stream_push( $data ) {
307 $out = "data: " . json_encode( $data );
308 echo $out;
309 echo "\n\n";
310 if (ob_get_level() > 0) {
311 ob_end_flush();
312 }
313 flush();
314 }
315
316 public function inject_chat() {
317 $params = $this->core->get_chatbot( $this->siteWideChatId );
318 $clean_params = [];
319 if ( !empty( $params ) ) {
320 $clean_params['window'] = true;
321 $clean_params['id'] = $this->siteWideChatId;
322 echo $this->chat_shortcode( $clean_params );
323 }
324 return null;
325 }
326
327 public function build_front_params( $botId, $customId ) {
328 $frontSystem = [
329 'botId' => $customId ? null : $botId,
330 'customId' => $customId,
331 'userData' => $this->core->get_user_data(),
332 'sessionId' => $this->core->get_session_id(),
333 'restNonce' => $this->core->get_nonce(),
334 'contextId' => get_the_ID(),
335 'pluginUrl' => MWAI_URL,
336 'restUrl' => untrailingslashit( get_rest_url() ),
337 'debugMode' => $this->core->get_option( 'debug_mode' ),
338 'typewriter' => $this->core->get_option( 'shortcode_chat_typewriter' ),
339 'speech_recognition' => $this->core->get_option( 'speech_recognition' ),
340 'speech_synthesis' => $this->core->get_option( 'speech_synthesis' ),
341 'stream' => $this->core->get_option( 'shortcode_chat_stream' ),
342 ];
343 return $frontSystem;
344 }
345
346 public function resolveBotInfo( &$atts )
347 {
348 $chatbot = null;
349 $botId = $atts['id'] ?? null;
350 $customId = $atts['custom_id'] ?? null;
351 if (!$botId && !$customId) {
352 $botId = "default";
353 }
354 if ( $botId ) {
355 $chatbot = $this->core->get_chatbot( $botId );
356 if (!$chatbot) {
357 $botId = $botId ?: 'N/A';
358 return [
359 'error' => "AI Engine: Chatbot '{$botId}' not found. If you meant to set an ID for your custom chatbot, please use 'custom_id' instead of 'id'.",
360 ];
361 }
362 }
363 $chatbot = $chatbot ?: $this->core->get_chatbot( 'default' );
364 if ( !empty( $customId ) ) {
365 $botId = null;
366 }
367 unset( $atts['id'] );
368 return [
369 'chatbot' => $chatbot,
370 'botId' => $botId,
371 'customId' => $customId,
372 ];
373 }
374
375 public function chat_shortcode( $atts ) {
376 $atts = empty( $atts ) ? [] : $atts;
377
378 // Let the user override the chatbot params
379 $atts = apply_filters( 'mwai_chatbot_params', $atts );
380
381 // Resolve the bot info
382 $resolvedBot = $this->resolveBotInfo( $atts, 'chatbot' );
383 if ( isset( $resolvedBot['error'] ) ) {
384 return $resolvedBot['error'];
385 }
386 $chatbot = $resolvedBot['chatbot'];
387 $botId = $resolvedBot['botId'];
388 $customId = $resolvedBot['customId'];
389
390 // Rename the keys of the atts into camelCase to match the internal params system.
391 $atts = array_map( function( $key, $value ) {
392 $key = str_replace( '_', ' ', $key );
393 $key = ucwords( $key );
394 $key = str_replace( ' ', '', $key );
395 $key = lcfirst( $key );
396 return [ $key => $value ];
397 }, array_keys( $atts ), $atts );
398 $atts = array_merge( ...$atts );
399
400 $frontParams = [];
401 foreach ( MWAI_CHATBOT_FRONT_PARAMS as $param ) {
402 if ( isset( $atts[$param] ) ) {
403 if ( $param === 'localMemory' ) {
404 $frontParams[$param] = $atts[$param] === 'true';
405 }
406 else {
407 $frontParams[$param] = $atts[$param];
408 }
409 }
410 else if ( isset( $chatbot[$param] ) ) {
411 $frontParams[$param] = $chatbot[$param];
412 }
413 }
414
415 // Server Params
416 // NOTE: We don't need the server params for the chatbot if there are no overrides, it means
417 // we are using the default or a specific chatbot.
418 $hasServerOverrides = count( array_intersect( array_keys( $atts ), MWAI_CHATBOT_SERVER_PARAMS ) ) > 0;
419 $serverParams = [];
420 if ( $hasServerOverrides ) {
421 foreach ( MWAI_CHATBOT_SERVER_PARAMS as $param ) {
422 if ( isset( $atts[$param] ) ) {
423 $serverParams[$param] = $atts[$param];
424 }
425 else {
426 $serverParams[$param] = $chatbot[$param] ?? null;
427 }
428 }
429 }
430
431 // Front Params
432 $frontSystem = $this->build_front_params( $botId, $customId );
433
434 // Clean Params
435 $frontParams = $this->clean_params( $frontParams );
436 $frontSystem = $this->clean_params( $frontSystem );
437 $serverParams = $this->clean_params( $serverParams );
438
439 // Server-side: Keep the System Params
440 if ( $hasServerOverrides ) {
441 if ( empty( $customId ) ) {
442 $customId = md5( json_encode( $serverParams ) );
443 $frontSystem['customId'] = $customId;
444 }
445 set_transient( 'mwai_custom_chatbot_' . $customId, $serverParams, 60 * 60 * 24 );
446 }
447
448 // Client-side: Prepare JSON for Front Params and System Params
449 $theme = isset( $frontParams['themeId'] ) ? $this->core->get_theme( $frontParams['themeId'] ) : null;
450 $jsonFrontParams = htmlspecialchars( json_encode( $frontParams ), ENT_QUOTES, 'UTF-8' );
451 $jsonFrontSystem = htmlspecialchars( json_encode( $frontSystem ), ENT_QUOTES, 'UTF-8' );
452 $jsonFrontTheme = htmlspecialchars( json_encode( $theme ), ENT_QUOTES, 'UTF-8' );
453 //$jsonAttributes = htmlspecialchars(json_encode($atts), ENT_QUOTES, 'UTF-8');
454
455 $this->enqueue_scripts();
456 return "<div class='mwai-chatbot-container' data-params='{$jsonFrontParams}' data-system='{$jsonFrontSystem}' data-theme='{$jsonFrontTheme}'></div>";
457 }
458
459 function shortcode_chat_discussions( $atts ) {
460 $atts = empty($atts) ? [] : $atts;
461
462 // Resolve the bot info
463 $resolvedBot = $this->resolveBotInfo( $atts );
464 if ( isset( $resolvedBot['error'] ) ) {
465 return $resolvedBot['error'];
466 }
467 $chatbot = $resolvedBot['chatbot'];
468 $botId = $resolvedBot['botId'];
469 $customId = $resolvedBot['customId'];
470
471 // Rename the keys of the atts into camelCase to match the internal params system.
472 $atts = array_map( function( $key, $value ) {
473 $key = str_replace( '_', ' ', $key );
474 $key = ucwords( $key );
475 $key = str_replace( ' ', '', $key );
476 $key = lcfirst( $key );
477 return [ $key => $value ];
478 }, array_keys( $atts ), $atts );
479 $atts = array_merge( ...$atts );
480
481 // Front Params
482 $frontParams = [];
483 foreach ( MWAI_DISCUSSIONS_FRONT_PARAMS as $param ) {
484 if ( isset( $atts[$param] ) ) {
485 $frontParams[$param] = $atts[$param];
486 }
487 else if ( isset( $chatbot[$param] ) ) {
488 $frontParams[$param] = $chatbot[$param];
489 }
490 }
491
492 // Server Params
493 $serverParams = [];
494 foreach ( MWAI_DISCUSSIONS_SERVER_PARAMS as $param ) {
495 if ( isset( $atts[$param] ) ) {
496 $serverParams[$param] = $atts[$param];
497 }
498 }
499
500 // Front System
501 $frontSystem = $this->build_front_params( $botId, $customId );
502
503 // Clean Params
504 $frontParams = $this->clean_params( $frontParams );
505 $frontSystem = $this->clean_params( $frontSystem );
506 $serverParams = $this->clean_params( $serverParams );
507
508 $theme = isset( $frontParams['themeId'] ) ? $this->core->get_theme( $frontParams['themeId'] ) : null;
509 $jsonFrontParams = htmlspecialchars( json_encode( $frontParams ), ENT_QUOTES, 'UTF-8' );
510 $jsonFrontSystem = htmlspecialchars( json_encode( $frontSystem ), ENT_QUOTES, 'UTF-8' );
511 $jsonFrontTheme = htmlspecialchars( json_encode( $theme ), ENT_QUOTES, 'UTF-8' );
512
513 return "<div class='mwai-discussions-container' data-params='{$jsonFrontParams}' data-system='{$jsonFrontSystem}' data-theme='{$jsonFrontTheme}'></div>";
514 }
515
516 function clean_params( &$params ) {
517 foreach ( $params as $param => $value ) {
518 if ( empty( $value ) || is_array( $value ) ) {
519 continue;
520 }
521 $lowerCaseValue = strtolower( $value );
522 if ( $lowerCaseValue === 'true' || $lowerCaseValue === 'false' || is_bool( $value ) ) {
523 $params[$param] = filter_var( $value, FILTER_VALIDATE_BOOLEAN );
524 }
525 else if ( is_numeric( $value ) ) {
526 $params[$param] = filter_var( $value, FILTER_VALIDATE_FLOAT );
527 }
528 }
529 return $params;
530 }
531
532 }
533