PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 1.0.0
AI Engine – The Chatbot, AI Framework & MCP for WordPress v1.0.0
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
691 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 = $mode === 'chat' ? 1 : $atts['max_results'];
247 $maxSentences = $atts['max_sentences'];
248 $sessionId = $this->core->get_session_id();
249 $rest_nonce = wp_create_nonce( 'wp_rest' );
250 $casuallyFineTuned = boolval( $atts['casually_fine_tuned'] );
251 $promptEnding = addslashes( trim( $atts['prompt_ending'] ) );
252 $completionEnding = addslashes( trim( $atts['completion_ending'] ) );
253 if ( $casuallyFineTuned ) {
254 $promptEnding = "\\n\\n===\\n\\n";
255 $completionEnding = "\\n\\n";
256 }
257 $debugMode = $chatStyles = $this->core->get_option( 'debug_mode' );
258
259 // OpenAI Parameters
260 $model = $atts['model'];
261 $temperature = $atts['temperature'];
262 $maxTokens = $atts['max_tokens'];
263 $apiKey = $atts['api_key'];
264
265 // Named functions
266 $onSentClickFn = "mwai_{$id}_onSendClick";
267 $addReplyFn = "mwai_{$id}_addReply";
268 $initChatBotFn = "mwai_{$id}_initChatBot";
269 $setButtonTextFn = "mwai_{$id}_setButtonText";
270 $onTidyOnGoingPromptFn = "mwai_{$id}_onUpdateOnGoingPrompt";
271 $injectTimerFn = "mwai_{$id}_injectTimer";
272 $textAreaResizeFn = "mwai_{$id}_textAreaResize";
273 $textAreaDelayedResizeFn = "mwai_{$id}_textAreaDelayedResize";
274
275 // Variables
276 $apiUrl = get_rest_url( null, $mode === 'images' ? 'ai-chatbot/v1/imagesbot' : 'ai-chatbot/v1/chat' );
277 $onGoingPrompt = "mwai_{$id}_onGoingPrompt";
278 $memorizedChat = "mwai_{$id}_memorizedChat";
279 $baseClasses = "mwai-chat";
280 $baseClasses .= ( $window ? " mwai-window" : "" );
281 $baseClasses .= ( !$window && $fullscreen ? " mwai-fullscreen" : "" );
282 $baseClasses .= ( $style === 'chatgpt' ? " mwai-chatgpt" : "" );
283 $baseClasses .= ( $window && !empty( $iconPosition ) ? (" mwai-" . $iconPosition) : "" );
284
285 // Output CSS
286 ob_start();
287 $style_content = "";
288 if ( $style === 'chatgpt' ) {
289 $style_content = $this->chatgpt_style( $id, $style );
290 }
291 echo apply_filters( 'mwai_chatbot_style', $style_content, $id );
292
293 // Output HTML & CSS
294 $chatStyles = $this->core->get_option( 'shortcode_chat_styles' );
295 $iconUrl = MWAI_URL . '/images/chat-green.svg';
296 if ( !empty( $icon ) ) {
297 $iconUrl = $icon;
298 }
299 else if ( !empty( $chatStyles ) && isset( $chatStyles['icon'] ) ) {
300 $url = $chatStyles['icon'];
301 $iconUrl = $this->core->isUrl( $url ) ? $url : (MWAI_URL . 'images/' . $chatStyles['icon']);
302 }
303 ?>
304 <div id="mwai-chat-<?= $id ?>" class="<?= $baseClasses ?>">
305 <?php if ( $window ) { ?>
306 <div class="mwai-open-button">
307 <?php if ( !empty( $iconText ) ) { ?>
308 <div class="mwai-icon-text"><?= $iconText ?></div>
309 <?php } ?>
310 <img width="64" height="64" src="<?= $iconUrl ?>" />
311 </div>
312 <div class="mwai-header">
313 <?php if ( $fullscreen ) { ?>
314 <div class="mwai-resize-button"></div>
315 <?php } ?>
316 <div class="mwai-close-button"></div>
317 </div>
318 <?php } ?>
319 <div class="mwai-content">
320 <div class="mwai-conversation">
321 </div>
322 <div class="mwai-input">
323 <textarea rows="1" placeholder="<?= $textInputPlaceholder ?>"></textarea>
324 <button><span><?= $textSend ?></span></button>
325 </div>
326 </div>
327 </div>
328
329 <script>
330 (function () {
331 let <?= $onGoingPrompt ?> = [];
332 let isMobile = window.matchMedia("only screen and (max-width: 760px)").matches;
333 let isWindow = <?= $window ? 'true' : 'false' ?>;
334 let isDebugMode = <?= $debugMode ? 'true' : 'false' ?>;
335 let isFullscreen = <?= $fullscreen ? 'true' : 'false' ?>;
336 let isCasuallyFineTuned = <?= $casuallyFineTuned ? 'true' : 'false' ?>;
337 let mode = '<?= $mode ?>';
338 let maxSentences = <?= $maxSentences ?>;
339 let memorizeChat = <?= $memorizeChat ? 'true' : 'false' ?>;
340 let <?= $memorizedChat ?> = [];
341
342 if (isDebugMode) {
343 window.mwai_<?= $id ?> = {
344 onGoingPrompt: <?= $onGoingPrompt ?>,
345 memorizedChat: <?= $memorizedChat ?>,
346 parameters: {
347 mode: mode,
348 model: '<?= $model ?>',
349 temperature: '<?= $temperature ?>',
350 maxTokens: '<?= $maxTokens ?>',
351 context: '<?= $context ?>',
352 start_sentence: '<?= $startSentence ?>',
353 isMobile: isMobile,
354 isWindow: isWindow,
355 isFullscreen: isFullscreen,
356 isCasuallyFineTuned: isCasuallyFineTuned,
357 }
358 };
359 }
360
361 // Set button text
362 function <?= $setButtonTextFn ?>() {
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 buttonSpan.innerHTML = '<?= $textClear ?>';
371 }
372 else {
373 buttonSpan.innerHTML = '<?= $textSend ?>';
374 }
375 }
376
377 // Inject timer
378 function <?= $injectTimerFn ?>(element) {
379 let intervalId;
380 let startTime = new Date();
381 let timerElement = null;
382
383 function updateTimer() {
384 let now = new Date();
385 let timer = Math.floor((now - startTime) / 1000);
386 if (!timerElement) {
387 if (timer > 0.5) {
388 timerElement = document.createElement('div');
389 timerElement.classList.add('mwai-timer');
390 element.appendChild(timerElement);
391 }
392 }
393 if (timerElement) {
394 let minutes = Math.floor(timer / 60);
395 let seconds = timer - (minutes * 60);
396 seconds = seconds < 10 ? "0" + seconds : seconds;
397 let display = minutes + ":" + seconds;
398 timerElement.innerHTML = display;
399 }
400 }
401
402 intervalId = setInterval(updateTimer, 500);
403
404 return function stopTimer() {
405 clearInterval(intervalId);
406 if (timerElement) {
407 timerElement.remove();
408 }
409 };
410 }
411
412 // Push the reply in the conversation
413 function <?= $addReplyFn ?>(text, type = 'user') {
414 var conversation = document.querySelector('#mwai-chat-<?= $id ?> .mwai-conversation');
415
416 if (memorizeChat) {
417 <?= $memorizedChat ?>.push({ text, type });
418 localStorage.setItem('mwai-chat-<?= $id ?>', JSON.stringify(<?= $memorizedChat ?>));
419 }
420
421 // If text is array, then it's image URLs. Let's create a simple gallery in HTML in $text.
422 if (Array.isArray(text)) {
423 var newText = '<div class="mwai-gallery">';
424 for (var i = 0; i < text.length; i++) {
425 newText += '<a href="' + text[i] + '" target="_blank"><img src="' + text[i] + '" />';
426 }
427 text = newText + '</div>';
428 }
429
430 var mwaiClasses = 'mwai-reply';
431 if (type === 'ai') {
432 mwaiClasses += ' mwai-ai';
433 }
434 else if (type === 'system') {
435 mwaiClasses += ' mwai-system';
436 }
437 else {
438 mwaiClasses += ' mwai-user';
439 }
440 var html = '<div class="' + mwaiClasses + '">';
441 if (type === 'ai') {
442 html += '<span class="mwai-name"><?= $aiName ?></span>';
443 }
444 else if (type === 'system') {
445 html += '<span class="mwai-name"><?= $sysName ?></span>';
446 }
447 else {
448 html += '<span class="mwai-name"><?= $userName ?></span>';
449 }
450 html += '<span class="mwai-text">' + text + '</span>';
451 html += '</div>';
452 conversation.innerHTML += html;
453 conversation.scrollTop = conversation.scrollHeight;
454 <?= $setButtonTextFn ?>();
455
456 // Syntax coloring
457 if (typeof hljs !== 'undefined') {
458 document.querySelectorAll('pre code').forEach((el) => {
459 hljs.highlightElement(el);
460 });
461 }
462 }
463
464 function <?= $onTidyOnGoingPromptFn ?>(onGoingPrompt, last = 15) {
465 let onGoingPromptLength = onGoingPrompt.length;
466 let start = (onGoingPromptLength - last) < 0 ? 0 : (onGoingPromptLength - last);
467 if (isCasuallyFineTuned) { onGoingPromptLength--; }
468 let conversationToUse = onGoingPrompt.slice(start, onGoingPromptLength);
469
470 // Casually fine tuned, let's use the last question
471 if (isCasuallyFineTuned) {
472 let lastLine = conversationToUse[conversationToUse.length - 1];
473 let prompt = lastLine.says + '<?= $promptEnding ?>'
474 return prompt;
475 }
476
477 // Otherwise let's compile the latest conversation
478 conversationToUse = conversationToUse.map(x => x.who + x.says);
479 let prompt = conversationToUse.join('\n');
480 if (isCasuallyFineTuned) {
481 prompt = '<?= $promptEnding ?>';
482 }
483 return prompt;
484 }
485
486 // Function to request the completion
487 function <?= $onSentClickFn ?>() {
488 let input = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input textarea');
489 let inputText = input.value.trim();
490
491 // Reset the conversation if empty
492 if (inputText === '') {
493 <?= $onGoingPrompt ?> = [];
494 document.querySelector('#mwai-chat-<?= $id ?> .mwai-conversation').innerHTML = '';
495 localStorage.removeItem('mwai-chat-<?= $id ?>');
496 <?= $memorizedChat ?> = [];
497 <?= $addReplyFn ?>('<?= $startSentence ?>', 'ai');
498 return;
499 }
500
501 // Disable the button
502 var button = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input button');
503 button.disabled = true;
504
505 // Add the user reply
506 <?= $addReplyFn ?>(inputText, 'user');
507 <?= $onGoingPrompt ?>.push({ who: '<?= $rawUserName ?>', says: inputText });
508 input.value = '';
509 input.setAttribute('rows', 1);
510 input.disabled = true;
511
512 // Let's build the prompt depending on the "system"
513 <?= $onGoingPrompt ?>.push({ who: '<?= $rawAiName ?>', says: '' });
514 let prompt = '<?= $context ?>' + '\n\n';
515 prompt += <?= $onTidyOnGoingPromptFn ?>(<?= $onGoingPrompt ?>, maxSentences);
516
517 console.log('onGoingPrompt', <?= $onGoingPrompt ?>);
518 console.log('prompt', prompt);
519
520 // Prompt for the images
521 const data = mode === 'images' ? {
522 env: '<?= $env ?>',
523 session: '<?= $sessionId ?>',
524 prompt: inputText,
525 rawInput: inputText,
526 maxResults: <?= $maxResults ?>,
527 model: '<?= $atts['model'] ?>',
528 apiKey: '<?= $atts['api_key'] ?>',
529 // Prompt for the chat
530 } : {
531 env: '<?= $env ?>',
532 session: '<?= $sessionId ?>',
533 prompt: prompt,
534 rawInput: inputText,
535 userName: '<?= $userName ?>',
536 aiName: '<?= $aiName ?>',
537 model: '<?= $model ?>',
538 temperature: '<?= $temperature ?>',
539 maxTokens: '<?= $maxTokens ?>',
540 stop: '<?= $completionEnding ?>',
541 maxResults: 1,
542 apiKey: '<?= $apiKey ?>',
543 };
544
545 // Start the timer
546 const stopTimer = <?= $injectTimerFn ?>(button);
547
548 // Send the request
549 if (isDebugMode) {
550 console.log('[BOT] Sent: ', data);
551 }
552 fetch('<?= $apiUrl ?>', { method: 'POST', headers: {
553 'Content-Type': 'application/json',
554 'X-WP-Nonce': '<?= $rest_nonce ?>'
555 },
556 body: JSON.stringify(data)
557 })
558 .then(response => response.json())
559 .then(data => {
560 if (isDebugMode) {
561 console.log('[BOT] Recv: ', data);
562 }
563 if (!data.success) {
564 <?= $addReplyFn ?>(data.message, 'system');
565 }
566 else {
567 <?= $addReplyFn ?>(data.images ? data.images : data.html, 'ai');
568 <?= $onGoingPrompt ?>[<?= $onGoingPrompt ?>.length - 1].says = data.answer;
569 }
570 button.disabled = false;
571 input.disabled = false;
572 stopTimer();
573
574 // Only focus only on desktop (to avoid the mobile keyboard to kick-in)
575 if (!isMobile) {
576 input.focus();
577 }
578 })
579 .catch(error => {
580 console.error(error);
581 button.disabled = false;
582 input.disabled = false;
583 stopTimer();
584 });
585 }
586
587 // Keep the textarea height in sync with the content
588 function <?= $textAreaResizeFn ?>(ev) {
589 ev.target.style.height = 'auto';
590 ev.target.style.height = ev.target.scrollHeight + 'px';
591 }
592
593 // Keep the textarea height in sync with the content
594 function <?= $textAreaDelayedResizeFn ?>(ev) {
595 window.setTimeout(<?= $textAreaResizeFn ?>, 0, event);
596 }
597
598 // Init the chatbot
599 function <?= $initChatBotFn ?>() {
600 var input = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input textarea');
601 var button = document.querySelector('#mwai-chat-<?= $id ?> .mwai-input button');
602
603 input.addEventListener('keypress', (event) => {
604 let text = event.target.value;
605 if (event.keyCode === 13 && !text.length && !event.shiftKey) {
606 event.preventDefault();
607 return;
608 }
609 if (event.keyCode === 13 && text.length && !event.shiftKey) {
610 <?= $onSentClickFn ?>();
611 }
612 });
613 input.addEventListener('keydown', (event) => {
614 var rows = input.getAttribute('rows');
615 if (event.keyCode === 13 && event.shiftKey) {
616 var lines = input.value.split('\n').length + 1;
617 //mwaiSetTextAreaHeight(input, lines);
618 }
619 });
620 input.addEventListener('keyup', (event) => {
621 var rows = input.getAttribute('rows');
622 var lines = input.value.split('\n').length ;
623 //mwaiSetTextAreaHeight(input, lines);
624 <?= $setButtonTextFn ?>();
625 });
626
627 input.addEventListener('change', <?= $textAreaResizeFn ?>, false);
628 input.addEventListener('cut', <?= $textAreaDelayedResizeFn ?>, false);
629 input.addEventListener('paste', <?= $textAreaDelayedResizeFn ?>, false);
630 input.addEventListener('drop', <?= $textAreaDelayedResizeFn ?>, false);
631 input.addEventListener('keydown', <?= $textAreaDelayedResizeFn ?>, false);
632
633 button.addEventListener('click', (event) => {
634 <?= $onSentClickFn ?>();
635 });
636
637 // If window, add event listener to mwai-open-button and mwai-close-button
638 if ( isWindow ) {
639 var openButton = document.querySelector('#mwai-chat-<?= $id ?> .mwai-open-button');
640 openButton.addEventListener('click', (event) => {
641 var chat = document.querySelector('#mwai-chat-<?= $id ?>');
642 chat.classList.add('mwai-open');
643 // Only focus only on desktop (to avoid the mobile keyboard to kick-in)
644 if (!isMobile) {
645 input.focus();
646 }
647 });
648 var closeButton = document.querySelector('#mwai-chat-<?= $id ?> .mwai-close-button');
649 closeButton.addEventListener('click', (event) => {
650 var chat = document.querySelector('#mwai-chat-<?= $id ?>');
651 chat.classList.remove('mwai-open');
652 });
653 if (isFullscreen) {
654 var resizeButton = document.querySelector('#mwai-chat-<?= $id ?> .mwai-resize-button');
655 resizeButton.addEventListener('click', (event) => {
656 var chat = document.querySelector('#mwai-chat-<?= $id ?>');
657 chat.classList.toggle('mwai-fullscreen');
658 });
659 }
660 }
661
662 // Get back the previous chat if any for the same ID
663 var chatHistory = [];
664 if (memorizeChat) {
665 chatHistory = localStorage.getItem('mwai-chat-<?= $id ?>');
666 if (chatHistory) {
667 chatHistory = JSON.parse(chatHistory);
668 chatHistory = chatHistory.filter(x => x && x.text && x.type);
669 chatHistory.forEach(x => { <?= $addReplyFn ?>(x.text, x.type) });
670 }
671 else {
672 chatHistory = [];
673 }
674 }
675 if (chatHistory.length === 0) {
676 <?= $addReplyFn ?>('<?= $startSentence ?>', 'ai');
677 }
678 }
679
680 // Let's go totally meoooow on this!
681 <?= $initChatBotFn ?>();
682 })();
683 </script>
684
685 <?php
686 $output = ob_get_contents();
687 ob_end_clean();
688 $output = apply_filters( 'mwai_chatbot', $output, $atts );
689 return $output;
690 }
691 }