PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 2.0.8
AI Engine – The Chatbot, AI Framework & MCP for WordPress v2.0.8
3.5.9 3.5.8 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 utilities.php 2 years ago
chatbot.php
502 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',
7 'textInputPlaceholder', 'textInputMaxLength', 'textCompliance', 'startSentence', 'localMemory',
8 'themeId', 'window', 'icon', 'iconText', 'iconAlt', 'iconPosition', 'fullscreen', 'copyButton'
9 ] );
10 define( 'MWAI_CHATBOT_SERVER_PARAMS', [ 'id', 'envId', 'env', 'mode', 'contentAware', 'context',
11 'embeddingsEnvId', 'embeddingsIndex', 'embeddingsNamespace', 'assistantId',
12 'model', 'temperature', 'maxTokens', 'contextMaxLength',
13 'maxResults', 'apiKey', 'service'
14 ] );
15
16 // Params for the discussions (front and server)
17
18 define( 'MWAI_DISCUSSIONS_FRONT_PARAMS', [ 'themeId', 'textNewChat' ] );
19 define( 'MWAI_DISCUSSIONS_SERVER_PARAMS', [ 'customId' ] );
20
21 class Meow_MWAI_Modules_Chatbot {
22 private $core = null;
23 private $namespace = 'mwai-ui/v1';
24 private $siteWideChatId = null;
25
26 public function __construct() {
27 global $mwai_core;
28 $this->core = $mwai_core;
29 add_shortcode( 'mwai_chatbot', array( $this, 'chat_shortcode' ) );
30 add_shortcode( 'mwai_chatbot_v2', array( $this, 'chat_shortcode' ) );
31 add_action( 'rest_api_init', array( $this, 'rest_api_init' ) );
32 $this->siteWideChatId = $this->core->get_option( 'botId' );
33 add_action( 'wp_enqueue_scripts', array( $this, 'register_scripts' ) );
34
35 if ( $this->core->get_option( 'shortcode_chat_discussions' ) ) {
36 add_shortcode( 'mwai_discussions', [ $this, 'shortcode_chat_discussions' ] );
37 }
38 }
39
40 public function register_scripts() {
41 $physical_file = trailingslashit( MWAI_PATH ) . 'app/chatbot.js';
42 $cache_buster = file_exists( $physical_file ) ? filemtime( $physical_file ) : MWAI_VERSION;
43 wp_register_script( 'mwai_chatbot', trailingslashit( MWAI_URL ) . 'app/chatbot.js',
44 [ 'wp-element' ], $cache_buster, false );
45 if ( !empty( $this->siteWideChatId ) && $this->siteWideChatId !== 'none' ) {
46 $this->enqueue_scripts();
47 add_action( 'wp_footer', array( $this, 'inject_chat' ) );
48 }
49 }
50
51 public function enqueue_scripts() {
52 wp_enqueue_script( "mwai_chatbot" );
53 if ( $this->core->get_option( 'shortcode_chat_syntax_highlighting' ) ) {
54 wp_enqueue_script( "mwai_highlight" );
55 }
56 }
57
58 public function rest_api_init() {
59 register_rest_route( $this->namespace, '/chats/submit', array(
60 'methods' => 'POST',
61 'callback' => [ $this, 'rest_chat' ],
62 'permission_callback' => array( $this->core, 'check_rest_nonce' )
63 ) );
64 }
65
66 public function basics_security_check( $botId, $customId, $newMessage ) {
67 if ( empty( $newMessage ) ) {
68 error_log("AI Engine: The query was rejected - message was empty.");
69 return false;
70 }
71 if ( !$botId && !$customId ) {
72 error_log("AI Engine: The query was rejected - no botId nor id was specified.");
73 return false;
74 }
75
76 $length = strlen( $newMessage );
77 if ( $length < 1 || $length > ( 4096 * 16 ) ) {
78 error_log("AI Engine: The query was rejected - message was too short or too long.");
79 return false;
80 }
81 return true;
82 }
83
84 public function rest_chat( $request ) {
85 $params = $request->get_json_params();
86 $botId = $params['botId'] ?? null;
87 $customId = $params['customId'] ?? null;
88 $stream = $params['stream'] ?? false;
89 $newMessage = trim( $params['newMessage'] ?? '' );
90 $newImageId = $params['newImageId'] ?? null;
91
92 if ( !$this->basics_security_check( $botId, $customId, $newMessage )) {
93 return new WP_REST_Response( [
94 'success' => false,
95 'message' => apply_filters( 'mwai_ai_exception', 'Sorry, your query has been rejected.' )
96 ], 403 );
97 }
98
99 try {
100 $data = $this->chat_submit( $botId, $newMessage, $newImageId, $params, $stream );
101 return new WP_REST_Response( [
102 'success' => true,
103 'reply' => $data['reply'],
104 'images' => $data['images'],
105 'usage' => $data['usage']
106 ], 200 );
107 }
108 catch ( Exception $e ) {
109 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
110 return new WP_REST_Response( [
111 'success' => false,
112 'message' => $message
113 ], 500 );
114 }
115 }
116
117 public function chat_submit( $botId, $newMessage, $newImageId, $params = [], $stream = false ) {
118 try {
119 $chatbot = null;
120 $customId = $params['customId'] ?? null;
121
122 // Custom Chatbot
123 if ( $customId ) {
124 $chatbot = get_transient( 'mwai_custom_chatbot_' . $customId );
125 }
126 // Registered Chatbot
127 if ( !$chatbot && $botId ) {
128 $chatbot = $this->core->get_chatbot( $botId );
129 }
130
131 if ( !$chatbot ) {
132 error_log("AI Engine: No chatbot was found for this query.");
133 throw new Exception( 'Sorry, your query has been rejected.' );
134 }
135
136 // Create QueryText
137 $context = null;
138 $mode = $chatbot['mode'] ?? 'chat';
139
140 if ( $mode === 'images' ) {
141 $query = new Meow_MWAI_Query_Image( $newMessage );
142
143 // Handle Params
144 $newParams = [];
145 foreach ( $chatbot as $key => $value ) {
146 $newParams[$key] = $value;
147 }
148 foreach ( $params as $key => $value ) {
149 $newParams[$key] = $value;
150 }
151 $params = apply_filters( 'mwai_chatbot_params', $newParams );
152 $params['env'] = empty( $params['env'] ) ? 'chatbot' : $params['env'];
153 $query->inject_params( $params );
154 }
155 else {
156 $query = $mode === 'assistant' ? new Meow_MWAI_Query_Assistant( $newMessage ) :
157 new Meow_MWAI_Query_Text( $newMessage, 1024 );
158 $streamCallback = null;
159
160 // Handle Params
161 $newParams = [];
162 foreach ( $chatbot as $key => $value ) {
163 $newParams[$key] = $value;
164 }
165 foreach ( $params as $key => $value ) {
166 $newParams[$key] = $value;
167 }
168 $params = apply_filters( 'mwai_chatbot_params', $newParams );
169 $params['env'] = empty( $params['env'] ) ? 'chatbot' : $params['env'];
170 $query->inject_params( $params );
171
172 // Support for Uploaded Image
173 if ( !empty( $newImageId ) ) {
174 $remote_upload = $this->core->get_option( 'image_remote_upload' );
175 if ( $remote_upload === 'data' ) {
176 $data = $this->core->files->get_base64_data( $newImageId );
177 $query->set_new_image_data( $data );
178 }
179 else {
180 $url = $this->core->files->get_url( $newImageId );
181 $query->set_new_image( $url );
182 }
183 }
184
185 // Takeover
186 $takeoverAnswer = apply_filters( 'mwai_chatbot_takeover', null, $query, $params );
187 if ( !empty( $takeoverAnswer ) ) {
188 return [
189 'reply' => $takeoverAnswer,
190 'images' => null,
191 'usage' => null
192 ];
193 }
194
195 // Moderation
196 if ( $this->core->get_option( 'shortcode_chat_moderation' ) ) {
197 global $mwai;
198 $isFlagged = $mwai->moderationCheck( $query->prompt );
199 if ( $isFlagged ) {
200 throw new Exception( 'Sorry, your message has been rejected by moderation.' );
201 }
202 }
203
204 // Awareness & Embeddings
205 if ( $query->mode === 'chat' || $query->mode === 'assistant' ) {
206 $context = $this->core->retrieve_context( $params, $query );
207 if ( !empty( $context ) ) {
208 $query->inject_context( $context['content'] );
209 }
210 }
211 }
212
213 // Process Query
214 if ( $stream ) {
215 $streamCallback = function( $reply ) {
216 //$raw = _wp_specialchars( $reply, ENT_NOQUOTES, 'UTF-8', true );
217 $raw = $reply;
218 $this->stream_push( [ 'type' => 'live', 'data' => $raw ] );
219 if ( ob_get_level() > 0 ) {
220 ob_flush();
221 }
222 flush();
223 };
224 header( 'Cache-Control: no-cache' );
225 header( 'Content-Type: text/event-stream' );
226 header( 'X-Accel-Buffering: no' ); // This is useful to disable buffering in nginx through headers.
227 ob_implicit_flush( true );
228 ob_end_flush();
229 }
230
231 $reply = $this->core->ai->run( $query, $streamCallback );
232 $rawText = $reply->result;
233 $extra = [];
234 if ( $context ) {
235 $extra = [ 'embeddings' => $context['embeddings'] ];
236 }
237 $rawText = apply_filters( 'mwai_chatbot_reply', $rawText, $query, $params, $extra );
238
239 $restRes = [
240 'reply' => $rawText,
241 'images' => $reply->getType() === 'images' ? $reply->results : null,
242 'usage' => $reply->usage
243 ];
244
245 // Process Reply
246 if ( $stream ) {
247 $this->stream_push( [
248 'type' => 'end',
249 'data' => json_encode([
250 'success' => true,
251 'reply' => $restRes['reply'],
252 'images' => $restRes['images'],
253 'usage' => $restRes['usage']
254 ])
255 ] );
256 die();
257 }
258 else {
259 return $restRes;
260 }
261
262 }
263 catch ( Exception $e ) {
264 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
265 if ( $stream ) {
266 $this->stream_push( [ 'type' => 'error', 'data' => $message ] );
267 die();
268 }
269 else {
270 throw $e;
271 }
272 }
273 }
274
275 public function stream_push( $data ) {
276 $out = "data: " . json_encode( $data );
277 echo $out;
278 echo "\n\n";
279 if (ob_get_level() > 0) {
280 ob_end_flush();
281 }
282 flush();
283 }
284
285 public function inject_chat() {
286 $params = $this->core->get_chatbot( $this->siteWideChatId );
287 $clean_params = [];
288 if ( !empty( $params ) ) {
289 $clean_params['window'] = true;
290 $clean_params['id'] = $this->siteWideChatId;
291 echo $this->chat_shortcode( $clean_params );
292 }
293 return null;
294 }
295
296 public function build_front_params( $botId, $customId ) {
297 $frontSystem = [
298 'botId' => $customId ? null : $botId,
299 'customId' => $customId,
300 'userData' => $this->core->get_user_data(),
301 'sessionId' => $this->core->get_session_id(),
302 'restNonce' => $this->core->get_nonce(),
303 'contextId' => get_the_ID(),
304 'pluginUrl' => MWAI_URL,
305 'restUrl' => untrailingslashit( get_rest_url() ),
306 'debugMode' => $this->core->get_option( 'debug_mode' ),
307 'typewriter' => $this->core->get_option( 'shortcode_chat_typewriter' ),
308 'speech_recognition' => $this->core->get_option( 'speech_recognition' ),
309 'speech_synthesis' => $this->core->get_option( 'speech_synthesis' ),
310 'stream' => $this->core->get_option( 'shortcode_chat_stream' ),
311 ];
312 return $frontSystem;
313 }
314
315 public function resolveBotInfo( &$atts )
316 {
317 $chatbot = null;
318 $botId = $atts['id'] ?? null;
319 $customId = $atts['custom_id'] ?? null;
320 if (!$botId && !$customId) {
321 $botId = "default";
322 }
323 if ( $botId ) {
324 $chatbot = $this->core->get_chatbot( $botId );
325 if (!$chatbot) {
326 $botId = $botId ?: 'N/A';
327 return [
328 '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'.",
329 ];
330 }
331 }
332 $chatbot = $chatbot ?: $this->core->get_chatbot( 'default' );
333 if ( !empty( $customId ) ) {
334 $botId = null;
335 }
336 unset( $atts['id'] );
337 return [
338 'chatbot' => $chatbot,
339 'botId' => $botId,
340 'customId' => $customId,
341 ];
342 }
343
344 public function chat_shortcode( $atts ) {
345 $atts = empty( $atts ) ? [] : $atts;
346
347 // Let the user override the chatbot params
348 $atts = apply_filters( 'mwai_chatbot_params', $atts );
349
350 // Resolve the bot info
351 $resolvedBot = $this->resolveBotInfo( $atts, 'chatbot' );
352 if ( isset( $resolvedBot['error'] ) ) {
353 return $resolvedBot['error'];
354 }
355 $chatbot = $resolvedBot['chatbot'];
356 $botId = $resolvedBot['botId'];
357 $customId = $resolvedBot['customId'];
358
359 // Rename the keys of the atts into camelCase to match the internal params system.
360 $atts = array_map( function( $key, $value ) {
361 $key = str_replace( '_', ' ', $key );
362 $key = ucwords( $key );
363 $key = str_replace( ' ', '', $key );
364 $key = lcfirst( $key );
365 return [ $key => $value ];
366 }, array_keys( $atts ), $atts );
367 $atts = array_merge( ...$atts );
368
369 $frontParams = [];
370 foreach ( MWAI_CHATBOT_FRONT_PARAMS as $param ) {
371 if ( isset( $atts[$param] ) ) {
372 if ( $param === 'localMemory' ) {
373 $frontParams[$param] = $atts[$param] === 'true';
374 }
375 else {
376 $frontParams[$param] = $atts[$param];
377 }
378 }
379 else if ( isset( $chatbot[$param] ) ) {
380 $frontParams[$param] = $chatbot[$param];
381 }
382 }
383
384 // Server Params
385 // NOTE: We don't need the server params for the chatbot if there are no overrides, it means
386 // we are using the default or a specific chatbot.
387 $hasServerOverrides = count( array_intersect( array_keys( $atts ), MWAI_CHATBOT_SERVER_PARAMS ) ) > 0;
388 $serverParams = [];
389 if ( $hasServerOverrides ) {
390 foreach ( MWAI_CHATBOT_SERVER_PARAMS as $param ) {
391 if ( isset( $atts[$param] ) ) {
392 $serverParams[$param] = $atts[$param];
393 }
394 else {
395 $serverParams[$param] = $chatbot[$param] ?? null;
396 }
397 }
398 }
399
400 // Front Params
401 $frontSystem = $this->build_front_params( $botId, $customId );
402
403 // Clean Params
404 $frontParams = $this->clean_params( $frontParams );
405 $frontSystem = $this->clean_params( $frontSystem );
406 $serverParams = $this->clean_params( $serverParams );
407
408 // Server-side: Keep the System Params
409 if ( $hasServerOverrides ) {
410 if ( empty( $customId ) ) {
411 $customId = md5( json_encode( $serverParams ) );
412 $frontSystem['customId'] = $customId;
413 }
414 set_transient( 'mwai_custom_chatbot_' . $customId, $serverParams, 60 * 60 * 24 );
415 }
416
417 // Client-side: Prepare JSON for Front Params and System Params
418 $theme = isset( $frontParams['themeId'] ) ? $this->core->get_theme( $frontParams['themeId'] ) : null;
419 $jsonFrontParams = htmlspecialchars( json_encode( $frontParams ), ENT_QUOTES, 'UTF-8' );
420 $jsonFrontSystem = htmlspecialchars( json_encode( $frontSystem ), ENT_QUOTES, 'UTF-8' );
421 $jsonFrontTheme = htmlspecialchars( json_encode( $theme ), ENT_QUOTES, 'UTF-8' );
422 //$jsonAttributes = htmlspecialchars(json_encode($atts), ENT_QUOTES, 'UTF-8');
423
424 $this->enqueue_scripts();
425 return "<div class='mwai-chatbot-container' data-params='{$jsonFrontParams}' data-system='{$jsonFrontSystem}' data-theme='{$jsonFrontTheme}'></div>";
426 }
427
428 function shortcode_chat_discussions( $atts ) {
429 $atts = empty($atts) ? [] : $atts;
430
431 // Resolve the bot info
432 $resolvedBot = $this->resolveBotInfo( $atts );
433 if ( isset( $resolvedBot['error'] ) ) {
434 return $resolvedBot['error'];
435 }
436 $chatbot = $resolvedBot['chatbot'];
437 $botId = $resolvedBot['botId'];
438 $customId = $resolvedBot['customId'];
439
440 // Rename the keys of the atts into camelCase to match the internal params system.
441 $atts = array_map( function( $key, $value ) {
442 $key = str_replace( '_', ' ', $key );
443 $key = ucwords( $key );
444 $key = str_replace( ' ', '', $key );
445 $key = lcfirst( $key );
446 return [ $key => $value ];
447 }, array_keys( $atts ), $atts );
448 $atts = array_merge( ...$atts );
449
450 // Front Params
451 $frontParams = [];
452 foreach ( MWAI_DISCUSSIONS_FRONT_PARAMS as $param ) {
453 if ( isset( $atts[$param] ) ) {
454 $frontParams[$param] = $atts[$param];
455 }
456 else if ( isset( $chatbot[$param] ) ) {
457 $frontParams[$param] = $chatbot[$param];
458 }
459 }
460
461 // Server Params
462 $serverParams = [];
463 foreach ( MWAI_DISCUSSIONS_SERVER_PARAMS as $param ) {
464 if ( isset( $atts[$param] ) ) {
465 $serverParams[$param] = $atts[$param];
466 }
467 }
468
469 // Front System
470 $frontSystem = $this->build_front_params( $botId, $customId );
471
472 // Clean Params
473 $frontParams = $this->clean_params( $frontParams );
474 $frontSystem = $this->clean_params( $frontSystem );
475 $serverParams = $this->clean_params( $serverParams );
476
477 $theme = isset( $frontParams['themeId'] ) ? $this->core->get_theme( $frontParams['themeId'] ) : null;
478 $jsonFrontParams = htmlspecialchars( json_encode( $frontParams ), ENT_QUOTES, 'UTF-8' );
479 $jsonFrontSystem = htmlspecialchars( json_encode( $frontSystem ), ENT_QUOTES, 'UTF-8' );
480 $jsonFrontTheme = htmlspecialchars( json_encode( $theme ), ENT_QUOTES, 'UTF-8' );
481
482 return "<div class='mwai-discussions-container' data-params='{$jsonFrontParams}' data-system='{$jsonFrontSystem}' data-theme='{$jsonFrontTheme}'></div>";
483 }
484
485 function clean_params( &$params ) {
486 foreach ( $params as $param => $value ) {
487 if ( empty( $value ) || is_array( $value ) ) {
488 continue;
489 }
490 $lowerCaseValue = strtolower( $value );
491 if ( $lowerCaseValue === 'true' || $lowerCaseValue === 'false' || is_bool( $value ) ) {
492 $params[$param] = filter_var( $value, FILTER_VALIDATE_BOOLEAN );
493 }
494 else if ( is_numeric( $value ) ) {
495 $params[$param] = filter_var( $value, FILTER_VALIDATE_FLOAT );
496 }
497 }
498 return $params;
499 }
500
501 }
502