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