PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 1.6.82
AI Engine – The Chatbot, AI Framework & MCP for WordPress v1.6.82
3.6.2 3.6.1 3.6.0 3.5.9 3.5.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 / core.php
ai-engine / classes Last commit date
engines 3 years ago modules 3 years ago admin.php 3 years ago api.php 3 years ago core.php 3 years ago init.php 3 years ago query.php 3 years ago queryembed.php 3 years ago queryimage.php 3 years ago querytext.php 3 years ago querytranscribe.php 3 years ago reply.php 3 years ago rest.php 3 years ago
core.php
546 lines
1 <?php
2
3 require_once( MWAI_PATH . '/vendor/autoload.php' );
4 require_once( MWAI_PATH . '/constants/init.php' );
5
6 use Rahul900day\Gpt3Encoder\Encoder;
7
8 define( 'MWAI_IMG_WAND', MWAI_URL . '/images/wand.png' );
9 define( 'MWAI_IMG_WAND_HTML', "<img style='height: 22px; margin-bottom: -5px; margin-right: 8px;'
10 src='" . MWAI_IMG_WAND . "' alt='AI Wand' />" );
11 define( 'MWAI_IMG_WAND_HTML_XS', "<img style='height: 16px; margin-bottom: -2px;'
12 src='" . MWAI_IMG_WAND . "' alt='AI Wand' />" );
13 class Meow_MWAI_Core
14 {
15 public $admin = null;
16 public $is_rest = false;
17 public $is_cli = false;
18 public $site_url = null;
19 public $ai = null;
20 private $option_name = 'mwai_options';
21 private $themes_option_name = 'mwai_themes';
22 private $chatbots_option_name = 'mwai_chatbots';
23 private $nonce = null;
24 public $defaultChatbotParams = MWAI_CHATBOT_PARAMS;
25
26 public function __construct() {
27 $this->site_url = get_site_url();
28 $this->is_rest = MeowCommon_Helpers::is_rest();
29 $this->is_cli = defined( 'WP_CLI' );
30 $this->ai = new Meow_MWAI_Engines_Core( $this );
31 add_action( 'plugins_loaded', array( $this, 'init' ) );
32 }
33
34 function init() {
35 global $mwai;
36 $mwai = new Meow_MWAI_API();
37 new Meow_MWAI_Modules_Security( $this );
38 if ( $this->is_rest ) {
39 new Meow_MWAI_Rest( $this );
40 }
41 if ( is_admin() ) {
42 new Meow_MWAI_Admin( $this );
43 new Meow_MWAI_Modules_Assistants( $this );
44 }
45 if ( $this->get_option( 'shortcode_chat' ) ) {
46 new Meow_MWAI_Modules_Chatbot();
47 new Meow_MWAI_Modules_Chatbot_Legacy();
48 new Meow_MWAI_Modules_Discussions();
49 }
50
51 // Advanced core
52 if ( class_exists( 'MeowPro_MWAI_Core' ) ) {
53 new MeowPro_MWAI_Core( $this );
54 }
55
56 // Dynamic max tokens
57 if ( $this->get_option( 'dynamic_max_tokens' ) ) {
58 add_filter( 'mwai_estimate_tokens', array( $this, 'dynamic_max_tokens' ), 10, 2 );
59 }
60 }
61
62 #region Roles & Capabilities
63
64 function can_access_settings() {
65 return apply_filters( 'mwai_allow_setup', current_user_can( 'manage_options' ) );
66 }
67
68 function can_access_features() {
69 $editor_or_admin = current_user_can( 'editor' ) || current_user_can( 'administrator' );
70 return apply_filters( 'mwai_allow_usage', $editor_or_admin );
71 }
72
73 #endregion
74
75 #region Text-Related Helpers
76
77 // Clean the text perfectly, resolve shortcodes, etc, etc.
78 function cleanText( $rawText = "" ) {
79 $text = html_entity_decode( $rawText );
80 $text = wp_strip_all_tags( $text );
81 $text = preg_replace( '/[\r\n]+/', "\n", $text );
82 return $text . " ";
83
84 // Before simplification:
85 // $text = strip_tags( $rawText );
86 // $text = strip_shortcodes( $text );
87 // $text = html_entity_decode( $text );
88 // $text = preg_replace( '/[\r\n]+/', "\n", $text );
89 // $sentences = preg_split( '/(?<=[.?!])(?=[a-zA-Z ])/', $text );
90 // foreach ( $sentences as $key => $sentence ) {
91 // $sentences[$key] = trim( $sentence );
92 // }
93 // $text = implode( " ", $sentences );
94 // $text = preg_replace( '/^[\pZ\pC]+|[\pZ\pC]+$/u', '', $text );
95 // return $text . " ";
96 }
97
98 // Make sure there are no duplicate sentences, and keep the length under a maximum length.
99 function cleanSentences( $text, $maxTokens = null ) {
100 //$sentences = preg_split( '/(?<=[.?!])(?=[a-zA-Z ])/', $text );
101 $maxTokens = $maxTokens ? $maxTokens : $this->get_option( 'context_max_tokens', 1024 );
102 $sentences = preg_split('/(?<=[.?!。.!?])+/u', $text);
103 $hashes = array();
104 $uniqueSentences = array();
105 $length = 0;
106 foreach ( $sentences as $sentence ) {
107 $sentence = preg_replace( '/^[\pZ\pC]+|[\pZ\pC]+$/u', '', $sentence );
108 $hash = md5( $sentence );
109 if ( !in_array( $hash, $hashes ) ) {
110 $tokensCount = apply_filters( 'mwai_estimate_tokens', 0, $sentence );
111 if ( $length + $tokensCount > $maxTokens ) {
112 continue;
113 }
114 $hashes[] = $hash;
115 $uniqueSentences[] = $sentence;
116 $length += $tokensCount;
117 }
118 }
119 $freshText = implode( " ", $uniqueSentences );
120 $freshText = preg_replace( '/^[\pZ\pC]+|[\pZ\pC]+$/u', '', $freshText );
121 return $freshText;
122 }
123
124 function getCleanPostContent( $postId ) {
125 $post = get_post( $postId );
126 if ( !$post ) {
127 return false;
128 }
129 $text = $post->post_content;
130 $pattern = '/\[mwai_.*?\]/';
131 $text = preg_replace( $pattern, '', $text );
132 if ( $this->get_option( 'resolve_shortcodes' ) ) {
133 $text = apply_filters( 'the_content', $text );
134 }
135 $text = $this->cleanText( $text );
136 $text = $this->cleanSentences( $text );
137 return $text;
138 }
139
140 function markdown_to_html( $content ) {
141 $Parsedown = new Parsedown();
142 $content = $Parsedown->text( $content );
143 return $content;
144 }
145
146 function get_post_language( $postId ) {
147 $locale = get_locale();
148 $code = strtolower( substr( $locale, 0, 2 ) );
149 $humanLanguage = strtr( $code, MWAI_ALL_LANGUAGES );
150 $lang = apply_filters( 'wpml_post_language_details', null, $postId );
151 if ( !empty( $lang ) ) {
152 $locale = $lang['locale'];
153 $humanLanguage = $lang['display_name'];
154 }
155 return strtolower( "$locale ($humanLanguage)" );
156 }
157 #endregion
158
159 #region Users/Sessions Helpers
160
161 function get_nonce() {
162 if ( isset( $this->nonce ) ) {
163 return $this->nonce;
164 }
165 $this->nonce = wp_create_nonce( 'wp_rest' );
166 return $this->nonce;
167 }
168
169 function get_session_id() {
170 if ( isset( $_COOKIE['mwai_session_id'] ) ) {
171 return $_COOKIE['mwai_session_id'];
172 }
173 return "N/A";
174 }
175
176 // Get the UserID from the data, or from the current user
177 function get_user_id( $data = null ) {
178 if ( isset( $data ) && isset( $data['userId'] ) ) {
179 return (int)$data['userId'];
180 }
181 if ( is_user_logged_in() ) {
182 $current_user = wp_get_current_user();
183 if ( $current_user->ID > 0 ) {
184 return $current_user->ID;
185 }
186 }
187 return null;
188 }
189
190 function getUserData() {
191 $user = wp_get_current_user();
192 if ( empty( $user ) || empty( $user->ID ) ) {
193 return null;
194 }
195 $placeholders = array(
196 'FIRST_NAME' => get_user_meta( $user->ID, 'first_name', true ),
197 'LAST_NAME' => get_user_meta( $user->ID, 'last_name', true ),
198 'USER_LOGIN' => isset( $user ) && isset($user->data) && isset( $user->data->user_login ) ?
199 $user->data->user_login : null,
200 'DISPLAY_NAME' => isset( $user ) && isset( $user->data ) && isset( $user->data->display_name ) ?
201 $user->data->display_name : null,
202 'AVATAR_URL' => get_avatar_url( get_current_user_id() ),
203 );
204 return $placeholders;
205 }
206
207 function get_ip_address( $data = null ) {
208 if ( isset( $data ) && isset( $data['ip'] ) ) {
209 $data['ip'] = (string)$data['ip'];
210 }
211 else {
212 if ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
213 $data['ip'] = sanitize_text_field( $_SERVER['REMOTE_ADDR'] );
214 }
215 else if ( isset( $_SERVER['HTTP_CLIENT_IP'] ) ) {
216 $data['ip'] = sanitize_text_field( $_SERVER['HTTP_CLIENT_IP'] );
217 }
218 else if ( isset( $_SERVER['HTTP_X_FORWARDED_ FOR'] ) ) {
219 $data['ip'] = sanitize_text_field( $_SERVER['HTTP_X_FORWARDED_FOR'] );
220 }
221 }
222 $ip = apply_filters( 'mwai_get_ip_address', $data['ip'] );
223 return $ip;
224 }
225
226 #endregion
227
228 #region Other Helpers
229
230 function isUrl( $url ) {
231 return strpos( $url, 'http' ) === 0 ? true : false;
232 }
233
234 function getPostTypes() {
235 $excluded = array( 'attachment', 'revision', 'nav_menu_item' );
236 $post_types = array();
237 $types = get_post_types( array( 'public' => true ), 'objects' );
238 foreach ( $types as $type ) {
239 if ( in_array( $type->name, $excluded ) ) {
240 continue;
241 }
242 $post_types[] = array(
243 'name' => $type->labels->name,
244 'type' => $type->name,
245 );
246 }
247 return $post_types;
248 }
249
250 function getCleanPost( $post ) {
251 if ( is_object( $post ) ) {
252 $post = (array)$post;
253 }
254 $language = $this->get_post_language( $post['ID'] );
255 $content = apply_filters( 'mwai_pre_post_content', $post['post_content'], $post['ID'] );
256 $content = $this->cleanText( $content );
257 $content = apply_filters( 'mwai_post_content', $content, $post['ID'] );
258 $title = $post['post_title'];
259 $excerpt = $post['post_excerpt'];
260 $url = get_permalink( $post['ID'] );
261 $checksum = wp_hash( $content . $title . $url );
262 return [
263 'postId' => $post['ID'],
264 'title' => $title,
265 'content' => $content,
266 'excerpt' => $excerpt,
267 'url' => $url,
268 'language' => $language,
269 'checksum' => $checksum,
270 ];
271 }
272
273 #endregion
274
275 #region Usage & Costs
276
277 public function dynamic_max_tokens( $tokens, $text ) {
278 // Approximation (fast, no lib)
279 $asciiCount = 0;
280 $nonAsciiCount = 0;
281 for ( $i = 0; $i < mb_strlen( $text ); $i++ ) {
282 $char = mb_substr( $text, $i, 1 );
283 if ( ord( $char ) < 128 ) {
284 $asciiCount++;
285 }
286 else {
287 $nonAsciiCount++;
288 }
289 }
290 $asciiTokens = $asciiCount / 3.5;
291 $nonAsciiTokens = $nonAsciiCount * 2.5;
292 $tokens = $asciiTokens + $nonAsciiTokens;
293
294 // More exact (slower, and lib)
295 if ( PHP_VERSION_ID >= 70400 && function_exists( 'mb_convert_encoding' ) ) {
296 try {
297 $token_array = Encoder::encode( $text );
298 if ( !empty( $token_array ) ) {
299 $tokens = count( $token_array );
300 }
301 }
302 catch ( Exception $e ) {
303 error_log( $e->getMessage() );
304 }
305 }
306
307 $tokens = $tokens;
308 return (int)$tokens;
309 }
310
311 public function recordTokensUsage( $model, $prompt_tokens, $completion_tokens = 0 ) {
312 if ( !is_numeric( $prompt_tokens ) ) {
313 throw new Exception( 'Record usage: prompt_tokens is not a number.' );
314 }
315 if ( !is_numeric( $completion_tokens ) ) {
316 $completion_tokens = 0;
317 }
318 if ( !$model ) {
319 throw new Exception( 'Record usage: model is missing.' );
320 }
321 $usage = $this->get_option( 'openai_usage' );
322 $month = date( 'Y-m' );
323 if ( !isset( $usage[$month] ) ) {
324 $usage[$month] = array();
325 }
326 if ( !isset( $usage[$month][$model] ) ) {
327 $usage[$month][$model] = array(
328 'prompt_tokens' => 0,
329 'completion_tokens' => 0,
330 'total_tokens' => 0
331 );
332 }
333 $usage[$month][$model]['prompt_tokens'] += $prompt_tokens;
334 $usage[$month][$model]['completion_tokens'] += $completion_tokens;
335 $usage[$month][$model]['total_tokens'] += $prompt_tokens + $completion_tokens;
336 $this->update_option( 'openai_usage', $usage );
337 return [
338 'prompt_tokens' => $prompt_tokens,
339 'completion_tokens' => $completion_tokens,
340 'total_tokens' => $prompt_tokens + $completion_tokens
341 ];
342 }
343
344 public function recordAudioUsage( $model, $seconds ) {
345 if ( !is_numeric( $seconds ) ) {
346 throw new Exception( 'Record usage: seconds is not a number.' );
347 }
348 if ( !$model ) {
349 throw new Exception( 'Record usage: model is missing.' );
350 }
351 $usage = $this->get_option( 'openai_usage' );
352 $month = date( 'Y-m' );
353 if ( !isset( $usage[$month] ) ) {
354 $usage[$month] = array();
355 }
356 if ( !isset( $usage[$month][$model] ) ) {
357 $usage[$month][$model] = array(
358 'seconds' => 0
359 );
360 }
361 $usage[$month][$model]['seconds'] += $seconds;
362 $this->update_option( 'openai_usage', $usage );
363 return [
364 'seconds' => $seconds
365 ];
366 }
367
368 public function recordImagesUsage( $model, $resolution, $images ) {
369 if ( !$model || !$resolution || !$images ) {
370 throw new Exception( 'Missing parameters for record_image_usage.' );
371 }
372 $usage = $this->get_option( 'openai_usage' );
373 $month = date( 'Y-m' );
374 if ( !isset( $usage[$month] ) ) {
375 $usage[$month] = array();
376 }
377 if ( !isset( $usage[$month][$model] ) ) {
378 $usage[$month][$model] = array(
379 'resolution' => array(),
380 'images' => 0
381 );
382 }
383 if ( !isset( $usage[$month][$model]['resolution'][$resolution] ) ) {
384 $usage[$month][$model]['resolution'][$resolution] = 0;
385 }
386 $usage[$month][$model]['resolution'][$resolution] += $images;
387 $usage[$month][$model]['images'] += $images;
388 $this->update_option( 'openai_usage', $usage );
389 return [
390 'resolution' => $resolution,
391 'images' => $images
392 ];
393 }
394
395 #endregion
396
397 #region Options
398 function getThemes()
399 {
400 $themes = get_option( $this->themes_option_name, [] );
401 $themes = empty( $themes ) ? [] : $themes;
402
403 $internalThemes = [
404 'chatgpt' => [
405 'type' => 'internal', 'name' => 'ChatGPT', 'themeId' => 'chatgpt',
406 'settings' => [], 'style' => ""
407 ],
408 'messages' => [
409 'type' => 'internal', 'name' => 'Messages', 'themeId' => 'messages',
410 'settings' => [], 'style' => ""
411 ],
412 ];
413 $customThemes = [];
414 foreach ( $themes as $theme ) {
415 if ( isset( $internalThemes[$theme['themeId']] ) ) {
416 $internalThemes[$theme['themeId']] = $theme;
417 continue;
418 }
419 $customThemes[] = $theme;
420 }
421 return array_merge(array_values($internalThemes), $customThemes);
422 }
423
424 function updateThemes( $themes ) {
425 update_option( $this->themes_option_name, $themes );
426 return $themes;
427 }
428
429 function getChatbots() {
430 $chatbots = get_option( $this->chatbots_option_name, [] );
431 $hasChanges = false;
432 if ( empty( $chatbots ) ) {
433 $chatbots = [ array_merge( MWAI_CHATBOT_DEFAULT_PARAMS, ['name' => 'Default', 'botId' => 'default' ] ) ];
434 }
435 foreach ( $chatbots as &$chatbot ) {
436 foreach ( MWAI_CHATBOT_DEFAULT_PARAMS as $key => $value ) {
437 if ( !isset( $chatbot[$key] ) ) {
438 $chatbot[$key] = $value;
439 }
440 }
441 // After September 2023, let's remove this if statement.
442 if ( isset( $chatbot['chatId'] ) ) {
443 $chatbot['botId'] = $chatbot['chatId'];
444 unset( $chatbot['chatId'] );
445 $hasChanges = true;
446 }
447 // After September 2023, let's remove this if statement.
448 if ( empty( $chatbot['botId'] && $chatbot['name'] === 'default' ) ) {
449 $chatbot['botId'] = sanitize_title( $chatbot['name'] );
450 $hasChanges = true;
451 }
452 }
453 if ( $hasChanges ) {
454 update_option( $this->chatbots_option_name, $chatbots );
455 }
456 return $chatbots;
457 }
458
459 function getChatbot( $botId ) {
460 $chatbots = $this->getChatbots();
461 foreach ( $chatbots as $chatbot ) {
462 if ( $chatbot['botId'] === (string)$botId ) {
463 // Somehow, the default was set to "openai" when creating a new chatbot, but that overrided
464 // the default value in the Settings. It should be always empty here (except if we add this
465 // into the Settings of the chatbot).
466 $chatbot['service'] = null;
467 return $chatbot;
468 }
469 }
470 return null;
471 }
472
473 function getTheme( $themeId ) {
474 $themes = $this->getThemes();
475 foreach ( $themes as $theme ) {
476 if ( $theme['themeId'] === $themeId ) {
477 return $theme;
478 }
479 }
480 return null;
481 }
482
483 function updateChatbots( $chatbots ) {
484 update_option( $this->chatbots_option_name, $chatbots );
485 return $chatbots;
486 }
487
488 function get_all_options() {
489 $options = get_option( $this->option_name, [] );
490 foreach ( MWAI_OPTIONS as $key => $value ) {
491 if ( !isset( $options[$key] ) ) {
492 $options[$key] = $value;
493 }
494 if ( $key === 'languages' ) {
495 // NOTE: If we decide to make a set of options for languages, we can keep it in the settings
496 $options[$key] = MWAI_LANGUAGES;
497 $options[$key] = apply_filters( 'mwai_languages', $options[$key] );
498 }
499 }
500 $options['shortcode_chat_default_params'] = MWAI_CHATBOT_PARAMS;
501 $options['chatbot_defaults'] = MWAI_CHATBOT_DEFAULT_PARAMS;
502 $options['default_limits'] = MWAI_LIMITS;
503 $options['openai_models'] = MWAI_OPENAI_MODELS;
504 return $options;
505 }
506
507 // Validate and keep the options clean and logical.
508 function sanitize_options() {
509 $options = $this->get_all_options();
510 $needs_update = false;
511
512 // We can sanitize our future options here, let's always remember it.
513 // Now, it is empty...
514
515 if ( $needs_update ) {
516 update_option( $this->option_name, $options, false );
517 }
518 return $options;
519 }
520
521 function update_options( $options ) {
522 if ( !update_option( $this->option_name, $options, false ) ) {
523 return false;
524 }
525 $options = $this->sanitize_options();
526 return $options;
527 }
528
529 function update_option( $option, $value ) {
530 $options = $this->get_all_options();
531 $options[$option] = $value;
532 return $this->update_options( $options );
533 }
534
535 function get_option( $option, $default = null ) {
536 $options = $this->get_all_options();
537 return $options[$option] ?? $default;
538 }
539
540 function reset_options() {
541 return $this->update_options( MWAI_OPTIONS );
542 }
543 #endregion
544 }
545
546 ?>