PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 1.3.81
AI Engine – The Chatbot, AI Framework & MCP for WordPress v1.3.81
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
571 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 = $this->cleanText( $post['post_content'] );
402 $title = $post['post_title'];
403 $excerpt = $post['post_excerpt'];
404 $url = get_permalink( $post['ID'] );
405 $checksum = wp_hash( $content . $title . $url );
406 return [
407 'postId' => $post['ID'],
408 'title' => $title,
409 'content' => $content,
410 'excerpt' => $excerpt,
411 'url' => $url,
412 'language' => $language,
413 'checksum' => $checksum,
414 ];
415 }
416
417 #endregion
418
419 #region Usage & Costs
420
421 public function dynamic_max_tokens( $tokens, $text ) {
422 // Approximation (fast, no lib)
423 $asciiCount = 0;
424 $nonAsciiCount = 0;
425 for ( $i = 0; $i < mb_strlen( $text ); $i++ ) {
426 $char = mb_substr( $text, $i, 1 );
427 if ( ord( $char ) < 128 ) {
428 $asciiCount++;
429 }
430 else {
431 $nonAsciiCount++;
432 }
433 }
434 $asciiTokens = $asciiCount / 3.5;
435 $nonAsciiTokens = $nonAsciiCount * 2.5;
436 $tokens = $asciiTokens + $nonAsciiTokens;
437
438 // More exact (slower, and lib)
439 if ( PHP_VERSION_ID >= 70400 && function_exists( 'mb_convert_encoding' ) ) {
440 try {
441 $token_array = Encoder::encode( $text );
442 if ( !empty( $token_array ) ) {
443 $tokens = count( $token_array );
444 }
445 }
446 catch ( Exception $e ) {
447 error_log( $e->getMessage() );
448 }
449 }
450
451 $tokens = $tokens;
452 return (int)$tokens;
453 }
454
455 public function record_tokens_usage( $model, $prompt_tokens, $completion_tokens = 0 ) {
456 if ( !is_numeric( $prompt_tokens ) ) {
457 throw new Exception( 'Record usage: prompt_tokens is not a number.' );
458 }
459 if ( !is_numeric( $completion_tokens ) ) {
460 $completion_tokens = 0;
461 }
462 if ( !$model ) {
463 throw new Exception( 'Record usage: model is missing.' );
464 }
465 $usage = $this->get_option( 'openai_usage' );
466 $month = date( 'Y-m' );
467 if ( !isset( $usage[$month] ) ) {
468 $usage[$month] = array();
469 }
470 if ( !isset( $usage[$month][$model] ) ) {
471 $usage[$month][$model] = array(
472 'prompt_tokens' => 0,
473 'completion_tokens' => 0,
474 'total_tokens' => 0
475 );
476 }
477 $usage[$month][$model]['prompt_tokens'] += $prompt_tokens;
478 $usage[$month][$model]['completion_tokens'] += $completion_tokens;
479 $usage[$month][$model]['total_tokens'] += $prompt_tokens + $completion_tokens;
480 $this->update_option( 'openai_usage', $usage );
481 return [
482 'prompt_tokens' => $prompt_tokens,
483 'completion_tokens' => $completion_tokens,
484 'total_tokens' => $prompt_tokens + $completion_tokens
485 ];
486 }
487
488 public function record_images_usage( $model, $resolution, $images ) {
489 if ( !$model || !$resolution || !$images ) {
490 throw new Exception( 'Missing parameters for record_image_usage.' );
491 }
492 $usage = $this->get_option( 'openai_usage' );
493 $month = date( 'Y-m' );
494 if ( !isset( $usage[$month] ) ) {
495 $usage[$month] = array();
496 }
497 if ( !isset( $usage[$month][$model] ) ) {
498 $usage[$month][$model] = array(
499 'resolution' => array(),
500 'images' => 0
501 );
502 }
503 if ( !isset( $usage[$month][$model]['resolution'][$resolution] ) ) {
504 $usage[$month][$model]['resolution'][$resolution] = 0;
505 }
506 $usage[$month][$model]['resolution'][$resolution] += $images;
507 $usage[$month][$model]['images'] += $images;
508 $this->update_option( 'openai_usage', $usage );
509 return [
510 'resolution' => $resolution,
511 'images' => $images
512 ];
513 }
514
515 #endregion
516
517 #region Options
518 function get_all_options() {
519 $options = get_option( $this->option_name, null );
520 foreach ( MWAI_OPTIONS as $key => $value ) {
521 if ( !isset( $options[$key] ) ) {
522 $options[$key] = $value;
523 }
524 if ( $key === 'languages' ) {
525 // TODO: If we decide to make a set of options for languages, we can keep it in the settings
526 $options[$key] = MWAI_LANGUAGES;
527 $options[$key] = apply_filters( 'mwai_languages', $options[$key] );
528 }
529 }
530 $options['shortcode_chat_default_params'] = MWAI_CHATBOT_PARAMS;
531 $options['default_limits'] = MWAI_LIMITS;
532 $options['openai_models'] = MWAI_OPENAI_MODELS;
533 return $options;
534 }
535
536 // Validate and keep the options clean and logical.
537 function sanitize_options() {
538 $options = $this->get_all_options();
539 $needs_update = false;
540
541 // We can sanitize our future options here, let's always remember it.
542 // Now, it is empty...
543
544 if ( $needs_update ) {
545 update_option( $this->option_name, $options, false );
546 }
547 return $options;
548 }
549
550 function update_options( $options ) {
551 if ( !update_option( $this->option_name, $options, false ) ) {
552 return false;
553 }
554 $options = $this->sanitize_options();
555 return $options;
556 }
557
558 function update_option( $option, $value ) {
559 $options = $this->get_all_options();
560 $options[$option] = $value;
561 return $this->update_options( $options );
562 }
563
564 function get_option( $option, $default = null ) {
565 $options = $this->get_all_options();
566 return $options[$option] ?? $default;
567 }
568 #endregion
569 }
570
571 ?>