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