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