PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 0.9.8
AI Engine – The Chatbot, AI Framework & MCP for WordPress v0.9.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
assistants.php 3 years ago chatbot-chatgpt.css 3 years ago chatbot-chatgpt.scss 3 years ago chatbot.php 3 years ago
chatbot.php
671 lines
1 <?php
2
3 class Meow_MWAI_Modules_Chatbot {
4 private $core = null;
5 private $namespace = 'ai-chatbot/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 add_action( 'wp_footer', array( $this, 'inject_chat' ) );
18 }
19
20 // Only for test now, but later we should probably import the JS/CSS
21 if ( $this->core->get_option( 'shortcode_chat_syntax_highlighting' ) ) {
22 wp_enqueue_script( 'mwai_chatbot',
23 '//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js', [], null, false );
24 wp_enqueue_style( 'mwai_chatbot',
25 '//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/stackoverflow-dark.min.css' );
26 }
27
28 if ( $this->core->get_option( 'shortcode_chat_styles' ) ) {
29 add_filter( 'mwai_chatbot_style', [ $this, 'apply_chat_styles' ], 10, 2 );
30 }
31
32 }
33
34 function rest_api_init() {
35 try {
36 register_rest_route( $this->namespace, '/chat', array(
37 'methods' => 'POST',
38 'callback' => array( $this, 'rest_chat' ),
39 'permission_callback' => '__return_true'
40 ) );
41 register_rest_route( $this->namespace, '/imagesbot', array(
42 'methods' => 'POST',
43 'callback' => array( $this, 'rest_imagesbot' ),
44 'permission_callback' => '__return_true'
45 ) );
46 }
47 catch ( Exception $e ) {
48 var_dump( $e );
49 }
50 }
51
52 function chatgpt_style( $id ) {
53 $css = file_get_contents( MWAI_PATH . '/classes/modules/chatbot-chatgpt.css' );
54 $css = str_replace( '#mwai-chat-id', "#mwai-chat-{$id}", $css );
55 return "<style>" . $css . "</style>";
56 }
57
58 function rest_chat( $request ) {
59 try {
60 $params = $request->get_json_params();
61 $session = $params['session'];
62 $env = $params['env'];
63 $prompt = $params['prompt'];
64 $model = $params['model'];
65 $temperature = $params['temperature'];
66 $maxTokens = intval( $params['maxTokens'] );
67 $apiKey = $params['apiKey'];
68 $stop = $params['stop'];
69 $query = new Meow_MWAI_QueryText( $prompt, 1024 );
70 if ( $model ) {
71 $query->setModel( $model );
72 }
73 if ( $temperature ) {
74 $query->setTemperature( $temperature );
75 }
76 if ( $maxTokens ) {
77 $query->setMaxTokens( $maxTokens );
78 }
79 if ( $stop ) {
80 $query->setStop( $stop );
81 }
82 if ( $apiKey ) {
83 $query->setApiKey( $apiKey );
84 }
85 if ( $env ) {
86 $query->setEnv( $env );
87 }
88 if ( $session ) {
89 $query->setSession( $session );
90 }
91 $answer = $this->core->ai->run( $query );
92 $rawText = $answer->result;
93 $html = apply_filters( 'mwai_chatbot_answer', $rawText );
94 $html = $this->core->markdown_to_html( $rawText );
95 return new WP_REST_Response([ 'success' => true, 'answer' => $rawText,
96 'html' => $html, 'usage' => $answer->usage ], 200 );
97 }
98 catch ( Exception $e ) {
99 return new WP_REST_Response([ 'success' => false, 'message' => $e->getMessage() ], 500 );
100 }
101 }
102
103 function rest_imagesbot( $request ) {
104 try {
105 $params = $request->get_json_params();
106 $session = $params['session'];
107 $env = $params['env'];
108 $prompt = $params['prompt'];
109 $maxResults = $params['maxResults'];
110 $apiKey = $params['apiKey'];
111 $query = new Meow_MWAI_QueryImage( $prompt );
112 if ( $maxResults ) {
113 $query->setMaxResults( $maxResults );
114 }
115 if ( $apiKey ) {
116 $query->setApiKey( $apiKey );
117 }
118 if ( $env ) {
119 $query->setEnv( $env );
120 }
121 if ( $session ) {
122 $query->setSession( $session );
123 }
124 $answer = $this->core->ai->run( $query );
125 return new WP_REST_Response([ 'success' => true, 'images' => $answer->results, 'usage' => $answer->usage ], 200 );
126 }
127 catch ( Exception $e ) {
128 return new WP_REST_Response([ 'success' => false, 'message' => $e->getMessage() ], 500 );
129 }
130 }
131
132 function apply_chat_styles( $css, $chatbotId ) {
133 $chatStyles = $this->core->get_option( 'shortcode_chat_styles' );
134 return preg_replace_callback( '/--mwai-(\w+):\s*([^;]+);/', function ( $matches ) use ($chatStyles ) {
135 if( isset( $chatStyles[$matches[1]] ) ) {
136 return "--mwai-" . $matches[1] . ": " . $chatStyles[$matches[1]] . ";";
137 }
138 return $matches[0];
139 }, $css );
140 }
141
142 function inject_chat() {
143 $params = $this->core->get_option( 'shortcode_chat_params' );
144 echo $this->chat( $params );
145 }
146
147 function imageschat( $atts ) {
148 $atts['mode'] = 'images';
149 return $this->chat( $atts );
150 }
151
152 function getCurrentUser() {
153 if ( is_user_logged_in() ) {
154 return wp_get_current_user();
155 }
156 return null;
157 }
158
159 function handlePlaceholders( $data, $guestName = "Guest: " ) {
160 if ( strpos( $data, '{' ) === false ) {
161 return $data;
162 }
163 $placeholders_meta = [ '{FIRST_NAME}', '{LAST_NAME}' ];
164 $placeholders_data = [ '{USER_LOGIN}', '{DISPLAY_NAME}' ];
165 $user = $this->getCurrentUser();
166 if ( $user ) {
167 foreach ( $placeholders_meta as $placeholder ) {
168 if ( strpos( $data, $placeholder ) === false ) { continue; }
169 $lcPlaceholder = substr( strtolower( $placeholder ), 1, -1 );
170 $value = get_user_meta( $user->ID, $lcPlaceholder, true );
171 $data = str_replace( $placeholder, $value, $data );
172 }
173 foreach ( $placeholders_data as $placeholder ) {
174 if ( strpos( $data, $placeholder ) === false ) { continue; }
175 $lcPlaceholder = substr( strtolower( $placeholder ), 1, -1 );
176 $value = $user->data->$lcPlaceholder;
177 $data = str_replace( $placeholder, $value, $data );
178 }
179 if ( !empty( $data ) ) {
180 return $data;
181 }
182 }
183 return $guestName;
184 }
185
186 function formatUserName( $userName, $guestName = "Guest: " ) {
187 // Default avatar
188 if ( empty( $userName ) ) {
189 $user = $this->getCurrentUser();
190 if ( $user ) {
191 // Gravatar
192 $userName = '<div class="mwai-avatar"><img src="' . get_avatar_url( $user->user_email ) . '" /></div>';
193 }
194 else {
195 // Default avatar
196 $userName = '<div class="mwai-avatar mwai-svg"><img src="' . MWAI_URL . '/images/avatar-user.svg" /></div>';
197 }
198 }
199 // Custom avatar
200 else if ( $this->core->isUrl( $userName ) ) {
201 $userName = '<div class="mwai-avatar"><img src="' . $userName . '" /></div>';
202 }
203 // Placeholders
204 else {
205 $userName = $this->handlePlaceholders( $userName, $guestName );
206 }
207 return $userName;
208 }
209
210 function formatAiName( $aiName ) {
211 // Default avatar
212 if ( empty( $aiName ) ) {
213 $aiName = '<div class="mwai-avatar mwai-svg"><img src="' . MWAI_URL . '/images/avatar-ai.svg" /></div>';
214 }
215 // Custom avatar
216 else if ( $this->core->isUrl( $aiName ) ) {
217 $aiName = '<div class="mwai-avatar"><img src="' . $aiName . '" /></div>';
218 }
219 return $aiName;
220 }
221
222 function chat( $atts ) {
223 // Use the core default parameters, or the user default parameters
224 $override = $this->core->get_option( 'shortcode_chat_params_override' );
225 $defaults_params = $override ? $this->core->get_option( 'shortcode_chat_params' ) :
226 $this->core->get_option( 'shortcode_chat_default_params' );
227
228 // Give a chance to modify the default parameters one last time
229 $defaults = apply_filters( 'mwai_chatbot_params_defaults', $defaults_params );
230
231 // Make sure all the mandatory params are set
232 foreach ( $this->core->defaultChatbotParams as $key => $value ) {
233 if ( !isset( $defaults[$key] ) ) {
234 $defaults[$key] = $value;
235 }
236 }
237
238 // Override with the shortcode, and before/after filters
239 $atts = apply_filters( 'mwai_chatbot_params_before', $atts );
240 $atts = shortcode_atts( $defaults, $atts );
241 $atts = apply_filters( 'mwai_chatbot_params', $atts );
242
243 // UI Parameters
244 $aiName = addslashes( trim($atts['ai_name']) );
245 $userName = addslashes( trim($atts['user_name']) );
246 $guestName = addslashes( trim($atts['guest_name']) );
247 $sysName = addslashes( trim($atts['sys_name']) );
248 $context = addslashes( $atts['context'] );
249 $context = preg_replace( '/\v+/', "\\n", $context );
250 $textSend = addslashes( trim( $atts['text_send'] ) );
251 $textClear = addslashes( trim( $atts['text_clear'] ) );
252 $textInputPlaceholder = addslashes( trim( $atts['text_input_placeholder'] ) );
253 $startSentence = addslashes( trim( $atts['start_sentence'] ) );
254 $window = filter_var( $atts['window'], FILTER_VALIDATE_BOOLEAN );
255 $fullscreen = filter_var( $atts['fullscreen'], FILTER_VALIDATE_BOOLEAN );
256 $icon = addslashes( trim($atts['icon']) );
257 $iconText = trim($atts['icon_text']);
258 $iconPosition = addslashes( trim($atts['icon_position']) );
259 $style = $atts['style'];
260
261 // Validade & Enhance UI Parameters
262 $aiName = $this->formatAiName( $aiName );
263 $userName = $this->formatUserName( $userName, $guestName );
264
265 // Chatbot System Parameters
266 $id = empty( $atts['id'] ) ? uniqid() : $atts['id'];
267 $memorizeChat = !empty( $atts['id'] );
268 $id = preg_replace( '/[^a-zA-Z0-9]/', '', $id );
269 $env = $atts['env'];
270 $mode = $atts['mode'];
271 $maxResults = $atts['max_results'];
272 $sessionId = $this->core->get_session_id();
273 $rest_nonce = wp_create_nonce( 'wp_rest' );
274 $casuallyFineTuned = boolval( $atts['casually_fine_tuned'] );
275 $promptEnding = addslashes( trim( $atts['prompt_ending'] ) );
276 $completionEnding = addslashes( trim( $atts['completion_ending'] ) );
277 if ( $casuallyFineTuned ) {
278 $promptEnding = "\\n\\n===\\n\\n";
279 $completionEnding = "\\n\\n";
280 }
281 $debugMode = $chatStyles = $this->core->get_option( 'debug_mode' );
282
283 // OpenAI Parameters
284 $model = $atts['model'];
285 $temperature = $atts['temperature'];
286 $maxTokens = $atts['max_tokens'];
287 $apiKey = $atts['api_key'];
288
289 // Named functions
290 $onSentClickFn = "mwai_{$id}_onSendClick";
291 $addReplyFn = "mwai_{$id}_addReply";
292 $initChatBotFn = "mwai_{$id}_initChatBot";
293 $setButtonTextFn = "mwai_{$id}_setButtonText";
294 $injectTimerFn = "mwai_{$id}_injectTimer";
295
296 // Variables
297 $apiUrl = get_rest_url( null, $mode === 'images' ? 'ai-chatbot/v1/imagesbot' : 'ai-chatbot/v1/chat' );
298 $onGoingPrompt = "mwai_{$id}_onGoingPrompt";
299 $memorizedChat = "mwai_{$id}_memorizedChat";
300 $baseClasses = "mwai-chat";
301 $baseClasses .= ( $window ? " mwai-window" : "" );
302 $baseClasses .= ( !$window && $fullscreen ? " mwai-fullscreen" : "" );
303 $baseClasses .= ( $style === 'chatgpt' ? " mwai-chatgpt" : "" );
304 $baseClasses .= ( $window && !empty( $iconPosition ) ? (" mwai-" . $iconPosition) : "" );
305
306 // Output CSS
307 ob_start();
308 $style_content = "";
309 if ( $style === 'chatgpt' ) {
310 $style_content = $this->chatgpt_style( $id, $style );
311 }
312 echo apply_filters( 'mwai_chatbot_style', $style_content, $id );
313
314 // Output HTML & CSS
315 $chatStyles = $this->core->get_option( 'shortcode_chat_styles' );
316 $iconUrl = MWAI_URL . '/images/chat-green.svg';
317 if ( !empty( $icon ) ) {
318 $iconUrl = $icon;
319 }
320 else if ( !empty( $chatStyles ) && isset( $chatStyles['icon'] ) ) {
321 $url = $chatStyles['icon'];
322 $iconUrl = $this->core->isUrl( $url ) ? $url : (MWAI_URL . 'images/' . $chatStyles['icon']);
323 }
324 ?>
325 <div id="mwai-chat-<?= $id ?>" class="<?= $baseClasses ?>">
326 <?php if ( $window ) { ?>
327 <div class="mwai-open-button">
328 <?php if ( !empty( $iconText ) ) { ?>
329 <div class="mwai-icon-text"><?= $iconText ?></div>
330 <?php } ?>
331 <img width="64" height="64" src="<?= $iconUrl ?>" />
332 </div>
333 <div class="mwai-header">
334 <?php if ( $fullscreen ) { ?>
335 <div class="mwai-resize-button"></div>
336 <?php } ?>
337 <div class="mwai-close-button"></div>
338 </div>
339 <?php } ?>
340 <div class="mwai-content">
341 <div class="mwai-conversation">
342 </div>
343 <div class="mwai-input">
344 <textarea rows="1" placeholder="<?= $textInputPlaceholder ?>"></textarea>
345 <button><span><?= $textSend ?></span></button>
346 </div>
347 </div>
348 </div>
349
350 <script>
351 (function () {
352 let <?= $onGoingPrompt ?> = '<?= $context ?>' + '\n\n';
353 let isMobile = window.matchMedia("only screen and (max-width: 760px)").matches;
354 let isWindow = <?= $window ? 'true' : 'false' ?>;
355 let isDebugMode = <?= $debugMode ? 'true' : 'false' ?>;
356 let isFullscreen = <?= $fullscreen ? 'true' : 'false' ?>;
357 let mode = '<?= $mode ?>';
358 let memorizeChat = <?= $memorizeChat ? 'true' : 'false' ?>;
359 let <?= $memorizedChat ?> = [];
360
361 if (isDebugMode) {
362 window.mwai_<?= $id ?> = {
363 onGoingPrompt: <?= $onGoingPrompt ?>,
364 memorizedChat: <?= $memorizedChat ?>,
365 parameters: {
366 mode: mode,
367 context: '<?= $context ?>',
368 isMobile: isMobile,
369 isWindow: isWindow,
370 isFullscreen: isFullscreen,
371 }
372 };
373 }
374
375 // Set button text
376 function <?= $setButtonTextFn ?>() {
377 let input = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input textarea');
378 let button = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input button');
379 let buttonSpan = button.querySelector('span');
380 if (<?= $memorizedChat ?>.length < 2) {
381 buttonSpan.innerHTML = '<?= $textSend ?>';
382 }
383 else if (!input.value.length) {
384 buttonSpan.innerHTML = '<?= $textClear ?>';
385 }
386 else {
387 buttonSpan.innerHTML = '<?= $textSend ?>';
388 }
389 }
390
391 // Inject timer
392 function <?= $injectTimerFn ?>(element) {
393 let intervalId;
394 let startTime = new Date();
395 let timerElement = null;
396
397 function updateTimer() {
398 let now = new Date();
399 let timer = Math.floor((now - startTime) / 1000);
400 if (!timerElement) {
401 if (timer > 0.5) {
402 timerElement = document.createElement('div');
403 timerElement.classList.add('mwai-timer');
404 element.appendChild(timerElement);
405 }
406 }
407 if (timerElement) {
408 let minutes = Math.floor(timer / 60);
409 let seconds = timer - (minutes * 60);
410 seconds = seconds < 10 ? "0" + seconds : seconds;
411 let display = minutes + ":" + seconds;
412 timerElement.innerHTML = display;
413 }
414 }
415
416 intervalId = setInterval(updateTimer, 500);
417
418 return function stopTimer() {
419 clearInterval(intervalId);
420 if (timerElement) {
421 timerElement.remove();
422 }
423 };
424 }
425
426 // Push the reply in the conversation
427 function <?= $addReplyFn ?>(text, type = 'user') {
428 var conversation = document.querySelector('#mwai-chat-<?= $id ?> .mwai-conversation');
429
430 if (memorizeChat) {
431 <?= $memorizedChat ?>.push({ text, type });
432 localStorage.setItem('mwai-chat-<?= $id ?>', JSON.stringify(<?= $memorizedChat ?>));
433 }
434
435 // If text is array, then it's image URLs. Let's create a simple gallery in HTML in $text.
436 if (Array.isArray(text)) {
437 var newText = '<div class="mwai-gallery">';
438 for (var i = 0; i < text.length; i++) {
439 newText += '<a href="' + text[i] + '" target="_blank"><img src="' + text[i] + '" />';
440 }
441 text = newText + '</div>';
442 }
443
444 var mwaiClasses = 'mwai-reply';
445 if (type === 'ai') {
446 mwaiClasses += ' mwai-ai';
447 }
448 else if (type === 'system') {
449 mwaiClasses += ' mwai-system';
450 }
451 else {
452 mwaiClasses += ' mwai-user';
453 }
454 var html = '<div class="' + mwaiClasses + '">';
455 if (type === 'ai') {
456 html += '<span class="mwai-name"><?= $aiName ?></span>';
457 }
458 else if (type === 'system') {
459 html += '<span class="mwai-name"><?= $sysName ?></span>';
460 }
461 else {
462 html += '<span class="mwai-name"><?= $userName ?></span>';
463 }
464 html += '<span class="mwai-text">' + text + '</span>';
465 html += '</div>';
466 conversation.innerHTML += html;
467 conversation.scrollTop = conversation.scrollHeight;
468 <?= $setButtonTextFn ?>();
469
470 // Syntax coloring
471 if (typeof hljs !== 'undefined') {
472 document.querySelectorAll('pre code').forEach((el) => {
473 hljs.highlightElement(el);
474 });
475 }
476 }
477
478 // Function to request the completion
479 function <?= $onSentClickFn ?>() {
480 let input = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input textarea');
481 let inputText = input.value.trim();
482
483 // Reset the conversation if empty
484 if (inputText === '') {
485 <?= $onGoingPrompt ?> = '<?= $context ?>' + '\n\n';
486 document.querySelector('#mwai-chat-<?= $id ?> .mwai-conversation').innerHTML = '';
487 localStorage.removeItem('mwai-chat-<?= $id ?>');
488 <?= $memorizedChat ?> = [];
489 <?= $addReplyFn ?>('<?= $startSentence ?>', 'ai');
490 return;
491 }
492
493 // Disable the button
494 var button = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input button');
495 button.disabled = true;
496
497 // Add the user reply
498 <?= $addReplyFn ?>(inputText, 'user');
499 <?= $onGoingPrompt ?> += '<?= $userName ?>' + inputText + '\n';
500 input.value = '';
501 input.setAttribute('rows', 1);
502 input.disabled = true;
503
504 // Let's build the prompt depending on the "system"
505 <?= $onGoingPrompt ?> += '<?= $aiName ?>';
506 let prompt = <?= $onGoingPrompt ?>;
507 if (<?= $casuallyFineTuned ? 1 : 0 ?>) {
508 prompt = inputText + '<?= $promptEnding ?>';
509 }
510
511 // Prompt for the images
512 const data = mode === 'images' ? {
513 env: '<?= $env ?>',
514 session: '<?= $sessionId ?>',
515 prompt: inputText,
516 maxResults: <?= $maxResults ?>,
517 model: '<?= $atts['model'] ?>',
518 apiKey: '<?= $atts['api_key'] ?>',
519 // Prompt for the chat
520 } : {
521 env: '<?= $env ?>',
522 session: '<?= $sessionId ?>',
523 prompt: prompt,
524 userName: '<?= $userName ?>',
525 aiName: '<?= $aiName ?>',
526 model: '<?= $model ?>',
527 temperature: '<?= $temperature ?>',
528 maxTokens: '<?= $maxTokens ?>',
529 stop: '<?= $completionEnding ?>',
530 maxResults: '<?= $maxResults ?>',
531 apiKey: '<?= $apiKey ?>',
532 };
533
534 // Start the timer
535 const stopTimer = <?= $injectTimerFn ?>(button);
536
537 // Send the request
538 if (isDebugMode) {
539 console.log('[BOT] Sent: ', data);
540 }
541 fetch('<?= $apiUrl ?>', { method: 'POST', headers: {
542 'Content-Type': 'application/json',
543 'X-WP-Nonce': '<?= $rest_nonce ?>'
544 },
545 body: JSON.stringify(data)
546 })
547 .then(response => response.json())
548 .then(data => {
549 if (isDebugMode) {
550 console.log('[BOT] Recv: ', data);
551 }
552 if (!data.success) {
553 <?= $addReplyFn ?>(data.message, 'system');
554 }
555 else {
556 <?= $addReplyFn ?>(data.images ? data.images : data.html, 'ai');
557 <?= $onGoingPrompt ?> += data.answer + '\n';
558 }
559 button.disabled = false;
560 input.disabled = false;
561 stopTimer();
562
563 // Only focus only on desktop (to avoid the mobile keyboard to kick-in)
564 if (!isMobile) {
565 input.focus();
566 }
567 })
568 .catch(error => {
569 console.error(error);
570 button.disabled = false;
571 input.disabled = false;
572 stopTimer();
573 });
574 }
575
576 // Keep the textarea height in sync with the content
577 function mwaiSetTextAreaHeight(textarea, lines) {
578 var rows = textarea.getAttribute('rows');
579 if (lines !== rows) {
580 textarea.setAttribute('rows', lines > 5 ? 5 : lines);
581 }
582 }
583
584 // Init the chatbot
585 function <?= $initChatBotFn ?>() {
586 var input = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input textarea');
587 var button = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input button');
588
589 input.addEventListener('keypress', (event) => {
590 let text = event.target.value;
591 if (event.keyCode === 13 && !text.length && !event.shiftKey) {
592 event.preventDefault();
593 return;
594 }
595 if (event.keyCode === 13 && text.length && !event.shiftKey) {
596 <?= $onSentClickFn ?>();
597 }
598 });
599 input.addEventListener('keydown', (event) => {
600 var rows = input.getAttribute('rows');
601 if (event.keyCode === 13 && event.shiftKey) {
602 var lines = input.value.split('\n').length + 1;
603 mwaiSetTextAreaHeight(input, lines);
604 }
605 });
606 input.addEventListener('keyup', (event) => {
607 var rows = input.getAttribute('rows');
608 var lines = input.value.split('\n').length ;
609 mwaiSetTextAreaHeight(input, lines);
610 <?= $setButtonTextFn ?>();
611 });
612
613 button.addEventListener('click', (event) => {
614 <?= $onSentClickFn ?>();
615 });
616
617 // If window, add event listener to mwai-open-button and mwai-close-button
618 if ( isWindow ) {
619 var openButton = document.querySelector('#mwai-chat-<?= $id ?> .mwai-open-button');
620 openButton.addEventListener('click', (event) => {
621 var chat = document.querySelector('#mwai-chat-<?= $id ?>');
622 chat.classList.add('mwai-open');
623 // Only focus only on desktop (to avoid the mobile keyboard to kick-in)
624 if (!isMobile) {
625 input.focus();
626 }
627 });
628 var closeButton = document.querySelector('#mwai-chat-<?= $id ?> .mwai-close-button');
629 closeButton.addEventListener('click', (event) => {
630 var chat = document.querySelector('#mwai-chat-<?= $id ?>');
631 chat.classList.remove('mwai-open');
632 });
633 if (isFullscreen) {
634 var resizeButton = document.querySelector('#mwai-chat-<?= $id ?> .mwai-resize-button');
635 resizeButton.addEventListener('click', (event) => {
636 var chat = document.querySelector('#mwai-chat-<?= $id ?>');
637 chat.classList.toggle('mwai-fullscreen');
638 });
639 }
640 }
641
642 // Get back the previous chat if any for the same ID
643 var chatHistory = [];
644 if (memorizeChat) {
645 chatHistory = localStorage.getItem('mwai-chat-<?= $id ?>');
646 if (chatHistory) {
647 chatHistory = JSON.parse(chatHistory);
648 chatHistory = chatHistory.filter(x => x && x.text && x.type);
649 chatHistory.forEach(x => { <?= $addReplyFn ?>(x.text, x.type) });
650 }
651 else {
652 chatHistory = [];
653 }
654 }
655 if (chatHistory.length === 0) {
656 <?= $addReplyFn ?>('<?= $startSentence ?>', 'ai');
657 }
658 }
659
660 // Let's go totally meoooow on this!
661 <?= $initChatBotFn ?>();
662 })();
663 </script>
664
665 <?php
666 $output = ob_get_contents();
667 ob_end_clean();
668 $output = apply_filters( 'mwai_chatbot', $output, $atts );
669 return $output;
670 }
671 }