PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 1.3.83
AI Engine – The Chatbot, AI Framework & MCP for WordPress v1.3.83
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
modules 3 years ago admin.php 3 years ago ai.php 3 years ago answer.php 3 years ago api.php 3 years ago core.php 3 years ago init.php 3 years ago openai.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 rest.php 3 years ago ui.php 3 years ago
core.php
573 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 class Meow_MWAI_Core
9 {
10 public $admin = null;
11 public $is_rest = false;
12 public $is_cli = false;
13 public $site_url = null;
14 public $ai = null;
15 private $option_name = 'mwai_options';
16 public $defaultChatbotParams = MWAI_CHATBOT_PARAMS;
17
18 public function __construct() {
19 $this->site_url = get_site_url();
20 $this->is_rest = MeowCommon_Helpers::is_rest();
21 $this->is_cli = defined( 'WP_CLI' ) && WP_CLI;
22 $this->ai = new Meow_MWAI_AI( $this );
23 add_action( 'plugins_loaded', array( $this, 'init' ) );
24 }
25
26 function init() {
27 global $mwai;
28 $mwai = new Meow_MWAI_API();
29 if ( $this->is_rest ) {
30 new Meow_MWAI_Rest( $this );
31 }
32 if ( is_admin() ) {
33 new Meow_MWAI_Admin( $this );
34 new Meow_MWAI_Modules_Assistants( $this );
35 }
36 else {
37 //new Meow_MWAI_UI( $this );
38 if ( $this->get_option( 'shortcode_chat' ) ) {
39 new Meow_MWAI_Modules_Chatbot();
40 }
41 }
42
43 // Advanced core
44 if ( class_exists( 'MeowPro_MWAI_Core' ) ) {
45 new MeowPro_MWAI_Core( $this );
46 }
47
48 // Dynamic max tokens
49 if ( $this->get_option( 'dynamic_max_tokens' ) ) {
50 add_filter( 'mwai_estimate_tokens', array( $this, 'dynamic_max_tokens' ), 10, 2 );
51 }
52 }
53
54 #region Roles & Capabilities
55
56 function can_access_settings() {
57 return apply_filters( 'mwai_allow_setup', current_user_can( 'manage_options' ) );
58 }
59
60 function can_access_features() {
61 $editor_or_admin = current_user_can( 'editor' ) || current_user_can( 'administrator' );
62 return apply_filters( 'mwai_allow_usage', $editor_or_admin );
63 }
64
65 #endregion
66
67 #region Text-Related Helpers
68
69 // Clean the text perfectly, resolve shortcodes, etc, etc.
70 function cleanText( $rawText = "" ) {
71 $text = html_entity_decode( $rawText );
72 $text = wp_strip_all_tags( $text );
73 $text = preg_replace( '/[\r\n]+/', "\n", $text );
74 return $text . " ";
75
76 // Before simplification:
77 // $text = strip_tags( $rawText );
78 // $text = strip_shortcodes( $text );
79 // $text = html_entity_decode( $text );
80 // $text = preg_replace( '/[\r\n]+/', "\n", $text );
81 // $sentences = preg_split( '/(?<=[.?!])(?=[a-zA-Z ])/', $text );
82 // foreach ( $sentences as $key => $sentence ) {
83 // $sentences[$key] = trim( $sentence );
84 // }
85 // $text = implode( " ", $sentences );
86 // $text = preg_replace( '/^[\pZ\pC]+|[\pZ\pC]+$/u', '', $text );
87 // return $text . " ";
88 }
89
90 // Make sure there are no duplicate sentences, and keep the length under a maximum length.
91 function cleanSentences( $text, $maxTokens = 512 ) {
92 //$sentences = preg_split( '/(?<=[.?!])(?=[a-zA-Z ])/', $text );
93 $sentences = preg_split('/(?<=[.?!。.!?])+/u', $text);
94 $hashes = array();
95 $uniqueSentences = array();
96 $length = 0;
97 foreach ( $sentences as $sentence ) {
98 $sentence = preg_replace( '/^[\pZ\pC]+|[\pZ\pC]+$/u', '', $sentence );
99 $hash = md5( $sentence );
100 if ( !in_array( $hash, $hashes ) ) {
101 $tokensCount = apply_filters( 'mwai_estimate_tokens', 0, $sentence );
102 if ( $length + $tokensCount > $maxTokens ) {
103 continue;
104 }
105 $hashes[] = $hash;
106 $uniqueSentences[] = $sentence;
107 $length += $tokensCount;
108 }
109 }
110 $freshText = implode( " ", $uniqueSentences );
111 $freshText = preg_replace( '/^[\pZ\pC]+|[\pZ\pC]+$/u', '', $freshText );
112 return $freshText;
113 }
114
115 function getCleanPostContent( $postId ) {
116 $post = get_post( $postId );
117 if ( !$post ) {
118 return false;
119 }
120 $post->post_content = apply_filters( 'the_content', $post->post_content );
121 $text = $this->cleanText( $post->post_content );
122 $text = $this->cleanSentences( $text );
123 return $text;
124 }
125
126 function markdown_to_html( $content ) {
127 $Parsedown = new Parsedown();
128 $content = $Parsedown->text( $content );
129 return $content;
130 }
131
132 function get_post_language( $postId ) {
133 $locale = get_locale();
134 $code = strtolower( substr( $locale, 0, 2 ) );
135 $lang_codes = array(
136 'aa' => 'Afar',
137 'ab' => 'Abkhazian',
138 'af' => 'Afrikaans',
139 'ak' => 'Akan',
140 'sq' => 'Albanian',
141 'am' => 'Amharic',
142 'ar' => 'Arabic',
143 'an' => 'Aragonese',
144 'hy' => 'Armenian',
145 'as' => 'Assamese',
146 'av' => 'Avaric',
147 'ae' => 'Avestan',
148 'ay' => 'Aymara',
149 'az' => 'Azerbaijani',
150 'ba' => 'Bashkir',
151 'bm' => 'Bambara',
152 'eu' => 'Basque',
153 'be' => 'Belarusian',
154 'bn' => 'Bengali',
155 'bh' => 'Bihari',
156 'bi' => 'Bislama',
157 'bs' => 'Bosnian',
158 'br' => 'Breton',
159 'bg' => 'Bulgarian',
160 'my' => 'Burmese',
161 'ca' => 'Catalan; Valencian',
162 'ch' => 'Chamorro',
163 'ce' => 'Chechen',
164 'zh' => 'Chinese',
165 'cu' => 'Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic',
166 'cv' => 'Chuvash',
167 'kw' => 'Cornish',
168 'co' => 'Corsican',
169 'cr' => 'Cree',
170 'cs' => 'Czech',
171 'da' => 'Danish',
172 'dv' => 'Divehi; Dhivehi; Maldivian',
173 'nl' => 'Dutch; Flemish',
174 'dz' => 'Dzongkha',
175 'en' => 'English',
176 'eo' => 'Esperanto',
177 'et' => 'Estonian',
178 'ee' => 'Ewe',
179 'fo' => 'Faroese',
180 'fj' => 'Fijjian',
181 'fi' => 'Finnish',
182 'fr' => 'French',
183 'fy' => 'Western Frisian',
184 'ff' => 'Fulah',
185 'ka' => 'Georgian',
186 'de' => 'German',
187 'gd' => 'Gaelic; Scottish Gaelic',
188 'ga' => 'Irish',
189 'gl' => 'Galician',
190 'gv' => 'Manx',
191 'el' => 'Greek, Modern',
192 'gn' => 'Guarani',
193 'gu' => 'Gujarati',
194 'ht' => 'Haitian; Haitian Creole',
195 'ha' => 'Hausa',
196 'he' => 'Hebrew',
197 'hz' => 'Herero',
198 'hi' => 'Hindi',
199 'ho' => 'Hiri Motu',
200 'hu' => 'Hungarian',
201 'ig' => 'Igbo',
202 'is' => 'Icelandic',
203 'io' => 'Ido',
204 'ii' => 'Sichuan Yi',
205 'iu' => 'Inuktitut',
206 'ie' => 'Interlingue',
207 'ia' => 'Interlingua (International Auxiliary Language Association)',
208 'id' => 'Indonesian',
209 'ik' => 'Inupiaq',
210 'it' => 'Italian',
211 'jv' => 'Javanese',
212 'ja' => 'Japanese',
213 'kl' => 'Kalaallisut; Greenlandic',
214 'kn' => 'Kannada',
215 'ks' => 'Kashmiri',
216 'kr' => 'Kanuri',
217 'kk' => 'Kazakh',
218 'km' => 'Central Khmer',
219 'ki' => 'Kikuyu; Gikuyu',
220 'rw' => 'Kinyarwanda',
221 'ky' => 'Kirghiz; Kyrgyz',
222 'kv' => 'Komi',
223 'kg' => 'Kongo',
224 'ko' => 'Korean',
225 'kj' => 'Kuanyama; Kwanyama',
226 'ku' => 'Kurdish',
227 'lo' => 'Lao',
228 'la' => 'Latin',
229 'lv' => 'Latvian',
230 'li' => 'Limburgan; Limburger; Limburgish',
231 'ln' => 'Lingala',
232 'lt' => 'Lithuanian',
233 'lb' => 'Luxembourgish; Letzeburgesch',
234 'lu' => 'Luba-Katanga',
235 'lg' => 'Ganda',
236 'mk' => 'Macedonian',
237 'mh' => 'Marshallese',
238 'ml' => 'Malayalam',
239 'mi' => 'Maori',
240 'mr' => 'Marathi',
241 'ms' => 'Malay',
242 'mg' => 'Malagasy',
243 'mt' => 'Maltese',
244 'mo' => 'Moldavian',
245 'mn' => 'Mongolian',
246 'na' => 'Nauru',
247 'nv' => 'Navajo; Navaho',
248 'nr' => 'Ndebele, South; South Ndebele',
249 'nd' => 'Ndebele, North; North Ndebele',
250 'ng' => 'Ndonga',
251 'ne' => 'Nepali',
252 'nn' => 'Norwegian Nynorsk; Nynorsk, Norwegian',
253 'nb' => 'Bokmål, Norwegian, Norwegian Bokmål',
254 'no' => 'Norwegian',
255 'ny' => 'Chichewa; Chewa; Nyanja',
256 'oc' => 'Occitan, Provençal',
257 'oj' => 'Ojibwa',
258 'or' => 'Oriya',
259 'om' => 'Oromo',
260 'os' => 'Ossetian; Ossetic',
261 'pa' => 'Panjabi; Punjabi',
262 'fa' => 'Persian',
263 'pi' => 'Pali',
264 'pl' => 'Polish',
265 'pt' => 'Portuguese',
266 'ps' => 'Pushto',
267 'qu' => 'Quechua',
268 'rm' => 'Romansh',
269 'ro' => 'Romanian',
270 'rn' => 'Rundi',
271 'ru' => 'Russian',
272 'sg' => 'Sango',
273 'sa' => 'Sanskrit',
274 'sr' => 'Serbian',
275 'hr' => 'Croatian',
276 'si' => 'Sinhala; Sinhalese',
277 'sk' => 'Slovak',
278 'sl' => 'Slovenian',
279 'se' => 'Northern Sami',
280 'sm' => 'Samoan',
281 'sn' => 'Shona',
282 'sd' => 'Sindhi',
283 'so' => 'Somali',
284 'st' => 'Sotho, Southern',
285 'es' => 'Spanish; Castilian',
286 'sc' => 'Sardinian',
287 'ss' => 'Swati',
288 'su' => 'Sundanese',
289 'sw' => 'Swahili',
290 'sv' => 'Swedish',
291 'ty' => 'Tahitian',
292 'ta' => 'Tamil',
293 'tt' => 'Tatar',
294 'te' => 'Telugu',
295 'tg' => 'Tajik',
296 'tl' => 'Tagalog',
297 'th' => 'Thai',
298 'bo' => 'Tibetan',
299 'ti' => 'Tigrinya',
300 'to' => 'Tonga (Tonga Islands)',
301 'tn' => 'Tswana',
302 'ts' => 'Tsonga',
303 'tk' => 'Turkmen',
304 'tr' => 'Turkish',
305 'tw' => 'Twi',
306 'ug' => 'Uighur; Uyghur',
307 'uk' => 'Ukrainian',
308 'ur' => 'Urdu',
309 'uz' => 'Uzbek',
310 've' => 'Venda',
311 'vi' => 'Vietnamese',
312 'vo' => 'Volapük',
313 'cy' => 'Welsh',
314 'wa' => 'Walloon',
315 'wo' => 'Wolof',
316 'xh' => 'Xhosa',
317 'yi' => 'Yiddish',
318 'yo' => 'Yoruba',
319 'za' => 'Zhuang; Chuang',
320 'zu' => 'Zulu',
321 );
322 $language = strtr( $code, $lang_codes );
323 $lang = apply_filters( 'wpml_post_language_details', null, $postId );
324 if ( !empty( $lang ) ) {
325 $language = $lang['display_name'];
326 }
327 return strtolower( $language );
328 }
329 #endregion
330
331 #region Users/Sessions Helpers
332
333 function get_session_id() {
334 if ( isset( $_COOKIE['mwai_session_id'] ) ) {
335 return $_COOKIE['mwai_session_id'];
336 }
337 return "N/A";
338 }
339
340 // Get the UserID from the data, or from the current user
341 function get_user_id( $data = null ) {
342 if ( isset( $data ) && isset( $data['userId'] ) ) {
343 return (int)$data['userId'];
344 }
345 if ( is_user_logged_in() ) {
346 $current_user = wp_get_current_user();
347 if ( $current_user->ID > 0 ) {
348 return $current_user->ID;
349 }
350 }
351 return null;
352 }
353
354 function get_ip_address( $data = null ) {
355 if ( isset( $data ) && isset( $data['ip'] ) ) {
356 $data['ip'] = (string)$data['ip'];
357 }
358 else {
359 if ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
360 $data['ip'] = sanitize_text_field( $_SERVER['REMOTE_ADDR'] );
361 }
362 else if ( isset( $_SERVER['HTTP_CLIENT_IP'] ) ) {
363 $data['ip'] = sanitize_text_field( $_SERVER['HTTP_CLIENT_IP'] );
364 }
365 else if ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
366 $data['ip'] = sanitize_text_field( $_SERVER['HTTP_X_FORWARDED_FOR'] );
367 }
368 }
369 return $data['ip'];
370 }
371
372 #endregion
373
374 #region Other Helpers
375
376 function isUrl( $url ) {
377 return strpos( $url, 'http' ) === 0 ? true : false;
378 }
379
380 function getPostTypes() {
381 $excluded = array( 'attachment', 'revision', 'nav_menu_item' );
382 $post_types = array();
383 $types = get_post_types( array( 'public' => true ), 'objects' );
384 foreach ( $types as $type ) {
385 if ( in_array( $type->name, $excluded ) ) {
386 continue;
387 }
388 $post_types[] = array(
389 'name' => $type->labels->name,
390 'type' => $type->name,
391 );
392 }
393 return $post_types;
394 }
395
396 function getCleanPost( $post ) {
397 if ( is_object( $post ) ) {
398 $post = (array)$post;
399 }
400 $language = $this->get_post_language( $post['ID'] );
401 $content = apply_filters( 'mwai_pre_post_content', $post['post_content'], $post['ID'] );
402 $content = $this->cleanText( $content );
403 $content = apply_filters( 'mwai_post_content', $content, $post['ID'] );
404 $title = $post['post_title'];
405 $excerpt = $post['post_excerpt'];
406 $url = get_permalink( $post['ID'] );
407 $checksum = wp_hash( $content . $title . $url );
408 return [
409 'postId' => $post['ID'],
410 'title' => $title,
411 'content' => $content,
412 'excerpt' => $excerpt,
413 'url' => $url,
414 'language' => $language,
415 'checksum' => $checksum,
416 ];
417 }
418
419 #endregion
420
421 #region Usage & Costs
422
423 public function dynamic_max_tokens( $tokens, $text ) {
424 // Approximation (fast, no lib)
425 $asciiCount = 0;
426 $nonAsciiCount = 0;
427 for ( $i = 0; $i < mb_strlen( $text ); $i++ ) {
428 $char = mb_substr( $text, $i, 1 );
429 if ( ord( $char ) < 128 ) {
430 $asciiCount++;
431 }
432 else {
433 $nonAsciiCount++;
434 }
435 }
436 $asciiTokens = $asciiCount / 3.5;
437 $nonAsciiTokens = $nonAsciiCount * 2.5;
438 $tokens = $asciiTokens + $nonAsciiTokens;
439
440 // More exact (slower, and lib)
441 if ( PHP_VERSION_ID >= 70400 && function_exists( 'mb_convert_encoding' ) ) {
442 try {
443 $token_array = Encoder::encode( $text );
444 if ( !empty( $token_array ) ) {
445 $tokens = count( $token_array );
446 }
447 }
448 catch ( Exception $e ) {
449 error_log( $e->getMessage() );
450 }
451 }
452
453 $tokens = $tokens;
454 return (int)$tokens;
455 }
456
457 public function record_tokens_usage( $model, $prompt_tokens, $completion_tokens = 0 ) {
458 if ( !is_numeric( $prompt_tokens ) ) {
459 throw new Exception( 'Record usage: prompt_tokens is not a number.' );
460 }
461 if ( !is_numeric( $completion_tokens ) ) {
462 $completion_tokens = 0;
463 }
464 if ( !$model ) {
465 throw new Exception( 'Record usage: model is missing.' );
466 }
467 $usage = $this->get_option( 'openai_usage' );
468 $month = date( 'Y-m' );
469 if ( !isset( $usage[$month] ) ) {
470 $usage[$month] = array();
471 }
472 if ( !isset( $usage[$month][$model] ) ) {
473 $usage[$month][$model] = array(
474 'prompt_tokens' => 0,
475 'completion_tokens' => 0,
476 'total_tokens' => 0
477 );
478 }
479 $usage[$month][$model]['prompt_tokens'] += $prompt_tokens;
480 $usage[$month][$model]['completion_tokens'] += $completion_tokens;
481 $usage[$month][$model]['total_tokens'] += $prompt_tokens + $completion_tokens;
482 $this->update_option( 'openai_usage', $usage );
483 return [
484 'prompt_tokens' => $prompt_tokens,
485 'completion_tokens' => $completion_tokens,
486 'total_tokens' => $prompt_tokens + $completion_tokens
487 ];
488 }
489
490 public function record_images_usage( $model, $resolution, $images ) {
491 if ( !$model || !$resolution || !$images ) {
492 throw new Exception( 'Missing parameters for record_image_usage.' );
493 }
494 $usage = $this->get_option( 'openai_usage' );
495 $month = date( 'Y-m' );
496 if ( !isset( $usage[$month] ) ) {
497 $usage[$month] = array();
498 }
499 if ( !isset( $usage[$month][$model] ) ) {
500 $usage[$month][$model] = array(
501 'resolution' => array(),
502 'images' => 0
503 );
504 }
505 if ( !isset( $usage[$month][$model]['resolution'][$resolution] ) ) {
506 $usage[$month][$model]['resolution'][$resolution] = 0;
507 }
508 $usage[$month][$model]['resolution'][$resolution] += $images;
509 $usage[$month][$model]['images'] += $images;
510 $this->update_option( 'openai_usage', $usage );
511 return [
512 'resolution' => $resolution,
513 'images' => $images
514 ];
515 }
516
517 #endregion
518
519 #region Options
520 function get_all_options() {
521 $options = get_option( $this->option_name, null );
522 foreach ( MWAI_OPTIONS as $key => $value ) {
523 if ( !isset( $options[$key] ) ) {
524 $options[$key] = $value;
525 }
526 if ( $key === 'languages' ) {
527 // TODO: If we decide to make a set of options for languages, we can keep it in the settings
528 $options[$key] = MWAI_LANGUAGES;
529 $options[$key] = apply_filters( 'mwai_languages', $options[$key] );
530 }
531 }
532 $options['shortcode_chat_default_params'] = MWAI_CHATBOT_PARAMS;
533 $options['default_limits'] = MWAI_LIMITS;
534 $options['openai_models'] = MWAI_OPENAI_MODELS;
535 return $options;
536 }
537
538 // Validate and keep the options clean and logical.
539 function sanitize_options() {
540 $options = $this->get_all_options();
541 $needs_update = false;
542
543 // We can sanitize our future options here, let's always remember it.
544 // Now, it is empty...
545
546 if ( $needs_update ) {
547 update_option( $this->option_name, $options, false );
548 }
549 return $options;
550 }
551
552 function update_options( $options ) {
553 if ( !update_option( $this->option_name, $options, false ) ) {
554 return false;
555 }
556 $options = $this->sanitize_options();
557 return $options;
558 }
559
560 function update_option( $option, $value ) {
561 $options = $this->get_all_options();
562 $options[$option] = $value;
563 return $this->update_options( $options );
564 }
565
566 function get_option( $option, $default = null ) {
567 $options = $this->get_all_options();
568 return $options[$option] ?? $default;
569 }
570 #endregion
571 }
572
573 ?>