PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 0.4.2
AI Engine – The Chatbot, AI Framework & MCP for WordPress v0.4.2
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-chatgpt.css 3 years ago chatbot-chatgpt.scss 3 years ago chatbot.php 3 years ago
chatbot.php
439 lines
1 <?php
2
3 class Meow_MWAI_Modules_Chatbot {
4 private $core = null;
5 private $namespace = 'ai-engine/v1';
6
7 public function __construct() {
8 global $mwai_core;
9 $this->core = $mwai_core;
10 if ( is_admin() ) { return; }
11 add_shortcode( 'mwai_chat', array( $this, 'chat' ) );
12 add_shortcode( 'mwai_chatbot', array( $this, 'chat' ) );
13 add_shortcode( 'mwai_imagesbot', array( $this, 'imageschat' ) );
14 add_action( 'rest_api_init', array( $this, 'rest_api_init' ) );
15 if ( $this->core->get_option( 'shortcode_chat_inject' ) ) {
16 add_action( 'wp_body_open', array( $this, 'inject_chat' ) );
17 }
18
19 // Only for test now, but later we should probably import the JS/CSS
20 if ( $this->core->get_option( 'shortcode_chat_syntax_highlighting' ) ) {
21 wp_enqueue_script( 'mwai_chatbot',
22 '//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js', [], null, false );
23 wp_enqueue_style( 'mwai_chatbot',
24 '//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/stackoverflow-dark.min.css' );
25 }
26 }
27
28 function rest_api_init() {
29 try {
30 register_rest_route( $this->namespace, '/chat', array(
31 'methods' => 'POST',
32 'callback' => array( $this, 'rest_chat' ),
33 'permission_callback' => '__return_true'
34 ) );
35 register_rest_route( $this->namespace, '/imagesbot', array(
36 'methods' => 'POST',
37 'callback' => array( $this, 'rest_imagesbot' ),
38 'permission_callback' => '__return_true'
39 ) );
40 }
41 catch ( Exception $e ) {
42 var_dump( $e );
43 }
44 }
45
46 function chatgpt_style( $id ) {
47 $css = file_get_contents( MWAI_PATH . '/classes/modules/chatbot-chatgpt.css' );
48 $css = str_replace( '#mwai-chat-id', "#mwai-chat-{$id}", $css );
49 return "<style>" . $css . "</style>";
50 }
51
52 function rest_chat( $request ) {
53 try {
54 $params = $request->get_json_params();
55 $session = $params['session'];
56 $env = $params['env'];
57 $prompt = $params['prompt'];
58 $model = $params['model'];
59 $temperature = $params['temperature'];
60 $maxTokens = intval( $params['maxTokens'] );
61 $apiKey = $params['apiKey'];
62 $stop = $params['stop'];
63 $query = new Meow_MWAI_QueryText( $prompt, 1024 );
64 if ( $model ) {
65 $query->setModel( $model );
66 }
67 if ( $temperature ) {
68 $query->setTemperature( $temperature );
69 }
70 if ( $maxTokens ) {
71 $query->setMaxTokens( $maxTokens );
72 }
73 if ( $stop ) {
74 $query->setStop( $stop );
75 }
76 if ( $apiKey ) {
77 $query->setApiKey( $apiKey );
78 }
79 if ( $env ) {
80 $query->setEnv( $env );
81 }
82 if ( $session ) {
83 $query->setSession( $session );
84 }
85 $answer = $this->core->ai->run( $query );
86 $rawText = $answer->result;
87 $html = apply_filters( 'mwai_chatbot_answer', $rawText );
88 $html = $this->core->markdown_to_html( $rawText );
89 return new WP_REST_Response([ 'success' => true, 'answer' => $rawText,
90 'html' => $html, 'usage' => $answer->usage ], 200 );
91 }
92 catch ( Exception $e ) {
93 return new WP_REST_Response([ 'success' => false, 'message' => $e->getMessage() ], 500 );
94 }
95 }
96
97 function rest_imagesbot( $request ) {
98 try {
99 $params = $request->get_json_params();
100 $session = $params['session'];
101 $env = $params['env'];
102 $prompt = $params['prompt'];
103 $maxResults = $params['maxResults'];
104 $apiKey = $params['apiKey'];
105 $query = new Meow_MWAI_QueryImage( $prompt );
106 if ( $maxResults ) {
107 $query->setMaxResults( $maxResults );
108 }
109 if ( $apiKey ) {
110 $query->setApiKey( $apiKey );
111 }
112 if ( $env ) {
113 $query->setEnv( $env );
114 }
115 if ( $session ) {
116 $query->setSession( $session );
117 }
118 $answer = $this->core->ai->run( $query );
119 return new WP_REST_Response([ 'success' => true, 'images' => $answer->results, 'usage' => $answer->usage ], 200 );
120 }
121 catch ( Exception $e ) {
122 return new WP_REST_Response([ 'success' => false, 'message' => $e->getMessage() ], 500 );
123 }
124 }
125
126 function inject_chat() {
127 $params = $this->core->get_option( 'shortcode_chat_params' );
128 echo $this->chat( $params );
129 }
130
131 function imageschat( $atts ) {
132 $atts['mode'] = 'images';
133 return $this->chat( $atts );
134 }
135
136 function chat( $atts ) {
137 // Use the core default parameters, or the user default parameters
138 $override = $this->core->get_option( 'shortcode_chat_params_override' );
139 $defaults_params = $override ? $this->core->get_option( 'shortcode_chat_params' ) :
140 $this->core->get_option( 'shortcode_chat_default_params' );
141 $defaults_params['id'] = uniqid();
142
143 // Give a chance to modify the default parameters one last time
144 $defaults = apply_filters( 'mwai_chatbot_params_defaults', $defaults_params );
145
146 // Make sure all the mandatory params are set
147 foreach ( $this->core->defaultChatbotParams as $key => $value ) {
148 if ( !isset( $defaults[$key] ) ) {
149 $defaults[$key] = $value;
150 }
151 }
152
153 // Override with the shortcode, and before/after filters
154 $atts = apply_filters( 'mwai_chatbot_params_before', $atts );
155 $atts = shortcode_atts( $defaults, $atts );
156 $atts = apply_filters( 'mwai_chatbot_params', $atts );
157
158 // UI Parameters
159 $aiName = addslashes( trim($atts['ai_name']) );
160 $userName = addslashes( trim($atts['user_name']) );
161 $sysName = addslashes( trim($atts['sys_name']) );
162 $context = addslashes( $atts['context'] );
163 $textSend = addslashes( trim( $atts['text_send'] ) );
164 $textInputPlaceholder = addslashes( trim( $atts['text_input_placeholder'] ) );
165 $startSentence = addslashes( trim( $atts['start_sentence'] ) );
166 $window = filter_var( $atts['window'], FILTER_VALIDATE_BOOLEAN );
167 $fullscreen = filter_var( $atts['fullscreen'], FILTER_VALIDATE_BOOLEAN );
168 $style = $atts['style'];
169
170 // Chatbot System Parameters
171 $id = $atts['id'];
172 $env = $atts['env'];
173 $mode = $atts['mode'];
174 $maxResults = $atts['max_results'];
175 $sessionId = $this->core->get_session_id();
176 $rest_nonce = wp_create_nonce( 'wp_rest' );
177 $casuallyFineTuned = boolval( $atts['casually_fined_tuned'] );
178 $promptEnding = addslashes( trim( $atts['prompt_ending'] ) );
179 $completionEnding = addslashes( trim( $atts['completion_ending'] ) );
180 if ( $casuallyFineTuned ) {
181 $promptEnding = "\\n\\n===\\n\\n";
182 $completionEnding = "\\n\\n";
183 }
184
185 // OpenAI Parameters
186 $model = $atts['model'];
187 $temperature = $atts['temperature'];
188 $maxTokens = $atts['max_tokens'];
189 $apiKey = $atts['api_key'];
190
191 // Named functions
192 $onSentClickFn = "mwai_{$id}_onSendClick";
193 $addReplyFn = "mwai_{$id}_addReply";
194 $initChatBotFn = "mwai_{$id}_initChatBot";
195
196 // Variables
197 $apiUrl = get_rest_url( null, $mode === 'images' ? 'ai-engine/v1/imagesbot' : 'ai-engine/v1/chat' );
198 $onGoingPrompt = "mwai_{$id}_onGoingPrompt";
199 $baseClasses = "mwai-chat";
200 $baseClasses .= ( $window ? " mwai-window" : "" );
201 $baseClasses .= ( !$window && $fullscreen ? " mwai-fullscreen" : "" );
202
203 // Output CSS
204 ob_start();
205 $style_content = "";
206 if ( $style === 'chatgpt' ) {
207 $style_content = $this->chatgpt_style( $id, $style );
208 }
209 echo apply_filters( 'mwai_chatbot_style', $style_content, $id );
210
211 // Output HTML & CSS
212 ?>
213 <div id="mwai-chat-<?= $id ?>" class="<?= $baseClasses ?>">
214 <?php if ( $window ) { ?>
215 <div class="mwai-open-button">
216 <img width="64" height="64" src="<?= plugins_url( '../../images/chat-green.svg', __FILE__ ) ?>" />
217 </div>
218 <div class="mwai-header">
219 <?php if ( $window ) { ?>
220 <div class="mwai-resize-button"></div>
221 <?php } ?>
222 <div class="mwai-close-button"></div>
223 </div>
224 <?php } ?>
225 <div class="mwai-content">
226 <div class="mwai-conversation">
227 </div>
228 <div class="mwai-input">
229 <textarea rows="1" placeholder="<?= $textInputPlaceholder ?>"></textarea>
230 <button><span><?= $textSend ?></span></button>
231 </div>
232 </div>
233 </div>
234
235 <script>
236 {
237 let <?= $onGoingPrompt ?> = '<?= $context ?>' + '\n\n';
238 let isMobile = window.matchMedia("only screen and (max-width: 760px)").matches;
239 let isWindow = <?= $window ? 'true' : 'false' ?>;
240 let mode = '<?= $mode ?>';
241
242 // Push the reply in the conversation
243 function <?= $addReplyFn ?>(text, type = 'user') {
244 var conversation = document.querySelector('#mwai-chat-<?= $id ?> .mwai-conversation');
245
246 // If text is array, then it's image URLs. Let's create a simple gallery in HTML in $text.
247 if (Array.isArray(text)) {
248 var newText = '<div class="mwai-gallery">';
249 for (var i = 0; i < text.length; i++) {
250 newText += '<a href="' + text[i] + '" target="_blank"><img src="' + text[i] + '" />';
251 }
252 text = newText + '</div>';
253 }
254
255 var mwaiClasses = 'mwai-reply';
256 if (type === 'ai') {
257 mwaiClasses += ' mwai-ai';
258 }
259 else if (type === 'system') {
260 mwaiClasses += ' mwai-system';
261 }
262 else {
263 mwaiClasses += ' mwai-user';
264 }
265 var html = '<div class="' + mwaiClasses + '">';
266 if (type === 'ai') {
267 html += '<span class="mwai-name"><?= $aiName ?></span>';
268 }
269 else if (type === 'system') {
270 html += '<span class="mwai-name"><?= $sysName ?></span>';
271 }
272 else {
273 html += '<span class="mwai-name"><?= $userName ?></span>';
274 }
275 html += '<span class="mwai-text">' + text + '</span>';
276 html += '</div>';
277 conversation.innerHTML += html;
278 conversation.scrollTop = conversation.scrollHeight;
279
280 // Syntax coloring
281 if (typeof hljs !== 'undefined') {
282 document.querySelectorAll('pre code').forEach((el) => {
283 hljs.highlightElement(el);
284 });
285 }
286 }
287
288 // Function to request the completion
289 function <?= $onSentClickFn ?>() {
290 let input = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input textarea');
291 let inputText = input.value.trim();
292
293 if (inputText === '') {
294 return;
295 }
296
297 // Disable the button
298 var button = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input button');
299 button.disabled = true;
300
301 // Add the user reply
302 <?= $addReplyFn ?>(inputText, 'user');
303 <?= $onGoingPrompt ?> += '<?= $userName ?>' + inputText + '\n';
304 input.value = '';
305 input.setAttribute('rows', 1);
306 input.disabled = true;
307
308 // Let's build the prompt depending on the "system"
309 <?= $onGoingPrompt ?> += '<?= $aiName ?>';
310 let prompt = <?= $onGoingPrompt ?>;
311 if (<?= $casuallyFineTuned ? 1 : 0 ?>) {
312 prompt = inputText + '<?= $promptEnding ?>';
313 }
314
315 // Prompt for the images
316 const data = mode === 'images' ? {
317 env: '<?= $env ?>',
318 session: '<?= $sessionId ?>',
319 prompt: inputText,
320 maxResults: <?= $maxResults ?>,
321 model: '<?= $atts['model'] ?>',
322 apiKey: '<?= $atts['api_key'] ?>',
323 // Prompt for the chat
324 } : {
325 env: '<?= $env ?>',
326 session: '<?= $sessionId ?>',
327 prompt: prompt,
328 userName: '<?= $userName ?>',
329 aiName: '<?= $aiName ?>',
330 model: '<?= $model ?>',
331 temperature: '<?= $temperature ?>',
332 maxTokens: '<?= $maxTokens ?>',
333 stop: '<?= $completionEnding ?>',
334 maxResults: '<?= $maxResults ?>',
335 apiKey: '<?= $apiKey ?>',
336 };
337 console.log('[BOT] Sent: ', data);
338 fetch('<?= $apiUrl ?>', { method: 'POST', headers: {
339 'Content-Type': 'application/json',
340 'X-WP-Nonce': '<?= $rest_nonce ?>'
341 },
342 body: JSON.stringify(data)
343 })
344 .then(response => response.json())
345 .then(data => {
346 console.log('[BOT] Recv: ', data);
347 if (!data.success) {
348 <?= $addReplyFn ?>(data.message, 'system');
349 }
350 else {
351 <?= $addReplyFn ?>(data.images ? data.images : data.html, 'ai');
352 <?= $onGoingPrompt ?> += data.answer + '\n';
353 }
354 button.disabled = false;
355 input.disabled = false;
356
357 // Only focus only on desktop (to avoid the mobile keyboard to kick-in)
358 if (!isMobile) {
359 input.focus();
360 }
361 })
362 .catch(error => {
363 console.error(error);
364 button.disabled = false;
365 input.disabled = false;
366 });
367 }
368
369 // Keep the textarea height in sync with the content
370 function mwaiSetTextAreaHeight(textarea, lines) {
371 var rows = textarea.getAttribute('rows');
372 if (lines !== rows) {
373 textarea.setAttribute('rows', lines > 5 ? 5 : lines);
374 }
375 }
376
377 // Init the chatbot
378 function <?= $initChatBotFn ?>() {
379 var input = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input textarea');
380 input.addEventListener('keypress', (event) => {
381 if (event.keyCode === 13 && !event.shiftKey) {
382 <?= $onSentClickFn ?>();
383 }
384 });
385 input.addEventListener('keydown', (event) => {
386 var rows = input.getAttribute('rows');
387 if (event.keyCode === 13 && event.shiftKey) {
388 var lines = input.value.split('\n').length + 1;
389 mwaiSetTextAreaHeight(input, lines);
390 }
391 });
392 input.addEventListener('keyup', (event) => {
393 var rows = input.getAttribute('rows');
394 var lines = input.value.split('\n').length ;
395 mwaiSetTextAreaHeight(input, lines);
396 });
397 var button = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input button');
398 button.addEventListener('click', (event) => {
399 <?= $onSentClickFn ?>();
400 });
401
402 // If window, add event listener to mwai-open-button and mwai-close-button
403 if ( isWindow ) {
404 var openButton = document.querySelector('#mwai-chat-<?= $id ?> .mwai-open-button');
405 openButton.addEventListener('click', (event) => {
406 var chat = document.querySelector('#mwai-chat-<?= $id ?>');
407 chat.classList.add('mwai-open');
408 // Only focus only on desktop (to avoid the mobile keyboard to kick-in)
409 if (!isMobile) {
410 input.focus();
411 }
412 });
413 var closeButton = document.querySelector('#mwai-chat-<?= $id ?> .mwai-close-button');
414 closeButton.addEventListener('click', (event) => {
415 var chat = document.querySelector('#mwai-chat-<?= $id ?>');
416 chat.classList.remove('mwai-open');
417 });
418 var resizeButton = document.querySelector('#mwai-chat-<?= $id ?> .mwai-resize-button');
419 resizeButton.addEventListener('click', (event) => {
420 var chat = document.querySelector('#mwai-chat-<?= $id ?>');
421 chat.classList.toggle('mwai-fullscreen');
422 });
423 }
424
425 <?= $addReplyFn ?>('<?= $startSentence ?>', 'ai');
426 }
427
428 // Let's go totally meoooow on this!
429 <?= $initChatBotFn ?>();
430 }
431 </script>
432
433 <?php
434 $output = ob_get_contents();
435 ob_end_clean();
436 $output = apply_filters( 'mwai_chatbot', $output, $atts );
437 return $output;
438 }
439 }